From a57baabc95f78624b4da1128503e8283d53de638 Mon Sep 17 00:00:00 2001 From: phate89 Date: Wed, 15 Feb 2023 12:37:13 +0100 Subject: [PATCH 001/145] [script.module.phate89] 1.2.2+matrix.1 (#2396) --- script.module.phate89/addon.xml | 2 +- script.module.phate89/changelog.txt | 3 ++ .../lib/phate89lib/kodiutils.py | 33 +++++++++++++------ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/script.module.phate89/addon.xml b/script.module.phate89/addon.xml index 10dc439a4..f25a3bada 100644 --- a/script.module.phate89/addon.xml +++ b/script.module.phate89/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/script.module.phate89/changelog.txt b/script.module.phate89/changelog.txt index a93a6edeb..439d9c5dd 100644 --- a/script.module.phate89/changelog.txt +++ b/script.module.phate89/changelog.txt @@ -1,3 +1,6 @@ +1.2.2 +- fixed crashes after nexus changes (thx to nixxo and ChristianSumma) + 1.2.1 - added function to get formatted date - code cleanup and improvements diff --git a/script.module.phate89/lib/phate89lib/kodiutils.py b/script.module.phate89/lib/phate89lib/kodiutils.py index 76fe47740..fdbd7ecb4 100644 --- a/script.module.phate89/lib/phate89lib/kodiutils.py +++ b/script.module.phate89/lib/phate89lib/kodiutils.py @@ -8,6 +8,7 @@ import xbmcaddon import xbmcplugin import xbmcgui +import xbmcvfs from . import staticutils ADDON = xbmcaddon.Addon() @@ -16,8 +17,8 @@ VERSION = ADDON.getAddonInfo('version') PATH = ADDON.getAddonInfo('path') DATA_PATH = ADDON.getAddonInfo('profile') -PATH_T = xbmc.translatePath(PATH) -DATA_PATH_T = xbmc.translatePath(DATA_PATH) +PATH_T = xbmcvfs.translatePath(PATH) +DATA_PATH_T = xbmcvfs.translatePath(DATA_PATH) IMAGE_PATH_T = os.path.join(PATH_T, 'resources', 'media', "") LANGUAGE = ADDON.getLocalizedString KODILANGUAGE = xbmc.getLocalizedString @@ -89,13 +90,13 @@ def showOkDialog(heading, line): xbmcgui.Dialog().ok(heading, line) -def addListItem(label="", params=None, label2=None, thumb=None, fanart=None, poster=None, arts=None, - videoInfo=None, properties=None, isFolder=True): +def createListItem(label="", params=None, label2=None, thumb=None, fanart=None, poster=None, arts=None, + videoInfo=None, properties=None, isFolder=True, path=None, subs=None): if arts is None: arts = {} if properties is None: properties = {} - item = xbmcgui.ListItem(label, label2) + item = xbmcgui.ListItem(label, label2, path) if thumb: arts['thumb'] = thumb if fanart: @@ -104,22 +105,33 @@ def addListItem(label="", params=None, label2=None, thumb=None, fanart=None, pos arts['poster'] = poster item.setArt(arts) item.setInfo('video', videoInfo) + if subs is not None: + item.setSubtitles(subs) if not isFolder: properties['IsPlayable'] = 'true' + for key, value in list(properties.items()): + item.setProperty(key, value) + return item + + +def addListItem(label="", params=None, label2=None, thumb=None, fanart=None, poster=None, arts=None, + videoInfo=None, properties=None, isFolder=True, path=None, subs=None): if isinstance(params, dict): url = staticutils.parameters(params) else: url = params - for key, value in list(properties.items()): - item.setProperty(key, value) + item = createListItem(label=label, params=params, label2=label2, + thumb=thumb, fanart=fanart, poster=poster, + arts=arts, videoInfo=videoInfo, properties=properties, + subs=subs, isFolder=isFolder) return xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=item, isFolder=isFolder) -def setResolvedUrl(url="", solved=True, subs=None, headers=None, ins=None, insdata=None): +def setResolvedUrl(url="", solved=True, subs=None, headers=None, ins=None, insdata=None, item=None, exit=True): headerUrl = "" if headers: headerUrl = urlencode(headers) - item = xbmcgui.ListItem(path=url + "|" + headerUrl) + item = xbmcgui.ListItem(path=url + "|" + headerUrl) if item is None else item if subs is not None: item.setSubtitles(subs) if ins: @@ -129,7 +141,8 @@ def setResolvedUrl(url="", solved=True, subs=None, headers=None, ins=None, insda for key, value in list(insdata.items()): item.setProperty(ins + '.' + key, value) xbmcplugin.setResolvedUrl(HANDLE, solved, item) - sys.exit() + if exit: + sys.exit() def append_subtitle(sUrl, subtitlename, sync=False, provider=None): From 705410b04ce86fc3e09ef2e2bb9f9982c6ee7f85 Mon Sep 17 00:00:00 2001 From: Heckie Date: Wed, 15 Feb 2023 13:20:47 +0100 Subject: [PATCH 002/145] [script.timers] 3.5.0 (#2405) --- script.timers/addon.xml | 23 +- script.timers/main.py | 1 - script.timers/migration.py | 22 +- .../resource.language.de_de/strings.po | 60 +++- .../resource.language.en_gb/strings.po | 56 ++- .../lib/contextmenu/abstract_set_timer.py | 45 ++- .../lib/contextmenu/set_quick_epg_timer.py | 20 +- .../resources/lib/contextmenu/set_timer.py | 23 +- .../resources/lib/player/player_utils.py | 8 +- .../resources/lib/timer/concurrency.py | 154 ++++++++ script.timers/resources/lib/timer/period.py | 32 ++ .../resources/lib/timer/scheduler.py | 54 ++- .../resources/lib/timer/scheduleraction.py | 65 ++-- script.timers/resources/lib/timer/storage.py | 337 +++++++++--------- script.timers/resources/lib/timer/timer.py | 162 +++++++-- .../resources/lib/utils/settings_utils.py | 18 +- .../resources/lib/utils/vfs_utils.py | 2 +- script.timers/resources/settings.xml | 53 ++- 18 files changed, 834 insertions(+), 301 deletions(-) create mode 100644 script.timers/resources/lib/timer/concurrency.py diff --git a/script.timers/addon.xml b/script.timers/addon.xml index 1ae98694e..613e520af 100644 --- a/script.timers/addon.xml +++ b/script.timers/addon.xml @@ -1,5 +1,5 @@ - + @@ -31,24 +31,24 @@ A powerful timer addon with the following features * Unlimited timer slots. All of them can be quickly set up by using context menu * single-click-setup for sleep and doze timers -* Timers can play any resource that it available in Kodi, e.g. music folders, video files, TV/radio programs, slideshows, ressources from 3rd party plugins, e.g. Zattoo channels. +* Timers can play any resource that it available in KODI, e.g. music folders, video files, TV/radio programs, slideshows, resources from 3rd party plugins, e.g. Zattoo channels. * Timers can be set from TV / Radio EPG, One-click-setup from epg (Quick Timer) * Different schedule modes: once, everyday, Mon-Fri, Fri-Sat, Sat-Sun, Sun-Thu, Mon-Thu, specific weekday and many more * Date change is supported, e.g. from 23:30 (p.m.) until 1:30 (a.m.) * Shuffle, repeat, 2 end modes, i.e. duration or specific time -* Actions related to media: start media and stop at end, just start media, start media at end, stop media immediately, stop media at end, powerdown system +* Actions related to media: start media and stop at end, just start media, start media at end, stop media immediately, stop media at end, power down system * Linear fading in timer period: fade-in, fade-out, no fading. Min and max volume can be set for each timer * Custom label for timer -* After KODI startup timers, that are in period, start retroactivly although KODI was not running at start time. Fading volume is calculated correctly. -* Feature in order to prevent that display is turned off if Kodi idles but is not in fullscreen mode -* MS Windows only: Feature in order to prevent that Windows displays lock screen if Kodi idles +* After KODI startup timers, that are in period, start retroactively although KODI was not running at start time. Fading volume is calculated correctly. +* Feature in order to prevent that display is turned off if KODI idles but is not in full screen mode +* MS Windows only: Feature in order to prevent that Windows displays lock screen if KODI idles Timer Addon mit folgenden Funktionen -* 15 Timer, die eingestellt werden können. Alle Timer können über das Kontextmenü geöffnet werden -* 2 zusätzliche Timer für "Einschlaf"- und "Schlummer"-Timer mit nur einem Klick +* Unbegrenzte Anzahl an Timer, die eingestellt werden können. Alle Timer können über das Kontextmenü geöffnet werden +* Timer für "Einschlaf"- und "Schlummer"-Timer mit nur einem Klick * Timer können alle Medien starten, die in Kodi sind wie Musik, Video, TV/Radio programme, Diashows, andere Addons, z.B. Zattoo. * Einstellung mit nur einem Klick aus EPG (Quick Timer) -* Verschiedene Zeitplanungen möglich: einmalig, pro Wochentag, Mo-Fr, Fr-Sa, Sa-So, So-Do, Mo-Do u.v.m. +* Beliebige Zeitplanungen möglich: einmalig, pro Wochentag, Mo-Fr, Fr-Sa, Sa-So, So-Do, Mo-Do, ... * Tageswechsel wird unterstützt, z.B. Timer von 23:30 bis 1:30 am nächsten Tag * Dauer kann über Zeitraum oder Zeitpunkt eingestellt werden * Aktionen mit Medien: starte Wiedergabe und beende diese nach Ablauf, starte Wiedergabe, starte Wiedergabe bei Ablauf, stoppe Wiedergabe sofort, stoppe Wiedergabe nach Ablauf, fahre System herunter @@ -65,6 +65,11 @@ https://github.com/Heckie75/kodi-addon-timers https://github.com/Heckie75/kodi-addon-timers +v3.5.0 (2023-02-07) +- New feature: priority of timers and competitive behavior +- New feature: System action to put playing device on standby via a CEC peripheral +- Fixed issue so that favourites can be scheduled again + v3.4.0 (2023-01-10) - New feature: Media action in order to pause audio or video, feature request #21 - Refactoring: moved state to timer object diff --git a/script.timers/main.py b/script.timers/main.py index 0265870e6..f8571d1f0 100644 --- a/script.timers/main.py +++ b/script.timers/main.py @@ -1,5 +1,4 @@ import xbmcaddon - from resources.lib.contextmenu.set_timer import SetTimer from resources.lib.player.player import Player from resources.lib.player.player_utils import preview, reset_volume diff --git a/script.timers/migration.py b/script.timers/migration.py index 4227f97df..1ff30fbba 100644 --- a/script.timers/migration.py +++ b/script.timers/migration.py @@ -1,7 +1,7 @@ import xbmc import xbmcaddon - -from resources.lib.timer import storage +from resources.lib.timer.concurrency import DEFAULT_PRIO +from resources.lib.timer.storage import Storage from resources.lib.utils.settings_utils import ( activate_on_settings_changed_events, deactivate_on_settings_changed_events) @@ -189,13 +189,14 @@ def get_item_from_setting(timer_id: int) -> dict: except: pass - storage._save_to_storage(storage=_storage) + Storage()._save_to_storage(storage=_storage) return 5 def migrate_from_5_to_6(addon: xbmcaddon.Addon) -> int: + storage = Storage() items = storage._load_from_storage() for item in items: item["start_offset"] = 0 @@ -207,6 +208,18 @@ def migrate_from_5_to_6(addon: xbmcaddon.Addon) -> int: return 6 +def migrate_from_6_to_7(addon: xbmcaddon.Addon) -> int: + + storage = Storage() + items = storage._load_from_storage() + for item in items: + item["priority"] = DEFAULT_PRIO + + storage._save_to_storage(items) + + return 7 + + def migrate() -> None: addon = xbmcaddon.Addon() @@ -230,6 +243,9 @@ def migrate() -> None: if settingsVersion == 5: settingsVersion = migrate_from_5_to_6(addon) + if settingsVersion == 6: + settingsVersion = migrate_from_6_to_7(addon) + addon.setSettingInt("settingsVersion", settingsVersion) activate_on_settings_changed_events() diff --git a/script.timers/resources/language/resource.language.de_de/strings.po b/script.timers/resources/language/resource.language.de_de/strings.po index 4aa606049..38c13ec18 100644 --- a/script.timers/resources/language/resource.language.de_de/strings.po +++ b/script.timers/resources/language/resource.language.de_de/strings.po @@ -65,10 +65,18 @@ msgctxt "#32027" msgid "Timers" msgstr "Timers" +msgctxt "#32028" +msgid "Priority" +msgstr "Priorität" + msgctxt "#32029" msgid "Timer deleted" msgstr "Timer gelöscht" +msgctxt "#32030" +msgid "Presets" +msgstr "Voreinstellungen" + msgctxt "#32032" msgid "Prevent lock screen" msgstr "Verhindere Bildschirmsperre" @@ -109,6 +117,18 @@ msgctxt "#32042" msgid "from" msgstr "von" +msgctxt "#32050" +msgid "This timer interrupts other timers" +msgstr "Dieser Timer unterbricht andere Timer" + +msgctxt "#32051" +msgid "Other timers interrupt this timer" +msgstr "Andere Timer unterbrechen diesen Timer" + +msgctxt "#32052" +msgid "Is %s more important?" +msgstr "Ist %s wichtiger?" + msgctxt "#32060" msgid "Schedule" msgstr "Zeitplanung" @@ -221,13 +241,17 @@ msgctxt "#32090" msgid "Volume" msgstr "Lautstärke" +msgctxt "#32091" +msgid "Fading" +msgstr "Ein-/Ausblenden" + msgctxt "#32092" msgid "Default volume" msgstr "Voreingestellte Lautstärke" -msgctxt "#32091" -msgid "Fading" -msgstr "Ein-/Ausblenden" +msgctxt "#32093" +msgid "Standby TV via CEC" +msgstr "Standby TV via CEC" msgctxt "#32095" msgid "Low volume" @@ -473,6 +497,22 @@ msgctxt "#32171" msgid "Offset for timers in seconds" msgstr "Versatz für Timer in Sekunden" +msgctxt "#32180" +msgid "Presets for epg quick timer" +msgstr "Voreinstellungen für EPG Quicktimer" + +msgctxt "#32181" +msgid "don't interrupt existing timers" +msgstr "bestehende Timer nicht unterbrechen" + +msgctxt "#32182" +msgid "latest added timer" +msgstr "zuletzt hinzugefügter Timer" + +msgctxt "#32183" +msgid "always ask" +msgstr "jedes mal fragen" + msgctxt "#32200" msgid "Monday" msgstr "Montag" @@ -637,6 +677,14 @@ msgctxt "#32335" msgid "Enter the duration after the timer ends." msgstr "Gebe die Dauer ein, nach der der Timer endet." +msgctxt "#32336" +msgid "Set value if this timer is more important than other. Higher value means more important. Values starting from 10 always win against new timers." +msgstr "Setze einen Wert wenn dieser Timer wichtiger ist als andere. Je höher der Wert desto wichtiger. Werte ab 10 gewinnen immer gegen neue Timer." + +msgctxt "#32337" +msgid "This is a high priority timer which overrule new timers." +msgstr "Dies ist ein Timer mit hoher Priorität, der neue Timer übersteuern kann." + msgctxt "#32340" msgid "Select the media action of the timer. Note that you must add a media to the timer by utilizing the context menu first." msgstr "Wähle die Mediaaktion aus, die der Timer ausführen soll. Beachte, dass Du zuerst ein Mediaelement über das Kontextmenu dem Timer hinzufügen musst." @@ -699,4 +747,8 @@ msgstr "Verhindere Sperrbildschirm von MS Windows während Kodi ausgeführt wird msgctxt "#32385" msgid "Optionally you can set an offset in seconds." -msgstr "Optional kann ein Versatz in Sekunden angegeben werden." \ No newline at end of file +msgstr "Optional kann ein Versatz in Sekunden angegeben werden." + +msgctxt "#32386" +msgid "Determine the strategy for priority of new quicktimers." +msgstr "Bestimme die Strategie für die Priorität neuer Quicktimer." diff --git a/script.timers/resources/language/resource.language.en_gb/strings.po b/script.timers/resources/language/resource.language.en_gb/strings.po index 185d5bfd9..3742f5d98 100644 --- a/script.timers/resources/language/resource.language.en_gb/strings.po +++ b/script.timers/resources/language/resource.language.en_gb/strings.po @@ -65,10 +65,18 @@ msgctxt "#32027" msgid "Timers" msgstr "" +msgctxt "#32028" +msgid "Priority" +msgstr "" + msgctxt "#32029" msgid "Timer deleted" msgstr "" +msgctxt "#32030" +msgid "Presets" +msgstr "" + msgctxt "#32032" msgid "Prevent lock screen" msgstr "" @@ -109,6 +117,18 @@ msgctxt "#32042" msgid "from" msgstr "" +msgctxt "#32050" +msgid "This timer interrupts other timers" +msgstr "" + +msgctxt "#32051" +msgid "Other timers interrupt this timer" +msgstr "" + +msgctxt "#32052" +msgid "Is %s more important?" +msgstr "" + msgctxt "#32060" msgid "Schedule" msgstr "" @@ -221,12 +241,16 @@ msgctxt "#32090" msgid "Volume" msgstr "" +msgctxt "#32091" +msgid "Fading" +msgstr "" + msgctxt "#32092" msgid "Default volume" msgstr "" -msgctxt "#32091" -msgid "Fading" +msgctxt "#32093" +msgid "Standby TV via CEC" msgstr "" msgctxt "#32095" @@ -473,6 +497,22 @@ msgctxt "#32171" msgid "Offset for timers in seconds" msgstr "" +msgctxt "#32180" +msgid "Presets for epg quick timer" +msgstr "" + +msgctxt "#32181" +msgid "don't interrupt existing timers" +msgstr "" + +msgctxt "#32182" +msgid "latest added timer" +msgstr "" + +msgctxt "#32183" +msgid "always ask" +msgstr "" + msgctxt "#32200" msgid "Monday" msgstr "" @@ -637,6 +677,14 @@ msgctxt "#32335" msgid "Enter the duration after the timer ends." msgstr "" +msgctxt "#32336" +msgid "Set value if this timer is more important than other. Higher value means more important. Values starting from 10 always win against new timers." +msgstr "" + +msgctxt "#32337" +msgid "This is a high priority timer which overrule new timers." +msgstr "" + msgctxt "#32340" msgid "Select the media action of the timer. Note that you must add a media to the timer by utilizing the context menu first." msgstr "" @@ -700,3 +748,7 @@ msgstr "" msgctxt "#32385" msgid "Optionally you can set an offset in seconds." msgstr "" + +msgctxt "#32386" +msgid "Determine the strategy for priority of new quicktimers." +msgstr "" diff --git a/script.timers/resources/lib/contextmenu/abstract_set_timer.py b/script.timers/resources/lib/contextmenu/abstract_set_timer.py index 451759f44..1a8d6caab 100644 --- a/script.timers/resources/lib/contextmenu/abstract_set_timer.py +++ b/script.timers/resources/lib/contextmenu/abstract_set_timer.py @@ -6,17 +6,15 @@ import xbmcgui from resources.lib.contextmenu import pvr_utils from resources.lib.player.mediatype import VIDEO -from resources.lib.timer import storage +from resources.lib.timer.concurrency import determine_overlappings +from resources.lib.timer.storage import Storage from resources.lib.timer.timer import (END_TYPE_DURATION, END_TYPE_NO, FADE_OFF, MEDIA_ACTION_START_STOP, SYSTEM_ACTION_NONE, Timer) from resources.lib.utils import datetime_utils, vfs_utils -from resources.lib.utils.settings_utils import trigger_settings_changed_event - -CONFIRM_ESCAPE = -1 -CONFIRM_NO = 0 -CONFIRM_YES = 1 -CONFIRM_EDIT = 2 +from resources.lib.utils.settings_utils import (CONFIRM_CUSTOM, CONFIRM_ESCAPE, + CONFIRM_NO, CONFIRM_YES, + trigger_settings_changed_event) class AbstractSetTimer: @@ -24,6 +22,7 @@ class AbstractSetTimer: def __init__(self, label: str, path: str, timerid=-1) -> None: self.addon = xbmcaddon.Addon() + self.storage = Storage() if not self.is_supported(label, path): yes = xbmcgui.Dialog().yesno(heading=self.addon.getLocalizedString( @@ -96,6 +95,15 @@ def __init__(self, label: str, path: str, timerid=-1) -> None: timer.vol_min = vol_min timer.vol_max = vol_max + timer.init() + overlappings = determine_overlappings( + timer, self.storage.load_timers_from_storage(), ignore_high_prio=True) + if overlappings: + answer = self.handle_overlapping_timers( + timer, overlapping_timers=overlappings) + if answer in [CONFIRM_ESCAPE, CONFIRM_CUSTOM]: + return + confirm = self.confirm(timer) if confirm in [CONFIRM_ESCAPE, CONFIRM_NO]: return @@ -128,7 +136,7 @@ def ask_label(self, label: str, path: str, is_epg: bool, timer: Timer) -> str: def ask_timer(self, timerid: int) -> int: - return storage.get_next_id() + return self.storage.get_next_id() def ask_days(self, label: str, path: str, is_epg: bool, timer: Timer) -> 'list[int]': @@ -162,6 +170,13 @@ def ask_fader(self, timer: Timer) -> 'tuple[int, int, int]': return FADE_OFF, timer.vol_min, timer.vol_max + def handle_overlapping_timers(self, timer: Timer, overlapping_timers: 'list[Timer]') -> int: + + timer.priority = max(overlapping_timers, + key=lambda t: t.priority).priority + 1 + + return CONFIRM_YES + def confirm(self, timer: Timer) -> int: return CONFIRM_YES @@ -169,18 +184,14 @@ def confirm(self, timer: Timer) -> int: def post_apply(self, timer: Timer, confirm: int) -> None: if confirm == CONFIRM_YES: - lines = list() - lines.append(timer.periods_to_human_readable()) - if timer.system_action: - lines.append("%s: %s" % (self.addon.getLocalizedString(32081), - self.addon.getLocalizedString(32081 + timer.system_action))) - + msg = ("$H\n%s: $P" % self.addon.getLocalizedString( + 32081)) if timer.system_action else "$H" xbmcgui.Dialog().notification(heading=timer.label, - message="\n".join(lines), icon=vfs_utils.get_asset_path("icon.png")) + message=timer.format(msg), icon=vfs_utils.get_asset_path("icon.png")) def _get_timer_preselection(self, timerid: int, label: str, path: str) -> 'tuple[Timer,bool]': - timer = storage.load_timer_from_storage(timerid) + timer = self.storage.load_timer_from_storage(timerid) if not timer: timer = Timer(timerid) timer.vol_min = self.addon.getSettingInt("vol_min_default") @@ -239,5 +250,5 @@ def _get_timer_preselection(self, timerid: int, label: str, path: str) -> 'tuple def apply(self, timer: Timer) -> None: - storage.save_timer(timer=timer) + self.storage.save_timer(timer=timer) trigger_settings_changed_event() diff --git a/script.timers/resources/lib/contextmenu/set_quick_epg_timer.py b/script.timers/resources/lib/contextmenu/set_quick_epg_timer.py index e02b8dc64..7e65b923e 100644 --- a/script.timers/resources/lib/contextmenu/set_quick_epg_timer.py +++ b/script.timers/resources/lib/contextmenu/set_quick_epg_timer.py @@ -1,6 +1,8 @@ from resources.lib.contextmenu.abstract_set_timer import (CONFIRM_YES, AbstractSetTimer) -from resources.lib.timer import storage +from resources.lib.timer.concurrency import (ask_overlapping_timers, + get_next_higher_prio, + get_next_lower_prio) from resources.lib.timer.timer import Timer @@ -8,7 +10,7 @@ class SetQuickEpgTimer(AbstractSetTimer): def perform_ahead(self, timer: Timer) -> bool: - timers = storage.load_timers_from_storage() + timers = self.storage.load_timers_from_storage() found = -1 for i, t in enumerate(timers): @@ -32,6 +34,20 @@ def ask_repeat_resume(self, timer: Timer) -> 'tuple[bool, bool]': return False, True + def handle_overlapping_timers(self, timer: Timer, overlapping_timers: 'list[Timer]') -> int: + + strategy = self.addon.getSettingInt("quicktimer_priority") + if strategy == 0: + timer.priority = get_next_lower_prio(overlapping_timers) + + elif strategy == 1: + timer.priority = get_next_higher_prio(overlapping_timers) + + elif strategy == 2: + return ask_overlapping_timers(timer, overlapping_timers) + + return CONFIRM_YES + def confirm(self, timer: Timer) -> int: return CONFIRM_YES diff --git a/script.timers/resources/lib/contextmenu/set_timer.py b/script.timers/resources/lib/contextmenu/set_timer.py index b4fcbbc21..5a448bb77 100644 --- a/script.timers/resources/lib/contextmenu/set_timer.py +++ b/script.timers/resources/lib/contextmenu/set_timer.py @@ -1,6 +1,7 @@ import xbmcgui -from resources.lib.contextmenu.abstract_set_timer import (CONFIRM_EDIT, +from resources.lib.contextmenu.abstract_set_timer import (CONFIRM_CUSTOM, AbstractSetTimer) +from resources.lib.timer.concurrency import ask_overlapping_timers from resources.lib.timer.timer import (MEDIA_ACTION_START, MEDIA_ACTION_START_STOP, Timer) from resources.lib.utils.datetime_utils import DEFAULT_TIME @@ -71,20 +72,16 @@ def ask_action(self, label: str, path: str, is_epg: bool, timer: Timer) -> 'tupl return timer.system_action, MEDIA_ACTION_START_STOP if timer.duration != DEFAULT_TIME else MEDIA_ACTION_START - def confirm(self, timer: Timer) -> int: + def handle_overlapping_timers(self, timer: Timer, overlapping_timers: 'list[Timer]') -> int: + + return ask_overlapping_timers(timer, overlapping_timers) - line1 = timer.label - line2 = timer.periods_to_human_readable() - line3 = "%s: %s" % (self.addon.getLocalizedString(32070), - self.addon.getLocalizedString( - 32072) if timer.duration != DEFAULT_TIME else self.addon.getLocalizedString(32073) - ) - line4 = "%s: %s" % (self.addon.getLocalizedString(32091), - self.addon.getLocalizedString(32120 + timer.fade)) + def confirm(self, timer: Timer) -> int: + msg = "$L\n$H\n%s: $M\n%s: $F\n$O" % (self.addon.getLocalizedString( + 32070), self.addon.getLocalizedString(32091)) return xbmcgui.Dialog().yesnocustom(heading=self.addon.getLocalizedString(32107), - message="\n".join( - [line1, line2, line3, line4]), + message=timer.format(msg).strip(), customlabel=self.addon.getLocalizedString( 32102), nolabel=self.addon.getLocalizedString( @@ -93,7 +90,7 @@ def confirm(self, timer: Timer) -> int: def post_apply(self, timer: Timer, confirm: int) -> None: - if confirm == CONFIRM_EDIT: + if confirm == CONFIRM_CUSTOM: load_timer_into_settings(timer) self.addon.openSettings() else: diff --git a/script.timers/resources/lib/player/player_utils.py b/script.timers/resources/lib/player/player_utils.py index 464ae75c0..f199a50b4 100644 --- a/script.timers/resources/lib/player/player_utils.py +++ b/script.timers/resources/lib/player/player_utils.py @@ -2,7 +2,7 @@ import xbmcaddon import xbmcgui from resources.lib.player.mediatype import AUDIO, PICTURE, TYPES, VIDEO -from resources.lib.timer import storage +from resources.lib.timer.storage import Storage from resources.lib.utils.jsonrpc_utils import json_rpc from resources.lib.utils.vfs_utils import (build_playlist, convert_to_playlist, get_asset_path, get_files_and_type, @@ -36,13 +36,13 @@ def __str__(self) -> str: self.repeat, self.shuffled, self.speed) - + def preview(addon: xbmcaddon.Addon, timerid: int, player: 'xbmc.Player') -> None: - timer = storage.load_timer_from_storage(timerid) + timer = Storage().load_timer_from_storage(timerid) - if timer._is_playing_media_timer(): + if timer.is_playing_media_timer(): xbmcgui.Dialog().notification(addon.getLocalizedString(32027), timer.label, icon=get_asset_path("icon.png")) diff --git a/script.timers/resources/lib/timer/concurrency.py b/script.timers/resources/lib/timer/concurrency.py new file mode 100644 index 000000000..9859dbf35 --- /dev/null +++ b/script.timers/resources/lib/timer/concurrency.py @@ -0,0 +1,154 @@ +import xbmcaddon +import xbmcgui +from resources.lib.player.player_utils import get_types_replaced_by_type +from resources.lib.timer.period import Period, timedelta +from resources.lib.timer.timer import (MEDIA_ACTION_START, + MEDIA_ACTION_START_AT_END, + MEDIA_ACTION_START_STOP, + MEDIA_ACTION_STOP, + MEDIA_ACTION_STOP_AT_END, + MEDIA_ACTION_STOP_START, Timer) +from resources.lib.utils import datetime_utils +from resources.lib.utils.settings_utils import (CONFIRM_CUSTOM, CONFIRM_NO, + CONFIRM_YES) + +MIN_PRIO = -10 +MAX_PRIO = 12 +HIGH_PRIO_MARK = 10 +DEFAULT_PRIO = 0 + + +def get_next_lower_prio(timers: 'list[Timer]') -> int: + + _min = min(timers, key=lambda t: t.priority).priority - 1 + return max(_min, MIN_PRIO) + + +def get_next_higher_prio(timers: 'list[Timer]') -> int: + + _max = max(timers, key=lambda t: t.priority if t.priority < + HIGH_PRIO_MARK else DEFAULT_PRIO).priority + return _max + 1 if _max < HIGH_PRIO_MARK - 1 else _max + + +def determine_overlappings(timer: Timer, timers: 'list[Timer]', ignore_high_prio=False) -> 'list[Timer]': + + def _disturbs(types: 'list[str]', type2: str, media_action1: int, media_action2: int, period1: Period, period2: Period) -> bool: + + if media_action1 == MEDIA_ACTION_START_STOP: + td_play_media1 = period1.start + td_stop_media1 = period1.end + replace = type2 in types + + elif media_action1 == MEDIA_ACTION_START: + td_play_media1 = period1.start + td_stop_media1 = None + replace = type2 in types + + elif media_action1 == MEDIA_ACTION_START_AT_END: + td_play_media1 = period1.end + td_stop_media1 = None + replace = type2 in types + + elif media_action1 == MEDIA_ACTION_STOP_START: + td_play_media1 = period1.end + td_stop_media1 = period1.start + replace = type2 in types + + elif media_action1 == MEDIA_ACTION_STOP: + td_play_media1 = None + td_stop_media1 = period1.start + replace = True + + elif media_action1 == MEDIA_ACTION_STOP_AT_END: + td_play_media1 = None + td_stop_media1 = period1.end + replace = True + + else: + return False + + if not replace: + return False + + if period1.start == period2.start and period1.end == period2.end: + return True + + elif media_action2 == MEDIA_ACTION_START_STOP: + + if td_play_media1: + s, e, hit = period2.hit(td_play_media1) + if s and e and hit: + return True + + if td_stop_media1: + s, e, hit = period2.hit(td_stop_media1) + if s and e and hit: + return True + + return False + + elif media_action2 == MEDIA_ACTION_STOP_START: + + if td_play_media1: + s, e, hit = period2.hit(td_play_media1) + return s and e and hit + + return False + + timer_replace_types = get_types_replaced_by_type(timer.media_type) + + overlapping_timers: 'list[Timer]' = list() + for t in timers: + + if t.id == timer.id or (ignore_high_prio and t.priority >= HIGH_PRIO_MARK): + continue + + t_replace_types = get_types_replaced_by_type(t.media_type) + + overlapping_periods: 'list[Period]' = list() + for p in t.periods: + + for n in timer.periods: + + if _disturbs(timer_replace_types, t.media_type, timer.media_action, t.media_action, n, p) or _disturbs(t_replace_types, timer.media_type, t.media_action, timer.media_action, p, n): + overlapping_periods.append(p) + + if overlapping_periods: + days = [ + datetime_utils.WEEKLY] if datetime_utils.WEEKLY in t.days else list() + days.extend([p.start.days for p in overlapping_periods]) + t.days = days + t.periods = overlapping_periods + overlapping_timers.append(t) + + overlapping_timers.sort(key=lambda t: (t.days, t.start, + t.media_action, t.system_action)) + + return overlapping_timers + + +def ask_overlapping_timers(timer: Timer, overlapping_timers: 'list[Timer]') -> int: + + addon = xbmcaddon.Addon() + + earlier_timers = [ + t for t in overlapping_timers if t.periods[0].start < timer.periods[0].start] + + lines = list() + for t in overlapping_timers: + lines.append(t.format("$L ($H)", 50, 12)) + lines.append("\n" + addon.getLocalizedString(32052) % + timer.format("$L ($T)", 50, 12)) + + answer = xbmcgui.Dialog().yesnocustom(heading=addon.getLocalizedString( + 32050 if earlier_timers else 32051), message="\n".join(lines), customlabel=addon.getLocalizedString(32022)) + if answer == CONFIRM_YES: + timer.priority = get_next_higher_prio(overlapping_timers) + return CONFIRM_YES + + elif answer == CONFIRM_NO: + timer.priority = get_next_lower_prio(overlapping_timers) + return CONFIRM_YES + + return CONFIRM_CUSTOM diff --git a/script.timers/resources/lib/timer/period.py b/script.timers/resources/lib/timer/period.py index c64e3c566..d333f2849 100644 --- a/script.timers/resources/lib/timer/period.py +++ b/script.timers/resources/lib/timer/period.py @@ -8,5 +8,37 @@ def __init__(self, start: timedelta, end: timedelta) -> None: self.start: timedelta = start self.end: timedelta = end + def _compare(self, period_start: timedelta, period_end: timedelta) -> 'tuple[timedelta,timedelta,timedelta]': + + self_start = self.start + self_end = self.end + week = timedelta(days=7) + + if self_start > self_end and period_start <= period_end: + self_end += week + if period_end < self_start: + period_start += week + period_end += week + + elif self_start <= self_end and period_start > period_end: + period_end += week + if self_end < period_start: + self_start += week + self_end += week + + max_start = max(self_start, period_start) + min_end = min(self_end, period_end) + + return self_start - period_start, self_end - period_end, min_end - max_start if max_start <= min_end else None + + def compare(self, period: 'Period') -> 'tuple[timedelta,timedelta,timedelta]': + + return self._compare(period.start, period.end) + + def hit(self, timestamp: timedelta) -> 'tuple[timedelta,timedelta, bool]': + + s, e, l = self._compare(timestamp, timestamp) + return s, e, l is not None + def __str__(self) -> str: return "Period[start=%s, end=%s]" % (self.start, self.end) diff --git a/script.timers/resources/lib/timer/scheduler.py b/script.timers/resources/lib/timer/scheduler.py index 6c4e49cf1..94d530637 100644 --- a/script.timers/resources/lib/timer/scheduler.py +++ b/script.timers/resources/lib/timer/scheduler.py @@ -4,11 +4,13 @@ import xbmcaddon import xbmcgui from resources.lib.player.player import Player -from resources.lib.timer import storage +from resources.lib.timer.concurrency import determine_overlappings from resources.lib.timer.scheduleraction import SchedulerAction +from resources.lib.timer.storage import Storage from resources.lib.timer.timer import (END_TYPE_DURATION, END_TYPE_TIME, STATE_WAITING, Timer) -from resources.lib.utils.datetime_utils import DateTimeDelta, parse_datetime_str +from resources.lib.utils.datetime_utils import (DateTimeDelta, + parse_datetime_str) from resources.lib.utils.settings_utils import (is_settings_changed_events, save_timer_from_settings) from resources.lib.utils.system_utils import (is_fullscreen, @@ -39,9 +41,10 @@ def __init__(self) -> None: self._player.setDefaultVolume(_default_volume) self._player.setVolume(_default_volume) - self.action = SchedulerAction(self._player) + self._storage = Storage() + self.action = SchedulerAction(self._player, self._storage) - storage.release_lock() + self._storage.release_lock() self._update() @@ -76,9 +79,15 @@ def _has_changed(former_timer: Timer, timer_from_storage: Timer) -> 'tuple[bool, changed |= (former_timer.media_action != timer_from_storage.media_action) - if former_timer._is_playing_media_timer(): + if former_timer.is_playing_media_timer(): restart |= (former_timer.path != timer_from_storage.path) changed |= (former_timer.path != timer_from_storage.path) + + restart |= (former_timer.priority != + timer_from_storage.priority) + changed |= (former_timer.priority != + timer_from_storage.priority) + changed |= (former_timer.media_type != timer_from_storage.media_type) changed |= (former_timer.repeat != timer_from_storage.repeat) @@ -92,35 +101,46 @@ def _has_changed(former_timer: Timer, timer_from_storage: Timer) -> 'tuple[bool, return changed, restart + def _reset_overlappings(timer: Timer) -> None: + + overlappings = determine_overlappings( + timer, scheduled_timers) + for overlap in overlappings: + overlap.state = STATE_WAITING + def _update_from_storage(scheduled_timers: 'list[Timer]') -> 'list[Timer]': for timer in scheduled_timers: + changed = False former_timer = [ t for t in self._timers if t.id == timer.id] - if not former_timer: - continue - timer.state = former_timer[0].state - timer.return_vol = former_timer[0].return_vol + if former_timer: + timer.state = former_timer[0].state + timer.return_vol = former_timer[0].return_vol + + changed, restart = _has_changed( + former_timer=former_timer[0], timer_from_storage=timer) - changed, restart = _has_changed( - former_timer=former_timer[0], timer_from_storage=timer) + if timer.state is not STATE_WAITING and restart: + timer.state = STATE_WAITING - if timer.state is not STATE_WAITING and restart: - timer.state = STATE_WAITING + if changed: + self._player.resetResumeOfTimer(timer=former_timer[0]) - if changed: - self._player.resetResumeOfTimer(timer=former_timer[0]) + if not former_timer or changed: + _reset_overlappings(timer) - scheduled_timers = storage.get_scheduled_timers() + scheduled_timers = self._storage.get_scheduled_timers() if self._timers: _update_from_storage(scheduled_timers) ids = [t.id for t in scheduled_timers] - removed_timers = list([t for t in self._timers if t.id not in ids]) + removed_timers = [t for t in self._timers if t.id not in ids] for removed_timer in removed_timers: + _reset_overlappings(removed_timer) self._player.resetResumeOfTimer(timer=removed_timer) self._timers = scheduled_timers diff --git a/script.timers/resources/lib/timer/scheduleraction.py b/script.timers/resources/lib/timer/scheduleraction.py index 7bf1c727c..e8a17ff25 100644 --- a/script.timers/resources/lib/timer/scheduleraction.py +++ b/script.timers/resources/lib/timer/scheduleraction.py @@ -7,23 +7,28 @@ from resources.lib.player.player import Player from resources.lib.player.player_utils import (get_types_replaced_by_type, run_addon) -from resources.lib.timer import storage +from resources.lib.timer.storage import Storage from resources.lib.timer.timer import (END_TYPE_NO, FADE_IN_FROM_MIN, FADE_OUT_FROM_CURRENT, STATE_ENDING, STATE_RUNNING, STATE_STARTING, - STATE_WAITING, SYSTEM_ACTION_HIBERNATE, - SYSTEM_ACTION_POWEROFF, SYSTEM_ACTION_QUIT_KODI, - SYSTEM_ACTION_SHUTDOWN_KODI, SYSTEM_ACTION_STANDBY, - TIMER_WEEKLY, Timer) + STATE_WAITING, + SYSTEM_ACTION_CEC_STANDBY, + SYSTEM_ACTION_HIBERNATE, + SYSTEM_ACTION_POWEROFF, + SYSTEM_ACTION_QUIT_KODI, + SYSTEM_ACTION_SHUTDOWN_KODI, + SYSTEM_ACTION_STANDBY, TIMER_WEEKLY, + Timer) from resources.lib.utils.datetime_utils import DateTimeDelta, abs_time_diff from resources.lib.utils.vfs_utils import get_asset_path class SchedulerAction: - def __init__(self, player: Player) -> None: + def __init__(self, player: Player, storage: Storage) -> None: self._player: Player = player + self.storage = storage self.upcoming_event: datetime = None self.upcoming_timer: Timer = None @@ -60,6 +65,7 @@ def _collectEndingTimer(timer: Timer) -> None: if timer.is_stop_at_end_timer(): _tts = self.timerToStopSlideshow if timer.media_type == PICTURE else self.timerToStopAV if (not _tts + or _tts.priority < timer.priority or _tts.is_resuming_timer() and timer.current_period.start >= _tts.current_period.start): self._setTimerToStopAny(timer) @@ -96,6 +102,13 @@ def _collectTimers(timers: 'list[Timer]', now: DateTimeDelta) -> None: def _handleNestedStoppingTimer(timerToStop: Timer) -> None: + def _reset_stop(): + if _stopMediatype in [AUDIO, VIDEO]: + self.timerToStopAV = None + + elif _stopMediatype == PICTURE: + self.timerToStopSlideshow = None + if timerToStop: _stopMediatype = timerToStop.media_type _types_replaced_by_type = get_types_replaced_by_type( @@ -103,23 +116,25 @@ def _handleNestedStoppingTimer(timerToStop: Timer) -> None: for overlappingTimer in self._runningTimers: if (overlappingTimer.media_type in _types_replaced_by_type and overlappingTimer.is_play_at_start_timer() and overlappingTimer.is_stop_at_end_timer() - and timerToStop.current_period.start < overlappingTimer.current_period.start + and timerToStop.current_period.start <= overlappingTimer.current_period.start and timerToStop.current_period.end < overlappingTimer.current_period.end): self._forceResumeResetTypes.extend( _types_replaced_by_type if not timerToStop.is_resuming_timer() else list()) - if _stopMediatype in [AUDIO, VIDEO]: - self.timerToStopAV = None + if overlappingTimer.priority < timerToStop.priority and timerToStop.is_playing_media_timer() and overlappingTimer.media_type in _types_replaced_by_type: + self._beginningTimers.append(overlappingTimer) + + _reset_stop() - elif _stopMediatype == PICTURE: - self.timerToStopSlideshow = None + enclosingTimers = [t for t in self._runningTimers if (t.current_period.start < timerToStop.current_period.start + and t.current_period.end > timerToStop.current_period.end) + and t.media_type in _stopMediatype] - return + if enclosingTimers and not [t for t in enclosingTimers if timerToStop.priority >= t.priority]: + _reset_stop() - if timerToStop.is_resuming_timer(): - enclosingTimers = [t for t in self._runningTimers if (t.current_period.start < timerToStop.current_period.start - and t.current_period.end > timerToStop.current_period.end)] + elif timerToStop.is_resuming_timer(): self._beginningTimers.extend(enclosingTimers) def _handleStartingTimers() -> None: @@ -132,7 +147,10 @@ def _handleStartingTimers() -> None: elif timer.return_vol == None: timer.return_vol = self._player.getVolume() - if timer.is_play_at_start_timer(): + higher_prio_runnings = [running for running in self._runningTimers if running.priority > timer.priority + and running.media_type in get_types_replaced_by_type(timer.media_type)] + + if not higher_prio_runnings and timer.is_play_at_start_timer(): self._setTimerToPlayAny(timer) elif timer.is_stop_at_start_timer(): @@ -143,7 +161,7 @@ def _handleStartingTimers() -> None: def _handleSystemAction() -> None: - if not self.timerWithSystemAction: + if not self.timerWithSystemAction or self.timerWithSystemAction.system_action == SYSTEM_ACTION_CEC_STANDBY: return addon = xbmcaddon.Addon() @@ -239,10 +257,10 @@ def _setTimerToPlayAny(self, timer: Timer) -> None: self.timersToRunScript.append(timer) elif timer.media_type == PICTURE: - self.timerToPlaySlideshow = timer + self.timerToPlaySlideshow = timer if self.timerToPlaySlideshow is None or self.timerToPlaySlideshow.priority < timer.priority else self.timerToPlaySlideshow else: - self.timerToPlayAV = timer + self.timerToPlayAV = timer if self.timerToPlayAV is None or self.timerToPlayAV.priority < timer.priority else self.timerToPlayAV def fade(self, dtd: DateTimeDelta) -> None: @@ -282,7 +300,7 @@ def _performPlayerAction(_now: DateTimeDelta) -> None: elif self.timerToUnpauseAV and self._player.isPaused(): self._player.pause() - for type in self._forceResumeResetTypes: + for type in set(self._forceResumeResetTypes): self._player.resetResumeStatus(type) if not self.timerToPlayAV or self.timerToPlayAV.media_type != VIDEO: @@ -335,9 +353,9 @@ def _reset(timers: 'list[Timer]') -> None: timer.days.remove(timer.current_period.start.days) if not timer.days: - storage.delete_timer(timer.id) + self.storage.delete_timer(timer.id) else: - storage.save_timer(timer=timer) + self.storage.save_timer(timer=timer) _reset(self._endingTimers) if self.timerWithSystemAction: @@ -368,6 +386,9 @@ def _performSystemAction() -> None: elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_POWEROFF: xbmc.executebuiltin("Powerdown()") + elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_CEC_STANDBY: + xbmc.executebuiltin("CECStandby()") + def _adjustState() -> None: for t in self._beginningTimers: diff --git a/script.timers/resources/lib/timer/storage.py b/script.timers/resources/lib/timer/storage.py index 1e38d95f6..8bd9cee0b 100644 --- a/script.timers/resources/lib/timer/storage.py +++ b/script.timers/resources/lib/timer/storage.py @@ -9,214 +9,207 @@ from resources.lib.timer.timer import STATE_WAITING, Timer -def _get_storage_path() -> str: +class Storage(): - addon = xbmcaddon.Addon() - profile_path = xbmcvfs.translatePath(addon.getAddonInfo('profile')) - return os.path.join(profile_path, "timers.json") + def _get_storage_path(self) -> str: + addon = xbmcaddon.Addon() + profile_path = xbmcvfs.translatePath(addon.getAddonInfo('profile')) + return os.path.join(profile_path, "timers.json") -def _aquire_lock() -> str: + def _aquire_lock(self) -> str: - lock_path = "%s.lck" % _get_storage_path() - lock = str(int(time.time())) + lock_path = "%s.lck" % self._get_storage_path() + lock = str(int(time.time())) - with xbmcvfs.File(lock_path, "w") as file: - file.write(lock) + with xbmcvfs.File(lock_path, "w") as file: + file.write(lock) - return lock + return lock + def release_lock(self) -> None: -def release_lock() -> None: + lock_file = "%s.lck" % self._get_storage_path() + if xbmcvfs.exists(lock_file): + xbmcvfs.rmdir(lock_file, force=True) - lock_file = "%s.lck" % _get_storage_path() - if xbmcvfs.exists(lock_file): - xbmcvfs.rmdir(lock_file, force=True) + def _wait_for_unlock(self) -> None: + lock_path = "%s.lck" % self._get_storage_path() -def _wait_for_unlock() -> None: + wait = 5 + while xbmcvfs.exists(lock_path) and wait > 0: - lock_path = "%s.lck" % _get_storage_path() + xbmc.sleep(100 + int(random.random() * 100)) + wait -= 1 - wait = 5 - while xbmcvfs.exists(lock_path) and wait > 0: + if wait == 0: + xbmc.log("%s is locked. Unlock now with small risk of data loss." % + self._get_storage_path(), xbmc.LOGWARNING) + self.release_lock() - xbmc.sleep(100 + int(random.random() * 100)) - wait -= 1 + def _load_from_storage(self) -> 'list[dict]': - if wait == 0: - xbmc.log("%s is locked. Unlock now with small risk of data loss." % - _get_storage_path(), xbmc.LOGWARNING) - release_lock() + self._wait_for_unlock() + storage_path = self._get_storage_path() + _storage = list() + if xbmcvfs.exists(storage_path): + with xbmcvfs.File(storage_path, "r") as file: + try: + _storage.extend(json.load(file)) + except: + # this should normally not be a problem, but it fails when running unit tests + xbmc.log("Can't read timers from storage.", + xbmc.LOGWARNING) -def _load_from_storage() -> 'list[dict]': + return _storage - _wait_for_unlock() + def _save_to_storage(self, storage: 'list[dict]') -> None: - storage_path = _get_storage_path() - _storage = list() - if xbmcvfs.exists(storage_path): - with xbmcvfs.File(storage_path, "r") as file: - try: - _storage.extend(json.load(file)) - except: - # this should normally not be a problem, but it fails when running unit tests - xbmc.log("Can't read timers from storage.", xbmc.LOGWARNING) + storage.sort(key=lambda item: item["id"]) + storage_path = self._get_storage_path() - return _storage + self._wait_for_unlock() + try: + lock = self._aquire_lock() + tmp = "%s.%s" % (storage_path, lock) + old = "%s.old" % storage_path + with xbmcvfs.File(tmp, "w") as file: + json.dump(obj=storage, fp=file, indent=2, sort_keys=True) + if xbmcvfs.exists(old): + xbmcvfs.delete(old) -def _save_to_storage(storage: 'list[dict]') -> None: + xbmcvfs.rename(storage_path, old) + xbmcvfs.rename(tmp, storage_path) - storage.sort(key=lambda item: item["id"]) - storage_path = _get_storage_path() + finally: + self.release_lock() - _wait_for_unlock() - try: - lock = _aquire_lock() - tmp = "%s.%s" % (storage_path, lock) - old = "%s.old" % storage_path - with xbmcvfs.File(tmp, "w") as file: - json.dump(obj=storage, fp=file, indent=2, sort_keys=True) + def load_timers_from_storage(self) -> 'list[Timer]': - if xbmcvfs.exists(old): - xbmcvfs.delete(old) + timers = list() + storage = self._load_from_storage() + for item in storage: + timers.append(self._init_timer_from_item(item)) - xbmcvfs.rename(storage_path, old) - xbmcvfs.rename(tmp, storage_path) + return timers - finally: - release_lock() + def load_timer_from_storage(self, id: int) -> Timer: + storage = self._load_from_storage() + for item in storage: + if item["id"] == id: + return self._init_timer_from_item(item) -def load_timers_from_storage() -> 'list[Timer]': + return None - timers = list() - storage = _load_from_storage() - for item in storage: - timers.append(_init_timer_from_item(item)) + def _init_timer_from_item(self, item: dict) -> Timer: - return timers + timer = Timer(item["id"]) + timer.label = item["label"] + timer.system_action = item["system_action"] + timer.media_action = item["media_action"] + timer.fade = item["fade"] + timer.vol_min = item["vol_min"] + timer.vol_max = item["vol_max"] + timer.path = item["path"] + timer.media_type = item["media_type"] + timer.repeat = item["repeat"] + timer.shuffle = item["shuffle"] + timer.resume = item["resume"] + item["days"].sort() + timer.days = item["days"] -def load_timer_from_storage(id: int) -> Timer: + timer.start = item["start"] + timer.start_offset = item["start_offset"] + timer.end_type = item["end_type"] + timer.end = item["end"] + timer.end_offset = item["end_offset"] + timer.duration = item["duration"] + timer.duration_offset = item["duration_offset"] - storage = _load_from_storage() - for item in storage: - if item["id"] == id: - return _init_timer_from_item(item) + timer.priority = item["priority"] - return None + timer.notify = item["notify"] + timer.return_vol = None + timer.state = STATE_WAITING + + timer.init() -def _init_timer_from_item(item: dict) -> Timer: + return timer + + def _find_item_index(self, storage: 'list[dict]', id: int) -> int: + + for i, item in enumerate(storage): + if item["id"] == id: + return i - timer = Timer(item["id"]) - timer.label = item["label"] - timer.system_action = item["system_action"] - timer.media_action = item["media_action"] - timer.fade = item["fade"] - timer.vol_min = item["vol_min"] - timer.vol_max = item["vol_max"] - timer.path = item["path"] - timer.media_type = item["media_type"] - timer.repeat = item["repeat"] - timer.shuffle = item["shuffle"] - timer.resume = item["resume"] + return -1 + + def save_timer(self, timer: Timer) -> None: + + timer.init() + + item = { + "days": timer.days, + "duration": timer.duration, + "duration_offset": timer.duration_offset, + "end": timer.end, + "end_offset": timer.end_offset, + "end_type": timer.end_type, + "fade": timer.fade, + "id": timer.id, + "label": timer.label, + "media_action": timer.media_action, + "media_type": timer.media_type, + "notify": timer.notify, + "path": timer.path, + "priority": timer.priority, + "repeat": timer.repeat, + "resume": timer.resume, + "shuffle": timer.shuffle, + "start": timer.start, + "start_offset": timer.start_offset, + "system_action": timer.system_action, + "vol_min": timer.vol_min, + "vol_max": timer.vol_max + } - item["days"].sort() - timer.days = item["days"] - - timer.start = item["start"] - timer.start_offset = item["start_offset"] - timer.end_type = item["end_type"] - timer.end = item["end"] - timer.end_offset = item["end_offset"] - timer.duration = item["duration"] - timer.duration_offset = item["duration_offset"] - - timer.notify = item["notify"] - - timer.return_vol = None - timer.state = STATE_WAITING - - timer.init() - - return timer - - -def _find_item_index(storage: 'list[dict]', id: int) -> int: - - for i, item in enumerate(storage): - if item["id"] == id: - return i - - return -1 - - -def save_timer(timer: Timer) -> None: - - timer.init() - - item = { - "days": timer.days, - "duration": timer.duration, - "duration_offset": timer.duration_offset, - "end": timer.end, - "end_offset": timer.end_offset, - "end_type": timer.end_type, - "fade": timer.fade, - "id": timer.id, - "label": timer.label, - "media_action": timer.media_action, - "media_type": timer.media_type, - "notify": timer.notify, - "path": timer.path, - "repeat": timer.repeat, - "resume": timer.resume, - "shuffle": timer.shuffle, - "start": timer.start, - "start_offset": timer.start_offset, - "system_action": timer.system_action, - "vol_min": timer.vol_min, - "vol_max": timer.vol_max - } - - storage = _load_from_storage() - idx = _find_item_index(storage, timer.id) - if idx == -1: - storage.append(item) - else: - storage[idx] = item - - _save_to_storage(storage) - - -def delete_timer(timer_id: int) -> None: - - storage = _load_from_storage() - idx = _find_item_index(storage, timer_id) - if idx >= 0: - storage.pop(idx) - _save_to_storage(storage=storage) - - -def get_scheduled_timers() -> 'list[Timer]': - - timers = load_timers_from_storage() - scheduled_timers = list([timer for timer in timers if timer.days]) - scheduled_timers.sort(key=lambda timer: (timer.days, timer.start, - timer.media_action, timer.system_action)) - return scheduled_timers - - -def get_next_id() -> int: - - storage = _load_from_storage() - - next_id = 0 - if storage: - next_id = max(storage, key=lambda item: item["id"])["id"] + 1 - - return next_id + storage = self._load_from_storage() + idx = self._find_item_index(storage, timer.id) + if idx == -1: + storage.append(item) + else: + storage[idx] = item + + self._save_to_storage(storage) + + def delete_timer(self, timer_id: int) -> None: + + storage = self._load_from_storage() + idx = self._find_item_index(storage, timer_id) + if idx >= 0: + storage.pop(idx) + self._save_to_storage(storage=storage) + + def get_scheduled_timers(self) -> 'list[Timer]': + + timers = self.load_timers_from_storage() + scheduled_timers = [timer for timer in timers if timer.days] + scheduled_timers.sort(key=lambda timer: (timer.days, timer.start, + timer.media_action, timer.system_action)) + return scheduled_timers + + def get_next_id(self) -> int: + + storage = self._load_from_storage() + + next_id = 0 + if storage: + next_id = max(storage, key=lambda item: item["id"])["id"] + 1 + + return next_id diff --git a/script.timers/resources/lib/timer/timer.py b/script.timers/resources/lib/timer/timer.py index 47fd01483..923ef6471 100644 --- a/script.timers/resources/lib/timer/timer.py +++ b/script.timers/resources/lib/timer/timer.py @@ -2,7 +2,8 @@ import xbmcaddon from resources.lib.timer.period import Period -from resources.lib.utils.datetime_utils import (DEFAULT_TIME, DateTimeDelta, apply_for_now, +from resources.lib.utils.datetime_utils import (DEFAULT_TIME, DateTimeDelta, + apply_for_now, format_from_seconds, parse_time, periods_to_human_readable, @@ -21,6 +22,7 @@ SYSTEM_ACTION_STANDBY = 3 SYSTEM_ACTION_HIBERNATE = 4 SYSTEM_ACTION_POWEROFF = 5 +SYSTEM_ACTION_CEC_STANDBY = 6 MEDIA_ACTION_NONE = 0 MEDIA_ACTION_START_STOP = 1 @@ -70,6 +72,7 @@ def __init__(self, i: int) -> None: self.vol_min: int = 75 self.vol_max: int = 100 self.notify: bool = True + self.priority: int = 0 # state self.periods: 'list[Period]' = list() @@ -179,20 +182,128 @@ def get_duration(self) -> str: else: return DEFAULT_TIME + def _timeStr(self, timeStr: str, offset: int) -> str: + + return "%s:%02i" % (timeStr, offset) if offset else timeStr + + def _mediaActionStr(self) -> str: + + if self.media_action == MEDIA_ACTION_START_STOP: + return self._addon.getLocalizedString(32072) + + elif self.media_action == MEDIA_ACTION_START: + return self._addon.getLocalizedString(32073) + + elif self.media_action == MEDIA_ACTION_START_AT_END: + return self._addon.getLocalizedString(32074) + + elif self.media_action == MEDIA_ACTION_STOP_START: + return self._addon.getLocalizedString(32075) + + elif self.media_action == MEDIA_ACTION_STOP: + return self._addon.getLocalizedString(32076) + + elif self.media_action == MEDIA_ACTION_STOP_AT_END: + return self._addon.getLocalizedString(32077) + + elif self.media_action == MEDIA_ACTION_PAUSE: + return self._addon.getLocalizedString(32089) + + else: + return self._addon.getLocalizedString(32071) + + def _systemActionStr(self) -> str: + + if self.system_action == SYSTEM_ACTION_SHUTDOWN_KODI: + return self._addon.getLocalizedString(32082) + + elif self.system_action == SYSTEM_ACTION_QUIT_KODI: + return self._addon.getLocalizedString(32083) + + elif self.system_action == SYSTEM_ACTION_STANDBY: + return self._addon.getLocalizedString(32084) + + elif self.system_action == SYSTEM_ACTION_HIBERNATE: + return self._addon.getLocalizedString(32085) + + elif self.system_action == SYSTEM_ACTION_POWEROFF: + return self._addon.getLocalizedString(32086) + + elif self.system_action == SYSTEM_ACTION_CEC_STANDBY: + return self._addon.getLocalizedString(32093) + + else: + return self._addon.getLocalizedString(32071) + + def _endTypeStr(self) -> str: + + if self.end_type == END_TYPE_DURATION: + return self._addon.getLocalizedString(32064) + + elif self.end_type == END_TYPE_TIME: + return self._addon.getLocalizedString(32065) + + else: + return self._addon.getLocalizedString(32063) + + def _fadeStr(self) -> str: + + if self.fade == FADE_IN_FROM_MIN: + return self._addon.getLocalizedString(32121) + + elif self.fade == FADE_OUT_FROM_MAX: + return self._addon.getLocalizedString(32122) + + elif self.fade == FADE_OUT_FROM_CURRENT: + return self._addon.getLocalizedString(32123) + + else: + return self._addon.getLocalizedString(32120) + + def _playerOptionStr(self) -> str: + + options = list() + if self.repeat: + options.append(self._addon.getLocalizedString(32078)) + + if self.shuffle: + options.append(self._addon.getLocalizedString(32088)) + + if self.resume: + options.append(self._addon.getLocalizedString(32079)) + + return ", ".join(options) + + def format(self, format: str, max_: int = 0, shorten: int = 0) -> str: + + format = format.replace("$H", str(self.periods_to_human_readable())) + format = format.replace("$S", self._timeStr( + self.start, self.start_offset)) + format = format.replace( + "$E", self._timeStr(self.end, self.end_offset)) + format = format.replace("$T", self._timeStr(self.start, self.start_offset) + ( + " - %s" % self._timeStr(self.end, self.end_offset) if self.end_type else "")) + format = format.replace("$e", self._endTypeStr()) + format = format.replace("$M", self._mediaActionStr()) + format = format.replace("$O", self._playerOptionStr()) + format = format.replace("$F", self._fadeStr()) + format = format.replace("$P", self._systemActionStr()) + format = format.replace("$L", self.label if not max_ or not shorten or (len(self.label) + len(format)) + < max_ else self.label[:max(max_ - len(format), shorten)] + "...") + return format + def periods_to_human_readable(self) -> str: self.init() - _start = "%s:%02i" % ( - self.start, self.start_offset) if self.start_offset else self.start - _end = "%s:%02i" % ( - self.end, self.end_offset) if self.end_offset else self.end + _start = self._timeStr(self.start, self.start_offset) + _end = self._timeStr(self.end, self.end_offset) return periods_to_human_readable(self.days, start=_start, end=_end if self.end_type != END_TYPE_NO else None) def is_fading_timer(self) -> bool: return self.fade != FADE_OFF and self.end_type != END_TYPE_NO - def _is_playing_media_timer(self) -> bool: + def is_playing_media_timer(self) -> bool: return self.media_action in [MEDIA_ACTION_START, MEDIA_ACTION_START_AT_END, MEDIA_ACTION_START_STOP, MEDIA_ACTION_STOP_START] and self.path @@ -230,23 +341,22 @@ def is_system_execution_timer(self) -> bool: def __str__(self) -> str: - return "Timer[id=%i, label=%s, state=%s, days=%s, start=%s:%02i, endtype=%s, duration=%s:%02i, end=%s:%02i, systemaction=%s, mediaaction=%s, path=%s, type=%s, repeat=%s, shuffle=%s, resume=%s, fade=%s, min=%i, max=%i, returnvol=%i, notify=%s]" % (self.id, self.label, ["waiting", "starting", "running", "ending"][self.state], - [["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "weekly"][d] for d in self.days], - self.start, - self.start_offset, - ["no", "duration", "time"][self.end_type], - self.duration, self.duration_offset, - self.end, self.end_offset, - ["off", "shutdown", "quit", "standby", "hibernate", "poweroff"][self.system_action or 0], - ["off", "start-stop", "start", "start-at-end", - "stop-start", "stop", "stop-at-end", "pause"][self.media_action or 0], - self.path, - self.media_type, - self.repeat, - self.shuffle, - self.resume, - ["off", "in", "out", "current_out"][self.fade], - self.vol_min, - self.vol_max, - self.return_vol or self.vol_max, - self.notify) + return "Timer[id=%i, label=%s, state=%s, prio=%i, days=%s, start=%s:%02i, endtype=%s, duration=%s:%02i, end=%s:%02i, systemaction=%s, mediaaction=%s, path=%s, type=%s, repeat=%s, shuffle=%s, resume=%s, fade=%s, min=%i, max=%i, returnvol=%i, notify=%s]" % (self.id, self.label, ["waiting", "starting", "running", "ending"][self.state], self.priority, + [["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "weekly"][d] for d in self.days], + self.start, + self.start_offset, + self._endTypeStr(), + self.duration, self.duration_offset, + self.end, self.end_offset, + self._systemActionStr(), + self._mediaActionStr(), + self.path, + self.media_type, + self.repeat, + self.shuffle, + self.resume, + self._fadeStr(), + self.vol_min, + self.vol_max, + self.return_vol or self.vol_max, + self.notify) diff --git a/script.timers/resources/lib/utils/settings_utils.py b/script.timers/resources/lib/utils/settings_utils.py index a486183f4..12380e0fd 100644 --- a/script.timers/resources/lib/utils/settings_utils.py +++ b/script.timers/resources/lib/utils/settings_utils.py @@ -2,7 +2,7 @@ import xbmcaddon import xbmcgui -from resources.lib.timer import storage +from resources.lib.timer.storage import Storage from resources.lib.timer.timer import (DEFAULT_TIME, END_TYPE_NO, FADE_OFF, MEDIA_ACTION_NONE, SYSTEM_ACTION_NONE, Timer) @@ -12,6 +12,11 @@ _SETTING_CHANGE_EVENTS_MAX_SECS = 5 _SETTING_CHANGE_EVENTS_ACTIVE = 0 +CONFIRM_ESCAPE = -1 +CONFIRM_NO = 0 +CONFIRM_YES = 1 +CONFIRM_CUSTOM = 2 + def deactivate_on_settings_changed_events() -> None: @@ -44,12 +49,13 @@ def trigger_settings_changed_event() -> None: def prepare_empty_timer_in_setting(timer_id=None) -> None: if timer_id == None: - timer_id = storage.get_next_id() + timer_id = Storage().get_next_id() deactivate_on_settings_changed_events() addon = xbmcaddon.Addon() addon.setSettingInt("timer_id", timer_id) addon.setSettingString("timer_label", addon.getLocalizedString(32257)) + addon.setSettingInt("timer_priority", 0) addon.setSetting("timer_days", "") addon.setSetting("timer_start", DEFAULT_TIME) addon.setSettingInt("timer_start_offset", 0) @@ -106,6 +112,7 @@ def save_timer_from_settings() -> None: timer.media_type = addon.getSettingString("timer_mediatype") timer.notify = addon.getSettingBool("timer_notify") timer.path = addon.getSettingString("timer_path") + timer.priority = addon.getSettingInt("timer_priority") timer.repeat = addon.getSettingBool("timer_repeat") timer.resume = addon.getSettingBool("timer_resume") timer.shuffle = addon.getSettingBool("timer_shuffle") @@ -115,14 +122,14 @@ def save_timer_from_settings() -> None: timer.vol_min = addon.getSettingInt("timer_vol_min") timer.vol_max = addon.getSettingInt("timer_vol_max") - storage.save_timer(timer=timer) + Storage().save_timer(timer=timer) def select_timer(multi=False, extra=None) -> 'tuple[list[Timer], list[int]]': addon = xbmcaddon.Addon() - timers = storage.load_timers_from_storage() + timers = Storage().load_timers_from_storage() if not timers and not extra: xbmcgui.Dialog().notification(addon.getLocalizedString( 32000), addon.getLocalizedString(32258)) @@ -159,7 +166,7 @@ def delete_timer() -> None: return for i in idx: - storage.delete_timer(timers[i].id) + Storage().delete_timer(timers[i].id) trigger_settings_changed_event() @@ -184,6 +191,7 @@ def load_timer_into_settings(timer: Timer) -> None: deactivate_on_settings_changed_events() addon.setSettingInt("timer_id", timer.id) addon.setSettingString("timer_label", timer.label) + addon.setSettingInt("timer_priority", timer.priority) addon.setSetting("timer_days", "|".join([str(d) for d in timer.days])) addon.setSetting("timer_start", timer.start) addon.setSettingInt("timer_start_offset", timer.start_offset) diff --git a/script.timers/resources/lib/utils/vfs_utils.py b/script.timers/resources/lib/utils/vfs_utils.py index c306d1c70..a099354bb 100644 --- a/script.timers/resources/lib/utils/vfs_utils.py +++ b/script.timers/resources/lib/utils/vfs_utils.py @@ -18,7 +18,7 @@ _AUDIO_PLUGIN_PREFIX = "plugin://plugin.audio." _VIDEO_PLUGIN_PREFIX = "plugin://plugin.video." _URI_MATCHER = "^[a-z]+://.+$" -_FAVOURITES_MATCHER = "^favourites://(PlayMedia|RunScript)\(%22(.+)%22\)/$" +_FAVOURITES_MATCHER = "^favourites://(PlayMedia|RunScript)\(%22(.+)%22\)/?$" _SCRIPT_MATCHER = "^((script|plugin)://)?script\..+$" _PLAYLIST_TYPES = [".m3u", ".m3u8", ".pls"] diff --git a/script.timers/resources/settings.xml b/script.timers/resources/settings.xml index 3c9b42355..01eb2d69c 100644 --- a/script.timers/resources/settings.xml +++ b/script.timers/resources/settings.xml @@ -76,6 +76,40 @@ -1 + + 3 + 0 + + -10 + 1 + 12 + + + false + + + -1 + + + + 0 + + + true + + + 32337 + + false + + + + -1 + 9 + + + + -1 @@ -401,6 +435,7 @@ + @@ -471,7 +506,7 @@ - + 1 @@ -523,8 +558,6 @@ - - 1 @@ -534,6 +567,20 @@ + + + 3 + 2 + + + + + + + + + + From a91c0d4daa70ca8dfc8c1d42f8fd4f4067522c58 Mon Sep 17 00:00:00 2001 From: mikesilvo164 Date: Wed, 15 Feb 2023 07:21:09 -0500 Subject: [PATCH 003/145] [service.library.data.provider] v0.4.2 (#2404) --- service.library.data.provider/addon.xml | 5 ++--- service.library.data.provider/resources/lib/data.py | 2 +- service.library.data.provider/resources/lib/library.py | 2 +- service.library.data.provider/resources/lib/router.py | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/service.library.data.provider/addon.xml b/service.library.data.provider/addon.xml index 01256e533..54cb9f85e 100644 --- a/service.library.data.provider/addon.xml +++ b/service.library.data.provider/addon.xml @@ -1,7 +1,6 @@ - + - @@ -16,7 +15,7 @@ GPL-2.0-only https://forum.kodi.tv/showthread.php?tid=210063 https://github.com/mikesilvo164/service.library.data.provider - Kodi v19 + Python 3 compatibility + Matrix fixes resources/icon.png resources/fanart.jpg diff --git a/service.library.data.provider/resources/lib/data.py b/service.library.data.provider/resources/lib/data.py index 51edc1dfa..39ec23af4 100644 --- a/service.library.data.provider/resources/lib/data.py +++ b/service.library.data.provider/resources/lib/data.py @@ -40,7 +40,7 @@ def get_playlist_stats(path): if ("activatewindow" in path.lower()) and ("://" in path) and ("," in path): if ("\"" in path): # remove " from path (gets added by favorites) - path = path.translate(None, '\"') + path = path.translate(str.maketrans('','', '\"')) playlistpath = path.split(",")[1] json_query = xbmc.executeJSONRPC('''{"jsonrpc": "2.0", "method": "Files.GetDirectory", "params": {"directory": "%s", "media": "video", diff --git a/service.library.data.provider/resources/lib/library.py b/service.library.data.provider/resources/lib/library.py index af21c24da..479e326ae 100644 --- a/service.library.data.provider/resources/lib/library.py +++ b/service.library.data.provider/resources/lib/library.py @@ -48,7 +48,7 @@ def _get_data(self, query_type, useCache): if useCache: # Check whether there is saved data - if self.WINDOW.getProperty(query_type + "-data") is not "": + if self.WINDOW.getProperty(query_type + "-data") != "": return self.WINDOW.getProperty(query_type + "-data") # We haven't got any data, so don't send back anything diff --git a/service.library.data.provider/resources/lib/router.py b/service.library.data.provider/resources/lib/router.py index b602efb16..025032176 100644 --- a/service.library.data.provider/resources/lib/router.py +++ b/service.library.data.provider/resources/lib/router.py @@ -46,8 +46,8 @@ def root(): ("randommusicvideos", ADDON_LANGUAGE(32022), "DefaultMusicVideos.png"), ("recentmusicvideos", ADDON_LANGUAGE(32023), "DefaultRecentlyAddedMusicVideos.png")] for call, title, thumb in items: - liz = xbmcgui.ListItem(label=title, - thumbnailImage=thumb) + liz = xbmcgui.ListItem(title) + liz.setArt({"thumb": thumb}) url = 'plugin://service.library.data.provider?type=%s' % call xbmcplugin.addDirectoryItem(handle=plugin.handle, url=url, From 87c72a87d32871937c4522d1a5798007aab3f870 Mon Sep 17 00:00:00 2001 From: mikesilvo164 Date: Wed, 15 Feb 2023 07:21:27 -0500 Subject: [PATCH 004/145] [script.skin.info.service] 1.2.0 (#2403) --- script.skin.info.service/Utils.py | 2 +- script.skin.info.service/addon.xml | 4 ++-- script.skin.info.service/default.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/script.skin.info.service/Utils.py b/script.skin.info.service/Utils.py index ba9a945d1..bd3d2417d 100644 --- a/script.skin.info.service/Utils.py +++ b/script.skin.info.service/Utils.py @@ -175,7 +175,7 @@ def set_movie_properties(json_response): title_header = "[B]" + str(json_response['result']['setdetails']['limits']['total']) + " " + xbmc.getLocalizedString(20342) + "[/B][CR]" for item in json_response['result']['setdetails']['movies']: art = item['art'] - streaminfo = media_streamdetails(item['file'].encode('utf-8').lower(), item['streamdetails']) + streaminfo = media_streamdetails(item['file'].lower(), item['streamdetails']) HOME.setProperty('SkinInfo.Set.Movie.%d.DBID' % count, str(item.get('movieid'))) HOME.setProperty('SkinInfo.Set.Movie.%d.Title' % count, item['label']) HOME.setProperty('SkinInfo.Set.Movie.%d.Plot' % count, item['plot']) diff --git a/script.skin.info.service/addon.xml b/script.skin.info.service/addon.xml index cad011753..89b2ba973 100644 --- a/script.skin.info.service/addon.xml +++ b/script.skin.info.service/addon.xml @@ -1,5 +1,5 @@ - + @@ -17,6 +17,6 @@ icon.png - Python 3 compatibility[CR]Add Album discart for Artists[CR]Add set details support for Home Window + Kodi Matrix/Nexus changes \ No newline at end of file diff --git a/script.skin.info.service/default.py b/script.skin.info.service/default.py index 89e51dbb1..6d34ae334 100644 --- a/script.skin.info.service/default.py +++ b/script.skin.info.service/default.py @@ -43,7 +43,7 @@ def run_backend(self): self.selecteditem = xbmc.getInfoLabel("ListItem.DBID") if (self.selecteditem != self.previousitem): self.previousitem = self.selecteditem - if (self.selecteditem is not ""): + if (self.selecteditem != ""): if xbmc.getCondVisibility("Container.Content(artists)"): self._set_artist_details(self.selecteditem) elif xbmc.getCondVisibility("Container.Content(albums)"): From ab78968b29f6904205f1e6e37a711d321d94f93b Mon Sep 17 00:00:00 2001 From: snapcase Date: Wed, 15 Feb 2023 07:22:46 -0500 Subject: [PATCH 005/145] [script.service.hue] 1.4.5 (#2400) --- script.service.hue/addon.xml | 23 +- .../resource.language.af_za/strings.po | 12 +- .../resource.language.am_et/strings.po | 12 +- .../resource.language.ar_sa/strings.po | 12 +- .../resource.language.ast_es/strings.po | 12 +- .../resource.language.az_az/strings.po | 12 +- .../resource.language.be_by/strings.po | 12 +- .../resource.language.bg_bg/strings.po | 12 +- .../resource.language.bs_ba/strings.po | 12 +- .../resource.language.ca_es/strings.po | 12 +- .../resource.language.cs_cz/strings.po | 16 +- .../resource.language.cy_gb/strings.po | 12 +- .../resource.language.da_dk/strings.po | 20 +- .../resource.language.de_de/strings.po | 138 +++++---- .../resource.language.el_gr/strings.po | 12 +- .../resource.language.en_au/strings.po | 12 +- .../resource.language.en_gb/strings.po | 12 +- .../resource.language.en_nz/strings.po | 12 +- .../resource.language.en_us/strings.po | 12 +- .../language/resource.language.eo/strings.po | 12 +- .../resource.language.es_ar/strings.po | 12 +- .../resource.language.es_es/strings.po | 22 +- .../resource.language.es_mx/strings.po | 12 +- .../resource.language.et_ee/strings.po | 12 +- .../resource.language.eu_es/strings.po | 12 +- .../resource.language.fa_af/strings.po | 12 +- .../resource.language.fa_ir/strings.po | 12 +- .../resource.language.fi_fi/strings.po | 20 +- .../resource.language.fo_fo/strings.po | 12 +- .../resource.language.fr_ca/strings.po | 12 +- .../resource.language.fr_fr/strings.po | 268 ++++++++--------- .../resource.language.gl_es/strings.po | 12 +- .../resource.language.he_il/strings.po | 12 +- .../resource.language.hi_in/strings.po | 12 +- .../resource.language.hr_hr/strings.po | 272 +++++++++--------- .../resource.language.hu_hu/strings.po | 12 +- .../resource.language.hy_am/strings.po | 12 +- .../resource.language.id_id/strings.po | 12 +- .../resource.language.is_is/strings.po | 12 +- .../resource.language.it_it/strings.po | 22 +- .../resource.language.ja_jp/strings.po | 12 +- .../resource.language.kn_in/strings.po | 12 +- .../resource.language.ko_kr/strings.po | 20 +- .../resource.language.lt_lt/strings.po | 12 +- .../resource.language.lv_lv/strings.po | 12 +- .../language/resource.language.mi/strings.po | 12 +- .../resource.language.mk_mk/strings.po | 12 +- .../resource.language.ml_in/strings.po | 12 +- .../resource.language.mn_mn/strings.po | 12 +- .../resource.language.ms_my/strings.po | 12 +- .../resource.language.mt_mt/strings.po | 12 +- .../resource.language.my_mm/strings.po | 12 +- .../resource.language.nb_no/strings.po | 12 +- .../resource.language.nl_nl/strings.po | 24 +- .../resource.language.oc_fr/strings.po | 12 +- .../resource.language.os_os/strings.po | 12 +- .../resource.language.pl_pl/strings.po | 12 +- .../resource.language.pt_br/strings.po | 12 +- .../resource.language.pt_pt/strings.po | 12 +- .../resource.language.ro_ro/strings.po | 12 +- .../resource.language.ru_ru/strings.po | 12 +- .../resource.language.si_lk/strings.po | 12 +- .../resource.language.sk_sk/strings.po | 12 +- .../resource.language.sl_si/strings.po | 12 +- .../resource.language.sq_al/strings.po | 12 +- .../resource.language.sr_rs/strings.po | 12 +- .../resource.language.sr_rs@latin/strings.po | 12 +- .../resource.language.sv_se/strings.po | 12 +- .../language/resource.language.szl/strings.po | 12 +- .../resource.language.ta_in/strings.po | 12 +- .../resource.language.te_in/strings.po | 12 +- .../resource.language.tg_tj/strings.po | 12 +- .../resource.language.th_th/strings.po | 12 +- .../resource.language.tr_tr/strings.po | 12 +- .../resource.language.uk_ua/strings.po | 12 +- .../resource.language.uz_uz/strings.po | 12 +- .../resource.language.vi_vn/strings.po | 12 +- .../resource.language.zh_cn/strings.po | 16 +- .../resource.language.zh_tw/strings.po | 12 +- script.service.hue/resources/lib/__init__.py | 5 +- script.service.hue/resources/lib/ambigroup.py | 5 +- script.service.hue/resources/lib/core.py | 50 ++-- .../resources/lib/hueconnection.py | 106 ++++--- script.service.hue/resources/lib/kodiutils.py | 26 +- script.service.hue/resources/lib/language.py | 4 +- .../resources/lib/lightgroup.py | 100 +++---- script.service.hue/resources/lib/menu.py | 31 +- script.service.hue/resources/lib/reporting.py | 17 +- 88 files changed, 1359 insertions(+), 650 deletions(-) diff --git a/script.service.hue/addon.xml b/script.service.hue/addon.xml index 49dad9348..fa31c365e 100644 --- a/script.service.hue/addon.xml +++ b/script.service.hue/addon.xml @@ -1,9 +1,8 @@ - + - @@ -21,27 +20,31 @@ https://github.com/zim514/script.service.hue https://forum.kodi.tv/showthread.php?tid=344886 - v1.3 -Refactor bridge connection -Fix and improve bridge discovery progress bar -Clean up localisation generation system -Weblate localisation update + +Remove dependency with SimpleCache +Fix service not disabling correctly +Fix reconnection +Improved Hue error handling Automatitza les llums Hue amb la reproducció de Kodi Automatizace Hue světel s přehráváním Kodi Automatiser Hue-lys sammen med afspilning i Kodi - Automatisiere Hue-Lichter mit der Kodi-Wiedergabe + Hue-Licht mit der Kodi-Wiedergabe automatisieren Automate Hue lights with Kodi playback Ohjaa Hue-valoja automaattisesti Kodin toistolla + Automatiser les lumières Hue V2 (Philips) avec la lecture Kodi + Automatski Hue svjetla s Kodi reprodukcijom Automatizza le luci Hue con la riproduzione di Kodi Kodi 재생으로 Hue 조명 자동화 Kodi 播放时自动调整 Hue 灯光 Automatitza les teves llums Hue amb Kodi. Creeu escenes en diverses habitacions que s'executen al reproduir, posar en pausa o aturar la reproducció multimèdia. Crea i suprimeix escenes de diverses habitacions des de la configuració del complement i, a continuació, selecciona quina vols aplicar als diferents esdeveniments de reproducció. Pots utilitzar les hores de sortida i posta del sol de Hue per desactivar automàticament el servei durant el dia i encendre els llums al capvespre durant la reproducció. Inclou suport d'Ambilight. Ovládejte Hue světla automaticky pomocí Kodi. Vytvořte scény pro začátek, přestávku i ukončení přehrávání a nechte Kodi reagovat automaticky na Vaše akce. Je možné využít východ i západ slunce. Obsahuje podporu pro Ambilight. Automatiser dine Hue-lys med Kodi. Opret scener i flere rum, der kører, når du afspiller, sætter på pause eller stopper medieafspilning. Opret og slet multirumsscener fra indstillinger og vælg derefter, hvilke der skal anvendes til forskellige afspilningstyper. Kan bruge Hues tider for solopgang og solnedgang til automatisk at deaktivere tjenesten i dagtimerne og tænde lysene ved solnedgang under afspilning. Inkluderer understøttelse af Ambilight. - Hue-Lichter mit Kodi automatisieren. Mehrraum-Szenen erstellen, die während der Wiedergabe, des Pausierens oder des Stoppens der Medienwiedergabe aktiv sind. Mehrraum-Szenen aus den Addon-Einstellungen heraus erstellen und löschen, dann auswählen, welche für verschiedene Wiedergabe-Ereignisse genutzt werden sollen. Kann Hues Sonnenaufgangs- und -untergangszeiten zum autmatischen Deaktivieren des Dienstes während der Tageszeit nutzen und die Lichter während der Wiedergabe bei Sonnenuntergang einschalten. Beinhaltet Ambilight-Unterstützung. + Hue-Licht mit Kodi automatisieren. Mehrraumszenen erstellen, die während der Wiedergabe, beim Pausieren oder Stoppen der Medienwiedergabe aktiv sind. Mehrraumszenen aus den Addon-Einstellungen heraus erstellen und löschen, dann auswählen, welche für verschiedene Wiedergabeereignisse genutzt werden sollen. Kann Hues Sonnenaufgangs- und -untergangszeiten zum automatischen Deaktivieren des Dienstes während der Tageszeit nutzen und die Lampen während der Wiedergabe bei Sonnenuntergang einschalten. Beinhaltet Ambilight-Unterstützung. Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support. Automatisoi Hue-valosi Kodilla. Luo monihuonevalaistusasetuksia, jotka suoritetaan median toiston alkaessa, tauotessa tai päättyessä. Luo ja poista valaistusasetuksia lisäosan asetuksista ja valitse niiden käyttö ei toistotapahtumissa. Huen auringonnousu- ja -laskuaikoja voidaan hyödyntää palvelun automaattiseen käytöstä poistoon päiväsaikaan ja valojen sytytykseen auringon laskiessa toiston aikana. Sisältää myös Ambilight-tuen. + Automatiser vos lumières Hue V2 (Philips) avec Kodi. Créez des scènes multi-pièces qui s'exécutent lorsque vous lisez, mettez en pause ou arrêtez la lecture multimédia. Créer et supprimer des scènes multi-pièces à partir des paramètres complémentaires, puis sélectionner celle à appliquer pour différents événements de lecture. Peut utiliser les heures de lever et de coucher du soleil de Hue pour désactiver automatiquement le service pendant la journée et allumer les lumières au coucher du soleil pendant la lecture. Inclut la prise en charge Ambilight. + Automatizirajte svoja Hue svjetla s Kodijem. Stvorite višesobnu scenu koja se pokreće kada Reproducirate, Pauzirate ili Zaustavite medijsku reprodukciju. Stvorite i obrišite višesobne scene iz postavki dodatka tada odaberite koju primijeniti za drugačiji događaj reprodukcije. Može se koristiti zasićenje vremena izlaska i zalaska sunca za automatsko onemogućavanje usluge tijekom dana i uključivanje svjetla pri zalasku sunca tijekom reprodukcije. Automatizza le tue luci Hue con Kodi. Crea scene multi-stanza che vengono eseguite quando riproduci, metti in pausa o interrompi la riproduzione multimediale. Crea ed elimina scene multi-room dalle impostazioni del componente aggiuntivo, quindi seleziona quali applicare per diversi eventi di riproduzione. Può utilizzare gli orari di alba e tramonto di Hue per disabilitare automaticamente il servizio durante il giorno e accendere le luci al tramonto durante la riproduzione. Include il supporto Ambilight. Kodi로 Hue 조명을 자동화하세요. 미디어 재생을 재생, 일시 중지 또는 중지할 때 실행되는 멀티룸 장면을 만듭니다. 애드온 설정에서 멀티룸 장면을 만들거나 삭제하고 다른 재생 이벤트에 적용할 장면을 선택합니다. Hue의 일출 및 일몰 시간을 사용하여 주간에는 서비스를 자동으로 비활성화하고 재생 중에 일몰 시 조명을 켤 수 있습니다. Ambilight 지원이 포함됩니다. 使用 Kodi 自动化 Hue 灯光。创建播放、暂停或停止媒体播放时运行的多房间场景。从插件设置中创建和删除多房间场景,然后选择要应用于不同播放事件的场景。可以使用 Hue 灯的日出和日落时间在白天自动禁用服务,并在日落后播放期间打开灯光。包括 Ambilight 支持。 @@ -50,6 +53,8 @@ Weblate localisation update Erfordert eine Hue Bridge V2 (quadratisch). Ambilight-Unterstützung nicht mit jeder Hardware verfügbar. Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware. Vaatii Hue Silta V2 (nelikulmainen) -laitteen. Ambilight ei ole käytettävissä kaikilla laitteilla. + Nécessite un bridge Hue V2 (carré). Ambilight n'est pas disponible sur tous les matériels. + Zahtijeva Hue Bridge V2 (Square). Ambijetalno svijtlo nije dostupno na svim hardverima. Richiede un Bridge Hue V2 (quadrato). Ambilight non disponibile su tutto l'hardware. Hue Bridge V2(정사각형)가 필요합니다. 모든 하드웨어에서 Ambilight를 사용할 수 있는 것은 아닙니다. 需要 Hue Bridge V2 桥接器(正方形)。并非所有硬件都支持环境光。 diff --git a/script.service.hue/resources/language/resource.language.af_za/strings.po b/script.service.hue/resources/language/resource.language.af_za/strings.po index 1a846c827..50f0d5784 100644 --- a/script.service.hue/resources/language/resource.language.af_za/strings.po +++ b/script.service.hue/resources/language/resource.language.af_za/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.am_et/strings.po b/script.service.hue/resources/language/resource.language.am_et/strings.po index 7ec0a9c2f..7799badbc 100644 --- a/script.service.hue/resources/language/resource.language.am_et/strings.po +++ b/script.service.hue/resources/language/resource.language.am_et/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ar_sa/strings.po b/script.service.hue/resources/language/resource.language.ar_sa/strings.po index 260a018c4..ddf60b0bd 100644 --- a/script.service.hue/resources/language/resource.language.ar_sa/strings.po +++ b/script.service.hue/resources/language/resource.language.ar_sa/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ast_es/strings.po b/script.service.hue/resources/language/resource.language.ast_es/strings.po index 4a17ab513..801c96f17 100644 --- a/script.service.hue/resources/language/resource.language.ast_es/strings.po +++ b/script.service.hue/resources/language/resource.language.ast_es/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.az_az/strings.po b/script.service.hue/resources/language/resource.language.az_az/strings.po index 511de0bf1..431f60bd7 100644 --- a/script.service.hue/resources/language/resource.language.az_az/strings.po +++ b/script.service.hue/resources/language/resource.language.az_az/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.be_by/strings.po b/script.service.hue/resources/language/resource.language.be_by/strings.po index a35fa6501..a47bbf878 100644 --- a/script.service.hue/resources/language/resource.language.be_by/strings.po +++ b/script.service.hue/resources/language/resource.language.be_by/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.bg_bg/strings.po b/script.service.hue/resources/language/resource.language.bg_bg/strings.po index ed45b62bf..c18c950cb 100644 --- a/script.service.hue/resources/language/resource.language.bg_bg/strings.po +++ b/script.service.hue/resources/language/resource.language.bg_bg/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.bs_ba/strings.po b/script.service.hue/resources/language/resource.language.bs_ba/strings.po index 72a3fb82c..50d9f18bc 100644 --- a/script.service.hue/resources/language/resource.language.bs_ba/strings.po +++ b/script.service.hue/resources/language/resource.language.bs_ba/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ca_es/strings.po b/script.service.hue/resources/language/resource.language.ca_es/strings.po index 3c2c53aae..560e8b14f 100644 --- a/script.service.hue/resources/language/resource.language.ca_es/strings.po +++ b/script.service.hue/resources/language/resource.language.ca_es/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.cs_cz/strings.po b/script.service.hue/resources/language/resource.language.cs_cz/strings.po index c0b9f34d7..452e40569 100644 --- a/script.service.hue/resources/language/resource.language.cs_cz/strings.po +++ b/script.service.hue/resources/language/resource.language.cs_cz/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "Bridge (most)" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "Vyhledat Hue Bridge" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -552,6 +552,18 @@ msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" + +#~ msgctxt "#30501" +#~ msgid "Discover Hue Bridge" +#~ msgstr "Vyhledat Hue Bridge" + #~ msgctxt "#30033" #~ msgid "{} secs." #~ msgstr "{} sek." diff --git a/script.service.hue/resources/language/resource.language.cy_gb/strings.po b/script.service.hue/resources/language/resource.language.cy_gb/strings.po index 470fc63c2..064f3618d 100644 --- a/script.service.hue/resources/language/resource.language.cy_gb/strings.po +++ b/script.service.hue/resources/language/resource.language.cy_gb/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.da_dk/strings.po b/script.service.hue/resources/language/resource.language.da_dk/strings.po index 95573a435..222c7eb8e 100644 --- a/script.service.hue/resources/language/resource.language.da_dk/strings.po +++ b/script.service.hue/resources/language/resource.language.da_dk/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-08-15 22:34+0000\n" +"PO-Revision-Date: 2023-01-21 23:15+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Danish \n" "Language: da_dk\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13\n" +"X-Generator: Weblate 4.15.1\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "Bridge" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "Find Hue Bridge" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Opdag Hue Bridge / Indtast IP" msgctxt "#30502" msgid "Bridge IP" @@ -552,6 +552,18 @@ msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "Bridge forældet. Opdater venligst din bridge." +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "FEJL: Scene eller lys blev ikke fundet, den kan være ændret eller blevet slettet. Tjek din konfiguration." + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" + +#~ msgctxt "#30501" +#~ msgid "Discover Hue Bridge" +#~ msgstr "Find Hue Bridge" + #~ msgctxt "#30504" #~ msgid "Bridge Serial" #~ msgstr "Bridge serienummer" diff --git a/script.service.hue/resources/language/resource.language.de_de/strings.po b/script.service.hue/resources/language/resource.language.de_de/strings.po index 1d7a039a5..332557ced 100644 --- a/script.service.hue/resources/language/resource.language.de_de/strings.po +++ b/script.service.hue/resources/language/resource.language.de_de/strings.po @@ -6,23 +6,23 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-09-26 10:30+0000\n" -"Last-Translator: Chillbo \n" +"PO-Revision-Date: 2023-02-05 08:15+0000\n" +"Last-Translator: Demian \n" "Language-Team: German \n" "Language: de_de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" -msgstr "Automatisiere Hue-Lichter mit der Kodi-Wiedergabe" +msgstr "Hue-Licht mit der Kodi-Wiedergabe automatisieren" msgctxt "Addon Description" msgid "Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support." -msgstr "Hue-Lichter mit Kodi automatisieren. Mehrraum-Szenen erstellen, die während der Wiedergabe, des Pausierens oder des Stoppens der Medienwiedergabe aktiv sind. Mehrraum-Szenen aus den Addon-Einstellungen heraus erstellen und löschen, dann auswählen, welche für verschiedene Wiedergabe-Ereignisse genutzt werden sollen. Kann Hues Sonnenaufgangs- und -untergangszeiten zum autmatischen Deaktivieren des Dienstes während der Tageszeit nutzen und die Lichter während der Wiedergabe bei Sonnenuntergang einschalten. Beinhaltet Ambilight-Unterstützung." +msgstr "Hue-Licht mit Kodi automatisieren. Mehrraumszenen erstellen, die während der Wiedergabe, beim Pausieren oder Stoppen der Medienwiedergabe aktiv sind. Mehrraumszenen aus den Addon-Einstellungen heraus erstellen und löschen, dann auswählen, welche für verschiedene Wiedergabeereignisse genutzt werden sollen. Kann Hues Sonnenaufgangs- und -untergangszeiten zum automatischen Deaktivieren des Dienstes während der Tageszeit nutzen und die Lampen während der Wiedergabe bei Sonnenuntergang einschalten. Beinhaltet Ambilight-Unterstützung." msgctxt "Addon Disclaimer" msgid "Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware." @@ -30,11 +30,11 @@ msgstr "Erfordert eine Hue Bridge V2 (quadratisch). Ambilight-Unterstützung nic msgctxt "#32100" msgid "Video Actions" -msgstr "Video-Aktionen" +msgstr "Videoaktionen" msgctxt "#32102" msgid "Audio Actions" -msgstr "Audio-Aktionen" +msgstr "Audioaktionen" msgctxt "#32201" msgid "Start/Resume" @@ -46,11 +46,11 @@ msgstr "Pause" msgctxt "#32203" msgid "Stop" -msgstr "Stop" +msgstr "Stopp" msgctxt "#32510" msgid "Scene Name:" -msgstr "Szenen-Name:" +msgstr "Szenenname:" msgctxt "#32511" msgid "Scene ID" @@ -58,15 +58,15 @@ msgstr "Szenen-ID" msgctxt "#32512" msgid "Select..." -msgstr "Wählen..." +msgstr "Wählen …" msgctxt "#30500" msgid "Bridge" msgstr "Bridge" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "Hue Bridge finden" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Hue Bridge ermitteln / IP eingeben" msgctxt "#30502" msgid "Bridge IP" @@ -94,7 +94,7 @@ msgstr "Bei Tageslicht abschalten" msgctxt "#30509" msgid "Activate during playback at sunset" -msgstr "Bei Sonnenuntergang aktivieren" +msgstr "Bei Wiedergabe zu Sonnenuntergang aktivieren" msgctxt "#30510" msgid "General" @@ -110,15 +110,15 @@ msgstr "Szenen" msgctxt "#30513" msgid "Play Scene Enabled" -msgstr "Wiedergabe-Szene aktiviert" +msgstr "Wiedergabeszene aktiviert" msgctxt "#30514" msgid "Pause Scene Enabled" -msgstr "Pause-Szene aktiviert" +msgstr "Pauseszene aktiviert" msgctxt "#30515" msgid "Stop Scene Enabled" -msgstr "Stop-Szene aktiviert" +msgstr "Stoppszene aktiviert" msgctxt "#30516" msgid "Disable time check if any light already on" @@ -130,11 +130,11 @@ msgstr "Szene bei bereits ausgeschaltetem Licht nicht aktivieren" msgctxt "#30521" msgid "[B][I]Warning: Not supported on all hardware[/B][/I]" -msgstr "[B][I]Warnung: Nicht mit jeder Hardware verfügbar[/B][/I]" +msgstr "[B][I]Warnung: Nicht mit jeder Hardware verfügbar[/I][/B]" msgctxt "#30522" msgid "CPU & Hue performance" -msgstr "CPU- & Hue-Leistung" +msgstr "CPU- und Hue-Leistung" msgctxt "#30523" msgid "Ambilight" @@ -146,11 +146,11 @@ msgstr "Erweitert" msgctxt "#32106" msgid "Video Activation" -msgstr "Video-Aktivierung" +msgstr "Videoaktivierung" msgctxt "#6101" msgid "Select Lights" -msgstr "Lichter wählen" +msgstr "Licht auswählen" msgctxt "#30520" msgid "Enabled" @@ -170,7 +170,7 @@ msgstr "Szene löschen" msgctxt "#30000" msgid "Hue Service" -msgstr "Hue Dienst" +msgstr "Hue-Dienst" msgctxt "#30004" msgid "Check your bridge and network" @@ -198,7 +198,7 @@ msgstr "Abgebrochen" msgctxt "#30015" msgid "Select Hue Lights..." -msgstr "Hue-Lichter auswählen..." +msgstr "Hue-Licht auswählen …" msgctxt "#30017" msgid "Found bridge: " @@ -206,7 +206,7 @@ msgstr "Bridge gefunden: " msgctxt "#30018" msgid "Discover bridge..." -msgstr "Bridge erkennen..." +msgstr "Bridge ermitteln …" msgctxt "#30021" msgid "Bridge connection failed" @@ -214,7 +214,7 @@ msgstr "Bridge-Verbindung fehlgeschlagen" msgctxt "#30022" msgid "Discovery started" -msgstr "Suche gestartet" +msgstr "Ermittlung gestartet" msgctxt "#30023" msgid "Bridge not configured" @@ -222,7 +222,7 @@ msgstr "Bridge nicht konfiguriert" msgctxt "#30024" msgid "Check Hue Bridge configuration" -msgstr "Hue Bridge-Konfiguration prüfen" +msgstr "Hue-Bridge-Konfiguration prüfen" msgctxt "#30025" msgid "ERROR: Scene not deleted" @@ -238,7 +238,7 @@ msgstr "Hue-Szene löschen" msgctxt "#30030" msgid "Enter Scene Name" -msgstr "Szenen-Namen eingeben" +msgstr "Szenenname eingeben" msgctxt "#30031" msgid "Transition Time:" @@ -250,11 +250,11 @@ msgstr "Abbruch" msgctxt "#30035" msgid "Lights:" -msgstr "Lampen:" +msgstr "Licht:" msgctxt "#30036" msgid "Scene Name:" -msgstr "Szenen-Name:" +msgstr "Szenenname:" msgctxt "#30037" msgid "Save" @@ -262,15 +262,15 @@ msgstr "Speichern" msgctxt "#30038" msgid "Create Hue Scene" -msgstr "Hue Szene erstellen" +msgstr "Hue-Szene erstellen" msgctxt "#30002" msgid "ERROR: Scene not created" -msgstr "ERROR: Scene not created" +msgstr "FEHLER: Szene nicht erstellt" msgctxt "#30039" msgid "Set a fade time in seconds, or 0 for an instant transition." -msgstr "Überblendungszeit in Sekunden festlegen, oder 0 für einen sofortigen Übergang." +msgstr "Überblendzeit in Sekunden festlegen oder 0 für einen sofortigen Übergang." msgctxt "#30040" msgid "Scene deleted" @@ -278,11 +278,11 @@ msgstr "Szene gelöscht" msgctxt "#30041" msgid "You may now assign your Scene to player actions." -msgstr "Die Szene kann nun Player-Aktionen zugewiesen werden." +msgstr "Die Szene kann nun Playeraktionen zugewiesen werden." msgctxt "#30042" msgid "Fade Time (Seconds)" -msgstr "Überblendungszeit (Sekunden)" +msgstr "Überblendzeit (Sekunden)" msgctxt "#30043" msgid "Error" @@ -298,7 +298,7 @@ msgstr "Szene erfolgreich erstellt!" msgctxt "#30046" msgid "Adjust lights to desired state in the Hue App to save as new scene." -msgstr "Lichter für den gewünschten Zustand in der Hue-App zum Speichern einer neuen Szene anpassen." +msgstr "Licht in der Hue-App auf den gewünschten Zustand einstellen und als neue Szene speichern." msgctxt "#30047" msgid "Connection lost. Check settings. Shutting down" @@ -310,19 +310,19 @@ msgstr "Verbindung verloren. In 2 Minuten erneut versuchen" msgctxt "#30049" msgid "Scene Name" -msgstr "Szenen-Name" +msgstr "Szenenname" msgctxt "#30050" msgid "N-UPnP discovery..." -msgstr "N-UPnP-Suche..." +msgstr "N-UPnP-Suche …" msgctxt "#30051" msgid "UPnP discovery..." -msgstr "UPnP-Suche..." +msgstr "UPnP-Suche …" msgctxt "#30005" msgid "Searching for bridge..." -msgstr "Suche nach Bridge..." +msgstr "Bridge wird gesucht …" msgctxt "#30052" msgid "Invalid start or end time, schedule disabled" @@ -334,15 +334,15 @@ msgstr "Helligkeit beim Start einstellen" msgctxt "#30057" msgid "Force on" -msgstr "Erzwinge an" +msgstr "Erzwingen an" msgctxt "#30058" msgid "Light Names:" -msgstr "Licht-Namen:" +msgstr "Lichtnamen:" msgctxt "#30065" msgid "Update interval (ms)" -msgstr "Update-Intervall (ms)" +msgstr "Updateintervall (ms)" msgctxt "#30066" msgid "Hue transition time (ms)" @@ -354,7 +354,7 @@ msgstr "Größe der Frame-Erfassung" msgctxt "#30068" msgid "Show Hue bridge capacity errors" -msgstr "Hue Bridge-Kapazitätsfehler anzeigen" +msgstr "Hue-Bridge-Kapazitätsfehler anzeigen" msgctxt "#30800" msgid "Minimum duration (Minutes)" @@ -362,23 +362,23 @@ msgstr "Mindestdauer (Minuten)" msgctxt "#30801" msgid "Enable for Movies" -msgstr "Aktivieren für Filme" +msgstr "Für Filme aktivieren" msgctxt "#30802" msgid "Enable for TV episodes" -msgstr "Aktivieren für Serien" +msgstr "Für Serien aktivieren" msgctxt "#30803" msgid "Enable for music videos" -msgstr "Aktivieren für Musik Videos" +msgstr "Für Musikvideos aktivieren" msgctxt "#30804" msgid "Enable for other videos (Discs)" -msgstr "Aktivieren für andere Videos (Discs)" +msgstr "Für andere Videos (Discs) aktivieren" msgctxt "#30805" msgid "Enable for live TV" -msgstr "Aktivieren für live TV" +msgstr "Für TV aktivieren" msgctxt "#30809" msgid "Saturation" @@ -386,11 +386,11 @@ msgstr "Sättigung" msgctxt "#30810" msgid "Minimum Brightness" -msgstr "Mindest-Helligkeit" +msgstr "Mindesthelligkeit" msgctxt "#30811" msgid "Maximum Brightness" -msgstr "Maximal-Helligkeit" +msgstr "Maximalhelligkeit" msgctxt "#30812" msgid "Disable connection message" @@ -414,7 +414,7 @@ msgstr "Übergangszeit beim Fortsetzen (Sek.)" msgctxt "#30071" msgid "Only colour lights are supported" -msgstr "Nur Farblichter werden unterstützt" +msgstr "Nur Farblampen werden unterstützt" msgctxt "#30072" msgid "Unsupported Hue Bridge" @@ -426,7 +426,7 @@ msgstr "Deaktivert" msgctxt "#30060" msgid "Play" -msgstr "Abspielen" +msgstr "Wiedergeben" msgctxt "#30061" msgid "Hue Status: " @@ -458,7 +458,7 @@ msgstr "Keine Licht für Ambilight ausgewählt." msgctxt "#30070" msgid "Ok" -msgstr "Ok" +msgstr "OK" msgctxt "#30075" msgid "Hue Bridge over capacity" @@ -478,7 +478,7 @@ msgstr "Bridge nicht gefunden[CR]Bridge und Netzwerk überprüfen." msgctxt "#30082" msgid "Press link button on bridge. Waiting for 90 seconds..." -msgstr "Link-Knopf auf der Bridge drücken. Für 90 Sekunden warten..." +msgstr "Linktaste auf der Bridge drücken. 90 Sekunden lang warten …" msgctxt "#30083" msgid "Unknown" @@ -486,11 +486,11 @@ msgstr "Unbekannt" msgctxt "#30084" msgid "User Found![CR]Saving settings..." -msgstr "Anwender gefunden![CR]Einstellungen werden gespeichert..." +msgstr "Anwender gefunden![CR]Einstellungen werden gespeichert …" msgctxt "#30085" msgid "Adjust lights to desired state in the Hue App to save as new scene.[CR]Set a fade time in seconds, or 0 for an instant transition." -msgstr "Lichter für den gewünschten Zustand in der Hue-App zum Speichern einer neuen Szene anpassen.[CR]Überblendungszeit in Sekunden festlegen, oder 0 für einen sofortigen Übergang." +msgstr "Licht in der Hue-App auf den gewünschten Zustand einstellen und als neue Szene speichern.[CR]Überblendzeit in Sekunden festlegen oder 0 für einen sofortigen Übergang." msgctxt "#30086" msgid "User not found[CR]Check your bridge and network." @@ -498,7 +498,7 @@ msgstr "Anwender nicht gefunden[CR]Bridge und Netzwerk überprüfen." msgctxt "#30087" msgid "Scene successfully created![CR]You may now assign your scene to player actions." -msgstr "Szene erfolgreich erstellt![CR]Die Szene kann nun Player-Aktionen zugewiesen werden." +msgstr "Szene erfolgreich erstellt![CR]Die Szene kann nun Playeraktionen zugewiesen werden." msgctxt "#30073" msgid "Do not show again" @@ -514,7 +514,7 @@ msgstr "Hue Bridge V1 (rund) wird nicht unterstützt. Hue Bridge V2 (quadratisch msgctxt "#30012" msgid "Unknown colour gamut for light:" -msgstr "" +msgstr "Unbekannter Farbraum für Licht:" msgctxt "#30016" msgid "Report errors" @@ -526,7 +526,7 @@ msgstr "Fehler niemals melden" msgctxt "#30032" msgid "Hue Service Error" -msgstr "Hue-Dienst-Fehler" +msgstr "Hue-Dienstfehler" msgctxt "#30029" msgid "Connection Error" @@ -534,23 +534,35 @@ msgstr "Verbindungsfehler" msgctxt "#30014" msgid "Error: Lights incompatible with Ambilight" -msgstr "Fehler: Lichter mit Ambilight inkompatibel" +msgstr "Fehler: Licht mit Ambilight inkompatibel" msgctxt "#30007" msgid "Bridge not found automatically. Please make sure your bridge is up to date and has access to the internet. [CR]Would you like to enter your bridge IP manually?" -msgstr "" +msgstr "Bridge wurde nicht automatisch gefunden. Bitte sicherstellen, dass die Bridge auf dem neuesten Stand ist und Zugang zum Internet hat.[CR]Soll die Bridge-IP manuell eingegeben werden?" msgctxt "#30009" msgid "Connecting..." -msgstr "" +msgstr "Verbinden …" msgctxt "#30027" msgid "Are you sure you want to delete this scene:" -msgstr "" +msgstr "Soll diese Szene wirklich gelöscht werden:" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." -msgstr "" +msgstr "Bridge ist nicht mehr aktuell. Bitte die Bridge aktualisieren." + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "FEHLER: Szene oder Licht nicht gefunden, möglicherweise wurde sie geändert oder gelöscht. Bitte Konfiguration überprüfen." + +msgctxt "#30033" +msgid "Reconnected" +msgstr "Neu verbunden" + +#~ msgctxt "#30501" +#~ msgid "Discover Hue Bridge" +#~ msgstr "Hue Bridge finden" #~ msgctxt "#30027" #~ msgid "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" diff --git a/script.service.hue/resources/language/resource.language.el_gr/strings.po b/script.service.hue/resources/language/resource.language.el_gr/strings.po index c212611e7..ac661e77a 100644 --- a/script.service.hue/resources/language/resource.language.el_gr/strings.po +++ b/script.service.hue/resources/language/resource.language.el_gr/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.en_au/strings.po b/script.service.hue/resources/language/resource.language.en_au/strings.po index 26dfd7c2d..c07115333 100644 --- a/script.service.hue/resources/language/resource.language.en_au/strings.po +++ b/script.service.hue/resources/language/resource.language.en_au/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -552,6 +552,14 @@ msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" + #~ msgctxt "#30027" #~ msgid "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" #~ msgstr "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" diff --git a/script.service.hue/resources/language/resource.language.en_gb/strings.po b/script.service.hue/resources/language/resource.language.en_gb/strings.po index 46e08a5b2..ee5848632 100644 --- a/script.service.hue/resources/language/resource.language.en_gb/strings.po +++ b/script.service.hue/resources/language/resource.language.en_gb/strings.po @@ -58,8 +58,8 @@ msgid "Bridge" msgstr "Bridge" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "Discover Hue Bridge" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -544,3 +544,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.en_nz/strings.po b/script.service.hue/resources/language/resource.language.en_nz/strings.po index 571444bed..840f899e9 100644 --- a/script.service.hue/resources/language/resource.language.en_nz/strings.po +++ b/script.service.hue/resources/language/resource.language.en_nz/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -552,6 +552,14 @@ msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" + #~ msgctxt "#30027" #~ msgid "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" #~ msgstr "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" diff --git a/script.service.hue/resources/language/resource.language.en_us/strings.po b/script.service.hue/resources/language/resource.language.en_us/strings.po index 7faa7d742..803c7a0ec 100644 --- a/script.service.hue/resources/language/resource.language.en_us/strings.po +++ b/script.service.hue/resources/language/resource.language.en_us/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -552,6 +552,14 @@ msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" + #~ msgctxt "#30027" #~ msgid "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" #~ msgstr "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" diff --git a/script.service.hue/resources/language/resource.language.eo/strings.po b/script.service.hue/resources/language/resource.language.eo/strings.po index a8e8e298b..fe17c111e 100644 --- a/script.service.hue/resources/language/resource.language.eo/strings.po +++ b/script.service.hue/resources/language/resource.language.eo/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.es_ar/strings.po b/script.service.hue/resources/language/resource.language.es_ar/strings.po index baa653932..b2059a157 100644 --- a/script.service.hue/resources/language/resource.language.es_ar/strings.po +++ b/script.service.hue/resources/language/resource.language.es_ar/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.es_es/strings.po b/script.service.hue/resources/language/resource.language.es_es/strings.po index 661c80024..e5e5f2f28 100644 --- a/script.service.hue/resources/language/resource.language.es_es/strings.po +++ b/script.service.hue/resources/language/resource.language.es_es/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-04-05 16:16+0000\n" +"PO-Revision-Date: 2023-01-03 23:15+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Spanish (Spain) \n" "Language: es_es\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.11.2\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -42,11 +42,11 @@ msgstr "" msgctxt "#32202" msgid "Pause" -msgstr "" +msgstr "Pausa" msgctxt "#32203" msgid "Stop" -msgstr "" +msgstr "Parar" msgctxt "#32510" msgid "Scene Name:" @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -258,7 +258,7 @@ msgstr "" msgctxt "#30037" msgid "Save" -msgstr "" +msgstr "Guardar" msgctxt "#30038" msgid "Create Hue Scene" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.es_mx/strings.po b/script.service.hue/resources/language/resource.language.es_mx/strings.po index 66335a399..6da2cdab0 100644 --- a/script.service.hue/resources/language/resource.language.es_mx/strings.po +++ b/script.service.hue/resources/language/resource.language.es_mx/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.et_ee/strings.po b/script.service.hue/resources/language/resource.language.et_ee/strings.po index 7534213a6..1d553eb43 100644 --- a/script.service.hue/resources/language/resource.language.et_ee/strings.po +++ b/script.service.hue/resources/language/resource.language.et_ee/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.eu_es/strings.po b/script.service.hue/resources/language/resource.language.eu_es/strings.po index 1b5ad8165..d0d02c261 100644 --- a/script.service.hue/resources/language/resource.language.eu_es/strings.po +++ b/script.service.hue/resources/language/resource.language.eu_es/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.fa_af/strings.po b/script.service.hue/resources/language/resource.language.fa_af/strings.po index e51cd4363..449705a15 100644 --- a/script.service.hue/resources/language/resource.language.fa_af/strings.po +++ b/script.service.hue/resources/language/resource.language.fa_af/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.fa_ir/strings.po b/script.service.hue/resources/language/resource.language.fa_ir/strings.po index ace759685..029e7dbfc 100644 --- a/script.service.hue/resources/language/resource.language.fa_ir/strings.po +++ b/script.service.hue/resources/language/resource.language.fa_ir/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.fi_fi/strings.po b/script.service.hue/resources/language/resource.language.fi_fi/strings.po index 9c8d7f0e5..8f4f435da 100644 --- a/script.service.hue/resources/language/resource.language.fi_fi/strings.po +++ b/script.service.hue/resources/language/resource.language.fi_fi/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-08-15 22:34+0000\n" +"PO-Revision-Date: 2023-02-05 08:15+0000\n" "Last-Translator: Oskari Lavinto \n" "Language-Team: Finnish \n" "Language: fi_fi\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "Silta" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "Etsi Hue Silta" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Etsi Hue Silta / Syötä IP-osoite" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,15 @@ msgstr "Haluatko varmasti poistaa seuraavan valaistusasetuksen:" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "Silta ei ole ajan tasalla. Päivitä sen laiteohjelmisto." + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "VIRHE: Valaistusasetusta tai valoa ei löytyny ja se on saattanut muuttua tai poistettu. Tarkista asetukset." + +msgctxt "#30033" +msgid "Reconnected" +msgstr "Yhdistetty uudelleen" + +#~ msgctxt "#30501" +#~ msgid "Discover Hue Bridge" +#~ msgstr "Etsi Hue Silta" diff --git a/script.service.hue/resources/language/resource.language.fo_fo/strings.po b/script.service.hue/resources/language/resource.language.fo_fo/strings.po index d1264109c..069f574f3 100644 --- a/script.service.hue/resources/language/resource.language.fo_fo/strings.po +++ b/script.service.hue/resources/language/resource.language.fo_fo/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.fr_ca/strings.po b/script.service.hue/resources/language/resource.language.fr_ca/strings.po index 7ad0f4a87..7272be8df 100644 --- a/script.service.hue/resources/language/resource.language.fr_ca/strings.po +++ b/script.service.hue/resources/language/resource.language.fr_ca/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.fr_fr/strings.po b/script.service.hue/resources/language/resource.language.fr_fr/strings.po index 72431b6a3..6d4d31bc6 100644 --- a/script.service.hue/resources/language/resource.language.fr_fr/strings.po +++ b/script.service.hue/resources/language/resource.language.fr_fr/strings.po @@ -6,95 +6,95 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-03-09 14:05+0000\n" -"Last-Translator: Christian Gade \n" +"PO-Revision-Date: 2023-01-15 23:20+0000\n" +"Last-Translator: skypichat \n" "Language-Team: French (France) \n" "Language: fr_fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.11.2\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" -msgstr "" +msgstr "Automatiser les lumières Hue V2 (Philips) avec la lecture Kodi" msgctxt "Addon Description" msgid "Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support." -msgstr "" +msgstr "Automatiser vos lumières Hue V2 (Philips) avec Kodi. Créez des scènes multi-pièces qui s'exécutent lorsque vous lisez, mettez en pause ou arrêtez la lecture multimédia. Créer et supprimer des scènes multi-pièces à partir des paramètres complémentaires, puis sélectionner celle à appliquer pour différents événements de lecture. Peut utiliser les heures de lever et de coucher du soleil de Hue pour désactiver automatiquement le service pendant la journée et allumer les lumières au coucher du soleil pendant la lecture. Inclut la prise en charge Ambilight." msgctxt "Addon Disclaimer" msgid "Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware." -msgstr "" +msgstr "Nécessite un bridge Hue V2 (carré). Ambilight n'est pas disponible sur tous les matériels." msgctxt "#32100" msgid "Video Actions" -msgstr "" +msgstr "Actions vidéo" msgctxt "#32102" msgid "Audio Actions" -msgstr "" +msgstr "Actions audio" msgctxt "#32201" msgid "Start/Resume" -msgstr "" +msgstr "Démarrer/Reprendre" msgctxt "#32202" msgid "Pause" -msgstr "" +msgstr "Pause" msgctxt "#32203" msgid "Stop" -msgstr "" +msgstr "Stop" msgctxt "#32510" msgid "Scene Name:" -msgstr "" +msgstr "Nom de la scène :" msgctxt "#32511" msgid "Scene ID" -msgstr "" +msgstr "ID de la scène" msgctxt "#32512" msgid "Select..." -msgstr "" +msgstr "Sélectionner..." msgctxt "#30500" msgid "Bridge" -msgstr "" +msgstr "Bridge" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Découverte du bridge Hue / Entrer l'adresse IP" msgctxt "#30502" msgid "Bridge IP" -msgstr "" +msgstr "IP du Bridge" msgctxt "#30503" msgid "Bridge User" -msgstr "" +msgstr "Utilisateur du Bridge" msgctxt "#30505" msgid "Enable Schedule (24h format)" -msgstr "" +msgstr "Activer la programmation (format 24h)" msgctxt "#30506" msgid "Start time:" -msgstr "" +msgstr "Heure de début :" msgctxt "#30507" msgid "End time:" -msgstr "" +msgstr "Heure de fin :" msgctxt "#30508" msgid "Disable during daylight" -msgstr "" +msgstr "Désactiver pendant la journée" msgctxt "#30509" msgid "Activate during playback at sunset" -msgstr "" +msgstr "Activer pendant la lecture au coucher du soleil" msgctxt "#30510" msgid "General" @@ -106,39 +106,39 @@ msgstr "Planifier" msgctxt "#30512" msgid "Scenes" -msgstr "" +msgstr "Scènes" msgctxt "#30513" msgid "Play Scene Enabled" -msgstr "" +msgstr "Lecture de scène activée" msgctxt "#30514" msgid "Pause Scene Enabled" -msgstr "" +msgstr "Pause scène activée" msgctxt "#30515" msgid "Stop Scene Enabled" -msgstr "" +msgstr "Arrêt Scène activée" msgctxt "#30516" msgid "Disable time check if any light already on" -msgstr "" +msgstr "Désactiver la vérification de l'heure si une lumière est déjà allumée" msgctxt "#30517" msgid "Don't enable scene if any light is off" -msgstr "" +msgstr "Ne pas activer la scène si une lumière est éteinte" msgctxt "#30521" msgid "[B][I]Warning: Not supported on all hardware[/B][/I]" -msgstr "" +msgstr "[B][I]Avertissement : Non pris en charge sur tous les matériels[/B][/I]" msgctxt "#30522" msgid "CPU & Hue performance" -msgstr "" +msgstr "Performances du processeur et de l'Ambilight" msgctxt "#30523" msgid "Ambilight" -msgstr "" +msgstr "Ambilight" msgctxt "#32101" msgid "Advanced" @@ -146,115 +146,115 @@ msgstr "Avancé" msgctxt "#32106" msgid "Video Activation" -msgstr "" +msgstr "Activation vidéo" msgctxt "#6101" msgid "Select Lights" -msgstr "" +msgstr "Sélectionner les lumières" msgctxt "#30520" msgid "Enabled" -msgstr "" +msgstr "Activé" msgctxt "#9001" msgid "Press connect button on Hue bridge" -msgstr "" +msgstr "Appuyer sur le bouton de connexion sur le bridge Hue" msgctxt "#9007" msgid "Create Scene" -msgstr "" +msgstr "Créer une scène" msgctxt "#9008" msgid "Delete Scene" -msgstr "" +msgstr "Supprimer la scène" msgctxt "#30000" msgid "Hue Service" -msgstr "" +msgstr "Service Hue" msgctxt "#30004" msgid "Check your bridge and network" -msgstr "" +msgstr "Vérifie votre bridge et votre réseau" msgctxt "#30006" msgid "Hue connected" -msgstr "" +msgstr "Hue connecté" msgctxt "#30008" msgid "Bridge not found" -msgstr "" +msgstr "Bridge non trouvé" msgctxt "#30010" msgid "User not found" -msgstr "" +msgstr "Utilisateur non trouvé" msgctxt "#30011" msgid "Complete!" -msgstr "" +msgstr "Compléter !" msgctxt "#30013" msgid "Cancelled" -msgstr "" +msgstr "Annulé" msgctxt "#30015" msgid "Select Hue Lights..." -msgstr "" +msgstr "Sélectionner Lumières Hue..." msgctxt "#30017" msgid "Found bridge: " -msgstr "" +msgstr "Bridge trouvé : " msgctxt "#30018" msgid "Discover bridge..." -msgstr "" +msgstr "Découvrir le bridge..." msgctxt "#30021" msgid "Bridge connection failed" -msgstr "" +msgstr "La connexion au bridge a échoué" msgctxt "#30022" msgid "Discovery started" -msgstr "" +msgstr "La découverte a commencé" msgctxt "#30023" msgid "Bridge not configured" -msgstr "" +msgstr "Bridge non configuré" msgctxt "#30024" msgid "Check Hue Bridge configuration" -msgstr "" +msgstr "Vérifier la configuration du bridge Hue" msgctxt "#30025" msgid "ERROR: Scene not deleted" -msgstr "" +msgstr "ERREUR : Scène non supprimée" msgctxt "#30026" msgid "Scene Created" -msgstr "" +msgstr "Scène créée" msgctxt "#30028" msgid "Delete Hue Scene" -msgstr "" +msgstr "Supprimer la scène du Hue" msgctxt "#30030" msgid "Enter Scene Name" -msgstr "" +msgstr "Entrer le nom de la scène" msgctxt "#30031" msgid "Transition Time:" -msgstr "" +msgstr "Temps de transition :" msgctxt "#30034" msgid "Cancel" -msgstr "" +msgstr "Annuler" msgctxt "#30035" msgid "Lights:" -msgstr "" +msgstr "Lumières :" msgctxt "#30036" msgid "Scene Name:" -msgstr "" +msgstr "Nom de la scène :" msgctxt "#30037" msgid "Save" @@ -262,27 +262,27 @@ msgstr "Enregistrer" msgctxt "#30038" msgid "Create Hue Scene" -msgstr "" +msgstr "Créer une scène de Hue" msgctxt "#30002" msgid "ERROR: Scene not created" -msgstr "ERROR: Scene not created" +msgstr "ERREUR : Scène non créée" msgctxt "#30039" msgid "Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Définir un temps de fondu en secondes, ou 0 pour une transition instantanée." msgctxt "#30040" msgid "Scene deleted" -msgstr "" +msgstr "Scène supprimée" msgctxt "#30041" msgid "You may now assign your Scene to player actions." -msgstr "" +msgstr "Vous pouvez maintenant attribuer votre scène aux actions des lecteurs." msgctxt "#30042" msgid "Fade Time (Seconds)" -msgstr "" +msgstr "Temps de fondu (secondes)" msgctxt "#30043" msgid "Error" @@ -290,139 +290,139 @@ msgstr "Erreur" msgctxt "#30044" msgid "Create New Scene" -msgstr "" +msgstr "Créer une nouvelle scène" msgctxt "#30045" msgid "Scene successfully created!" -msgstr "" +msgstr "Scène créée avec succès !" msgctxt "#30046" msgid "Adjust lights to desired state in the Hue App to save as new scene." -msgstr "" +msgstr "Ajuster les lumières à l'état souhaité dans l'application Hue pour enregistrer en tant que nouvelle scène." msgctxt "#30047" msgid "Connection lost. Check settings. Shutting down" -msgstr "" +msgstr "Connexion perdue. Vérifier les paramètres. Éteindre" msgctxt "#30048" msgid "Connection lost. Trying again in 2 minutes" -msgstr "" +msgstr "Connexion perdue. Réessayer dans 2 minutes" msgctxt "#30049" msgid "Scene Name" -msgstr "" +msgstr "Nom de la scène" msgctxt "#30050" msgid "N-UPnP discovery..." -msgstr "" +msgstr "Découverte N-UPnP..." msgctxt "#30051" msgid "UPnP discovery..." -msgstr "" +msgstr "Découverte UPnP..." msgctxt "#30005" msgid "Searching for bridge..." -msgstr "" +msgstr "Recherche d'un bridge..." msgctxt "#30052" msgid "Invalid start or end time, schedule disabled" -msgstr "" +msgstr "Heure de début ou de fin non valide, programmation désactivée" msgctxt "#30056" msgid "Set brightness on start" -msgstr "" +msgstr "Régler la luminosité au démarrage" msgctxt "#30057" msgid "Force on" -msgstr "" +msgstr "Forcer ON" msgctxt "#30058" msgid "Light Names:" -msgstr "" +msgstr "Noms des éclairages :" msgctxt "#30065" msgid "Update interval (ms)" -msgstr "" +msgstr "Intervalle de mise à jour (ms)" msgctxt "#30066" msgid "Hue transition time (ms)" -msgstr "" +msgstr "Temps de transition de teinte (ms)" msgctxt "#30067" msgid "Frame capture size" -msgstr "" +msgstr "Taille de capture d'image" msgctxt "#30068" msgid "Show Hue bridge capacity errors" -msgstr "" +msgstr "Afficher les erreurs de capacité du bridge Hue" msgctxt "#30800" msgid "Minimum duration (Minutes)" -msgstr "" +msgstr "Durée minimale (Minutes)" msgctxt "#30801" msgid "Enable for Movies" -msgstr "" +msgstr "Activer pour les films" msgctxt "#30802" msgid "Enable for TV episodes" -msgstr "" +msgstr "Activer pour les épisodes séries TV" msgctxt "#30803" msgid "Enable for music videos" -msgstr "" +msgstr "Activer pour les clips musicaux" msgctxt "#30804" msgid "Enable for other videos (Discs)" -msgstr "" +msgstr "Activer pour les autres vidéos (Disques)" msgctxt "#30805" msgid "Enable for live TV" -msgstr "" +msgstr "Activer pour la télévision" msgctxt "#30809" msgid "Saturation" -msgstr "" +msgstr "Saturation" msgctxt "#30810" msgid "Minimum Brightness" -msgstr "" +msgstr "Luminosité minimale" msgctxt "#30811" msgid "Maximum Brightness" -msgstr "" +msgstr "Luminosité maximale" msgctxt "#30812" msgid "Disable connection message" -msgstr "" +msgstr "Désactiver le message de connexion" msgctxt "#30813" msgid "Average image processing time:" -msgstr "" +msgstr "Temps moyen de traitement des images:" msgctxt "#30814" msgid "On playback stop" -msgstr "" +msgstr "A l'arrêt de la lecture" msgctxt "#30815" msgid "Resume light state" -msgstr "" +msgstr "Reprendre l'état de la lumière" msgctxt "#30816" msgid "Resume transition time (secs.)" -msgstr "" +msgstr "Reprendre le temps de transition (sec.)" msgctxt "#30071" msgid "Only colour lights are supported" -msgstr "" +msgstr "Seules les lumières de couleur sont prises en charge" msgctxt "#30072" msgid "Unsupported Hue Bridge" -msgstr "" +msgstr "Bridge Hue non pris en charge" msgctxt "#30055" msgid "Disabled" -msgstr "" +msgstr "Désactivé" msgctxt "#30060" msgid "Play" @@ -430,7 +430,7 @@ msgstr "Lire" msgctxt "#30061" msgid "Hue Status: " -msgstr "" +msgstr "État du Hue : " msgctxt "#30062" msgid "Settings" @@ -438,116 +438,124 @@ msgstr "Paramètres" msgctxt "#30063" msgid "Disabled by daylight" -msgstr "" +msgstr "Désactivé à la lumière du jour" msgctxt "#30064" msgid "ERROR: Scene not found" -msgstr "" +msgstr "ERREUR : Scène introuvable" msgctxt "#30080" msgid "The following error occurred:" -msgstr "" +msgstr "L'erreur suivante s'est produite :" msgctxt "#30081" msgid "Automatically report this error?" -msgstr "" +msgstr "Signaler automatiquement cette erreur ?" msgctxt "#30069" msgid "No lights selected for Ambilight." -msgstr "" +msgstr "Aucune lumière sélectionnée pour Ambilight." msgctxt "#30070" msgid "Ok" -msgstr "" +msgstr "Ok" msgctxt "#30075" msgid "Hue Bridge over capacity" -msgstr "" +msgstr "Bridge Hue surcapacité" msgctxt "#30076" msgid "Network not ready" -msgstr "" +msgstr "Réseau non prêt" msgctxt "#30077" msgid "The Hue Bridge is over capacity. Increase refresh rate or reduce the number of Ambilights." -msgstr "" +msgstr "Le bridge du Hue est en surcapacité. Augmenter le taux de rafraîchissement ou réduire le nombre d'Ambilights." msgctxt "#30078" msgid "Bridge not found[CR]Check your bridge and network." -msgstr "" +msgstr "Bridge introuvable[CR]Vérifier votre bridge et votre réseau." msgctxt "#30082" msgid "Press link button on bridge. Waiting for 90 seconds..." -msgstr "" +msgstr "Appuyer sur le bouton de liaison sur le bridge. Attendre 90 secondes..." msgctxt "#30083" msgid "Unknown" -msgstr "" +msgstr "Inconnue" msgctxt "#30084" msgid "User Found![CR]Saving settings..." -msgstr "" +msgstr "Utilisateur trouvé ![CR]Enregistrement des paramètres..." msgctxt "#30085" msgid "Adjust lights to desired state in the Hue App to save as new scene.[CR]Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Ajuster les lumières à l'état souhaité dans l'application Hue pour enregistrer en tant que nouvelle scène.[CR]Définir un temps de fondu en secondes, ou 0 pour une transition instantanée." msgctxt "#30086" msgid "User not found[CR]Check your bridge and network." -msgstr "" +msgstr "Utilisateur introuvable[CR]Vérifiez votre bridge et votre réseau." msgctxt "#30087" msgid "Scene successfully created![CR]You may now assign your scene to player actions." -msgstr "" +msgstr "Scène créée avec succès ![CR]Vous pouvez maintenant attribuer votre scène aux actions des lecteurs." msgctxt "#30073" msgid "Do not show again" -msgstr "" +msgstr "Ne pas montrer de nouveau" msgctxt "#30074" msgid "Disable Hue Labs during playback" -msgstr "" +msgstr "Désactiver Hue Labs pendant la lecture" msgctxt "#30001" msgid "Hue Bridge V1 (Round) is unsupported. Hue Bridge V2 (Square) is required." -msgstr "" +msgstr "Hue Bridge V1 (rond) n'est pas pris en charge. Hue Bridge V2 (carré) est requis." msgctxt "#30012" msgid "Unknown colour gamut for light:" -msgstr "" +msgstr "Gamme de couleurs inconnue pour la lumière :" msgctxt "#30016" msgid "Report errors" -msgstr "" +msgstr "Signaler des erreurs" msgctxt "#30020" msgid "Never report errors" -msgstr "" +msgstr "Ne signaler jamais les erreurs" msgctxt "#30032" msgid "Hue Service Error" -msgstr "" +msgstr "Erreur de service Hue" msgctxt "#30029" msgid "Connection Error" -msgstr "" +msgstr "Erreur de connexion" msgctxt "#30014" msgid "Error: Lights incompatible with Ambilight" -msgstr "" +msgstr "Erreur : Lumières incompatibles avec Ambilight" msgctxt "#30007" msgid "Bridge not found automatically. Please make sure your bridge is up to date and has access to the internet. [CR]Would you like to enter your bridge IP manually?" -msgstr "" +msgstr "Bridge non trouvé automatiquement. Assurez-vous que votre bridge est à jour et qu'il a accès à Internet. [CR]Souhaitez-vous saisir manuellement l'IP de votre bridge ?" msgctxt "#30009" msgid "Connecting..." -msgstr "" +msgstr "Connexion..." msgctxt "#30027" msgid "Are you sure you want to delete this scene:" -msgstr "" +msgstr "Êtes-vous sûr de vouloir supprimer cette scène :" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." +msgstr "Bridge obsolète. Veuillez mettre à jour votre bridge." + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" msgstr "" diff --git a/script.service.hue/resources/language/resource.language.gl_es/strings.po b/script.service.hue/resources/language/resource.language.gl_es/strings.po index 657c9b5ae..6236c4967 100644 --- a/script.service.hue/resources/language/resource.language.gl_es/strings.po +++ b/script.service.hue/resources/language/resource.language.gl_es/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.he_il/strings.po b/script.service.hue/resources/language/resource.language.he_il/strings.po index e80f57dae..b59d48f73 100644 --- a/script.service.hue/resources/language/resource.language.he_il/strings.po +++ b/script.service.hue/resources/language/resource.language.he_il/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.hi_in/strings.po b/script.service.hue/resources/language/resource.language.hi_in/strings.po index 53cf55a30..174db49d2 100644 --- a/script.service.hue/resources/language/resource.language.hi_in/strings.po +++ b/script.service.hue/resources/language/resource.language.hi_in/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.hr_hr/strings.po b/script.service.hue/resources/language/resource.language.hr_hr/strings.po index d5c5a3648..e3bc98fd8 100644 --- a/script.service.hue/resources/language/resource.language.hr_hr/strings.po +++ b/script.service.hue/resources/language/resource.language.hr_hr/strings.po @@ -6,95 +6,95 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-03-09 14:05+0000\n" -"Last-Translator: Christian Gade \n" +"PO-Revision-Date: 2023-01-07 17:08+0000\n" +"Last-Translator: gogogogi \n" "Language-Team: Croatian \n" "Language: hr_hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.11.2\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" -msgstr "" +msgstr "Automatski Hue svjetla s Kodi reprodukcijom" msgctxt "Addon Description" msgid "Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support." -msgstr "" +msgstr "Automatizirajte svoja Hue svjetla s Kodijem. Stvorite višesobnu scenu koja se pokreće kada Reproducirate, Pauzirate ili Zaustavite medijsku reprodukciju. Stvorite i obrišite višesobne scene iz postavki dodatka tada odaberite koju primijeniti za drugačiji događaj reprodukcije. Može se koristiti zasićenje vremena izlaska i zalaska sunca za automatsko onemogućavanje usluge tijekom dana i uključivanje svjetla pri zalasku sunca tijekom reprodukcije." msgctxt "Addon Disclaimer" msgid "Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware." -msgstr "" +msgstr "Zahtijeva Hue Bridge V2 (Square). Ambijetalno svijtlo nije dostupno na svim hardverima." msgctxt "#32100" msgid "Video Actions" -msgstr "" +msgstr "Video radnje" msgctxt "#32102" msgid "Audio Actions" -msgstr "" +msgstr "Zvučne radnje" msgctxt "#32201" msgid "Start/Resume" -msgstr "" +msgstr "Pokreni/Nastavi" msgctxt "#32202" msgid "Pause" -msgstr "" +msgstr "Pauziraj" msgctxt "#32203" msgid "Stop" -msgstr "" +msgstr "Zaustavi" msgctxt "#32510" msgid "Scene Name:" -msgstr "" +msgstr "Naziv scene:" msgctxt "#32511" msgid "Scene ID" -msgstr "" +msgstr "ID scene" msgctxt "#32512" msgid "Select..." -msgstr "" +msgstr "Odaberi..." msgctxt "#30500" msgid "Bridge" -msgstr "" +msgstr "Most" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Otkrij Hue most / Upiši IP" msgctxt "#30502" msgid "Bridge IP" -msgstr "" +msgstr "IP mosta" msgctxt "#30503" msgid "Bridge User" -msgstr "" +msgstr "Korisnik mosta" msgctxt "#30505" msgid "Enable Schedule (24h format)" -msgstr "" +msgstr "Omogući raspored (24 satni format)" msgctxt "#30506" msgid "Start time:" -msgstr "" +msgstr "Početno vrijeme:" msgctxt "#30507" msgid "End time:" -msgstr "" +msgstr "Završno vrijeme:" msgctxt "#30508" msgid "Disable during daylight" -msgstr "" +msgstr "Onemogući tijekom dnevnog svjetla" msgctxt "#30509" msgid "Activate during playback at sunset" -msgstr "" +msgstr "Aktiviraj tijekom reprodukcije pri zalasku sunca" msgctxt "#30510" msgid "General" @@ -106,39 +106,39 @@ msgstr "Planirano vrijeme" msgctxt "#30512" msgid "Scenes" -msgstr "" +msgstr "Scene" msgctxt "#30513" msgid "Play Scene Enabled" -msgstr "" +msgstr "Reprodukcija scene omogućena" msgctxt "#30514" msgid "Pause Scene Enabled" -msgstr "" +msgstr "Pauziranje scene omogućeno" msgctxt "#30515" msgid "Stop Scene Enabled" -msgstr "" +msgstr "Zaustavljanje scene omogućeno" msgctxt "#30516" msgid "Disable time check if any light already on" -msgstr "" +msgstr "Onemogući provjeru vremena ako je neko svjetlo već upaljeno" msgctxt "#30517" msgid "Don't enable scene if any light is off" -msgstr "" +msgstr "Nemoj omogućiti scenu ako je bilo koje svjetlo isključeno" msgctxt "#30521" msgid "[B][I]Warning: Not supported on all hardware[/B][/I]" -msgstr "" +msgstr "[B][I]Upozorenje: Nije podržano na svom hardveru[/B][/I]" msgctxt "#30522" msgid "CPU & Hue performance" -msgstr "" +msgstr "CPU i Hue preformanse" msgctxt "#30523" msgid "Ambilight" -msgstr "" +msgstr "Ambijentalno svijetlo" msgctxt "#32101" msgid "Advanced" @@ -146,143 +146,143 @@ msgstr "Napredno" msgctxt "#32106" msgid "Video Activation" -msgstr "" +msgstr "Video aktivacija" msgctxt "#6101" msgid "Select Lights" -msgstr "" +msgstr "Odaberi svjetla" msgctxt "#30520" msgid "Enabled" -msgstr "" +msgstr "Omogućeno" msgctxt "#9001" msgid "Press connect button on Hue bridge" -msgstr "" +msgstr "Pritisni tipku povezivanja na Hue mostu" msgctxt "#9007" msgid "Create Scene" -msgstr "" +msgstr "Stvori scenu" msgctxt "#9008" msgid "Delete Scene" -msgstr "" +msgstr "Obriši scenu" msgctxt "#30000" msgid "Hue Service" -msgstr "" +msgstr "Hue usluga" msgctxt "#30004" msgid "Check your bridge and network" -msgstr "" +msgstr "Provjerite svoj most i mrežu" msgctxt "#30006" msgid "Hue connected" -msgstr "" +msgstr "Hue povezan" msgctxt "#30008" msgid "Bridge not found" -msgstr "" +msgstr "Most nije pronađen" msgctxt "#30010" msgid "User not found" -msgstr "" +msgstr "Korisnik nije pronađen" msgctxt "#30011" msgid "Complete!" -msgstr "" +msgstr "Završeno!" msgctxt "#30013" msgid "Cancelled" -msgstr "" +msgstr "Prekinuto" msgctxt "#30015" msgid "Select Hue Lights..." -msgstr "" +msgstr "Odaberi Hue svjetla..." msgctxt "#30017" msgid "Found bridge: " -msgstr "" +msgstr "Pronađeni most: " msgctxt "#30018" msgid "Discover bridge..." -msgstr "" +msgstr "Otkrij most..." msgctxt "#30021" msgid "Bridge connection failed" -msgstr "" +msgstr "Neuspjelo povezivanje mosta" msgctxt "#30022" msgid "Discovery started" -msgstr "" +msgstr "Otkrivanje pokrenuto" msgctxt "#30023" msgid "Bridge not configured" -msgstr "" +msgstr "Most nije podešen" msgctxt "#30024" msgid "Check Hue Bridge configuration" -msgstr "" +msgstr "Provjeri podešavanje Hue mosta" msgctxt "#30025" msgid "ERROR: Scene not deleted" -msgstr "" +msgstr "GREŠKA: Scena nije obrisana" msgctxt "#30026" msgid "Scene Created" -msgstr "" +msgstr "Scena je stvorena" msgctxt "#30028" msgid "Delete Hue Scene" -msgstr "" +msgstr "Obriši Hue scenu" msgctxt "#30030" msgid "Enter Scene Name" -msgstr "" +msgstr "Upiši naziv scene" msgctxt "#30031" msgid "Transition Time:" -msgstr "" +msgstr "Vrijeme prijelaza:" msgctxt "#30034" msgid "Cancel" -msgstr "" +msgstr "Odustani" msgctxt "#30035" msgid "Lights:" -msgstr "" +msgstr "Svjetla:" msgctxt "#30036" msgid "Scene Name:" -msgstr "" +msgstr "Naziv scene:" msgctxt "#30037" msgid "Save" -msgstr "" +msgstr "Spremi" msgctxt "#30038" msgid "Create Hue Scene" -msgstr "" +msgstr "Stvori Hue scenu" msgctxt "#30002" msgid "ERROR: Scene not created" -msgstr "" +msgstr "GREŠKA: Scena nije stvorena" msgctxt "#30039" msgid "Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Postavi vrijeme zatamnjenja u sekundama ili 0 za trenutni prijelaz." msgctxt "#30040" msgid "Scene deleted" -msgstr "" +msgstr "Scena je obrisana" msgctxt "#30041" msgid "You may now assign your Scene to player actions." -msgstr "" +msgstr "Sada možete dodijeliti vašu Scenu u radnju reprodukcije." msgctxt "#30042" msgid "Fade Time (Seconds)" -msgstr "" +msgstr "Vrijeme zatamnjenja (sekunde)" msgctxt "#30043" msgid "Error" @@ -290,139 +290,139 @@ msgstr "Greška" msgctxt "#30044" msgid "Create New Scene" -msgstr "" +msgstr "Stvori novu scenu" msgctxt "#30045" msgid "Scene successfully created!" -msgstr "" +msgstr "Scena je uspješno stvorena!" msgctxt "#30046" msgid "Adjust lights to desired state in the Hue App to save as new scene." -msgstr "" +msgstr "Prilagodi svjetla na željeno stanje u Hue aplikaciji za spremanje kao nove scene." msgctxt "#30047" msgid "Connection lost. Check settings. Shutting down" -msgstr "" +msgstr "Povezivanje je izgubljeno. Provjerite postavke. Isključivanje" msgctxt "#30048" msgid "Connection lost. Trying again in 2 minutes" -msgstr "" +msgstr "Povezivanje izgubljeno. Ponovni pokušaj za 2 minute" msgctxt "#30049" msgid "Scene Name" -msgstr "" +msgstr "Naziv scene" msgctxt "#30050" msgid "N-UPnP discovery..." -msgstr "" +msgstr "N-UPnP otkrivanje..." msgctxt "#30051" msgid "UPnP discovery..." -msgstr "" +msgstr "UPnP otkrivanje..." msgctxt "#30005" msgid "Searching for bridge..." -msgstr "" +msgstr "Pretraživanje mosta..." msgctxt "#30052" msgid "Invalid start or end time, schedule disabled" -msgstr "" +msgstr "Nevaljano početno ili završno vrijeme, raspored je onemogućen" msgctxt "#30056" msgid "Set brightness on start" -msgstr "" +msgstr "Postavi svjetlinu pri početku" msgctxt "#30057" msgid "Force on" -msgstr "" +msgstr "Prisli" msgctxt "#30058" msgid "Light Names:" -msgstr "" +msgstr "Nazivi svjetla:" msgctxt "#30065" msgid "Update interval (ms)" -msgstr "" +msgstr "Razdoblje nadopune (ms)" msgctxt "#30066" msgid "Hue transition time (ms)" -msgstr "" +msgstr "Hue vrijeme prijelaza (ms)" msgctxt "#30067" msgid "Frame capture size" -msgstr "" +msgstr "Veličina snimanja okvira" msgctxt "#30068" msgid "Show Hue bridge capacity errors" -msgstr "" +msgstr "Prikaži greške kapaciteta Hue mosta" msgctxt "#30800" msgid "Minimum duration (Minutes)" -msgstr "" +msgstr "Najmanje trajanje (Minute)" msgctxt "#30801" msgid "Enable for Movies" -msgstr "" +msgstr "Omogući za filmove" msgctxt "#30802" msgid "Enable for TV episodes" -msgstr "" +msgstr "Omogući za TV epizode" msgctxt "#30803" msgid "Enable for music videos" -msgstr "" +msgstr "Omogući za glazbene spotove" msgctxt "#30804" msgid "Enable for other videos (Discs)" -msgstr "" +msgstr "Omogući za druge video snimke (Diskove)" msgctxt "#30805" msgid "Enable for live TV" -msgstr "" +msgstr "Omogući za TV uživo" msgctxt "#30809" msgid "Saturation" -msgstr "" +msgstr "Zasićenje" msgctxt "#30810" msgid "Minimum Brightness" -msgstr "" +msgstr "Najmanja svjetlost" msgctxt "#30811" msgid "Maximum Brightness" -msgstr "" +msgstr "Najveća svjetlost" msgctxt "#30812" msgid "Disable connection message" -msgstr "" +msgstr "Onemogući poruku povezivanja" msgctxt "#30813" msgid "Average image processing time:" -msgstr "" +msgstr "Prosječno vrijeme obrade slike:" msgctxt "#30814" msgid "On playback stop" -msgstr "" +msgstr "Pri zaustavljanju reprodukcije" msgctxt "#30815" msgid "Resume light state" -msgstr "" +msgstr "Nastavi stanje svijetla" msgctxt "#30816" msgid "Resume transition time (secs.)" -msgstr "" +msgstr "Nastavi vrijeme prijelaza (sek.)" msgctxt "#30071" msgid "Only colour lights are supported" -msgstr "" +msgstr "Podržana su samo svjetla u boji" msgctxt "#30072" msgid "Unsupported Hue Bridge" -msgstr "" +msgstr "Nepodržani Hue most" msgctxt "#30055" msgid "Disabled" -msgstr "" +msgstr "Onemogućeno" msgctxt "#30060" msgid "Play" @@ -430,124 +430,132 @@ msgstr "Reproduciraj" msgctxt "#30061" msgid "Hue Status: " -msgstr "" +msgstr "Hue stanje: " msgctxt "#30062" msgid "Settings" -msgstr "" +msgstr "Postavke" msgctxt "#30063" msgid "Disabled by daylight" -msgstr "" +msgstr "Onemogućeno dnevnom svjetlošću" msgctxt "#30064" msgid "ERROR: Scene not found" -msgstr "" +msgstr "GREŠKA: Scena nije pronađena" msgctxt "#30080" msgid "The following error occurred:" -msgstr "" +msgstr "Sljedeća greška se dogodila:" msgctxt "#30081" msgid "Automatically report this error?" -msgstr "" +msgstr "Automatski prijavi ovu grešku?" msgctxt "#30069" msgid "No lights selected for Ambilight." -msgstr "" +msgstr "Nema odabranih svjetla za ambijetalno svijetlo." msgctxt "#30070" msgid "Ok" -msgstr "" +msgstr "U redu" msgctxt "#30075" msgid "Hue Bridge over capacity" -msgstr "" +msgstr "Hue most je preko kapaciteta" msgctxt "#30076" msgid "Network not ready" -msgstr "" +msgstr "Mreža nije spremna" msgctxt "#30077" msgid "The Hue Bridge is over capacity. Increase refresh rate or reduce the number of Ambilights." -msgstr "" +msgstr "Hue Bridge je preko kapaciteta. Povećajte osvježavanje kako bi smanjili broj ambijetalnog svjetla." msgctxt "#30078" msgid "Bridge not found[CR]Check your bridge and network." -msgstr "" +msgstr "Most nije pronađen[CR]Provjerite svoj most i mrežu." msgctxt "#30082" msgid "Press link button on bridge. Waiting for 90 seconds..." -msgstr "" +msgstr "Pritisnite tipku povezivanja na mostu. Pričekajte 90 sekundi..." msgctxt "#30083" msgid "Unknown" -msgstr "" +msgstr "Nepoznato" msgctxt "#30084" msgid "User Found![CR]Saving settings..." -msgstr "" +msgstr "Korisnik je pronađen![CR]Spremanje postavki..." msgctxt "#30085" msgid "Adjust lights to desired state in the Hue App to save as new scene.[CR]Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Prilagodite svjetla na željeno stanje u Hue aplikaciji kako bi spremili kao novu scenu.[CR]Postavite vrijeme zatamnjenja u sekundama, ili 0 za trenutni prijelaz." msgctxt "#30086" msgid "User not found[CR]Check your bridge and network." -msgstr "" +msgstr "Korisnik nije pronađen[CR]Provjerite svoj most i mrežu." msgctxt "#30087" msgid "Scene successfully created![CR]You may now assign your scene to player actions." -msgstr "" +msgstr "Scena je uspješno stvorena![CR]Sada možete dodijeliti svoju scenu radnjama reproduktora." msgctxt "#30073" msgid "Do not show again" -msgstr "" +msgstr "Ne prikazuj ponovno" msgctxt "#30074" msgid "Disable Hue Labs during playback" -msgstr "" +msgstr "Onemogući Hue Labs tijekom reprodukcije" msgctxt "#30001" msgid "Hue Bridge V1 (Round) is unsupported. Hue Bridge V2 (Square) is required." -msgstr "" +msgstr "Hue Bridge V1 (Round) je nepodržan. Hue Bridge V2 (Square) je potreban." msgctxt "#30012" msgid "Unknown colour gamut for light:" -msgstr "" +msgstr "Nepoznat gamut boja za svjetla:" msgctxt "#30016" msgid "Report errors" -msgstr "" +msgstr "Prijavi greške" msgctxt "#30020" msgid "Never report errors" -msgstr "" +msgstr "Nikada ne prijavljuj greške" msgctxt "#30032" msgid "Hue Service Error" -msgstr "" +msgstr "Greška Hue usluge" msgctxt "#30029" msgid "Connection Error" -msgstr "" +msgstr "Greška povezivanja" msgctxt "#30014" msgid "Error: Lights incompatible with Ambilight" -msgstr "" +msgstr "Greška: Svjetla su nekompatibilna s ambijentalnim svjetlom" msgctxt "#30007" msgid "Bridge not found automatically. Please make sure your bridge is up to date and has access to the internet. [CR]Would you like to enter your bridge IP manually?" -msgstr "" +msgstr "Most nije automatski pronađen. Pobrinite se da imate najnoviji most i pristup internetu. [CR]Želite li upisati vaš IP mosta ručno?" msgctxt "#30009" msgid "Connecting..." -msgstr "" +msgstr "Povezivanje..." msgctxt "#30027" msgid "Are you sure you want to delete this scene:" -msgstr "" +msgstr "Sigurno želite obrisati ovu scenu:" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." +msgstr "Most je zastario. Nadopunite svoj most." + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" msgstr "" diff --git a/script.service.hue/resources/language/resource.language.hu_hu/strings.po b/script.service.hue/resources/language/resource.language.hu_hu/strings.po index da42f0f4d..3c59c2344 100644 --- a/script.service.hue/resources/language/resource.language.hu_hu/strings.po +++ b/script.service.hue/resources/language/resource.language.hu_hu/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.hy_am/strings.po b/script.service.hue/resources/language/resource.language.hy_am/strings.po index 360b76411..4898e1d4c 100644 --- a/script.service.hue/resources/language/resource.language.hy_am/strings.po +++ b/script.service.hue/resources/language/resource.language.hy_am/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.id_id/strings.po b/script.service.hue/resources/language/resource.language.id_id/strings.po index 776b0bad7..43513bb5e 100644 --- a/script.service.hue/resources/language/resource.language.id_id/strings.po +++ b/script.service.hue/resources/language/resource.language.id_id/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.is_is/strings.po b/script.service.hue/resources/language/resource.language.is_is/strings.po index a7f7e3f78..e47cb95b6 100644 --- a/script.service.hue/resources/language/resource.language.is_is/strings.po +++ b/script.service.hue/resources/language/resource.language.is_is/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.it_it/strings.po b/script.service.hue/resources/language/resource.language.it_it/strings.po index 6a7d47131..5f0d49170 100644 --- a/script.service.hue/resources/language/resource.language.it_it/strings.po +++ b/script.service.hue/resources/language/resource.language.it_it/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-08-15 22:34+0000\n" +"PO-Revision-Date: 2023-02-05 08:15+0000\n" "Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "Bridge" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "Rileva Hue Bridge" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Scopri Hue Bridge / Inserisci IP" msgctxt "#30502" msgid "Bridge IP" @@ -450,7 +450,7 @@ msgstr "Si è verificato il seguente errore:" msgctxt "#30081" msgid "Automatically report this error?" -msgstr "Segnalo automaticamente questo errore?" +msgstr "Segnalare automaticamente questo errore?" msgctxt "#30069" msgid "No lights selected for Ambilight." @@ -551,3 +551,15 @@ msgstr "Sei sicuro di voler eliminare questa scena:" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "Bridge non aggiornato. Aggiorna il tuo bridge." + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "ERRORE: scena o luce non trovata, potrebbe essere stata modificata o eliminata. Controlla la tua configurazione." + +msgctxt "#30033" +msgid "Reconnected" +msgstr "Ricollegato" + +#~ msgctxt "#30501" +#~ msgid "Discover Hue Bridge" +#~ msgstr "Rileva Hue Bridge" diff --git a/script.service.hue/resources/language/resource.language.ja_jp/strings.po b/script.service.hue/resources/language/resource.language.ja_jp/strings.po index 7bd7d06d6..7cd80d9dd 100644 --- a/script.service.hue/resources/language/resource.language.ja_jp/strings.po +++ b/script.service.hue/resources/language/resource.language.ja_jp/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.kn_in/strings.po b/script.service.hue/resources/language/resource.language.kn_in/strings.po index 1e786fe33..866271fd7 100644 --- a/script.service.hue/resources/language/resource.language.kn_in/strings.po +++ b/script.service.hue/resources/language/resource.language.kn_in/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ko_kr/strings.po b/script.service.hue/resources/language/resource.language.ko_kr/strings.po index 7108c1040..faff6007b 100644 --- a/script.service.hue/resources/language/resource.language.ko_kr/strings.po +++ b/script.service.hue/resources/language/resource.language.ko_kr/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-07-03 13:14+0000\n" +"PO-Revision-Date: 2023-02-05 08:15+0000\n" "Last-Translator: Minho Park \n" "Language-Team: Korean \n" "Language: ko_kr\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.13\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "브리지" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "Hue 브리지 찾기" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Hue Bridge 발견 / IP 입력" msgctxt "#30502" msgid "Bridge IP" @@ -552,6 +552,18 @@ msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "브리지가 오래되었습니다. 브리지를 업데이트하십시오." +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "오류: 장면 또는 조명을 찾을 수 없습니다. 변경되었거나 삭제되었을 수 있습니다. 설정을 확인하십시오." + +msgctxt "#30033" +msgid "Reconnected" +msgstr "다시 연결됨" + +#~ msgctxt "#30501" +#~ msgid "Discover Hue Bridge" +#~ msgstr "Hue 브리지 찾기" + #~ msgctxt "#30027" #~ msgid "Are you sure you want to delete this scene:[CR][B]{scene[1]}[/B]" #~ msgstr "이 장면을 삭제합니까:[CR][B]{장면[1]}[/B]" diff --git a/script.service.hue/resources/language/resource.language.lt_lt/strings.po b/script.service.hue/resources/language/resource.language.lt_lt/strings.po index f4761a470..c6a0a3e33 100644 --- a/script.service.hue/resources/language/resource.language.lt_lt/strings.po +++ b/script.service.hue/resources/language/resource.language.lt_lt/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.lv_lv/strings.po b/script.service.hue/resources/language/resource.language.lv_lv/strings.po index b96a126bf..d113d33fd 100644 --- a/script.service.hue/resources/language/resource.language.lv_lv/strings.po +++ b/script.service.hue/resources/language/resource.language.lv_lv/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.mi/strings.po b/script.service.hue/resources/language/resource.language.mi/strings.po index 15f18b64c..e8396b125 100644 --- a/script.service.hue/resources/language/resource.language.mi/strings.po +++ b/script.service.hue/resources/language/resource.language.mi/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.mk_mk/strings.po b/script.service.hue/resources/language/resource.language.mk_mk/strings.po index 08db3bfa7..7b4506bcf 100644 --- a/script.service.hue/resources/language/resource.language.mk_mk/strings.po +++ b/script.service.hue/resources/language/resource.language.mk_mk/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ml_in/strings.po b/script.service.hue/resources/language/resource.language.ml_in/strings.po index d5802398d..d411da16c 100644 --- a/script.service.hue/resources/language/resource.language.ml_in/strings.po +++ b/script.service.hue/resources/language/resource.language.ml_in/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.mn_mn/strings.po b/script.service.hue/resources/language/resource.language.mn_mn/strings.po index cf2a0bda6..9c6c2c5d7 100644 --- a/script.service.hue/resources/language/resource.language.mn_mn/strings.po +++ b/script.service.hue/resources/language/resource.language.mn_mn/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ms_my/strings.po b/script.service.hue/resources/language/resource.language.ms_my/strings.po index 4c7a56948..10161af53 100644 --- a/script.service.hue/resources/language/resource.language.ms_my/strings.po +++ b/script.service.hue/resources/language/resource.language.ms_my/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.mt_mt/strings.po b/script.service.hue/resources/language/resource.language.mt_mt/strings.po index a96408d68..87ded4f29 100644 --- a/script.service.hue/resources/language/resource.language.mt_mt/strings.po +++ b/script.service.hue/resources/language/resource.language.mt_mt/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.my_mm/strings.po b/script.service.hue/resources/language/resource.language.my_mm/strings.po index 28affe444..6821051ae 100644 --- a/script.service.hue/resources/language/resource.language.my_mm/strings.po +++ b/script.service.hue/resources/language/resource.language.my_mm/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.nb_no/strings.po b/script.service.hue/resources/language/resource.language.nb_no/strings.po index 3f292cec9..8c3163872 100644 --- a/script.service.hue/resources/language/resource.language.nb_no/strings.po +++ b/script.service.hue/resources/language/resource.language.nb_no/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.nl_nl/strings.po b/script.service.hue/resources/language/resource.language.nl_nl/strings.po index cd603b453..53086d976 100644 --- a/script.service.hue/resources/language/resource.language.nl_nl/strings.po +++ b/script.service.hue/resources/language/resource.language.nl_nl/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-03-11 02:20+0000\n" +"PO-Revision-Date: 2022-09-12 08:14+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Dutch \n" "Language: nl_nl\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.11.2\n" +"X-Generator: Weblate 4.14\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -42,11 +42,11 @@ msgstr "" msgctxt "#32202" msgid "Pause" -msgstr "" +msgstr "Pauze" msgctxt "#32203" msgid "Stop" -msgstr "" +msgstr "Stop" msgctxt "#32510" msgid "Scene Name:" @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -258,7 +258,7 @@ msgstr "" msgctxt "#30037" msgid "Save" -msgstr "" +msgstr "Opslaan" msgctxt "#30038" msgid "Create Hue Scene" @@ -434,7 +434,7 @@ msgstr "" msgctxt "#30062" msgid "Settings" -msgstr "" +msgstr "Instellingen" msgctxt "#30063" msgid "Disabled by daylight" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.oc_fr/strings.po b/script.service.hue/resources/language/resource.language.oc_fr/strings.po index 702fc6003..7fbfc4bff 100644 --- a/script.service.hue/resources/language/resource.language.oc_fr/strings.po +++ b/script.service.hue/resources/language/resource.language.oc_fr/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.os_os/strings.po b/script.service.hue/resources/language/resource.language.os_os/strings.po index fd88a4c46..9402960ff 100644 --- a/script.service.hue/resources/language/resource.language.os_os/strings.po +++ b/script.service.hue/resources/language/resource.language.os_os/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.pl_pl/strings.po b/script.service.hue/resources/language/resource.language.pl_pl/strings.po index 39c4a0c54..651700c1a 100644 --- a/script.service.hue/resources/language/resource.language.pl_pl/strings.po +++ b/script.service.hue/resources/language/resource.language.pl_pl/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.pt_br/strings.po b/script.service.hue/resources/language/resource.language.pt_br/strings.po index 9c44a9a7f..0af200e30 100644 --- a/script.service.hue/resources/language/resource.language.pt_br/strings.po +++ b/script.service.hue/resources/language/resource.language.pt_br/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.pt_pt/strings.po b/script.service.hue/resources/language/resource.language.pt_pt/strings.po index 40e1ffeb6..5d2793232 100644 --- a/script.service.hue/resources/language/resource.language.pt_pt/strings.po +++ b/script.service.hue/resources/language/resource.language.pt_pt/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ro_ro/strings.po b/script.service.hue/resources/language/resource.language.ro_ro/strings.po index a8304443b..aae8b1037 100644 --- a/script.service.hue/resources/language/resource.language.ro_ro/strings.po +++ b/script.service.hue/resources/language/resource.language.ro_ro/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ru_ru/strings.po b/script.service.hue/resources/language/resource.language.ru_ru/strings.po index e3e026672..d73f8d970 100644 --- a/script.service.hue/resources/language/resource.language.ru_ru/strings.po +++ b/script.service.hue/resources/language/resource.language.ru_ru/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.si_lk/strings.po b/script.service.hue/resources/language/resource.language.si_lk/strings.po index a2fa713f0..45a8e0a31 100644 --- a/script.service.hue/resources/language/resource.language.si_lk/strings.po +++ b/script.service.hue/resources/language/resource.language.si_lk/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.sk_sk/strings.po b/script.service.hue/resources/language/resource.language.sk_sk/strings.po index 20e70f046..32f416a76 100644 --- a/script.service.hue/resources/language/resource.language.sk_sk/strings.po +++ b/script.service.hue/resources/language/resource.language.sk_sk/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.sl_si/strings.po b/script.service.hue/resources/language/resource.language.sl_si/strings.po index e92165126..76d3beaa7 100644 --- a/script.service.hue/resources/language/resource.language.sl_si/strings.po +++ b/script.service.hue/resources/language/resource.language.sl_si/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.sq_al/strings.po b/script.service.hue/resources/language/resource.language.sq_al/strings.po index 6d32fb944..92afabf74 100644 --- a/script.service.hue/resources/language/resource.language.sq_al/strings.po +++ b/script.service.hue/resources/language/resource.language.sq_al/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.sr_rs/strings.po b/script.service.hue/resources/language/resource.language.sr_rs/strings.po index a984a95b1..96ec31c5f 100644 --- a/script.service.hue/resources/language/resource.language.sr_rs/strings.po +++ b/script.service.hue/resources/language/resource.language.sr_rs/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.sr_rs@latin/strings.po b/script.service.hue/resources/language/resource.language.sr_rs@latin/strings.po index 3774ecc46..e9bc0aa95 100644 --- a/script.service.hue/resources/language/resource.language.sr_rs@latin/strings.po +++ b/script.service.hue/resources/language/resource.language.sr_rs@latin/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.sv_se/strings.po b/script.service.hue/resources/language/resource.language.sv_se/strings.po index dd6f5665d..85d72e644 100644 --- a/script.service.hue/resources/language/resource.language.sv_se/strings.po +++ b/script.service.hue/resources/language/resource.language.sv_se/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.szl/strings.po b/script.service.hue/resources/language/resource.language.szl/strings.po index b8279c5d4..51d202239 100644 --- a/script.service.hue/resources/language/resource.language.szl/strings.po +++ b/script.service.hue/resources/language/resource.language.szl/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.ta_in/strings.po b/script.service.hue/resources/language/resource.language.ta_in/strings.po index 4e185c57e..00cca9506 100644 --- a/script.service.hue/resources/language/resource.language.ta_in/strings.po +++ b/script.service.hue/resources/language/resource.language.ta_in/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.te_in/strings.po b/script.service.hue/resources/language/resource.language.te_in/strings.po index b54ca3f97..a50fa566e 100644 --- a/script.service.hue/resources/language/resource.language.te_in/strings.po +++ b/script.service.hue/resources/language/resource.language.te_in/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.tg_tj/strings.po b/script.service.hue/resources/language/resource.language.tg_tj/strings.po index 07beaaa7a..6759491e4 100644 --- a/script.service.hue/resources/language/resource.language.tg_tj/strings.po +++ b/script.service.hue/resources/language/resource.language.tg_tj/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.th_th/strings.po b/script.service.hue/resources/language/resource.language.th_th/strings.po index 9b6a40fc9..7de46c139 100644 --- a/script.service.hue/resources/language/resource.language.th_th/strings.po +++ b/script.service.hue/resources/language/resource.language.th_th/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.tr_tr/strings.po b/script.service.hue/resources/language/resource.language.tr_tr/strings.po index 15a8ef7bb..69fa53767 100644 --- a/script.service.hue/resources/language/resource.language.tr_tr/strings.po +++ b/script.service.hue/resources/language/resource.language.tr_tr/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.uk_ua/strings.po b/script.service.hue/resources/language/resource.language.uk_ua/strings.po index 3b914a568..a5c97fe91 100644 --- a/script.service.hue/resources/language/resource.language.uk_ua/strings.po +++ b/script.service.hue/resources/language/resource.language.uk_ua/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.uz_uz/strings.po b/script.service.hue/resources/language/resource.language.uz_uz/strings.po index db5d55da8..857120c51 100644 --- a/script.service.hue/resources/language/resource.language.uz_uz/strings.po +++ b/script.service.hue/resources/language/resource.language.uz_uz/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.vi_vn/strings.po b/script.service.hue/resources/language/resource.language.vi_vn/strings.po index 3b7ec3104..24ea2bd10 100644 --- a/script.service.hue/resources/language/resource.language.vi_vn/strings.po +++ b/script.service.hue/resources/language/resource.language.vi_vn/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/language/resource.language.zh_cn/strings.po b/script.service.hue/resources/language/resource.language.zh_cn/strings.po index 840aba8ce..3bb6cfcb1 100644 --- a/script.service.hue/resources/language/resource.language.zh_cn/strings.po +++ b/script.service.hue/resources/language/resource.language.zh_cn/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "桥接器" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "发现 Hue 桥接器" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,15 @@ msgstr "是否确实要删除此场景:" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "桥接器已过时。请更新您的桥接器。" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" + +#~ msgctxt "#30501" +#~ msgid "Discover Hue Bridge" +#~ msgstr "发现 Hue 桥接器" diff --git a/script.service.hue/resources/language/resource.language.zh_tw/strings.po b/script.service.hue/resources/language/resource.language.zh_tw/strings.po index fe018e4c6..3cefc96e9 100644 --- a/script.service.hue/resources/language/resource.language.zh_tw/strings.po +++ b/script.service.hue/resources/language/resource.language.zh_tw/strings.po @@ -65,8 +65,8 @@ msgid "Bridge" msgstr "" msgctxt "#30501" -msgid "Discover Hue Bridge" -msgstr "" +msgid "Discover Hue Bridge / Enter IP" +msgstr "Discover Hue Bridge / Enter IP" msgctxt "#30502" msgid "Bridge IP" @@ -551,3 +551,11 @@ msgstr "" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." msgstr "" + +msgctxt "#30003" +msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." +msgstr "" + +msgctxt "#30033" +msgid "Reconnected" +msgstr "" diff --git a/script.service.hue/resources/lib/__init__.py b/script.service.hue/resources/lib/__init__.py index c08c0773e..e30b5b3a4 100644 --- a/script.service.hue/resources/lib/__init__.py +++ b/script.service.hue/resources/lib/__init__.py @@ -8,7 +8,8 @@ from collections import deque from threading import Event -import simplecache + + import xbmc import xbmcaddon import xbmcvfs @@ -28,8 +29,6 @@ ADDONVERSION = ADDON.getAddonInfo('version') KODIVERSION = xbmc.getInfoLabel('System.BuildVersion') -CACHE = simplecache.SimpleCache() - def timer(func): # Logs the runtime of the decorated function diff --git a/script.service.hue/resources/lib/ambigroup.py b/script.service.hue/resources/lib/ambigroup.py index a54f3dbb5..d7496974d 100644 --- a/script.service.hue/resources/lib/ambigroup.py +++ b/script.service.hue/resources/lib/ambigroup.py @@ -143,7 +143,6 @@ def _resume_light_state(self): if "201" in exc.type_id: # 201 Param not modifiable because light is off error. 901: internal hue bridge error. pass else: - xbmc.log(f"[script.service.hue] resumeLightState: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}") reporting.process_exception(exc) def _ambi_loop(self): @@ -356,9 +355,9 @@ def _get_light_states(lights, bridge): for L in lights: try: states[L] = (bridge.lights[L]()) - except QhueException as exc: - xbmc.log(f"[script.service.hue] Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}") except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) + except Exception as exc: + reporting.process_exception(exc) return states diff --git a/script.service.hue/resources/lib/core.py b/script.service.hue/resources/lib/core.py index 46bfb785e..1b70d5fbe 100644 --- a/script.service.hue/resources/lib/core.py +++ b/script.service.hue/resources/lib/core.py @@ -10,11 +10,11 @@ import requests import xbmc -from resources.lib import ADDON, CACHE, SETTINGS_CHANGED, ADDONID, AMBI_RUNNING +from resources.lib import ADDON, SETTINGS_CHANGED, ADDONID, AMBI_RUNNING from resources.lib import ambigroup, lightgroup, kodiutils, hueconnection from resources.lib.hueconnection import HueConnection from resources.lib.language import get_string as _ -from resources.lib.kodiutils import validate_settings, notification +from resources.lib.kodiutils import validate_settings, notification, cache_set, cache_get def core(): @@ -85,27 +85,26 @@ def _commands(monitor, command): def _service(monitor): hue_connection = HueConnection(monitor, silent=ADDON.getSettingBool("disableConnectionMessage"), discover=False) - service_enabled = CACHE.get(f"{ADDONID}.service_enabled") + service_enabled = cache_get("service_enabled") if hue_connection.connected: light_groups = [lightgroup.LightGroup(0, hue_connection, lightgroup.VIDEO), lightgroup.LightGroup(1, hue_connection, lightgroup.AUDIO), ambigroup.AmbiGroup(3, hue_connection)] - connection_retries = 0 timer = 60 daylight = hue_connection.get_daylight() new_daylight = daylight - CACHE.set(f"{ADDONID}.daylight", daylight) - CACHE.set(f"{ADDONID}.service_enabled", True) + cache_set("daylight", daylight) + cache_set("service_enabled", True) # xbmc.log("[script.service.hue] Core service starting. Connected: {}".format(CONNECTED)) while hue_connection.connected and not monitor.abortRequested(): # check if service was just re-enabled and if so activate groups prev_service_enabled = service_enabled - service_enabled = CACHE.get(f"{ADDONID}.service_enabled") + service_enabled = cache_get("service_enabled") if service_enabled and not prev_service_enabled: activate(light_groups) @@ -113,8 +112,8 @@ def _service(monitor): if not service_enabled: AMBI_RUNNING.clear() - # process cached waiting commands - action = CACHE.get(f"{ADDONID}.action") + # process CACHED waiting commands + action = cache_get("action") if action: _process_actions(action, light_groups) @@ -128,32 +127,23 @@ def _service(monitor): # every minute, check for sunset & connection if timer > 59: timer = 0 - # check connection to Hue hue_connection and fetch daylight status + + # fetch daylight status, reconnect to Hue if it fails try: - if connection_retries > 0: - hue_connection.connect_bridge(silent=True) - if hue_connection.connected: - new_daylight = hue_connection.get_daylight() - connection_retries = 0 - else: + new_daylight = hue_connection.get_daylight() + except requests.exceptions.RequestException as error: + if hue_connection.reconnect(monitor): new_daylight = hue_connection.get_daylight() - except (requests.RequestException, ConnectionError) as error: - connection_retries = connection_retries + 1 - if connection_retries <= 10: - xbmc.log(f"[script.service.hue] Bridge Connection Error. Attempt: {connection_retries}/10 : {error}") - notification(_("Hue Service"), _("Connection lost. Trying again in 2 minutes")) - timer = -60 else: - xbmc.log(f"[script.service.hue] Bridge Connection Error. Attempt: {connection_retries}/10. Shutting down : {error}") notification(_("Hue Service"), _("Connection lost. Check settings. Shutting down")) - hue_connection.connected = False + return # check if sunset took place if new_daylight != daylight: xbmc.log(f"[script.service.hue] Daylight change. current: {daylight}, new: {new_daylight}") daylight = new_daylight - CACHE.set(f"{ADDONID}.daylight", daylight) + cache_set("daylight", daylight) if not daylight and service_enabled: xbmc.log("[script.service.hue] Sunset activate") activate(light_groups) @@ -166,13 +156,13 @@ def _service(monitor): def _process_actions(action, light_groups): - # process an action command stored in the cache. + # process an action command stored in the CACHE. action_action = action[0] action_light_group_id = int(action[1]) - 1 xbmc.log(f"[script.service.hue] Action command: {action}, action_action: {action_action}, action_light_group_id: {action_light_group_id}") light_groups[action_light_group_id].run_action(action_action) - CACHE.set(f"{ADDONID}.action", None) + cache_set("action", None) class HueMonitor(xbmc.Monitor): @@ -190,11 +180,11 @@ def onNotification(self, sender, method, data): if method == "Other.disable": xbmc.log("[script.service.hue] Notification received: Disable") - CACHE.set(f"{ADDONID}.service_enabled", False) + cache_set("service_enabled", False) if method == "Other.enable": xbmc.log("[script.service.hue] Notification received: Enable") - CACHE.set(f"{ADDONID}.service_enabled", True) + cache_set("service_enabled", True) if method == "Other.actions": json_loads = json.loads(data) @@ -202,7 +192,7 @@ def onNotification(self, sender, method, data): light_group_id = json_loads['group'] action = json_loads['command'] xbmc.log(f"[script.service.hue] Action Notification: group: {light_group_id}, command: {action}") - CACHE.set("script.service.hue.action", (action, light_group_id), expiration=(timedelta(seconds=5))) + cache_set("script.service.hue.action", (action, light_group_id), expiration=(timedelta(seconds=5))) def activate(light_groups): diff --git a/script.service.hue/resources/lib/hueconnection.py b/script.service.hue/resources/lib/hueconnection.py index 59122aa85..f2020fc65 100644 --- a/script.service.hue/resources/lib/hueconnection.py +++ b/script.service.hue/resources/lib/hueconnection.py @@ -28,20 +28,20 @@ def __init__(self, monitor, silent=True, discover=False): self.connected = False if discover: - self.discover_bridge() + self.discover() else: - self.connect_bridge(silent) + self.connect(silent) - def connect_bridge(self, silent=False): + def connect(self, silent=False): - xbmc.log(f"[script.service.hue] in connect_bridge() with settings: bridgeIP: {self.bridge_ip}, bridgeUser: {self.bridge_user}") + xbmc.log(f"[script.service.hue] in connect() with settings: bridgeIP: {self.bridge_ip}, bridgeUser: {self.bridge_user}") if self.bridge_ip and self.bridge_user: if not self._check_version(): - xbmc.log("[script.service.hue] in connect_bridge(): Bridge not responding to connection test, attempt finding a new bridge IP.") + xbmc.log("[script.service.hue] in connect(): Bridge not responding to connection test, attempt finding a new bridge IP.") if self._discover_bridge_ip(): - xbmc.log(f"[script.service.hue] in connect_bridge(): New IP found: {self.bridge_ip}. Saving") + xbmc.log(f"[script.service.hue] in connect(): New IP found: {self.bridge_ip}. Saving") ADDON.setSettingString("bridgeIP", self.bridge_ip) else: xbmc.log("[script.service.hue] Bridge not found") @@ -68,8 +68,37 @@ def connect_bridge(self, silent=False): notification(_("Hue Service"), _("Bridge not configured"), icon=xbmcgui.NOTIFICATION_ERROR) self.connected = False - def discover_bridge(self): - xbmc.log("[script.service.hue] Start bridgeDiscover") + def reconnect(self, monitor): + xbmc.log(f"[script.service.hue] reconnect() with settings: bridgeIP: {self.bridge_ip}, bridgeUser: {self.bridge_user}") + retries = 0 + + while retries < 11 and not monitor.abortRequested(): + if self._check_version(): + xbmc.log(f"[script.service.hue] reconnect(): Check version successful! ") + notification(_("Hue Service"), _("Reconnected")) + return True + else: + if self._discover_bridge_ip(): + xbmc.log(f"[script.service.hue] in reconnect(): New IP found: {self.bridge_ip}. Saving") + if self._check_version(): + xbmc.log(f"[script.service.hue] in reconnect(): Version check successful. Saving bridge IP") + ADDON.setSettingString("bridgeIP", self.bridge_ip) + return True + else: + xbmc.log(f"[script.service.hue] Bridge not found. Attempt {retries}/10. Trying again in 2 minutes.") + notification(_("Hue Service"), _("Connection lost. Trying again in 2 minutes")) + + retries = retries + 1 + monitor.waitForAbort(120) # Retry in 2 minutes + + # give up + xbmc.log(f"[script.service.hue] Reconnect. Attempt: {retries}/10. Shutting down") + notification(_("Hue Service"), _("Connection lost. Check settings. Shutting down")) + self.connected = False + return False + + def discover(self): + xbmc.log("[script.service.hue] Start discover") # Create new config if none exists. Returns success or fail as bool ADDON.setSettingString("bridgeIP", "") ADDON.setSettingString("bridgeUser", "") @@ -113,7 +142,7 @@ def discover_bridge(self): self.monitor.waitForAbort(5) progress_bar.close() xbmc.log("[script.service.hue] Bridge discovery complete") - self.connect_bridge(True) + self.connect(True) return True elif progress_bar.iscanceled(): @@ -155,8 +184,11 @@ def _discover_bridge_ip(self): # discover hue bridge IP silently for non-interactive discovery / bridge IP change. xbmc.log("[script.service.hue] In discoverBridgeIP") if self._discover_nupnp(): + xbmc.log(f"[script.service.hue] In discoverBridgeIP, discover_nupnp SUCCESS: {self.bridge_ip}") if self._check_version(): + xbmc.log(f"[script.service.hue] In discoverBridgeIP, check version SUCCESS") return True + xbmc.log(f"[script.service.hue] In discoverBridgeIP, discover_nupnp FAIL: {self.bridge_ip}") return False def _discover_nupnp(self): @@ -164,7 +196,7 @@ def _discover_nupnp(self): try: req = requests.get('https://discovery.meethue.com/') result = req.json() - except requests.RequestException as error: + except requests.exceptions.RequestException as error: xbmc.log(f"[script.service.hue] Nupnp failed: {error}") return None except (JSONDecodeError, json.JSONDecodeError) as error: # when discovery.meethue.com returns empty JSON or 429 @@ -183,16 +215,19 @@ def _discover_nupnp(self): def _check_bridge_model(self): bridge = qhue.Bridge(self.bridge_ip, None, timeout=QHUE_TIMEOUT) + model = "" + try: bridge_config = bridge.config() model = bridge_config["modelid"] - except QhueException as exc: - xbmc.log(f"[script.service.hue] Exception: checkBridgeModel {exc.type_id}: {exc.message} {traceback.format_exc()}") - reporting.process_exception(exc) - return None except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) + return None + except Exception as exc: + reporting.process_exception(exc) + return None + if model == "BSB002": xbmc.log(f"[script.service.hue] Bridge model OK: {model}") return True @@ -204,10 +239,6 @@ def _check_version(self): b = qhue.Bridge(self.bridge_ip, None, timeout=QHUE_TIMEOUT) try: api_version = b.config()['apiversion'] - except QhueException as error: - xbmc.log(f"[script.service.hue] Version check connection failed. {error.type_id}: {error.message} {traceback.format_exc()}") - reporting.process_exception(error) - return False except requests.RequestException as error: xbmc.log(f"[script.service.hue] Version check connection failed. {error}") return False @@ -215,6 +246,9 @@ def _check_version(self): notification(_("Hue Service"), _("Bridge outdated. Please update your bridge."), icon=xbmcgui.NOTIFICATION_ERROR) xbmc.log(f"[script.service.hue] in _version_check(): Connected! Bridge too old: {api_version}, error: {error}") return False + except Exception as exc: + reporting.process_exception(exc) + return False api_split = api_version.split(".") @@ -231,7 +265,10 @@ def _check_user(self): b = qhue.Bridge(self.bridge_ip, self.bridge_user, timeout=QHUE_TIMEOUT) try: zigbee = b.config()['zigbeechannel'] - except (requests.RequestException, qhue.QhueException, KeyError): + except (requests.RequestException, QhueException, KeyError): + return False + except Exception as exc: + reporting.process_exception(exc) return False if zigbee: @@ -355,10 +392,13 @@ def delete_hue_scene(self): except QhueException as exc: xbmc.log(f"[script.service.hue]: Delete Hue Scene QhueException: {exc.type_id}: {exc.message} {traceback.format_exc()}") notification(_("Hue Service"), _("ERROR: Scene not deleted") + f"[CR]{exc.message}") - # xbmc.log(f"[script.service.hue] In kodiHue createHueGroup. Res: {result}") + # xbmc.log(f"[script.service.hue] In kodiHue createHueGroup. Res: {result}") + return except requests.RequestException as exc: xbmc.log(f"[script.service.hue]: Delete Hue Scene requestsException: {result} {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) + return + if result[0]["success"]: notification(_("Hue Service"), _("Scene deleted")) else: @@ -368,14 +408,14 @@ def delete_hue_scene(self): def select_hue_lights(self): try: hue_lights = self.bridge.lights() - except QhueException as exc: - xbmc.log(f"[script.service.hue]: Select Hue Lights QhueException: {exc.type_id}: {exc.message} {traceback.format_exc()}") - notification(_("Hue Service"), _("Bridge connection failed"), icon=xbmcgui.NOTIFICATION_ERROR) - return None + except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) return None + except Exception as exc: + reporting.process_exception(exc) + return None items = [] index = [] @@ -406,15 +446,12 @@ def select_hue_scene(self): try: hue_scenes = self.bridge.scenes() - except QhueException as exc: - xbmc.log(f"[script.service.hue]: Select Hue Lights QhueException: {exc.type_id}: {exc.message} {traceback.format_exc()}") - notification(_("Hue Service"), _("Bridge connection failed"), icon=xbmcgui.NOTIFICATION_ERROR) - reporting.process_exception(exc) - return None except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) return None + except Exception as exc: + reporting.process_exception(exc) items = [] index = [] @@ -440,19 +477,14 @@ def select_hue_scene(self): return None def get_daylight(self): - try: - daylight = self.bridge.sensors['1']()['state']['daylight'] - except QhueException as exc: - xbmc.log(f"[script.service.hue]: Get Daylight Qhue Exception: {exc.type_id}: {exc.message} {traceback.format_exc()}") - reporting.process_exception(exc) - return + daylight = self.bridge.sensors['1']()['state']['daylight'] return daylight def _get_light_name(self, light): try: name = self.bridge.lights()[light]['name'] - except (qhue.QhueException, requests.RequestException) as exc: - xbmc.log(f"[script.service.hue] getLightName Qhue Exception: {exc} {traceback.format_exc()}") + except Exception as exc: + reporting.process_exception(exc) return None if name is None: diff --git a/script.service.hue/resources/lib/kodiutils.py b/script.service.hue/resources/lib/kodiutils.py index e3db3bd22..8d43e6d85 100644 --- a/script.service.hue/resources/lib/kodiutils.py +++ b/script.service.hue/resources/lib/kodiutils.py @@ -4,13 +4,17 @@ # See LICENSE.TXT for more information. import datetime +import json +from json import JSONDecodeError import xbmc import xbmcgui -from resources.lib import ADDON +from resources.lib import ADDON, ADDONID from resources.lib.language import get_string as _ +cache_window = xbmcgui.Window(10000) + def validate_settings(): _validate_schedule() @@ -48,3 +52,23 @@ def convert_time(time): def notification(header, message, time=5000, icon=ADDON.getAddonInfo('icon'), sound=False): xbmcgui.Dialog().notification(header, message, icon, time, sound) + + +def cache_get(key: str): + data_str = cache_window.getProperty(f"{ADDONID}.{key}]") + + try: + data = json.loads(data_str) + # xbmc.log(f"[script.service.hue] Cache Get: {key}, {data}") + return data + except JSONDecodeError: + # Occurs when Cache is empty or unreadable (Eg. Old SimpleCache data still in memory because Kodi hasn't restarted) + #xbmc.log(f"[script.service.hue] cache_get JSONDecodeError: {key}: {data_str}") + return None + + +def cache_set(key, data): + data_str = json.dumps(data) + # xbmc.log(f"[script.service.hue] Cache Set: {key}, {data_str} - {data_type}") + cache_window.setProperty(f"{ADDONID}.{key}]", data_str) + return diff --git a/script.service.hue/resources/lib/language.py b/script.service.hue/resources/lib/language.py index 7a57a3b91..cb226dc44 100644 --- a/script.service.hue/resources/lib/language.py +++ b/script.service.hue/resources/lib/language.py @@ -35,7 +35,7 @@ def get_string(t): _strings['scene id'] = 32511 _strings['select...'] = 32512 _strings['bridge'] = 30500 -_strings['discover hue bridge'] = 30501 +_strings['discover hue bridge / enter ip'] = 30501 _strings['bridge ip'] = 30502 _strings['bridge user'] = 30503 _strings['enable schedule (24h format)'] = 30505 @@ -157,3 +157,5 @@ def get_string(t): _strings['connecting...'] = 30009 _strings['are you sure you want to delete this scene:'] = 30027 _strings['bridge outdated. please update your bridge.'] = 30019 +_strings['error: scene or light not found, it may have changed or been deleted. check your configuration.'] = 30003 +_strings['reconnected'] = 30033 diff --git a/script.service.hue/resources/lib/lightgroup.py b/script.service.hue/resources/lib/lightgroup.py index 2617e6fcb..90c5c1432 100644 --- a/script.service.hue/resources/lib/lightgroup.py +++ b/script.service.hue/resources/lib/lightgroup.py @@ -9,10 +9,10 @@ import requests import xbmc import xbmcgui -from qhue import QhueException -from resources.lib import CACHE, ADDON, reporting, ADDONID -from resources.lib.kodiutils import convert_time, notification + +from resources.lib import ADDON, reporting, ADDONID +from resources.lib.kodiutils import convert_time, notification, cache_get from .language import get_string as _ STATE_STOPPED = 0 @@ -53,8 +53,7 @@ def __repr__(self): def onAVStarted(self): if self.enabled: - xbmc.log( - f"In KodiGroup[{self.light_group_id}], onPlaybackStarted. Group enabled: {self.enabled},startBehavior: {self.start_behavior} , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}, self.mediaType: {self.media_type},self.playbackType(): {self.playback_type()}") + xbmc.log(f"[script.service.hue] In LightGroup[{self.light_group_id}], onPlaybackStarted. Group enabled: {self.enabled},startBehavior: {self.start_behavior} , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}, self.mediaType: {self.media_type},self.playbackType(): {self.playback_type()}") self.state = STATE_PLAYING self.last_media_type = self.playback_type() @@ -71,12 +70,13 @@ def onAVStarted(self): else: self.video_info_tag = None + xbmc.log(f"[script.service.hue] onAVStarted: check_active_time: {self.check_active_time()}, check_already_active: {self.check_already_active(self.start_scene)}") if (self.check_active_time() or self.check_already_active(self.start_scene)) and self.check_keep_lights_off_rule(self.start_scene) and self.start_behavior and self.media_type == self.playback_type(): self.run_action("play") def onPlayBackPaused(self): if self.enabled: - xbmc.log(f"[script.service.hue] In KodiGroup[{self.light_group_id}], onPlaybackPaused() , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}") + xbmc.log(f"[script.service.hue] In LightGroup[{self.light_group_id}], onPlaybackPaused() , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}") self.state = STATE_PAUSED if self.media_type == VIDEO and not self.check_video_activation( @@ -89,7 +89,7 @@ def onPlayBackPaused(self): def onPlayBackStopped(self): if self.enabled: - xbmc.log(f"[script.service.hue] In KodiGroup[{self.light_group_id}], onPlaybackStopped() , mediaType: {self.media_type}, lastMediaType: {self.last_media_type} ") + xbmc.log(f"[script.service.hue] In LightGroup[{self.light_group_id}], onPlaybackStopped() , mediaType: {self.media_type}, lastMediaType: {self.last_media_type} ") self.state = STATE_STOPPED try: @@ -102,35 +102,33 @@ def onPlayBackStopped(self): self.run_action("stop") def onPlayBackResumed(self): - # xbmc.log("[script.service.hue] In KodiGroup[{}], onPlaybackResumed()".format(self.light_group_id)) + # xbmc.log("[script.service.hue] In LightGroup[{}], onPlaybackResumed()".format(self.light_group_id)) self.onAVStarted() def onPlayBackError(self): - # xbmc.log("[script.service.hue] In KodiGroup[{}], onPlaybackError()".format(self.light_group_id)) + # xbmc.log("[script.service.hue] In LightGroup[{}], onPlaybackError()".format(self.light_group_id)) self.onPlayBackStopped() def onPlayBackEnded(self): - # xbmc.log("[script.service.hue] In KodiGroup[{}], onPlaybackEnded()".format(self.light_group_id)) + # xbmc.log("[script.service.hue] In LightGroup[{}], onPlaybackEnded()".format(self.light_group_id)) self.onPlayBackStopped() def run_action(self, action): - if action == "play": - scene = self.start_scene - elif action == "pause": - scene = self.pause_scene - elif action == "stop": - scene = self.stop_scene - else: - xbmc.log(f"[script.service.hue] Unknown action type: {action}") - raise RuntimeError - try: - self.group0.action(scene=scene) - except QhueException as exc: - xbmc.log(f"[script.service.hue] run_action: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}") - if "3" in exc.type_id or "7" in exc.type_id: - xbmc.log("[script.service.hue] Scene not found") - notification(_("Hue Service"), _("ERROR: Scene not found"), icon=xbmcgui.NOTIFICATION_ERROR) + + service_enabled = cache_get("service_enabled") + if service_enabled: + if action == "play": + scene = self.start_scene + elif action == "pause": + scene = self.pause_scene + elif action == "stop": + scene = self.stop_scene else: + xbmc.log(f"[script.service.hue] Unknown action type: {action}") + raise RuntimeError + try: + self.group0.action(scene=scene) + except Exception as exc: reporting.process_exception(exc) def activate(self): @@ -154,30 +152,26 @@ def playback_type(self): @staticmethod def check_active_time(): - service_enabled = CACHE.get(f"{ADDONID}.service_enabled") - daylight = CACHE.get("script.service.hue.daylight") - # xbmc.log("[script.service.hue] Schedule: {}, daylightDisable: {}, daylight: {}, startTime: {}, endTime: {}".format(ADDON.getSettingBool("enableSchedule"), ADDON.getSettingBool("daylightDisable"), daylight, - # ADDON.getSettingBool("startTime"), ADDON.getSettingBool("endTime"))) + service_enabled = cache_get("service_enabled") + daylight = cache_get("script.service.hue.daylight") + xbmc.log("[script.service.hue] Schedule: {}, daylightDisable: {}, daylight: {}, startTime: {}, endTime: {}".format(ADDON.getSettingBool("enableSchedule"), ADDON.getSettingBool("daylightDisable"), daylight, + ADDON.getSettingString("startTime"), ADDON.getSettingString("endTime"))) if ADDON.getSettingBool("daylightDisable") and daylight: xbmc.log("[script.service.hue] Disabled by daylight") return False - if service_enabled: - if ADDON.getSettingBool("enableSchedule"): - start = convert_time(ADDON.getSettingString("startTime")) - end = convert_time(ADDON.getSettingString("endTime")) - now = datetime.datetime.now().time() - if (now > start) and (now < end): - # xbmc.log("[script.service.hue] Enabled by schedule") - return True - # xbmc.log("[script.service.hue] Disabled by schedule") - return False - # xbmc.log("[script.service.hue] Schedule not enabled") - return True - - # xbmc.log("[script.service.hue] Service disabled") - return False + if ADDON.getSettingBool("enableSchedule"): + start = convert_time(ADDON.getSettingString("startTime")) + end = convert_time(ADDON.getSettingString("endTime")) + now = datetime.datetime.now().time() + if (now > start) and (now < end): + xbmc.log("[script.service.hue] Enabled by schedule") + return True + xbmc.log("[script.service.hue] Disabled by schedule") + return False + xbmc.log("[script.service.hue] Schedule not enabled") + return True def check_video_activation(self, info_tag): try: @@ -224,17 +218,11 @@ def check_already_active(self, scene): # xbmc.log("[script.service.hue] Check if scene light already active: True") return True # xbmc.log("[script.service.hue] Check if scene light already active: False") - except QhueException as exc: - if ["7", "3"] in exc.type_id: - xbmc.log("[script.service.hue] Scene not found") - notification(_("Hue Service"), _("ERROR: Scene not found"), icon=xbmcgui.NOTIFICATION_ERROR) - else: - xbmc.log(f"[script.service.hue] checkAlreadyActive: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}") - reporting.process_exception(exc) except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) - + except Exception as exc: + reporting.process_exception(exc) return False def check_keep_lights_off_rule(self, scene): @@ -251,11 +239,11 @@ def check_keep_lights_off_rule(self, scene): xbmc.log("[script.service.hue] Check if lights should stay off: True") return False xbmc.log("[script.service.hue] Check if lights should stay off: False") - except QhueException as exc: - xbmc.log(f"[script.service.hue] checkKeepLightsOffRule: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}") - reporting.process_exception(exc) except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) + except Exception as exc: + reporting.process_exception(exc) + return True diff --git a/script.service.hue/resources/lib/menu.py b/script.service.hue/resources/lib/menu.py index e10b65291..2c9cd479e 100644 --- a/script.service.hue/resources/lib/menu.py +++ b/script.service.hue/resources/lib/menu.py @@ -12,7 +12,9 @@ import xbmcvfs from xbmcgui import ListItem -from resources.lib import ADDON, CACHE, ADDONID, ADDONPATH +import resources.lib.kodiutils +from resources.lib import ADDON, ADDONID, ADDONPATH +from resources.lib.kodiutils import cache_set, cache_get from .language import get_string as _ @@ -29,15 +31,16 @@ def menu(): elif command == "settings": ADDON.openSettings() + xbmc.executebuiltin('Container.Refresh') elif command == "toggle": - if CACHE.get(f"{ADDONID}.service_enabled") and _get_status() != "Disabled by daylight": + if cache_get("service_enabled") and _get_status() != "Disabled by daylight": xbmc.log("[script.service.hue] Disable service") - CACHE.set(f"{ADDONID}.service_enabled", False) + cache_set("service_enabled", False) elif _get_status() != "Disabled by daylight": xbmc.log("[script.service.hue] Enable service") - CACHE.set(f"{ADDONID}.service_enabled", True) + cache_set("service_enabled", True) else: xbmc.log("[script.service.hue] Disabled by daylight, ignoring") @@ -55,12 +58,13 @@ def menu(): xbmcplugin.endOfDirectory(handle=addon_handle, cacheToDisc=True) else: - CACHE.set(f"{ADDONID}.action", (action, light_group_id), expiration=(timedelta(seconds=5))) + cache_set("action", (action, light_group_id)) else: xbmc.log(f"[script.service.hue] Unknown command. Handle: {addon_handle}, route: {route}, Arguments: {sys.argv}") def build_menu(base_url, addon_handle): + xbmc.log(f"[script.service.hue] build_menu: status: {_get_status()}") status_item = ListItem(_("Hue Status: ") + _get_status()) status_icon = _get_status_icon() if status_icon: @@ -79,20 +83,25 @@ def build_menu(base_url, addon_handle): def _get_status(): - enabled = CACHE.get(f"{ADDONID}.service_enabled") - daylight = CACHE.get(f"{ADDONID}.daylight") + enabled = cache_get("service_enabled") + daylight = cache_get("daylight") daylight_disable = ADDON.getSettingBool("daylightDisable") + xbmc.log(f"[script.service.hue] _get_status enabled: {enabled} - {type(enabled)}, daylight: {daylight}, daylight_disable: {daylight_disable}") + # xbmc.log("[script.service.hue] Current status: {}".format(daylight_disable)) if daylight and daylight_disable: return _("Disabled by daylight") - elif enabled: + if enabled: return _("Enabled") - return _("Disabled") + elif not enabled: + return _("Disabled") + else: + return "NoneType" def _get_status_icon(): - enabled = CACHE.get(f"{ADDONID}.service_enabled") - daylight = CACHE.get(f"{ADDONID}.daylight") + enabled = cache_get("service_enabled") + daylight = cache_get("daylight") daylight_disable = ADDON.getSettingBool("daylightDisable") # xbmc.log("[script.service.hue] Current status: {}".format(daylight_disable)) if daylight and daylight_disable: diff --git a/script.service.hue/resources/lib/reporting.py b/script.service.hue/resources/lib/reporting.py index 32707e9db..ec4bec591 100644 --- a/script.service.hue/resources/lib/reporting.py +++ b/script.service.hue/resources/lib/reporting.py @@ -5,19 +5,28 @@ import platform import sys +import traceback import rollbar import xbmc import xbmcgui +from qhue import QhueException from resources.lib import ADDONVERSION, ROLLBAR_API_KEY, KODIVERSION, ADDONPATH, ADDON +from resources.lib.kodiutils import notification from resources.lib.language import get_string as _ def process_exception(exc, level="critical", error=""): - if ADDON.getSettingBool("error_reporting"): - if _error_report_dialog(exc): - _report_error(level, error, exc) + xbmc.log(f"[script.service.hue] Exception: {type(exc)}, {exc}, {error}, {traceback.format_exc()}") + + if type(exc) == QhueException and exc.type_id in ["3", "7"]: # 3: resource not found, 7: invalid value for parameter + xbmc.log("[script.service.hue] Qhue resource not found, not reporting to rollbar") + notification(_("Hue Service"), _("ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration."), icon=xbmcgui.NOTIFICATION_ERROR) + else: + if ADDON.getSettingBool("error_reporting"): + if _error_report_dialog(exc): + _report_error(level, error, exc) def _error_report_dialog(exc): @@ -30,7 +39,7 @@ def _error_report_dialog(exc): def _report_error(level="critical", error="", exc=""): - if "dev" in ADDONVERSION or "alpha" in ADDONVERSION or "beta" in ADDONVERSION: + if any(val in ADDONVERSION for val in ["dev", "alpha", "beta"]): env = "dev" else: env = "production" From 0bbfc13363e34d15e1767b15981c5a5d13d608be Mon Sep 17 00:00:00 2001 From: Paul Backhouse Date: Wed, 15 Feb 2023 12:23:13 +0000 Subject: [PATCH 006/145] [weather.metoffice] 3.0.1 (#2383) --- weather.metoffice/addon.xml | 4 +-- weather.metoffice/resources/settings.xml | 8 ++--- weather.metoffice/src/default.py | 33 +++++++++++-------- weather.metoffice/src/metoffice/constants.py | 16 +++++---- weather.metoffice/src/metoffice/properties.py | 8 +---- weather.metoffice/src/metoffice/utilities.py | 31 +++++++---------- weather.metoffice/src/setlocation.py | 26 +++++---------- 7 files changed, 58 insertions(+), 68 deletions(-) diff --git a/weather.metoffice/addon.xml b/weather.metoffice/addon.xml index fde780529..3a1c8d4a2 100644 --- a/weather.metoffice/addon.xml +++ b/weather.metoffice/addon.xml @@ -1,5 +1,5 @@ - + @@ -22,4 +22,4 @@ In using this addon you agree to the terms and conditions specified under the Met Office Datapoint terms and conditions. http://www.metoffice.gov.uk/datapoint/terms-conditions. Data provided by Met Office Datapoint is covered by the Open Government License. http://www.nationalarchives.gov.uk/doc/open-government-licence/version/2/. Use at your own risk. The authors accept no liability. - + \ No newline at end of file diff --git a/weather.metoffice/resources/settings.xml b/weather.metoffice/resources/settings.xml index 7962f5d95..a37d91516 100644 --- a/weather.metoffice/resources/settings.xml +++ b/weather.metoffice/resources/settings.xml @@ -1,13 +1,13 @@ - + - + - + @@ -18,4 +18,4 @@ - + \ No newline at end of file diff --git a/weather.metoffice/src/default.py b/weather.metoffice/src/default.py index a2ee2dbd1..0edab66e3 100644 --- a/weather.metoffice/src/default.py +++ b/weather.metoffice/src/default.py @@ -18,6 +18,10 @@ from metoffice.constants import WINDOW, ADDON, API_KEY, ADDON_DATA_PATH, ADDON_BANNER_PATH from metoffice import urlcache, properties, utilities import socket +import sys + +import setlocation + socket.setdefaulttimeout(20) @@ -27,31 +31,34 @@ def main(): try: urlcache.URLCache(ADDON_DATA_PATH).erase() finally: - ADDON.setSetting('EraseCache', 'false') # @UndefinedVariable + ADDON.setSetting('EraseCache', 'false') if not API_KEY: raise Exception(_("No API Key."), _("Enter your Met Office API Key under settings.")) + if sys.argv[1] in ['ObservationLocation', 'ForecastLocation', 'RegionalLocation']: + setlocation.main(sys.argv[1]) + properties.observation() properties.daily() properties.threehourly() properties.sunrisesunset() - WINDOW.setProperty('WeatherProvider', ADDON.getAddonInfo('name')) # @UndefinedVariable - WINDOW.setProperty('WeatherProviderLogo', ADDON_BANNER_PATH) # @UndefinedVariable - WINDOW.setProperty('ObservationLocation', ADDON.getSetting('ObservationLocation')) # @UndefinedVariable - WINDOW.setProperty('Current.Location', ADDON.getSetting('ForecastLocation')) # @UndefinedVariable - WINDOW.setProperty('ForecastLocation', ADDON.getSetting('ForecastLocation')) # @UndefinedVariable - WINDOW.setProperty('RegionalLocation', ADDON.getSetting('RegionalLocation')) # @UndefinedVariable - WINDOW.setProperty('Location1', ADDON.getSetting('ForecastLocation')) # @UndefinedVariable - WINDOW.setProperty('Locations', '1') # @UndefinedVariable + WINDOW.setProperty('WeatherProvider', ADDON.getAddonInfo('name')) + WINDOW.setProperty('WeatherProviderLogo', ADDON_BANNER_PATH) + WINDOW.setProperty('ObservationLocation', ADDON.getSetting('ObservationLocation')) + WINDOW.setProperty('Current.Location', ADDON.getSetting('ForecastLocation')) + WINDOW.setProperty('ForecastLocation', ADDON.getSetting('ForecastLocation')) + WINDOW.setProperty('RegionalLocation', ADDON.getSetting('RegionalLocation')) + WINDOW.setProperty('Location1', ADDON.getSetting('ForecastLocation')) + WINDOW.setProperty('Locations', '1') # Explicitly set unused flags to false, so there are no unusual side # effects/residual data when moving from another weather provider. - WINDOW.setProperty('36Hour.IsFetched', '') # @UndefinedVariable - WINDOW.setProperty('Weekend.IsFetched', '') # @UndefinedVariable - WINDOW.setProperty('Map.IsFetched', '') # @UndefinedVariable - WINDOW.setProperty('Weather.CurrentView', '') # @UndefinedVariable + WINDOW.setProperty('36Hour.IsFetched', '') + WINDOW.setProperty('Weekend.IsFetched', '') + WINDOW.setProperty('Map.IsFetched', '') + WINDOW.setProperty('Weather.CurrentView', '') if __name__ == '__main__': diff --git a/weather.metoffice/src/metoffice/constants.py b/weather.metoffice/src/metoffice/constants.py index 4756d6c8a..d1a7f5ee7 100644 --- a/weather.metoffice/src/metoffice/constants.py +++ b/weather.metoffice/src/metoffice/constants.py @@ -1,8 +1,11 @@ -import xbmc # @UnresolvedImport -import xbmcgui # @UnresolvedImport -import xbmcaddon # @UnresolvedImport +import xbmc +import xbmcgui +import xbmcaddon +import xbmcvfs import urllib.parse import pytz + +# Magic numbers. See https://kodi.wiki/view/Window_IDs WEATHER_WINDOW_ID = 12600 ADDON_BROWSER_WINDOW_ID = 10040 @@ -17,9 +20,10 @@ ADDON = xbmcaddon.Addon(id="weather.metoffice") DIALOG = xbmcgui.Dialog() + KEYBOARD = xbmc.Keyboard() -ADDON_BANNER_PATH = xbmc.translatePath('special://home/addons/%s/resources/banner.png' % ADDON.getAddonInfo('id')) -ADDON_DATA_PATH = xbmc.translatePath('special://profile/addon_data/%s/' % ADDON.getAddonInfo('id')) +ADDON_BANNER_PATH = xbmcvfs.translatePath('special://home/addons/%s/resources/banner.png' % ADDON.getAddonInfo('id')) +ADDON_DATA_PATH = xbmcvfs.translatePath('special://profile/addon_data/%s/' % ADDON.getAddonInfo('id')) TEMPERATUREUNITS = xbmc.getRegion('tempunit') @@ -101,7 +105,7 @@ 'latitude': 'latitude', 'longitude': 'longitude'} ] -GEOIP_PROVIDER = GEOIP_PROVIDERS[int(GEOIP)] +GEOIP_PROVIDER = GEOIP_PROVIDERS[int(GEOIP) if GEOIP else 0] URL_TEMPLATE = "http://datapoint.metoffice.gov.uk/public/data/{format}/{resource}/{group}/{datatype}/{object}?{get}" diff --git a/weather.metoffice/src/metoffice/properties.py b/weather.metoffice/src/metoffice/properties.py index 62c7109d9..ae1725423 100644 --- a/weather.metoffice/src/metoffice/properties.py +++ b/weather.metoffice/src/metoffice/properties.py @@ -21,7 +21,6 @@ TEMPERATUREUNITS, LATITUDE, LONGITUDE -@utilities.panelbusy('LeftPane') def observation(): utilities.log("Fetching Hourly Observation for '%s (%s)' from the Met Office..." % ( OBSERVATION_LOCATION, OBSERVATION_LOCATION_ID)) @@ -78,7 +77,6 @@ def observation(): raise -@utilities.panelbusy('RightPane') def daily(): utilities.log("Fetching Daily Forecast for '%s (%s)' from the Met Office..." % ( FORECAST_LOCATION, FORECAST_LOCATION_ID)) @@ -150,7 +148,6 @@ def daily(): WINDOW.setProperty('Daily.IsFetched', 'true') -@utilities.panelbusy('RightPane') def threehourly(): utilities.log("Fetching 3 Hourly Forecast for '%s (%s)' from the Met Office..." % ( FORECAST_LOCATION, FORECAST_LOCATION_ID)) @@ -210,7 +207,6 @@ def sunrisesunset(): WINDOW.setProperty('Today.Sunset', sun.sunset().strftime(TIME_FORMAT)) -@utilities.panelbusy('RightPane') def text(): utilities.log("Fetching Text Forecast for '%s (%s)' from the Met Office..." % ( REGIONAL_LOCATION, REGIONAL_LOCATION_ID)) @@ -248,7 +244,6 @@ def text(): WINDOW.setProperty('TextForecast.IsFetched', 'true') -@utilities.panelbusy('RightPane') def forecastlayer(): utilities.log("Fetching '{0}' Forecast Map with index '{1}'...".format( FORECASTMAP_LAYER_SELECTION, FORECASTMAP_SLIDER)) @@ -326,7 +321,6 @@ def forecastlayer(): 'true') -@utilities.panelbusy('RightPane') def observationlayer(): utilities.log("Fetching '{0}' Observation Map with index '{1}'...".format( OBSERVATIONMAP_LAYER_SELECTION, OBSERVATIONMAP_SLIDER)) @@ -450,4 +444,4 @@ def image_resize(filename): (width, height) = img.size if width == RAW_DATAPOINT_IMG_WIDTH: img.crop((CROP_WIDTH, CROP_HEIGHT, width-CROP_WIDTH, - height-CROP_HEIGHT)).save(filename, img.format) + height-CROP_HEIGHT)).save(filename, img.format) diff --git a/weather.metoffice/src/metoffice/utilities.py b/weather.metoffice/src/metoffice/utilities.py index 0ae580f53..b8bebbbae 100644 --- a/weather.metoffice/src/metoffice/utilities.py +++ b/weather.metoffice/src/metoffice/utilities.py @@ -3,10 +3,10 @@ import time import traceback import math -import xbmc # @UnresolvedImport -import xbmcgui # @UnresolvedImport +import xbmc +import xbmcgui -from .constants import WEATHER_WINDOW_ID, ADDON_BROWSER_WINDOW_ID, DIALOG, WINDOW, TEMPERATUREUNITS, ADDON +from .constants import WEATHER_WINDOW_ID, ADDON_BROWSER_WINDOW_ID, DIALOG, TEMPERATUREUNITS, ADDON def log(msg, level=xbmc.LOGINFO): @@ -20,6 +20,12 @@ def strptime(dt, fmt): def failgracefully(f): + """ + Function decorator. When a script fails (raises an exception) we + don't want it to make an awful 'parp' noise. Instead catch the + generic exception, log it and if the user is on a weather page, + show something to the user in a dialog box. + """ @wraps(f) def wrapper(*args, **kwds): try: @@ -42,27 +48,14 @@ def xbmcbusy(f): @wraps(f) def wrapper(*args, **kwds): if xbmcgui.getCurrentWindowId() == WEATHER_WINDOW_ID or xbmcgui.getCurrentWindowId() == ADDON_BROWSER_WINDOW_ID: - xbmc.executebuiltin("ActivateWindow(busydialog)") + xbmc.executebuiltin("ActivateWindow(busydialognocancel)") try: return f(*args, **kwds) finally: - xbmc.executebuiltin("Dialog.Close(busydialog)") + xbmc.executebuiltin("Dialog.Close(busydialognocancel)") return wrapper -def panelbusy(pane): - def decorate(f): - @wraps(f) - def wrapper(*args, **kwargs): - WINDOW.setProperty('{0}.IsBusy'.format(pane), 'true') # @UndefinedVariable - try: - return f(*args, **kwargs) - finally: - WINDOW.clearProperty('{0}.IsBusy'.format(pane)) # @UndefinedVariable - return wrapper - return decorate - - def f_or_nla(f): @wraps(f) def wrapper(*args, **kwds): @@ -158,7 +151,7 @@ def gettext(s): "No locations found containing": 32010, "Matching Sites": 32011} try: - translation = ADDON.getLocalizedString(translatable[s]) # @UndefinedVariable + translation = ADDON.getLocalizedString(translatable[s]) if not translation: raise TranslationError else: diff --git a/weather.metoffice/src/setlocation.py b/weather.metoffice/src/setlocation.py index f687211a7..fc2aea7e9 100644 --- a/weather.metoffice/src/setlocation.py +++ b/weather.metoffice/src/setlocation.py @@ -5,7 +5,6 @@ the user. On successful selection internal addon setting is set. """ -import sys from datetime import datetime, timedelta from operator import itemgetter import json @@ -13,7 +12,7 @@ from metoffice.utilities import gettext as _ from metoffice.constants import ( - API_KEY, ADDON_DATA_PATH, GEOIP_PROVIDER, KEYBOARD, DIALOG, + ADDON_DATA_PATH, GEOIP_PROVIDER, KEYBOARD, DIALOG, ADDON, FORECAST_SITELIST_URL, OBSERVATION_SITELIST_URL, REGIONAL_SITELIST_URL, LONG_REGIONAL_NAMES, GEOLOCATION ) @@ -85,29 +84,22 @@ def getsitelist(location, text=""): @utilities.failgracefully def main(location): - if not API_KEY: - raise Exception(_("No API Key."), _("Enter your Met Office API Key under settings.")) - KEYBOARD.doModal() # @UndefinedVariable - text = KEYBOARD.isConfirmed() and KEYBOARD.getText() # @UndefinedVariable + KEYBOARD.doModal() + text = KEYBOARD.isConfirmed() and KEYBOARD.getText() sitelist = getsitelist(location, text) if sitelist == []: - DIALOG.ok(_("No Matches"), _("No locations found containing")+" {0}".format(text)) # @UndefinedVariable + DIALOG.ok(_("No Matches"), _("No locations found containing")+" {0}".format(text)) utilities.log("No locations found containing '%s'" % text) else: display_list = [site['display'] for site in sitelist] - selected = DIALOG.select(_("Matching Sites"), display_list) # @UndefinedVariable + selected = DIALOG.select(_("Matching Sites"), display_list) if selected != -1: - ADDON.setSetting(location, sitelist[selected]['name']) # @UndefinedVariable - ADDON.setSetting("%sID" % location, sitelist[selected]['id']) # @UndefinedVariable - ADDON.setSetting("%sLatitude" % location, str(sitelist[selected].get('latitude'))) # @UndefinedVariable - ADDON.setSetting("%sLongitude" % location, str(sitelist[selected].get('longitude'))) # @UndefinedVariable + ADDON.setSetting(location, sitelist[selected]['name']) + ADDON.setSetting("%sID" % location, sitelist[selected]['id']) + ADDON.setSetting("%sLatitude" % location, str(sitelist[selected].get('latitude'))) + ADDON.setSetting("%sLongitude" % location, str(sitelist[selected].get('longitude'))) utilities.log("Setting '{location}' to '{name} ({id})'".format(location=location, name=sitelist[selected]['name'].encode( 'utf-8'), id=sitelist[selected]['id'])) - - -if __name__ == '__main__': - # check sys.argv - main(sys.argv[1]) From c428c88a83652a82a55157d19f38ed4f7f300b5c Mon Sep 17 00:00:00 2001 From: CaTz Date: Wed, 15 Feb 2023 14:23:48 +0200 Subject: [PATCH 007/145] [service.subtitles.napisy24pl] 3.0.6 (#2401) * [service.subtitles.napisy24pl] 3.0.5 * [service.subtitles.napisy24pl] 3.0.6 --- service.subtitles.napisy24pl/addon.xml | 2 +- .../resources/lib/NapisyUtils.py | 8 ++--- service.subtitles.napisy24pl/service.py | 31 +++++++++---------- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/service.subtitles.napisy24pl/addon.xml b/service.subtitles.napisy24pl/addon.xml index f740fd347..78f09147d 100644 --- a/service.subtitles.napisy24pl/addon.xml +++ b/service.subtitles.napisy24pl/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/service.subtitles.napisy24pl/resources/lib/NapisyUtils.py b/service.subtitles.napisy24pl/resources/lib/NapisyUtils.py index b9a80b9cb..b24f0d24e 100644 --- a/service.subtitles.napisy24pl/resources/lib/NapisyUtils.py +++ b/service.subtitles.napisy24pl/resources/lib/NapisyUtils.py @@ -180,9 +180,7 @@ def _search_tvshow(self, item): if search_result is None: return results # return empty set - search_result = json.loads(search_result, encoding="utf-8") - - results = [] + search_result = json.loads(search_result) for result in search_result: html = bs4.BeautifulSoup(result["table"], "html.parser") @@ -349,9 +347,9 @@ def request(self, url, query_string=None, data=None, ajax=False, referer=None, c pass if 'application/json' in response.headers.get('content-type', ''): - content = json.loads(content, encoding="utf-8") + content = json.loads(content) elif 'text/html' in response.headers.get('content-type', ''): - content = content.decode('utf-8') + content = content.decode('utf-8', 'replace') response.close() except Exception as e: diff --git a/service.subtitles.napisy24pl/service.py b/service.subtitles.napisy24pl/service.py index 4975abdc5..3b5a3c3e6 100644 --- a/service.subtitles.napisy24pl/service.py +++ b/service.subtitles.napisy24pl/service.py @@ -3,14 +3,11 @@ import sys from urllib.parse import unquote -try: - import xbmc - import xbmcvfs - import xbmcaddon - import xbmcplugin - import xbmcgui -except ImportError: - from tests.stubs import xbmc, xbmcgui, xbmcaddon, xbmcplugin, xbmcvfs +import xbmc +import xbmcvfs +import xbmcaddon +import xbmcplugin +import xbmcgui __addon__ = xbmcaddon.Addon() __scriptid__ = __addon__.getAddonInfo('id') @@ -23,7 +20,6 @@ __resource__ = xbmcvfs.translatePath(os.path.join(__cwd__, 'resources', 'lib')) __temp__ = xbmcvfs.translatePath(os.path.join(__profile__, 'temp', '')) - from resources.lib.NapisyUtils import NapisyHelper, log, normalizeString, clean_title, parse_rls_title @@ -51,13 +47,14 @@ def search(item): xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=listitem, isFolder=False) return + def get_params(): param = [] paramstring = sys.argv[2] if len(paramstring) >= 2: params = paramstring cleanedparams = params.replace('?', '') - if (params[len(params) - 1] == '/'): + if params[len(params) - 1] == '/': params = params[0:len(params) - 2] pairsofparams = cleanedparams.split('&') param = {} @@ -73,6 +70,8 @@ def get_params(): params = get_params() if params['action'] in ['search', 'manualsearch']: + log("Version: '%s'" % (__version__,)) + item = {} item['temp'] = False item['rar'] = False @@ -100,9 +99,6 @@ def get_params(): else: item['title'] = unquote(params['searchstring']) - for lang in unquote(params['languages']).split(","): - item['3let_language'].append(xbmc.convertLanguage(lang, xbmc.ISO_639_2)) - log("Item before cleaning: \n %s" % item) # clean title + tvshow params @@ -113,14 +109,14 @@ def get_params(): item['season'] = "0" item['episode'] = item['episode'][-1:] - if (item['file_original_path'].find("http") > -1): + if item['file_original_path'].find("http") > -1: item['temp'] = True - elif (item['file_original_path'].find("rar://") > -1): + elif item['file_original_path'].find("rar://") > -1: item['rar'] = True item['file_original_path'] = os.path.dirname(item['file_original_path'][6:]) - elif (item['file_original_path'].find("stack://") > -1): + elif item['file_original_path'].find("stack://") > -1: stackPath = item['file_original_path'].split(" , ") item['file_original_path'] = stackPath[0][8:] @@ -134,7 +130,8 @@ def get_params(): helper = NapisyHelper() subs = helper.download(params["id"]) - ## we can return more than one subtitle for multi CD versions, for now we are still working out how to handle that in XBMC core + # # we can return more than one subtitle for multi CD versions, for now we are still working out how to handle + # that in XBMC core for sub in subs: listitem = xbmcgui.ListItem(label=sub) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=sub, listitem=listitem, isFolder=False) From 39660f35cbe286edd491250b617a71b071ac3f1a Mon Sep 17 00:00:00 2001 From: pizzamx Date: Wed, 15 Feb 2023 20:24:35 +0800 Subject: [PATCH 008/145] [script.subtitles.zimukux] 0.1.9 (#2384) --- script.subtitles.zimukux/addon.xml | 8 +- .../resource.language.en_GB/strings.po | 82 ++++++++++++++++ .../resource.language.zh_CN/strings.po | 82 ++++++++++++++++ .../resources/lib/sub_provider_service.py | 64 +++++++++---- .../resources/lib/zimuku_agent.py | 93 +++++++++++++------ .../resources/lib/zimuku_archive.py | 15 +-- .../resources/settings.xml | 47 +++++++++- 7 files changed, 333 insertions(+), 58 deletions(-) create mode 100644 script.subtitles.zimukux/resources/language/resource.language.en_GB/strings.po create mode 100644 script.subtitles.zimukux/resources/language/resource.language.zh_CN/strings.po diff --git a/script.subtitles.zimukux/addon.xml b/script.subtitles.zimukux/addon.xml index 0913f7854..7b1c3d554 100644 --- a/script.subtitles.zimukux/addon.xml +++ b/script.subtitles.zimukux/addon.xml @@ -1,5 +1,5 @@  - + @@ -20,6 +20,12 @@ resources/fanart.png +v0.1.9(2022/12/23) +- Merged https://github.com/pizzamx/zimuku_for_kodi/pull/14 +- New setting allow showing only language suffix of sub file name to prevent the UI from scrolling (slowly!) +- New setting to allow search with year info. to make result more accurate (default to False, attributed to @fsi044689) +- Minor tweaks, please refer to PR comment + v0.1.8(2022/10/10) - zimuku.org captcha design changed again and this plugin works again diff --git a/script.subtitles.zimukux/resources/language/resource.language.en_GB/strings.po b/script.subtitles.zimukux/resources/language/resource.language.en_GB/strings.po new file mode 100644 index 000000000..8646eb193 --- /dev/null +++ b/script.subtitles.zimukux/resources/language/resource.language.en_GB/strings.po @@ -0,0 +1,82 @@ +msgid "" +msgstr "" + +msgctxt "#30100" +msgid "Site config for ZiMuKu" +msgstr "" + +msgctxt "#30101" +msgid "Site URL" +msgstr "" + +msgctxt "#30200" +msgid "Sub preference" +msgstr "" + +msgctxt "#30210" +msgid "Preferred sub type" +msgstr "" + +msgctxt "#30211" +msgid "No preference" +msgstr "" + +msgctxt "#30212" +msgid "ASS - colorful kind with various fonts" +msgstr "" + +msgctxt "#30213" +msgid "SRT - text only" +msgstr "" + +msgctxt "#30220" +msgid "Preferred sub language" +msgstr "" + +msgctxt "#30221" +msgid "No preference" +msgstr "" + +msgctxt "#30222" +msgid "Simplified Chinese" +msgstr "" + +msgctxt "#30223" +msgid "Traditional Chinese" +msgstr "" + +msgctxt "#30224" +msgid "Engish + Simplified Chinese" +msgstr "" + +msgctxt "#30225" +msgid "English + Traditional Chinese" +msgstr "" + +msgctxt "#30230" +msgid "Cut duplicated part of sub filename to avoid scrolling" +msgstr "" + +msgctxt "#30240" +msgid "Use year to make search result more accurate" +msgstr "" + +msgctxt "#30300" +msgid "Proxy Settings" +msgstr "" + +msgctxt "#30310" +msgid "Follow kodi proxy settings" +msgstr "" + +msgctxt "#30311" +msgid "Use proxy" +msgstr "" + +msgctxt "#30312" +msgid "Proxy server" +msgstr "" + +msgctxt "#30901" +msgid "Choose subtitle" +msgstr "" \ No newline at end of file diff --git a/script.subtitles.zimukux/resources/language/resource.language.zh_CN/strings.po b/script.subtitles.zimukux/resources/language/resource.language.zh_CN/strings.po new file mode 100644 index 000000000..9c9765737 --- /dev/null +++ b/script.subtitles.zimukux/resources/language/resource.language.zh_CN/strings.po @@ -0,0 +1,82 @@ +msgid "" +msgstr "" + +msgctxt "#30100" +msgid "Site config for ZiMuKu" +msgstr "「字幕库」网站配置" + +msgctxt "#30101" +msgid "Site URL" +msgstr "网址" + +msgctxt "#30200" +msgid "Sub preference" +msgstr "字幕下载偏好" + +msgctxt "#30210" +msgid "Preferred sub type" +msgstr "优先选择的字幕类型" + +msgctxt "#30211" +msgid "No preference" +msgstr "无偏好" + +msgctxt "#30212" +msgid "ASS - colorful kind with various fonts" +msgstr "ASS - 花里胡哨那种带字体的" + +msgctxt "#30213" +msgid "SRT - text only" +msgstr "SRT - 纯文本那种" + +msgctxt "#30220" +msgid "Preferred sub language" +msgstr "优先选择的字幕语言" + +msgctxt "#30221" +msgid "No preference" +msgstr "无偏好" + +msgctxt "#30222" +msgid "Simplified Chinese" +msgstr "简体中文" + +msgctxt "#30223" +msgid "Traditional Chinese" +msgstr "繁体中文" + +msgctxt "#30224" +msgid "Engish + Simplified Chinese" +msgstr "双语(简)" + +msgctxt "#30225" +msgid "English + Traditional Chinese" +msgstr "双语(繁)" + +msgctxt "#30230" +msgid "Cut duplicated part of sub filename to avoid scrolling" +msgstr "隐藏文件名相同的部分,防止过长滚动" + +msgctxt "#30240" +msgid "Use year to make search result more accurate" +msgstr "使用年份信息让搜索结果更精确" + +msgctxt "#30300" +msgid "Proxy Settings" +msgstr "代理服务器设置" + +msgctxt "#30310" +msgid "Follow kodi proxy settings" +msgstr "使用 Kodi 的代理设置" + +msgctxt "#30311" +msgid "Use proxy" +msgstr "另行指定代理服务器" + +msgctxt "#30312" +msgid "Proxy server" +msgstr "代理服务器信息" + +msgctxt "#30901" +msgid "Choose subtitle" +msgstr "请选择压缩包中的字幕" \ No newline at end of file diff --git a/script.subtitles.zimukux/resources/lib/sub_provider_service.py b/script.subtitles.zimukux/resources/lib/sub_provider_service.py index a9d07335b..7a7dc5117 100644 --- a/script.subtitles.zimukux/resources/lib/sub_provider_service.py +++ b/script.subtitles.zimukux/resources/lib/sub_provider_service.py @@ -48,7 +48,8 @@ class Logger: def log(self, module, msg, level=xbmc.LOGDEBUG): - xbmc.log("{0}::{1} - {2}".format(__scriptname__, module, msg), level=level) + xbmc.log("{0}::{1} - {2}".format(__scriptname__, + module, msg), level=level) class Unpacker: @@ -56,21 +57,24 @@ def unpack(self, path): return zimuku_archive.unpack(path) -def Search(item): - if item['mansearch']: - search_str = item['mansearchstr'] - elif item['tvshow'] != '': - search_str = item['tvshow'] +def Search(items): + user_year = __addon__.getSetting("useyear") + search_suffix = ' '+items['year'] if user_year == 'true' else '' + if items['mansearch']: + search_str = items['mansearchstr'] + elif items['tvshow'] != '': + search_str = items['tvshow']+search_suffix else: - search_str = item['title'] + search_str = items['title']+search_suffix logger.log(sys._getframe().f_code.co_name, "Search for [%s], item: %s" % - (os.path.basename(item['file_original_path']), item), level=xbmc.LOGINFO) + (os.path.basename(items['file_original_path']), items), level=xbmc.LOGINFO) - subtitle_list = agent.search(search_str, item) + subtitle_list = agent.search(search_str, items) if len(subtitle_list) != 0: for s in subtitle_list: - listitem = xbmcgui.ListItem(label=s["language_name"], label2=s["filename"]) + listitem = xbmcgui.ListItem( + label=s["language_name"], label2=s["filename"]) listitem.setArt({ 'icon': s["rating"], 'thumb': s["language_flag"] @@ -78,15 +82,20 @@ def Search(item): listitem.setProperty("sync", "false") listitem.setProperty("hearing_imp", "false") - url = "plugin://%s/?action=download&link=%s" % (__scriptid__, s["link"]) + url = "plugin://%s/?action=download&link=%s" % ( + __scriptid__, s["link"]) xbmcplugin.addDirectoryItem( handle=int(sys.argv[1]), url=url, listitem=listitem, isFolder=False) else: - logger.log(sys._getframe().f_code.co_name, "字幕未找到,参数:%s" % item, level=xbmc.LOGINFO) + logger.log(sys._getframe().f_code.co_name, "字幕未找到,参数:%s" % + items, level=xbmc.LOGINFO) def Download(url): + """ + 调用 agent 的下载功能,用户在 UI 选定之后传回给 Kodi + """ if not xbmcvfs.exists(__temp__.replace('\\', '/')): xbmcvfs.mkdirs(__temp__) dirs, files = xbmcvfs.listdir(__temp__) @@ -95,22 +104,26 @@ def Download(url): logger.log(sys._getframe().f_code.co_name, "Download page: %s" % (url)) - l1, l2 = agent.download(url) - logger.log(sys._getframe().f_code.co_name, "%s; %s" % (l1, l2)) - sub_name_list, sub_file_list = agent.get_preferred_subs(l1, l2) + l1, l2, l3 = agent.download(url) + logger.log(sys._getframe().f_code.co_name, "%s; %s; %s" % (l1, l2, l3)) + sub_name_list, short_sub_name_list, sub_file_list = agent.get_preferred_subs( + l1, l2, l3) if len(sub_name_list) == 0: - #FIXME: 不应该有这问题 + # FIXME: 不应该有这问题 return [] if len(sub_name_list) == 1: selected_sub = sub_file_list[0] else: - sel = xbmcgui.Dialog().select('请选择压缩包中的字幕', sub_name_list) + cut_fn = __addon__.getSetting("cutsubfn") + sel = xbmcgui.Dialog().select('请选择压缩包中的字幕', short_sub_name_list if cut_fn == + 'true' else sub_name_list) if sel == -1: sel = 0 selected_sub = sub_file_list[sel] - logger.log(sys._getframe().f_code.co_name, "SUB FILE TO USE: %s" % selected_sub) + logger.log(sys._getframe().f_code.co_name, + "SUB FILE TO USE: %s" % selected_sub) return [selected_sub] @@ -134,6 +147,10 @@ def get_params(): def handle_params(params): + """ + 对应界面上的按钮/功能,一个是搜索,一个是下载 + """ + if params['action'] == 'search' or params['action'] == 'manualsearch': item = {'temp': False, 'rar': False, 'mansearch': False} item['year'] = xbmc.getInfoLabel("VideoPlayer.Year") # Year @@ -152,7 +169,8 @@ def handle_params(params): item['mansearchstr'] = params['searchstring'] for lang in urllib.parse.unquote(params['languages']).split(","): - item['3let_language'].append(xbmc.convertLanguage(lang, xbmc.ISO_639_2)) + item['3let_language'].append( + xbmc.convertLanguage(lang, xbmc.ISO_639_2)) if item['title'] == "": # no original title, get just Title @@ -174,7 +192,8 @@ def handle_params(params): elif (item['file_original_path'].find("rar://") > -1): item['rar'] = True - item['file_original_path'] = os.path.dirname(item['file_original_path'][6:]) + item['file_original_path'] = os.path.dirname( + item['file_original_path'][6:]) elif (item['file_original_path'].find("stack://") > -1): stackPath = item['file_original_path'].split(" , ") @@ -203,6 +222,11 @@ def run(): tpe = __addon__.getSetting("subtype") lang = __addon__.getSetting("sublang") + if __addon__.getSetting("proxy_follow_kodi") != "true": + proxy = ("" if __addon__.getSetting("proxy_use") != "true" + else __addon__.getSetting("proxy_server")) + os.environ["HTTP_PROXY"] = os.environ["HTTPS_PROXY"] = proxy + agent = zmkagnt.Zimuku_Agent(zimuku_base_url, __temp__, logger, Unpacker(), {'subtype': tpe, 'sublang': lang}) diff --git a/script.subtitles.zimukux/resources/lib/zimuku_agent.py b/script.subtitles.zimukux/resources/lib/zimuku_agent.py index 3cfc1011b..75eb949ca 100644 --- a/script.subtitles.zimukux/resources/lib/zimuku_agent.py +++ b/script.subtitles.zimukux/resources/lib/zimuku_agent.py @@ -32,7 +32,7 @@ def __init__(self, base_url, dl_location, logger, unpacker, settings): self.ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)' self.ZIMUKU_BASE = base_url self.INIT_PAGE = base_url + '/?security_verify_data=313932302c31303830' - #self.ZIMUKU_API = '%s/search?q=%%s&vertoken=%%s' % base_url + # self.ZIMUKU_API = '%s/search?q=%%s&vertoken=%%s' % base_url self.TOKEN_PARAM = 'security_verify_data=313932302c31303830' self.ZIMUKU_API = '%s/search?q=%%s' % base_url self.DOWNLOAD_LOCATION = dl_location @@ -84,8 +84,8 @@ def get_page(self, url, **kwargs): a = requests.adapters.HTTPAdapter(max_retries=3) s.mount('http://', a) - #url += '&' if '?' in url else '?' - #url += 'security_verify_data=313932302c31303830' + # url += '&' if '?' in url else '?' + # url += 'security_verify_data=313932302c31303830' self.logger.log(sys._getframe().f_code.co_name, 'requests GET [%s]' % (url), level=3) @@ -211,7 +211,7 @@ def get_vertoken(self, resp): (Exception, e), level=3) return '' - def search(self, title, item): + def search(self, title, items): """ 搜索字幕 @@ -231,7 +231,7 @@ def search(self, title, item): """ subtitle_list = [] - #vertoken = self.get_vertoken() + # vertoken = self.get_vertoken() get_cookie_url = '%s&%s' % (self.ZIMUKU_API % (urllib.parse.quote(title)), self.TOKEN_PARAM) @@ -244,15 +244,15 @@ def search(self, title, item): # 真正的搜索 self.logger.log(sys._getframe().f_code.co_name, "Search API url: %s" % (url)) - headers, data = self.get_page(url) + _, data = self.get_page(url) soup = BeautifulSoup(data, 'html.parser') except Exception as e: self.logger.log(sys._getframe().f_code.co_name, 'ERROR SEARCHING, E=(%s: %s)' % (Exception, e), level=3) return [] - s_e = 'S%02dE%02d' % (int(item['season']), int(item['episode']) - ) if item['season'] != '' and item['episode'] != '' else 'N/A' + s_e = 'S%02dE%02d' % (int(items['season']), int(items['episode']) + ) if items['season'] != '' and items['episode'] != '' else 'N/A' if s_e != 'N/A': # 1. 从搜索结果中看看是否能直接找到 sub_list = soup.find_all('tr') @@ -265,11 +265,11 @@ def search(self, title, item): # break 还是全列出来吧 if len(subtitle_list) != 0: - return subtitle_list + return self.double_filter(subtitle_list, items) # 2. 直接找不到,看是否存在同一季的链接,进去找 season_name_chn = ('一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二', '十三', '十四', '十五')[ - int(item['season']) - 1] if s_e != 'N/A' else 'N/A' + int(items['season']) - 1] if s_e != 'N/A' else 'N/A' season_list = soup.find_all("div", class_="item prel clearfix") page_list = soup.find('div', class_='pagination') @@ -309,7 +309,8 @@ def search(self, title, item): sub_name = sub.a.text if s_e in sub_name.upper(): subtitle_list.append(self.extract_sub_info(sub, 2)) - return subtitle_list # 如果匹配到了季,那就得返回了,没有就是没有 + # 如果匹配到了季,那就得返回了,没有就是没有 + return self.double_filter(subtitle_list, items) # 精确查找没找到,那就返回所有 subtitle_list = [] @@ -330,7 +331,18 @@ def search(self, title, item): for sub in reversed(subs): subtitle_list.append(self.extract_sub_info(sub, 2)) - return subtitle_list + return self.double_filter(subtitle_list, items) + + def double_filter(self, subtitle_list, items): + # 适用当前集数再次过滤字幕 + try: + episode = int(items['episode']) + es = 'E%02d' % episode + filtered = [ + s for s in subtitle_list if es in s['filename'].upper()] + return filtered if len(filtered) > 0 else subtitle_list + except: + return subtitle_list def find_in_list(self, lst, include, *kws): """ @@ -362,19 +374,20 @@ def find_in_list(self, lst, include, *kws): new_lst.append(e) return new_lst - def get_preferred_subs(self, sub_name_list, sub_file_list): + def get_preferred_subs(self, sub_name_list, short_sub_name_list, sub_file_list): """ 根据插件的参数找出偏好的字幕 Params: - sub_name_list 文件名 - sub_file_list 对应的文件绝对路径 + sub_name_list 文件名 + short_sub_name_list 短文件名 + sub_file_list 对应的文件绝对路径 Return: - [], [] 返回筛选列表。如果筛选结果是空,意味着没有匹配上任意一条,那就返回传进来的列表;也可能不止一条,比如只指定了 srt 然后有不止一条 + [], [], [] 返回筛选列表。如果筛选结果是空,意味着没有匹配上任意一条,那就返回传进来的列表;也可能不止一条,比如只指定了 srt 然后有不止一条 """ if len(sub_name_list) <= 1: - return sub_name_list, sub_file_list + return sub_name_list, short_sub_name_list, sub_file_list else: tpe = self.plugin_settings['subtype'] lang = self.plugin_settings['sublang'] @@ -384,7 +397,7 @@ def get_preferred_subs(self, sub_name_list, sub_file_list): level=1) if tpe == 'none ' and lang == 'none': - return sub_name_list, sub_file_list + return sub_name_list, short_sub_name_list, sub_file_list filtered_name_list = sub_name_list if tpe != 'none': filtered_name_list = self.find_in_list( @@ -414,11 +427,11 @@ def get_preferred_subs(self, sub_name_list, sub_file_list): self.logger.log(sys._getframe().f_code.co_name, "筛完语言:%s" % filtered_name_list, level=1) if len(filtered_name_list) == 0: - return sub_name_list, sub_file_list + return sub_name_list, short_sub_name_list, sub_file_list # 把原先的路径找回来 indices = [sub_name_list.index(x) for x in filtered_name_list] - return filtered_name_list, [sub_file_list[x] for x in indices] + return filtered_name_list, [short_sub_name_list[x] for x in indices], [sub_file_list[x] for x in indices] def download(self, url): """ @@ -428,7 +441,11 @@ def download(self, url): url 字幕详情页面,如 http://zimuku.org/detail/155262.html Return: - [], [] 返回两个列表,第一个为文件名(用于不止一个时在 Kodi 界面上让用户选择),第二个为完整路径(用户送给播放器使用) + [], [], [] 返回 3 个列表 + 第一个为文件名(用于不止一个时在 Kodi 界面上让用户选择) + 第二个是极短文件名(通过参数 cutsubfn 控制,避免文件名过长滚动) + 短文件名本来在 sub_provider_service 做更合适(PR 也是这么提的),但问题是那样不好写 testcase,所以先放这里 + 第三个为完整路径(用户送给播放器使用) """ exts = (".srt", ".sub", ".smi", ".ssa", ".ass", ".sup") supported_archive_exts = (".zip", ".7z", ".tar", ".bz2", ".rar", @@ -451,22 +468,25 @@ def download(self, url): except: self.logger.log(sys._getframe().f_code.co_name, "Error (%d) [%s]" % ( sys.exc_info()[2].tb_lineno, sys.exc_info()[1]), level=3) - return [], [] + return [], [], [] filename, data = self.download_links(links, url) if filename == '': # No file received. - return [], [] + return [], [], [] + + # 小写扩展名 + dot = filename.rfind(".") + if dot != -1: + filename = filename[:dot] + filename[dot:].lower() rtn_list = [] if filename.endswith(exts): full_path = self.store_file(filename, data) fn = self.fix_garbled_filename(os.path.basename(full_path)) - return [fn], [full_path] + return [fn], [fn], [full_path] elif filename.endswith(supported_archive_exts): full_path = self.store_file(filename, data) - # libarchive requires the access to the file, so sleep a while to ensure the file. - time.sleep(0.5) archive_path, sub_name_list = self.unpacker.unpack(full_path) # 返回的文件名不能做乱码修正,不然找不到…… @@ -475,12 +495,25 @@ def download(self, url): sub_name_list = [self.fix_garbled_filename( x) for x in sub_name_list] - return sub_name_list, sub_file_list + if len(sub_name_list) > 1: + # 不显示相同的前缀,防止文件名过长滚动 + shortest_fn = min(sub_name_list, key=len) + diff_index = next(filter( + lambda i: any(s[i] != shortest_fn[i] + for s in sub_name_list), + range(len(shortest_fn)) + )) + dot = shortest_fn[:diff_index].rfind('.') + 1 + short_sub_name_list = [s[dot:] for s in sub_name_list] + + return sub_name_list, short_sub_name_list, sub_file_list + else: + return sub_name_list, sub_name_list, sub_file_list else: self.logger.log(sys._getframe().f_code.co_name, "UNSUPPORTED FILE: % s" % (filename), level=2) # xbmc.executebuiltin(('XBMC.Notification("zimuku","不支持的压缩格式,请选择其他字幕文件。")'), True) - return [], [] + return [], [], [] def fix_garbled_filename(self, fn): # hack to fix encoding problem of zip file @@ -512,8 +545,8 @@ def store_file(self, filename, data): ts, os.path.splitext(filename)[1])).replace('\\', '/') with open(tempfile, "wb") as sub_file: sub_file.write(data) - # May require close file explicitly to ensure the file. - sub_file.close() + sub_file.flush() + os.fsync(sub_file.fileno()) return tempfile.replace('\\', '/') def download_links(self, links, referer): diff --git a/script.subtitles.zimukux/resources/lib/zimuku_archive.py b/script.subtitles.zimukux/resources/lib/zimuku_archive.py index 1ad4451ac..1eeed48b3 100644 --- a/script.subtitles.zimukux/resources/lib/zimuku_archive.py +++ b/script.subtitles.zimukux/resources/lib/zimuku_archive.py @@ -40,11 +40,10 @@ def unpack(file_path): so raise TypeError to avoid the worst condition. """ exts = (".srt", ".sub", ".smi", ".ssa", ".ass", ".sup") - supported_archive_exts = (".zip", ".7z", ".tar", ".bz2", ".rar", ".gz", - ".xz", ".iso", ".tgz", ".tbz2", ".cbr") - self_archive_exts = (".zip", ".rar") + # supported_archive_exts = (".zip", ".7z", ".tar", ".bz2", ".rar", ".gz", ".xz", ".iso", ".tgz", ".tbz2", ".cbr") + self_archive_exts = (".zip", ".rar", ".7z") - if not file_path.endswith(supported_archive_exts): + if not file_path.endswith(self_archive_exts): log(sys._getframe().f_code.co_name, "Unknown file ext: %s" % (os.path.basename(file_path)), level=xbmc.LOGERROR) @@ -57,7 +56,7 @@ def unpack(file_path): 'protocol': ext, 'archive_file': archive_file } - if file_path.endswith(self_archive_exts): + if file_path.endswith((".zip", ".rar")): log(sys._getframe().f_code.co_name, "UNPACK %s FILE: %s" % (ext, archive_path), level=xbmc.LOGDEBUG) @@ -72,7 +71,8 @@ def unpack(file_path): subtitle_list = [] for subfile in files: - if subfile.endswith(exts): + # 小写扩展名 + if subfile[-4:].lower().endswith(exts): subtitle_list.append(subfile) elif file_path.endswith('.7z'): @@ -107,4 +107,7 @@ def unpack_7z(file_path): """ decompress_path = '' subtitle_list = [] + log(sys._getframe().f_code.co_name, "目前不知道怎么解压 7z: %s" % + (file_path), level=xbmc.LOGERROR) + return decompress_path, subtitle_list diff --git a/script.subtitles.zimukux/resources/settings.xml b/script.subtitles.zimukux/resources/settings.xml index c64c38ae2..cea3d900c 100644 --- a/script.subtitles.zimukux/resources/settings.xml +++ b/script.subtitles.zimukux/resources/settings.xml @@ -33,7 +33,7 @@ - 1 + 0 30220 @@ -48,7 +48,52 @@ + + 0 + false + + + + 0 + false + + + + + + 0 + true + + + + 0 + true + + + false + + + + 0 + + 30312 + + protocol://[user:pass@]host:port + + true + + + + + false + true + + + + + + \ No newline at end of file From 3b3909bac192f6d748042a4f2498e15f32234feb Mon Sep 17 00:00:00 2001 From: Allertj <44700026+Allertj@users.noreply.github.com> Date: Wed, 15 Feb 2023 13:24:56 +0100 Subject: [PATCH 009/145] [script.sublissimo] 2.0.3 (#2399) --- script.sublissimo/addon.xml | 10 +- .../resource.language.de_de/strings.po | 938 ++++++++++++++++++ .../resource.language.hr_hr/strings.po | 938 ++++++++++++++++++ 3 files changed, 1883 insertions(+), 3 deletions(-) create mode 100644 script.sublissimo/resources/language/resource.language.de_de/strings.po create mode 100644 script.sublissimo/resources/language/resource.language.hr_hr/strings.po diff --git a/script.sublissimo/addon.xml b/script.sublissimo/addon.xml index 00f43ff4d..084ad133d 100644 --- a/script.sublissimo/addon.xml +++ b/script.sublissimo/addon.xml @@ -1,5 +1,5 @@ - + @@ -11,8 +11,8 @@ all MIT ajvmdev@gmail.com - Version 2.0.2 - - New: Chinese, Finnish and Italian translations + Version 2.0.3 + - New: Croatian and German translations - Minor bugfixes https://github.com/Allertj/script.sublissimo @@ -20,12 +20,16 @@ resources/icon.png resources/fanart.jpg + Mit der Fernbedienung Untertitel bearbeiten und synchronisieren Edit and synchronize subtitles with your remote + Uredite i uskladite podnaslove s vašim daljinskim Muokkaa ja ajoita tekstitykset kauko-ohjaimellasi Modifica e sincronizza i sottotitoli con il telecomando 리모컨으로 자막 편집 및 동기화 使用遥控器编辑和同步字幕 + Mit diesem Skript lassen sich bestimmte Zeilen bearbeiten, Untertitel verschieben oder strecken und mit anderen Untertiteln synchronisieren. Sie können auch mit einer Videodatei synchronisiert werden.[CR][CR]Um diesen Editor einfach zu verwenden, ihn während der Wiedergabe des Videos und des Untertitels, den bearbeiten werden soll, starten. With this script you can edit specific lines, move or stretch subtitles, and synchronize with other subtitles. You can also synchronize with a videofile.[CR][CR]To easily use this editor, launch it when the video and subtitle you wish to edit are playing. + S ovom skriptom možete urediti određene retke, pomaknuti ili raširiti podnaslove, i uskladiti s ostalim podnaslovima. Možete još uskladiti i s video datotekom.[CR][CR]Za lakše korištenje ovog uređivača, pokrenite ga kada se video i podnaslov kojeg želite urediti reproduciraju. Tällä lisäosalla voidaan muokata yksittäisiä tekstitysrivejä, siirtää ja venyttää tekstityksiä sekä tahdistaa niitä muiden tekstitysten ja videotiedostojen kanssa.[CR][CR]Editorin käynnistys onnistuu helposti suoraan toistettaessa muokkausta vaativaa videota ja tekstitystä. Con questo script puoi modificare righe specifiche, spostare o allungare i sottotitoli e sincronizzare con altri sottotitoli. Puoi anche sincronizzare con un file video.[CR][CR]Per utilizzare facilmente questo editor, avvialo quando il video e i sottotitoli che desideri modificare sono in riproduzione. 이 스크립트를 사용하면 특정 줄을 편집하고, 자막을 이동하거나 늘리고, 다른 자막과 동기화할 수 있습니다. 비디오 파일과 동기화할 수도 있습니다. diff --git a/script.sublissimo/resources/language/resource.language.de_de/strings.po b/script.sublissimo/resources/language/resource.language.de_de/strings.po new file mode 100644 index 000000000..4b7e51d1d --- /dev/null +++ b/script.sublissimo/resources/language/resource.language.de_de/strings.po @@ -0,0 +1,938 @@ +# Kodi Media Center language file +# Addon Name: Sublissimo +# Addon id: script.sublissimo +# Addon Provider: AJVM +msgid "" +msgstr "" +"Project-Id-Version: XBMC Addons\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2023-02-05 11:15+0000\n" +"Last-Translator: Demian \n" +"Language-Team: German \n" +"Language: de_de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.15.2\n" + +msgctxt "Addon Summary" +msgid "Edit and synchronize subtitles with your remote" +msgstr "Mit der Fernbedienung Untertitel bearbeiten und synchronisieren" + +msgctxt "Addon Description" +msgid "With this script you can edit specific lines, move or stretch subtitles, and synchronize with other subtitles. You can also synchronize with a videofile.[CR][CR]To easily use this editor, launch it when the video and subtitle you wish to edit are playing." +msgstr "Mit diesem Skript lassen sich bestimmte Zeilen bearbeiten, Untertitel verschieben oder strecken und mit anderen Untertiteln synchronisieren. Sie können auch mit einer Videodatei synchronisiert werden.[CR][CR]Um diesen Editor einfach zu verwenden, ihn während der Wiedergabe des Videos und des Untertitels, den bearbeiten werden soll, starten." + +msgctxt "#31000" +msgid "Scroll subtitles" +msgstr "Untertitel scrollen" + +msgctxt "#30001" +msgid "Edit or delete lines" +msgstr "Zeilen bearbeiten oder löschen" + +msgctxt "#31002" +msgid "Move subtitles" +msgstr "Untertitel verschieben" + +msgctxt "#31003" +msgid "Stretch/shrink subtitles" +msgstr "Untertitel strecken/stauchen" + +msgctxt "#31004" +msgid "Synchronize with other subtitle" +msgstr "Mit anderen Untertiteln synchronisieren" + +msgctxt "#31005" +msgid "Synchronize with video file" +msgstr "Mit Videodatei synchronisieren" + +msgctxt "#31006" +msgid "Search in subtitle" +msgstr "In Untertitel suchen" + +msgctxt "#31007" +msgid "Check integrity" +msgstr "Integrität prüfen" + +msgctxt "#31008" +msgid "Save subtitles" +msgstr "Untertitel speichern" + +msgctxt "#31009" +msgid "Quit" +msgstr "Beenden" + +msgctxt "#31010" +msgid "Synchronize by frame rate" +msgstr "Nach Bildrate synchronisieren" + +msgctxt "#31011" +msgid "Play video with edited subtitle" +msgstr "Video mit geänderten Untertiteln wiedergeben" + +msgctxt "#31013" +msgid "Advanced options" +msgstr "Erweiterte Optionen" + +msgctxt "#31001" +msgid "Sublissimo" +msgstr "Sublissimo" + +msgctxt "#33000" +msgid "" +"Select the subtitle to synchronize with. Then:[CR]- Select a timecode in the " +"beginning to a line as reference[CR]- Select the roughly the same line in " +"your subtitle[CR]- Then do same with two lines near the end of both files." +msgstr "Untertitel auswählen, mit dem synchronisiert werden soll. Dann:[CR]- Einen Timecode am Anfang einer Zeile als Referenz auswählen[CR]- Ungefähr die gleiche Zeile im anderen Untertitel auswählen[CR]- Dann dasselbe mit zwei Zeilen nahe dem Ende beider Dateien tun." + +msgctxt "#32001" +msgid "Edit line" +msgstr "Zeile bearbeiten" + +msgctxt "#32002" +msgid "Delete First Subtitle" +msgstr "Ersten Untertitel löschen" + +msgctxt "#32003" +msgid "Delete Last Subtitle" +msgstr "Letzten Untertitel löschen" + +msgctxt "#32004" +msgid "Manually Scroll and Delete" +msgstr "Manuell scrollen und löschen" + +msgctxt "#32005" +msgid "Back" +msgstr "Zurück" + +msgctxt "#32006" +msgid "Delete this subtitle?" +msgstr "Diesen Untertitel löschen?" + +msgctxt "#32007" +msgid "Select subtitle to edit" +msgstr "Untertitel zum Bearbeiten auswählen" + +msgctxt "#32008" +msgid "Return" +msgstr "Zurück" + +msgctxt "#32009" +msgid "Delete" +msgstr "Löschen" + +msgctxt "#32010" +msgid "All subtitles" +msgstr "Alle Untertitel" + +msgctxt "#32011" +msgid "Found:" +msgstr "Gefunden:" + +msgctxt "#32012" +msgid "OK" +msgstr "OK" + +msgctxt "#32013" +msgid "More Info" +msgstr "Mehr Informationen" + +msgctxt "#32014" +msgid "Error" +msgstr "Fehler" + +msgctxt "#32015" +msgid "Select subtitle to synchronize with" +msgstr "Untertitel auswählen, mit dem zu synchronisieren ist" + +msgctxt "#32016" +msgid "Please select a .srt or a .sub file" +msgstr "Bitte eine .srt- oder .sub-Datei auswählen" + +msgctxt "#32017" +msgid "Success" +msgstr "Erfolgreich" + +msgctxt "#32018" +msgid "Current first subtitle" +msgstr "Aktuell erster Untertitel" + +msgctxt "#32019" +msgid "First subtitle is now:" +msgstr "Erster Untertitel ist jetzt:" + +msgctxt "#32020" +msgid "Please select a video file." +msgstr "Bitte eine Videodatei auswählen." + +msgctxt "#32021" +msgid "Current last subtitle" +msgstr "Aktuell letzter Untertitel" + +msgctxt "#32022" +msgid "Last subtitle is now:" +msgstr "Letzter Untertitel ist jetzt:" + +msgctxt "#32023" +msgid "Enter search string" +msgstr "Suchbegriff eingeben" + +msgctxt "#32024" +msgid "Yes" +msgstr "Ja" + +msgctxt "#32025" +msgid "No" +msgstr "Nein" + +msgctxt "#32026" +msgid "This editor only works with .srt or .sub files" +msgstr "Diese Editor arbeitet nur mit .srt- oder .sub-Dateien" + +msgctxt "#32027" +msgid "File not found: " +msgstr "Datei nicht gefunden: " + +msgctxt "#32028" +msgid "" +"Write the new timestamp for the end position, seperated by a ':'. For " +"instance: 01:22:23:000" +msgstr "Den neuen Zeitstempel für die Endposition schreiben, getrennt durch ein „:“. Zum Beispiel: 01:22:23:000" + +msgctxt "#32029" +msgid "For example: 01:22:23:000" +msgstr "Zum Beispiel: 01:22:23:000" + +msgctxt "#32030" +msgid "Report" +msgstr "Bericht" + +msgctxt "#32031" +msgid "No problems detected" +msgstr "Keine Probleme erkannt" + +msgctxt "#32032" +msgid "Line:" +msgstr "Zeile:" + +msgctxt "#33032" +msgid "Line " +msgstr "Zeile " + +msgctxt "#32033" +msgid "Possible problems: " +msgstr "Mögliche Probleme: " + +msgctxt "#32034" +msgid "Select subtitle to continue..." +msgstr "Untertitel auswählen, um fortzufahren …" + +msgctxt "#32035" +msgid "Select subtitle to edit" +msgstr "Zu bearbeitenden Untertitel auswählen" + +msgctxt "#32036" +msgid "Your subtitle starts at " +msgstr "Der Untertitel startet bei " + +msgctxt "#32037" +msgid "Your subtitle ends at " +msgstr "Der Untertitel endet bei " + +msgctxt "#32038" +msgid "Save with _edited.srt added" +msgstr "Mit Zusatz _edited.srt speichern" + +msgctxt "#32039" +msgid "Save with current filename" +msgstr "Mit aktuellem Dateinamen speichern" + +msgctxt "#32040" +msgid "Save with custom filename" +msgstr "Mit benutzerdefiniertem Dateinamen speichern" + +msgctxt "#32041" +msgid "Exit without saving" +msgstr "Beenden ohne zu speichern" + +msgctxt "#32042" +msgid "Give new filename: " +msgstr "Neuen Dateiname eingeben " + +msgctxt "#32043" +msgid "Written to: " +msgstr "Schreiben in: " + +msgctxt "#32044" +msgid "" +"To use the file, select it in the Kodi player subtitle menu when playing the " +"file" +msgstr "Um die Datei zu verwenden, ist sie bei der Wiedergabe im Untertitelmenü des Kodi-Players auszuwählen" + +msgctxt "#32045" +msgid "File not written" +msgstr "Datei nicht geschrieben" + +msgctxt "#32046" +msgid "Warning" +msgstr "Warnung" + +msgctxt "#32047" +msgid "You might have unsaved progress on your file" +msgstr "Die Datei enthält möglicherweise nicht gespeicherte Änderungen" + +msgctxt "#32048" +msgid "Exit Anyway" +msgstr "Trotzdem beenden" + +msgctxt "#32049" +msgid "Save" +msgstr "Speichern" + +msgctxt "#32050" +msgid "Subtitles succesfully synced" +msgstr "Untertitel erfolgreich synchronisiert" + +msgctxt "#32051" +msgid "Move forwards" +msgstr "Vorwärts bewegen" + +msgctxt "#32052" +msgid "Move backwards" +msgstr "Rückwärts bewegen" + +msgctxt "#32053" +msgid "Give new time for first subtitle" +msgstr "Neue Zeit für ersten Untertitel angeben" + +msgctxt "#32054" +msgid "Move forwards by: HH:MM:SS:MSE" +msgstr "Vorwärts verschieben um: HH:MM:SS:MSE" + +msgctxt "#32055" +msgid "Move forwards by: HH:MM:SS:MSE" +msgstr "Vorwärts verschieben um: HH:MM:SS:MSE" + +msgctxt "#32056" +msgid "" +"Please enter valid timecode: HH:MM:SS:MSE. Hours, minutes, seconds, " +"milliseconds. For instance: 01:23:45:000" +msgstr "Bitte einen gültigen Zeitcode eingeben: HH:MM:SS:MSE. Stunden, Minuten, Sekunden, Millisekunden. Zum Beispiel: 01:23:45:000" + +msgctxt "#32057" +msgid "How to sync two subtitles" +msgstr "Wie man zwei Untertitel synchronisiert" + +msgctxt "#32058" +msgid "" +"In order to synchronize, you will need a subtitle which matches the video " +"perfectly, but has different subtitles, usually from a different language. " +"In the next slide, first select this subtitle.[CR][CR]Then, you'll be asked " +"to select a timecode in this file, which will be used as reference. Ideally, " +"it is the first spoken line from the video. In the next screen, select the " +"line from your original subtitle which matches the first.[CR]" +"[CR]Subsequently, you'll be asked again to select a line from your reference " +"subtitle and to match this with the same line in your original subtitle. " +"Usually the best choice is the last spoken line from the video. After this " +"your two subtitles will sync![CR][CR]Check 'Scroll subtitles' to view them " +"and 'Save subtitles' to write them to a file." +msgstr "Zum Synchronisieren wird ein Untertitel benötigt, der perfekt zum Video passt, aber andere Untertitel hat, meist in einer anderen Sprache. Auf der nächsten Seite zunächst diesen Untertitel auswählen.[CR][CR]Dann muss ein Zeitcode aus dieser Datei gewählt werden, der als Referenz dienen soll. Im Idealfall ist dies die erste gesprochene Zeile des Videos. Im nächsten Schritt wird die Zeile aus dem Originaluntertitel gewählt, die mit der ersten übereinstimmt.[CR][CR]Anschließend erfolgt erneut die Aufforderung, eine Zeile aus Ihrem Referenzuntertitel auszuwählen und diese mit der gleichen Zeile in dem Originaluntertitel abzugleichen. Normalerweise ist die beste Wahl die letzte gesprochene Zeile des Videos. Danach werden die beiden Untertitel synchronisiert![CR][CR]„Untertitel scrollen“ markieren, um sie anzuzeigen und „Untertitel speichern“, um sie in eine Datei zu schreiben." + +msgctxt "#32059" +msgid "File not found" +msgstr "Datei nicht gefunden" + +msgctxt "#32060" +msgid "" +"In the next screen, select the video to synchronize with. Go to the point in " +"the video where the first subtitle starts. When you pause the video, choose " +"'Select as start' in the menu, then do the same with the last subtitle." +msgstr "Auf der nächsten Seite das Video auswählen, mit dem synchronisiert werden soll. Zu der Stelle im Video gehen, an dem der erste Untertitel startet. Wenn das Video angehalten wurde, im Menü „Als Start auswählen“ wählen, dann genauso mit dem letzten Untertitel verfahren." + +msgctxt "#32061" +msgid "How to sync with a video file" +msgstr "Wie man mit einer Videodatei synchronisiert" + +msgctxt "#32062" +msgid "" +"In the next screen, open the videofile from the library which belongs to the " +"subtitle you have opened. Skip or fast forward to the point where the " +"subtitle should roughly be placed. Pause.[CR][CR]When you paused the video, " +"a menu will pop up with several options. Select 'View or edit first " +"subtitle'. When your first subtitle is not the first line from the video, " +"select 'Delete' until the first subtitle is also the first line from the " +"video.[CR][CR]Then finetune the position of the video, possibly by using the " +"'Skip forward 1 second' or 'Skip backward 1 second' buttons. If the position " +"is perfect, choose 'Select as start'.[CR]Now fast forward to the end of the " +"video, and repeat the same process.[CR][CR]After this, your file will be " +"synced to the video." +msgstr "Auf der nächsten Seite die Videodatei aus der Bibliothek öffnen, die zum geöffneten Untertitel gehört. An Punkt springen oder vorspulen, an dem der Untertitel ungefähr platziert werden soll. Pause drücken.[CR][CR]Wenn das Video angehalten wurde, wird ein Menü mit verschiedenen Optionen angezeigt. „Ersten Untertitel anzeigen oder bearbeiten“ auswählen. Sollte der erste Untertitel nicht die erste Zeile des Videos sein, „Löschen“ wählen, bis der erste Untertitel auch die erste Zeile des Videos ist.[CR][CR]Danach die Position des Videos feinabstimmen, ggf. mittels „1 Sekunde vorwärts springen“ oder „1 Sekunde rückwärts springen“. Wenn die Position perfekt ist, „Als Start auswählen“ anklicken.[CR]Nun zum Ende des Videos vorspulen und den gleichen Vorgang wiederholen.[CR][CR]Daraufhin wird die Datei mit dem Video synchronisiert." + +msgctxt "#32063" +msgid "Select timecode of first subtitle to sync with" +msgstr "Zeitcode des ersten Untertitels für den Sync auswählen" + +msgctxt "#32064" +msgid "Time selected" +msgstr "Gewählte Zeit" + +msgctxt "#33064" +msgid "Time selected" +msgstr "Gewählte Zeit" + +msgctxt "#32065" +msgid "Select timecode of subtitle which is roughly the same" +msgstr "Zeitcode des Untertitels wählen, der ungefähr gleich ist" + +msgctxt "#32066" +msgid "Select time of last subtitle to sync" +msgstr "Zeit des letzten zu synchronisierenden Untertitels wählen" + +msgctxt "#32067" +msgid "Select time of last subtitle" +msgstr "Zeit des letzten Untertitels wählen" + +msgctxt "#32068" +msgid "New timecode" +msgstr "Neuer Zeitcode" + +msgctxt "#32069" +msgid "" +"Write the new timestamp for the start position, seperated by a ':'. For " +"instance: 01:22:23:000" +msgstr "Den neuen Zeitstempel für die Startposition schreiben, getrennt durch ein „:“. Zum Beispiel: 01:22:23:000" + +msgctxt "#32070" +msgid "Subtitles moved forward by: {}" +msgstr "Untertitel vorwärts bewegt um: {}" + +msgctxt "#32071" +msgid "Subtitles moved backward by {}" +msgstr "Untertitel rückwärts bewegt um: {}" + +msgctxt "#32072" +msgid "First subtitle now starts at {}" +msgstr "Erster Untertitel startet jetzt bei {}" + +msgctxt "#33072" +msgid "Last subtitle now starts at {}" +msgstr "Letzter Untertitel startet jetzt bei {}" + +msgctxt "#32073" +msgid " Paused at: " +msgstr " Pausiert bei: " + +msgctxt "#32074" +msgid "Continue playing" +msgstr "Wiedergabe fortsetzen" + +msgctxt "#32075" +msgid "Select as start of first subtitle" +msgstr "Als Start für ersten Untertitel auswählen" + +msgctxt "#32076" +msgid "Skip backwards 1 second" +msgstr "1 Sekunde rückwärts springen" + +msgctxt "#32077" +msgid "Skip forwards 1 second" +msgstr "1 Sekunde vorwärts springen" + +msgctxt "#32078" +msgid "Exit to Main Menu" +msgstr "Zurück zum Hauptmenü" + +msgctxt "#32079" +msgid "View or delete first subtitle" +msgstr "Ersten Untertitel anzeigen oder löschen" + +msgctxt "#32080" +msgid "View or delete last subtitle" +msgstr "Letzten Untertitel anzeigen oder löschen" + +msgctxt "#32081" +msgid "Select as start of last subtitle" +msgstr "Als Start für letzten Untertitel auswählen" + +msgctxt "#32082" +msgid "Set as first subtitle?" +msgstr "Als ersten Untertitel festlegen?" + +msgctxt "#32083" +msgid "Do you want your subtitle to start at: " +msgstr "Soll der Untertitel starten bei: " + +msgctxt "#32084" +msgid "Reset start time" +msgstr "Startzeit zurücksetzen" + +msgctxt "#32085" +msgid "Selected start: " +msgstr "Gewählter Start: " + +msgctxt "#32086" +msgid "Selected times:" +msgstr "Gewählte Zeiten:" + +msgctxt "#32087" +msgid "Your first subtitle starts at: " +msgstr "Der erste Untertitel startet bei: " + +msgctxt "#32088" +msgid "Your last subtitle starts at: " +msgstr "Der letzte Untertitel startet bei: " + +msgctxt "#32089" +msgid "Select" +msgstr "Auswählen" + +msgctxt "#32090" +msgid "Reset times" +msgstr "Zeiten zurücksetzen" + +msgctxt "#33065" +msgid "Time selected" +msgstr "Gewählte Zeit" + +msgctxt "#32091" +msgid "Select a line with a timecode" +msgstr "Eine Zeile mit Zeitcode auswählen" + +msgctxt "#32092" +msgid "" +"Please select a line with a timecode, like:[CR]'01:23:45,679 --> " +"01:23:45,679'" +msgstr "Bitte eine Zeile mit Zeitcode auswählen, wie[CR]„01:23:45,679 --> 01:23:45,679“" + +msgctxt "#32093" +msgid "Choose movie" +msgstr "Film auswählen" + +msgctxt "#32094" +msgid "Choose TV Show" +msgstr "Serie auswählen" + +msgctxt "#32095" +msgid "View entire library" +msgstr "Gesamte Bibliothek anzeigen" + +msgctxt "#32096" +msgid "Exit to main menu with changes" +msgstr "Zurück zum Hauptmenü mit Änderungen" + +msgctxt "#32097" +msgid "Save the shown subtitle" +msgstr "Angezeigten Untertitel speichern" + +msgctxt "#32098" +msgid "Exit to main menu w/o changes" +msgstr "Zurück zum Hauptmenü ohne Änderungen" + +msgctxt "#32099" +msgid "Exit completely" +msgstr "Vollständig beenden" + +msgctxt "#32100" +msgid "Reset to another framerate" +msgstr "Auf eine andere Framerate zurücksetzen" + +msgctxt "#32101" +msgid "Save and Continue playing" +msgstr "Speichern und Wiedergabe fortsetzen" + +msgctxt "#32102" +msgid "" +"The subtitle is loaded with the new framerate. Pause to reset to another " +"frame rate or to save." +msgstr "Der Untertitel wurde mit der neuen Framerate geladen. Pausieren, um eine andere Framerate einzustellen oder zu speichern." + +msgctxt "#32103" +msgid "Please enter a valid number" +msgstr "Bitte eine gültige Zahl eingeben" + +msgctxt "#32104" +msgid "Get frame rate from video" +msgstr "Bildrate aus Video ermitteln" + +msgctxt "#32105" +msgid "Sync options by frame rate" +msgstr "Sync-Optionen nach Framerate" + +msgctxt "#32106" +msgid "Frame rate" +msgstr "Bildrate" + +msgctxt "#32107" +msgid "New ending time" +msgstr "Neue Endzeit" + +msgctxt "#32108" +msgid "Old starting time: " +msgstr "Alte Startzeit: " + +msgctxt "#34108" +msgid "Starting time: " +msgstr "Startzeit: " + +msgctxt "#32109" +msgid "Old ending time: " +msgstr "Alte Endzeit: " + +msgctxt "#34110" +msgid "New starting time: " +msgstr "Neue Startzeit: " + +msgctxt "#32110" +msgid "New ending time: " +msgstr "Neue Endzeit: " + +msgctxt "#32111" +msgid "Save and Exit" +msgstr "Speichern und beenden" + +msgctxt "#32112" +msgid "Calculate manually" +msgstr "Manuell berechnen" + +msgctxt "#32113" +msgid "Provide sum or factor" +msgstr "Summe oder Faktor vorgeben" + +msgctxt "#32114" +msgid "Calculate factor or provide factor" +msgstr "Faktor berechnen oder Faktor vorgeben" + +msgctxt "#32115" +msgid "" +"In the next screen, write a sum with the current framerate divided by the " +"real frame rate. If the current frame rate is 25 and it should be 24, type " +"'25/24'. Or type your own factor, like '1.2'" +msgstr "Auf der nächsten Seite ist die Summe der aktuellen Framerate geteilt durch die tatsächliche Framerate einzugeben. Wenn die aktuelle Framerate 25 ist und sie eigentlich 24 sein sollte, „25/24“ eingeben. Oder einen eigenen Faktor eintippen, z. B. „1,2“" + +msgctxt "#32116" +msgid "Play with the file you opened before" +msgstr "Mit der zuvor geöffneten Datei wiedergeben" + +msgctxt "#32117" +msgid "Provide factor" +msgstr "Faktor vorgeben" + +msgctxt "#32118" +msgid "Stretch by providing factor" +msgstr "Strecken um den angegebenen Faktor" + +msgctxt "#32119" +msgid "Stretch by giving new end time" +msgstr "Strecken durch Eingabe einer neuen Endzeit" + +msgctxt "#32120" +msgid "The frame rate of this video is " +msgstr "Die Bildrate dieses Videos ist " + +msgctxt "#32121" +msgid "" +"The video is playing with the modified subtitle. Pause to save or to return " +"to the menu." +msgstr "Das Video wird mit den geänderten Untertiteln wiedergegeben. Pausieren, um zu speichern oder um zum Menü zurückzukehren." + +msgctxt "#32122" +msgid "Subtitles loaded" +msgstr "Untertitel geladen" + +msgctxt "#32123" +msgid "" +"The video is playing with the saved subtitle. The filename of the subtitle " +"is: " +msgstr "Das Video wird mit dem gespeicherten Untertitel abgespielt. Der Dateiname des Untertitels ist: " + +msgctxt "#32124" +msgid "Jump to time of current first subtitle" +msgstr "Sprung zur Zeit des aktuell ersten Untertitels" + +msgctxt "#32125" +msgid "Jump to time of last subtitle" +msgstr "Sprung zur Zeit des letzten Untertitels" + +msgctxt "#32126" +msgid "Choose another" +msgstr "Andere wählen" + +msgctxt "#32127" +msgid "Enter frame rate" +msgstr "Bildrate eingeben" + +msgctxt "#32128" +msgid "Open other subtitle" +msgstr "Anderen Untertitel öffnen" + +msgctxt "#32129" +msgid "Why do I see this screen?" +msgstr "Warum erscheint dieser Bildschirm?" + +msgctxt "#32130" +msgid "You have selected a .sub file" +msgstr "Es wurde eine .sub-Datei ausgewählt" + +msgctxt "#32131" +msgid "" +"You have selected a .sub file, which uses frame rates to indicate when " +"subtitles should be shown. To edit these subtitles, you have to select a " +"frame rate. You can start a video to see what frame rate it has or just pick " +"a random one if you want to use a sync option." +msgstr "Es wurde eine .sub-Datei ausgewählt, die anhand der Framerate angibt, wann die Untertitel erscheinen sollen. Um diese Untertitel zu bearbeiten, muss eine Framerate festgelegt werden. Um die Framerate zu ermitteln, kann das Video gestartet oder eine zufällige Framerate ausgewählt werden, falls eine Sync-Option genutzt werden soll." + +msgctxt "#32132" +msgid "This file might not be a valid subtitle" +msgstr "Diese Datei ist möglicherweise kein gültiger Untertitel" + +msgctxt "#32133" +msgid "Load anyway" +msgstr "Trotzdem laden" + +msgctxt "#32134" +msgid "Choose other" +msgstr "Andere wählen" + +msgctxt "#32135" +msgid "Not a valid .sub file" +msgstr "Keine gültige .sub-Datei" + +msgctxt "#32136" +msgid "This file does not appear to be a valid .sub file." +msgstr "iese Datei scheint keine gültige .sub-Datei zu sein." + +msgctxt "#32137" +msgid "All found HTML colorcodes reset to white." +msgstr "Alle gefundenen HTML-Farbcodes werden auf weiß zurückgesetzt." + +msgctxt "#32138" +msgid "Reset color code to white" +msgstr "Farbcodes auf weiß zurücksetzen" + +msgctxt "#32139" +msgid "Reset color to a custom color" +msgstr "Farbcodes auf bestimmte Farbe zurücksetzen" + +msgctxt "#32140" +msgid "" +"Not a valid code for a color. Use 8 digits in a hexadecimal notation: " +"'FF00FF00'" +msgstr "Kein gültiger Code für eine Farbe. 8 Zeichen in hexadezimaler Schreibweise verwenden: „FF00FF00“" + +msgctxt "#32141" +msgid "Provide color coding. Use 8 digits. Leave empty to cancel" +msgstr "Farbcodierung angeben. 8 Zeichen verwenden. Leer lassen um abzubrechen" + +msgctxt "#32142" +msgid "All found HTML colorcodes reset to " +msgstr "Alle gefundenen HTML-Farbcodes zurücksetzen auf " + +msgctxt "#35000" +msgid "Cancel" +msgstr "Abbrechen" + +msgctxt "#35001" +msgid "Load subtitle" +msgstr "Untertitel laden" + +msgctxt "#35002" +msgid "Manually" +msgstr "Manuell" + +msgctxt "#35003" +msgid "Do you want to edit this subtitle?" +msgstr "Soll dieser Untertitel bearbeitet werden?" + +msgctxt "#35004" +msgid "Playback will stop, but can be resumed from the menu." +msgstr "Die Wiedergabe wird gestoppt, kann aber über das Menü fortgesetzt werden." + +msgctxt "#35005" +msgid "" +"A subtitlefile could not be found. Do you want to select one manually and " +"continue with current video?" +msgstr "Eine Untertiteldatei wurde nicht gefunden. Soll ein Untertitel manuell ausgewählt und mit dem aktuellen Video fortgefahren werden?" + +msgctxt "#35006" +msgid "Video:" +msgstr "Video:" + +msgctxt "#35007" +msgid "Subtitle:" +msgstr "Untertitel:" + +msgctxt "#35008" +msgid "Play with " +msgstr "Wiedergeben mit " + +msgctxt "#35009" +msgid "Edit and synchronize subtitles with your remote" +msgstr "Mit der Fernbedienung Untertitel bearbeiten und synchronisieren" + +msgctxt "#35010" +msgid "" +"With this script you can edit specific lines, move or stretch subtitles, and " +"synchronize with other subtitles. You can also synchronize with a videofile." +msgstr "Mit diesem Skript lassen sich bestimmte Zeilen bearbeiten, Untertitel verschieben oder strecken und mit anderen Untertiteln synchronisieren. Sie können auch mit einer Videodatei synchronisiert werden." + +msgctxt "#35011" +msgid "Return to Menu" +msgstr "Zurück zum Menü" + +msgctxt "#35016" +msgid "" +"Somewhere in the process of syncing an error occurred. Most of the time this " +"is caused by:[CR] - A .srt file which uses non-standard timestamps.[CR] - A ." +"srt file which has a digit missing in one of its timestamps.[CR] - A file " +"which is not an actual .srt file[CR][CR]Use Main Menu -> Advanced Options -> " +"Check Integrity to scan for faulty timestamps or use a different .srt file." +msgstr "Im Synchronisierungsprozesses ist irgendwo ein Fehler aufgetreten. In den meisten Fällen wird dies verursacht durch:[CR] - Eine .srt-Datei, die nicht standardisierte Zeitstempel verwendet.[CR] - Eine .srt-Datei, bei der eine Ziffer in einem der Zeitstempel fehlt.[CR] - Eine Datei, die keine echte .srt-Datei ist[CR][CR]Über „Hauptmenü -> Erweiterte Optionen -> Integrität prüfen“ kann nach fehlerhaften Zeitstempeln gesucht werden oder man nimmt eine andere .srt-Datei." + +msgctxt "#35012" +msgid "The following error has occurred:" +msgstr "Folgender Fehler ist aufgetreten:" + +msgctxt "#35013" +msgid "Details of Error" +msgstr "Details zum Fehler" + +msgctxt "#35017" +msgid "Characterset not detected" +msgstr "Zeichensatz nicht erkannt" + +msgctxt "#35018" +msgid "" +"The correct characterset of this file could not be detected. The file is now " +"loading with the UTF-8 set and errors are replaced with questionmarks." +msgstr "Der richtige Zeichensatz dieser Datei konnte nicht erkannt werden. Die Datei wird jetzt mit als UTF-8 geladen und Fehler werden durch Fragezeichen ersetzt." + +msgctxt "#35019" +msgid "Select textline" +msgstr "Textzeile auswählen" + +msgctxt "#35020" +msgid "Select time to sync to" +msgstr "Zeit für Sync auswählen" + +msgctxt "#35021" +msgid "Shift forwards by microseconds" +msgstr "Vorwärtsschieben um Mikrosekunden" + +msgctxt "#35022" +msgid "Shift backwards by microseconds" +msgstr "Rückwärtsschieben um Mikrosekunden" + +msgctxt "#35023" +msgid "Shift forwards by minutes" +msgstr "Vorwärtsschieben um Minuten" + +msgctxt "#35024" +msgid "Shift backwards by minutes" +msgstr "Rückwärtsschieben um Minuten" + +msgctxt "#35025" +msgid "Select which subtitle to delete" +msgstr "Zu löschenden Untertitel auswählen" + +msgctxt "#35026" +msgid "Minutes" +msgstr "Minuten" + +msgctxt "#35027" +msgid "Microseconds" +msgstr "Mikrosekunden" + +msgctxt "#35028" +msgid "See contents" +msgstr "Siehe Inhalt" + +msgctxt "#35029" +msgid "Open anyway" +msgstr "Trotzdem öffnen" + +msgctxt "#35030" +msgid "Unlikely to be a subtitle" +msgstr "Unwahrscheinlich, dass es ein Untertitel ist" + +msgctxt "#35031" +msgid "This file is quite large and unlikely to be a subtitle" +msgstr "Diese Datei ist ziemlich groß und wird wahrscheinlich kein Untertitel sein" + +msgctxt "#35032" +msgid "Could not load subtitle" +msgstr "Untertitel konnte nicht geladen werden" + +msgctxt "#35033" +msgid "Could not find any subtitles in the file. Is it a valid subtitle?" +msgstr "Es konnten keine Untertitel in der Datei gefunden werden. Ist es ein gültiger Untertitel?" + +msgctxt "#35034" +msgid "Scanning..." +msgstr "Wird durchsucht …" + +msgctxt "#35035" +msgid "Checking which encoding to use for this file." +msgstr "Überprüfung, welcher Zeichensatz für diese Datei zu verwenden ist." + +msgctxt "#35036" +msgid "This does not seem to be a valid .sub file." +msgstr "Dies scheint keine gültige .sub-Datei zu sein." + +msgctxt "#35037" +msgid "This does not seem to be a valid .srt file." +msgstr "Dies scheint keine gültige .srt-Datei zu sein." + +msgctxt "#35038" +msgid "Results" +msgstr "Ergebnis" + +msgctxt "#35039" +msgid "The encoding is: " +msgstr "Der Zeichensatz ist: " + +msgctxt "#35040" +msgid "The following lines were skipped:" +msgstr "Folgende Zeilen wurden übersprungen:" + +msgctxt "#35041" +msgid "Repair manually" +msgstr "Manuell reparieren" + +msgctxt "#35042" +msgid "Jump to Specific subtitle" +msgstr "Zu bestimmtem Untertitel springen" + +msgctxt "#35043" +msgid "View or delete subtitle that is marked as first" +msgstr "Untertitel anzeigen oder löschen, der als Erster markiert ist" + +msgctxt "#35044" +msgid "View or delete subtitle that is marked as last" +msgstr "Untertitel anzeigen oder löschen, der als Letzter markiert ist" + +msgctxt "#35045" +msgid "Mark other subtitle as last to sync with" +msgstr "Anderen Untertitel als den Letzten für den Sync markieren" + +msgctxt "#35046" +msgid "Mark other subtitle as first to sync with" +msgstr "Anderen Untertitel als den Ersten für den Sync markieren" + +msgctxt "#35047" +msgid "Change start time" +msgstr "Startzeit ändern" + +msgctxt "#35048" +msgid "Change end Time" +msgstr "Endzeit ändern" + +msgctxt "#35049" +msgid "Skip backward 100 milliseconds" +msgstr "100 Millisekunden rückwärts springen" + +msgctxt "#35050" +msgid "Do you want: [CR]{}[CR]To appear at {}?" +msgstr "Soll[CR]{}[CR]bei {} erscheinen?" diff --git a/script.sublissimo/resources/language/resource.language.hr_hr/strings.po b/script.sublissimo/resources/language/resource.language.hr_hr/strings.po new file mode 100644 index 000000000..e8dd7c60b --- /dev/null +++ b/script.sublissimo/resources/language/resource.language.hr_hr/strings.po @@ -0,0 +1,938 @@ +# Kodi Media Center language file +# Addon Name: Sublissimo +# Addon id: script.sublissimo +# Addon Provider: AJVM +msgid "" +msgstr "" +"Project-Id-Version: XBMC Addons\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2023-01-14 11:15+0000\n" +"Last-Translator: gogogogi \n" +"Language-Team: Croatian \n" +"Language: hr_hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.15\n" + +msgctxt "Addon Summary" +msgid "Edit and synchronize subtitles with your remote" +msgstr "Uredite i uskladite podnaslove s vašim daljinskim" + +msgctxt "Addon Description" +msgid "With this script you can edit specific lines, move or stretch subtitles, and synchronize with other subtitles. You can also synchronize with a videofile.[CR][CR]To easily use this editor, launch it when the video and subtitle you wish to edit are playing." +msgstr "S ovom skriptom možete urediti određene retke, pomaknuti ili raširiti podnaslove, i uskladiti s ostalim podnaslovima. Možete još uskladiti i s video datotekom.[CR][CR]Za lakše korištenje ovog uređivača, pokrenite ga kada se video i podnaslov kojeg želite urediti reproduciraju." + +msgctxt "#31000" +msgid "Scroll subtitles" +msgstr "Pomiči podnaslove" + +msgctxt "#30001" +msgid "Edit or delete lines" +msgstr "Uredi ili obriši retke" + +msgctxt "#31002" +msgid "Move subtitles" +msgstr "Pomakni podnaslove" + +msgctxt "#31003" +msgid "Stretch/shrink subtitles" +msgstr "Rastegni/Skupi podnaslove" + +msgctxt "#31004" +msgid "Synchronize with other subtitle" +msgstr "Uskladi s drugim podnaslovom" + +msgctxt "#31005" +msgid "Synchronize with video file" +msgstr "Uskladi s video datotekom" + +msgctxt "#31006" +msgid "Search in subtitle" +msgstr "Pretraži u podnaslovu" + +msgctxt "#31007" +msgid "Check integrity" +msgstr "Provjeri integritet" + +msgctxt "#31008" +msgid "Save subtitles" +msgstr "Spremi podnaslov" + +msgctxt "#31009" +msgid "Quit" +msgstr "Zatvori" + +msgctxt "#31010" +msgid "Synchronize by frame rate" +msgstr "Uskladi po broju sličica u sekundi" + +msgctxt "#31011" +msgid "Play video with edited subtitle" +msgstr "Reproduciraj video s uređenim podnaslovom" + +msgctxt "#31013" +msgid "Advanced options" +msgstr "Napredne mogućnosti" + +msgctxt "#31001" +msgid "Sublissimo" +msgstr "Sublissimo" + +msgctxt "#33000" +msgid "" +"Select the subtitle to synchronize with. Then:[CR]- Select a timecode in the " +"beginning to a line as reference[CR]- Select the roughly the same line in " +"your subtitle[CR]- Then do same with two lines near the end of both files." +msgstr "Odaberite podnaslov za usklađivanje. Then:[CR]- Odaberite vrijeme na početku retka kao početnu točku[CR]- Odaberite otprilike isti redak u vašem podnaslovu[CR]- Tada učinite isto s dva retka blizu kraja obje datoteke." + +msgctxt "#32001" +msgid "Edit line" +msgstr "Uredi redak" + +msgctxt "#32002" +msgid "Delete First Subtitle" +msgstr "Obriši prvi podnaslov" + +msgctxt "#32003" +msgid "Delete Last Subtitle" +msgstr "Obriši posljednji podnaslov" + +msgctxt "#32004" +msgid "Manually Scroll and Delete" +msgstr "Ručno pomiči i obriši" + +msgctxt "#32005" +msgid "Back" +msgstr "Natrag" + +msgctxt "#32006" +msgid "Delete this subtitle?" +msgstr "Obriši ovaj podnaslov?" + +msgctxt "#32007" +msgid "Select subtitle to edit" +msgstr "Odaberi podnaslov za uređivanje" + +msgctxt "#32008" +msgid "Return" +msgstr "Povratak" + +msgctxt "#32009" +msgid "Delete" +msgstr "Obriši" + +msgctxt "#32010" +msgid "All subtitles" +msgstr "Svi podnaslovi" + +msgctxt "#32011" +msgid "Found:" +msgstr "Pronađeno:" + +msgctxt "#32012" +msgid "OK" +msgstr "U redu" + +msgctxt "#32013" +msgid "More Info" +msgstr "Više informacija" + +msgctxt "#32014" +msgid "Error" +msgstr "Greška" + +msgctxt "#32015" +msgid "Select subtitle to synchronize with" +msgstr "Odaberi podnaslov za usklađivanje" + +msgctxt "#32016" +msgid "Please select a .srt or a .sub file" +msgstr "Odaberite .srt ili a .sub datoteku" + +msgctxt "#32017" +msgid "Success" +msgstr "Uspješno" + +msgctxt "#32018" +msgid "Current first subtitle" +msgstr "Trenutno prvi podnaslov" + +msgctxt "#32019" +msgid "First subtitle is now:" +msgstr "Prvi podnaslov je sada:" + +msgctxt "#32020" +msgid "Please select a video file." +msgstr "Odaberite video datoteku." + +msgctxt "#32021" +msgid "Current last subtitle" +msgstr "Trenutni posljednji podnaslov" + +msgctxt "#32022" +msgid "Last subtitle is now:" +msgstr "Posljednji podnaslov je sada:" + +msgctxt "#32023" +msgid "Enter search string" +msgstr "Upišite zahtjev za pretragu" + +msgctxt "#32024" +msgid "Yes" +msgstr "Da" + +msgctxt "#32025" +msgid "No" +msgstr "Ne" + +msgctxt "#32026" +msgid "This editor only works with .srt or .sub files" +msgstr "Ovaj uređivač radi samo s .srt ili .sub datotekama" + +msgctxt "#32027" +msgid "File not found: " +msgstr "Datoteka nije pronađena: " + +msgctxt "#32028" +msgid "" +"Write the new timestamp for the end position, seperated by a ':'. For " +"instance: 01:22:23:000" +msgstr "Napišite novo vrijeme za završni položaj odvojenu ':'. Na primjer: 01:22:23:000" + +msgctxt "#32029" +msgid "For example: 01:22:23:000" +msgstr "Na primjer: 01:22:23:000" + +msgctxt "#32030" +msgid "Report" +msgstr "Prijavak" + +msgctxt "#32031" +msgid "No problems detected" +msgstr "Nema otkrivenih problema" + +msgctxt "#32032" +msgid "Line:" +msgstr "Redak:" + +msgctxt "#33032" +msgid "Line " +msgstr "Redak " + +msgctxt "#32033" +msgid "Possible problems: " +msgstr "Mogući problemi: " + +msgctxt "#32034" +msgid "Select subtitle to continue..." +msgstr "Odaberite podnaslov za nastavak..." + +msgctxt "#32035" +msgid "Select subtitle to edit" +msgstr "Odaberi podnaslov za uređivanje" + +msgctxt "#32036" +msgid "Your subtitle starts at " +msgstr "Vaš podnaslov započinje na " + +msgctxt "#32037" +msgid "Your subtitle ends at " +msgstr "Vaš podnaslov završava na " + +msgctxt "#32038" +msgid "Save with _edited.srt added" +msgstr "Spremi s _edited.srt dodatkom" + +msgctxt "#32039" +msgid "Save with current filename" +msgstr "Spremi s trenutnim nazivom datoteke" + +msgctxt "#32040" +msgid "Save with custom filename" +msgstr "Spremi s prilagođenim nazivom datoteke" + +msgctxt "#32041" +msgid "Exit without saving" +msgstr "Zatvori bez spremanja" + +msgctxt "#32042" +msgid "Give new filename: " +msgstr "Zadaj novi naziv datoteke: " + +msgctxt "#32043" +msgid "Written to: " +msgstr "Zapisano u: " + +msgctxt "#32044" +msgid "" +"To use the file, select it in the Kodi player subtitle menu when playing the " +"file" +msgstr "Za korištenje datoteke, odaberite u izborniku podnaslova Kodi reproduktora kada se reproducira datoteka" + +msgctxt "#32045" +msgid "File not written" +msgstr "Datoteka nije zapisana" + +msgctxt "#32046" +msgid "Warning" +msgstr "Upozorenje" + +msgctxt "#32047" +msgid "You might have unsaved progress on your file" +msgstr "Možda imate nespremljene promjene na vašoj datoteci" + +msgctxt "#32048" +msgid "Exit Anyway" +msgstr "Svejedno zatvori" + +msgctxt "#32049" +msgid "Save" +msgstr "Spremi" + +msgctxt "#32050" +msgid "Subtitles succesfully synced" +msgstr "Podnaslov je uspješno usklađen" + +msgctxt "#32051" +msgid "Move forwards" +msgstr "Pomakni naprijed" + +msgctxt "#32052" +msgid "Move backwards" +msgstr "Pomakni unatrag" + +msgctxt "#32053" +msgid "Give new time for first subtitle" +msgstr "Zadaj novo vrijeme za prvi podnaslov" + +msgctxt "#32054" +msgid "Move forwards by: HH:MM:SS:MSE" +msgstr "Pomakni unaprijed za: HH:MM:SS:MSE" + +msgctxt "#32055" +msgid "Move forwards by: HH:MM:SS:MSE" +msgstr "Pomakni unaprijed za: HH:MM:SS:MSE" + +msgctxt "#32056" +msgid "" +"Please enter valid timecode: HH:MM:SS:MSE. Hours, minutes, seconds, " +"milliseconds. For instance: 01:23:45:000" +msgstr "Upišite valjano vrijeme: HH:MM:SS:MSE. Sati, minute, sekunde, millisekunde. Na primjer: 01:23:45:000" + +msgctxt "#32057" +msgid "How to sync two subtitles" +msgstr "Kako uskladiti dva podnaslova" + +msgctxt "#32058" +msgid "" +"In order to synchronize, you will need a subtitle which matches the video " +"perfectly, but has different subtitles, usually from a different language. " +"In the next slide, first select this subtitle.[CR][CR]Then, you'll be asked " +"to select a timecode in this file, which will be used as reference. Ideally, " +"it is the first spoken line from the video. In the next screen, select the " +"line from your original subtitle which matches the first.[CR]" +"[CR]Subsequently, you'll be asked again to select a line from your reference " +"subtitle and to match this with the same line in your original subtitle. " +"Usually the best choice is the last spoken line from the video. After this " +"your two subtitles will sync![CR][CR]Check 'Scroll subtitles' to view them " +"and 'Save subtitles' to write them to a file." +msgstr "Kako bi uskladili podnaslov, potreban vam je podnaslov koji se perfektno poklapa s videom, ali ima drukčije podnaslove, uobičajeno je na drugom jeziku. Na sljedećem zaslonu, prvo odaberite ovaj podnaslov.[CR][CR]Tada ćete biti upitani da odaberete vrijeme u ovoj datoteci, koja će se koristiti kao početna točka. Idealno, to je prvi izgovoreni redak u videu. U sljedećem zaslonu, odaberite redak iz vašeg izvornog podnaslova koji se podudara s prvim.[CR][CR]Naknadno, ponovno ćete biti upitani da odaberete redak s vašeg početnog podnaslova i da ga podudarate s istim retkom u vašem izvornom podnaslovu. Uobičajeno najbolji odabir je posljednja izgovoreni redak u videu. Nakon ovog vaša dva podnaslova će se uskladiti![CR][CR]Provjerite 'Pomičite podnaslove' kako bi ih vidjeli i 'Spremite podnaslove' kako bi ih zapisali u datoteku." + +msgctxt "#32059" +msgid "File not found" +msgstr "Datoteka nije pronađena" + +msgctxt "#32060" +msgid "" +"In the next screen, select the video to synchronize with. Go to the point in " +"the video where the first subtitle starts. When you pause the video, choose " +"'Select as start' in the menu, then do the same with the last subtitle." +msgstr "U sljedećem zaslonu, odaberite video za usklađivanje. Idite na točku u videu gdje prvi podnaslov započinje. Kada pauzirate video, odaberite 'Odaberi kao početak' u izborniku, tada učinite isto s posljednjim podnaslovom." + +msgctxt "#32061" +msgid "How to sync with a video file" +msgstr "Kako uskladiti s video datotekom" + +msgctxt "#32062" +msgid "" +"In the next screen, open the videofile from the library which belongs to the " +"subtitle you have opened. Skip or fast forward to the point where the " +"subtitle should roughly be placed. Pause.[CR][CR]When you paused the video, " +"a menu will pop up with several options. Select 'View or edit first " +"subtitle'. When your first subtitle is not the first line from the video, " +"select 'Delete' until the first subtitle is also the first line from the " +"video.[CR][CR]Then finetune the position of the video, possibly by using the " +"'Skip forward 1 second' or 'Skip backward 1 second' buttons. If the position " +"is perfect, choose 'Select as start'.[CR]Now fast forward to the end of the " +"video, and repeat the same process.[CR][CR]After this, your file will be " +"synced to the video." +msgstr "U sljedećem zaslonu, otvorite video datoteku koja pripada podnaslovu koji ste otvorili. Premotajte gdje bi podnaslov otprilike trebao biti smješten. Pauzirajte.[CR][CR]Kada ste pauzirali video, pojavit će se izbornik s nekoliko mogućnosti. Odaberite 'Pogledaj ili uredi prvi podnaslov'. Kada vaš podnaslov nije prvi redak u videu, Odaberite 'Obriši' sve dok prvi podnaslov nije prvi redak iz videa.[CR][CR]Tada precizno prilagodite položaj videa, što je moguće korištenjem 'Premotaj unaprijed 1 sekundu' ili 'Premotaj unazad 1 sekundu' tipkama. Ako je položaj savršen, odaberite 'Odaberi kao početak'.[CR]Sada Brzo premotajte na kraj videa, i ponovite isti proces.[CR][CR]Nakon ovog, vaša datoteka će se uskladiti prema videu." + +msgctxt "#32063" +msgid "Select timecode of first subtitle to sync with" +msgstr "Odaberi vrijeme prvog podnaslova za usklađivanje" + +msgctxt "#32064" +msgid "Time selected" +msgstr "Vrijeme odabrano" + +msgctxt "#33064" +msgid "Time selected" +msgstr "Vrijeme odabrano" + +msgctxt "#32065" +msgid "Select timecode of subtitle which is roughly the same" +msgstr "Odaberi vrijeme podnaslova otprilike isto" + +msgctxt "#32066" +msgid "Select time of last subtitle to sync" +msgstr "Odaberi vrijeme posljednjeg podnaslova za usklađivanje" + +msgctxt "#32067" +msgid "Select time of last subtitle" +msgstr "Odaberi vrijeme posljednjeg podnaslova" + +msgctxt "#32068" +msgid "New timecode" +msgstr "Novo vrijeme" + +msgctxt "#32069" +msgid "" +"Write the new timestamp for the start position, seperated by a ':'. For " +"instance: 01:22:23:000" +msgstr "Zapiši novo vrijeme za početni položaj, odvojeno ':'. Na primjer: 01:22:23:000" + +msgctxt "#32070" +msgid "Subtitles moved forward by: {}" +msgstr "Podnaslovi su pomaknuti unaprijed za: {}" + +msgctxt "#32071" +msgid "Subtitles moved backward by {}" +msgstr "Podnaslovi su pomaknuti unatrag za {}" + +msgctxt "#32072" +msgid "First subtitle now starts at {}" +msgstr "Prvi podnaslov sada započinje na {}" + +msgctxt "#33072" +msgid "Last subtitle now starts at {}" +msgstr "Posljednji podnaslov sada započinje na {}" + +msgctxt "#32073" +msgid " Paused at: " +msgstr " Pauzirano na: " + +msgctxt "#32074" +msgid "Continue playing" +msgstr "Nastavi reprodukciju" + +msgctxt "#32075" +msgid "Select as start of first subtitle" +msgstr "Odaberi kao početak prvog podnaslova" + +msgctxt "#32076" +msgid "Skip backwards 1 second" +msgstr "Premotaj unatrag za 1 sekundu" + +msgctxt "#32077" +msgid "Skip forwards 1 second" +msgstr "Premotaj unaprijed za 1 sekundu" + +msgctxt "#32078" +msgid "Exit to Main Menu" +msgstr "Izađi u glavni izbornik" + +msgctxt "#32079" +msgid "View or delete first subtitle" +msgstr "Pogledaj ili obriši prvi podnaslov" + +msgctxt "#32080" +msgid "View or delete last subtitle" +msgstr "Pogledaj ili obriši posljednji podnaslov" + +msgctxt "#32081" +msgid "Select as start of last subtitle" +msgstr "Odaberi kao početak posljednjeg podnaslova" + +msgctxt "#32082" +msgid "Set as first subtitle?" +msgstr "Postavi kao prvi podnaslov?" + +msgctxt "#32083" +msgid "Do you want your subtitle to start at: " +msgstr "Želite li da vaš podnaslov započne na: " + +msgctxt "#32084" +msgid "Reset start time" +msgstr "Poništi početno vrijeme" + +msgctxt "#32085" +msgid "Selected start: " +msgstr "Odaberi početak: " + +msgctxt "#32086" +msgid "Selected times:" +msgstr "Odaberi vremena:" + +msgctxt "#32087" +msgid "Your first subtitle starts at: " +msgstr "Vaš prvi podnaslov započinje na: " + +msgctxt "#32088" +msgid "Your last subtitle starts at: " +msgstr "Vaš posljednji podnaslov započinje na: " + +msgctxt "#32089" +msgid "Select" +msgstr "Odaberi" + +msgctxt "#32090" +msgid "Reset times" +msgstr "Poništi vremena" + +msgctxt "#33065" +msgid "Time selected" +msgstr "Vrijeme odabrano" + +msgctxt "#32091" +msgid "Select a line with a timecode" +msgstr "Odaberi redak s vremenom" + +msgctxt "#32092" +msgid "" +"Please select a line with a timecode, like:[CR]'01:23:45,679 --> " +"01:23:45,679'" +msgstr "Odaberite redak s vremenom, poput:[CR]'01:23:45,679 --> 01:23:45,679'" + +msgctxt "#32093" +msgid "Choose movie" +msgstr "Odaberi film" + +msgctxt "#32094" +msgid "Choose TV Show" +msgstr "Odaberi TV seriju" + +msgctxt "#32095" +msgid "View entire library" +msgstr "Pogledaj cijelu videoteku" + +msgctxt "#32096" +msgid "Exit to main menu with changes" +msgstr "Izađi u glavni izbornik s promjenama" + +msgctxt "#32097" +msgid "Save the shown subtitle" +msgstr "Spremi prikazani podnaslov" + +msgctxt "#32098" +msgid "Exit to main menu w/o changes" +msgstr "Izađi u glavni izbornik s zapisanom/izlaznim promjenama" + +msgctxt "#32099" +msgid "Exit completely" +msgstr "Izađi u potpunosti" + +msgctxt "#32100" +msgid "Reset to another framerate" +msgstr "Vrati na drugu sličicu" + +msgctxt "#32101" +msgid "Save and Continue playing" +msgstr "Spremi i nastavi reprodukciju" + +msgctxt "#32102" +msgid "" +"The subtitle is loaded with the new framerate. Pause to reset to another " +"frame rate or to save." +msgstr "Podnaslov je učitan s novom brzinom sličica u sekundi. Pauziraj za vraćanje na drugu brzinu sličica u sekundi ili za spremanje." + +msgctxt "#32103" +msgid "Please enter a valid number" +msgstr "Upišite valjan broj" + +msgctxt "#32104" +msgid "Get frame rate from video" +msgstr "Dobij broj sličica iz videa" + +msgctxt "#32105" +msgid "Sync options by frame rate" +msgstr "Mogućnosti usklađivanja po broju sličica" + +msgctxt "#32106" +msgid "Frame rate" +msgstr "Broj sličica" + +msgctxt "#32107" +msgid "New ending time" +msgstr "Novo završno vrijeme" + +msgctxt "#32108" +msgid "Old starting time: " +msgstr "Novo početno vrijeme: " + +msgctxt "#34108" +msgid "Starting time: " +msgstr "Početno vrijeme: " + +msgctxt "#32109" +msgid "Old ending time: " +msgstr "Staro završno vrijeme: " + +msgctxt "#34110" +msgid "New starting time: " +msgstr "Novo početno vrijeme: " + +msgctxt "#32110" +msgid "New ending time: " +msgstr "Novo završno vrijeme: " + +msgctxt "#32111" +msgid "Save and Exit" +msgstr "Spremi i zatvori" + +msgctxt "#32112" +msgid "Calculate manually" +msgstr "Izračunaj ručno" + +msgctxt "#32113" +msgid "Provide sum or factor" +msgstr "Navedite zbroj ili faktor" + +msgctxt "#32114" +msgid "Calculate factor or provide factor" +msgstr "Izračunajte faktor ili navedite faktor" + +msgctxt "#32115" +msgid "" +"In the next screen, write a sum with the current framerate divided by the " +"real frame rate. If the current frame rate is 25 and it should be 24, type " +"'25/24'. Or type your own factor, like '1.2'" +msgstr "Na sljedećem zaslonu napišite zbroj s trenutnom brzinom sličica u sekundi podijeljenom sa stvarnom brzinom sličica u sekundi. Ako je trenutni broj sličica u sekundi 25, a trebao bi biti 24, upišite '25/24'. Ili upišite vlastiti faktor, poput '1,2'" + +msgctxt "#32116" +msgid "Play with the file you opened before" +msgstr "Reproducirajte s datotekom koju ste otvorili prije" + +msgctxt "#32117" +msgid "Provide factor" +msgstr "Navedi faktor" + +msgctxt "#32118" +msgid "Stretch by providing factor" +msgstr "Rastegni navođenjem faktora" + +msgctxt "#32119" +msgid "Stretch by giving new end time" +msgstr "Rastegni davanjem novog vremena završetka" + +msgctxt "#32120" +msgid "The frame rate of this video is " +msgstr "Broj sličica vremena je " + +msgctxt "#32121" +msgid "" +"The video is playing with the modified subtitle. Pause to save or to return " +"to the menu." +msgstr "Video se reproducira s promijenjenim podnaslovom. Pauzirajte za spremanje ili povratak u izbornik." + +msgctxt "#32122" +msgid "Subtitles loaded" +msgstr "Podnaslov učitan" + +msgctxt "#32123" +msgid "" +"The video is playing with the saved subtitle. The filename of the subtitle " +"is: " +msgstr "Video se reproducira sa spremljenim podnaslovom. Naziv podnaslova je: " + +msgctxt "#32124" +msgid "Jump to time of current first subtitle" +msgstr "Idi na vrijeme trenutno prvog podnaslova" + +msgctxt "#32125" +msgid "Jump to time of last subtitle" +msgstr "Idi na vrijeme trenutno posljednjeg podnaslova" + +msgctxt "#32126" +msgid "Choose another" +msgstr "Odaberi drugo" + +msgctxt "#32127" +msgid "Enter frame rate" +msgstr "Upišite broj sličica u sekundi" + +msgctxt "#32128" +msgid "Open other subtitle" +msgstr "Otvori drugi podnaslov" + +msgctxt "#32129" +msgid "Why do I see this screen?" +msgstr "Zašto vidim ovaj zaslon?" + +msgctxt "#32130" +msgid "You have selected a .sub file" +msgstr "Odabrali ste .sub datoteku" + +msgctxt "#32131" +msgid "" +"You have selected a .sub file, which uses frame rates to indicate when " +"subtitles should be shown. To edit these subtitles, you have to select a " +"frame rate. You can start a video to see what frame rate it has or just pick " +"a random one if you want to use a sync option." +msgstr "Odabrali ste .sub datoteku koja koristi broj sličica u sekundi za označavanje kada se podnaslovi trebaju prikazati. Za uređivanje ovih podnaslova morate odabrati broj sličica u sekundi. Možete započeti video kako bi vidjeli koji broj sličica u sekundi ima ili jednostavno odaberite naizmjenični ako želite koristiti mogućnost usklađivanja." + +msgctxt "#32132" +msgid "This file might not be a valid subtitle" +msgstr "Ova datoteka možda nije valjan podnaslov" + +msgctxt "#32133" +msgid "Load anyway" +msgstr "Svejedno učitaj" + +msgctxt "#32134" +msgid "Choose other" +msgstr "Odaberi drugi" + +msgctxt "#32135" +msgid "Not a valid .sub file" +msgstr "Nije valjana .sub datoteka" + +msgctxt "#32136" +msgid "This file does not appear to be a valid .sub file." +msgstr "Izgleda da ova datoteka nije valjana .sub datoteka." + +msgctxt "#32137" +msgid "All found HTML colorcodes reset to white." +msgstr "Svi pronađeni HTML kôdovi boje će biti vraćen u bijelu boju." + +msgctxt "#32138" +msgid "Reset color code to white" +msgstr "Vrati kôdove boja u bijelu boju" + +msgctxt "#32139" +msgid "Reset color to a custom color" +msgstr "Vrati boju u prilagođenu boju" + +msgctxt "#32140" +msgid "" +"Not a valid code for a color. Use 8 digits in a hexadecimal notation: " +"'FF00FF00'" +msgstr "Nije valjan kôd za boju. Koristite 8 znamenkasti heksadecimalni kôd: 'FF00FF00'" + +msgctxt "#32141" +msgid "Provide color coding. Use 8 digits. Leave empty to cancel" +msgstr "Omogućite kôdiranje boja. Koristite 8 znamenki. Ostavite prazno ili poništite" + +msgctxt "#32142" +msgid "All found HTML colorcodes reset to " +msgstr "Svi pronađeni HTML kôdovi boja su vraćeni na " + +msgctxt "#35000" +msgid "Cancel" +msgstr "Odustani" + +msgctxt "#35001" +msgid "Load subtitle" +msgstr "Učitaj podnaslov" + +msgctxt "#35002" +msgid "Manually" +msgstr "Ručno" + +msgctxt "#35003" +msgid "Do you want to edit this subtitle?" +msgstr "Želite li urediti ovaj podnaslov?" + +msgctxt "#35004" +msgid "Playback will stop, but can be resumed from the menu." +msgstr "Reprodukcija će se zaustaviti, ali se može nastaviti iz izbornika." + +msgctxt "#35005" +msgid "" +"A subtitlefile could not be found. Do you want to select one manually and " +"continue with current video?" +msgstr "Datoteka podnaslova se ne može pronaći. Želite li odabrati jednu ručno i nastaviti s trenutnim videom?" + +msgctxt "#35006" +msgid "Video:" +msgstr "Video:" + +msgctxt "#35007" +msgid "Subtitle:" +msgstr "Podnaslov:" + +msgctxt "#35008" +msgid "Play with " +msgstr "Reproduciraj s " + +msgctxt "#35009" +msgid "Edit and synchronize subtitles with your remote" +msgstr "Uredite i uskladite podnaslove s vašim daljinskim" + +msgctxt "#35010" +msgid "" +"With this script you can edit specific lines, move or stretch subtitles, and " +"synchronize with other subtitles. You can also synchronize with a videofile." +msgstr "S ovom skriptom možete uređivati određene retke, pomicati ili rastezati podnaslove i usklađivati ih s drugim podnaslovima. Možete usklađivati i s video datotekom." + +msgctxt "#35011" +msgid "Return to Menu" +msgstr "Povratak u izbornik" + +msgctxt "#35016" +msgid "" +"Somewhere in the process of syncing an error occurred. Most of the time this " +"is caused by:[CR] - A .srt file which uses non-standard timestamps.[CR] - A ." +"srt file which has a digit missing in one of its timestamps.[CR] - A file " +"which is not an actual .srt file[CR][CR]Use Main Menu -> Advanced Options -> " +"Check Integrity to scan for faulty timestamps or use a different .srt file." +msgstr "Negdje u procesu usklađivanja nastala je greška. Većinom je ovo uzrokovano:[CR] - .srt datoteka koja koristi nestandardne vremenske oznake.[CR] - .srt datoteka kojoj nedostaje brojka u jednoj vremenskoj oznaci.[CR] - Datoteka koja nije .srt datoteka[CR][CR]Koristite Glavni izbornik -> Napredne mogućnosti -> Provjeri integritet za pretragu pogrešnih vremenskih oznaka ili koristite drugu .srt datoteku." + +msgctxt "#35012" +msgid "The following error has occurred:" +msgstr "Dogodila se sljedeća greška:" + +msgctxt "#35013" +msgid "Details of Error" +msgstr "Pojedinosti greške" + +msgctxt "#35017" +msgid "Characterset not detected" +msgstr "Skup znakova nije otkriven" + +msgctxt "#35018" +msgid "" +"The correct characterset of this file could not be detected. The file is now " +"loading with the UTF-8 set and errors are replaced with questionmarks." +msgstr "Ispravan skup znakova ne može se otkriti. Datoteka se sada učitava u UTF-8 skupu i greške su zamijenjene upitnikom." + +msgctxt "#35019" +msgid "Select textline" +msgstr "Odaberite redak teksta" + +msgctxt "#35020" +msgid "Select time to sync to" +msgstr "Odaberi vrijeme za usklađivanje" + +msgctxt "#35021" +msgid "Shift forwards by microseconds" +msgstr "Pomakni unaprijed za mikrosekundu" + +msgctxt "#35022" +msgid "Shift backwards by microseconds" +msgstr "Pomakni unatrag za mikrosekundu" + +msgctxt "#35023" +msgid "Shift forwards by minutes" +msgstr "Pomakni unaprijed za minutu" + +msgctxt "#35024" +msgid "Shift backwards by minutes" +msgstr "Pomakni unatrag za minutu" + +msgctxt "#35025" +msgid "Select which subtitle to delete" +msgstr "Odaberi podnaslov za brisanje" + +msgctxt "#35026" +msgid "Minutes" +msgstr "Minuta" + +msgctxt "#35027" +msgid "Microseconds" +msgstr "Mikrosekundi" + +msgctxt "#35028" +msgid "See contents" +msgstr "Pogledaj sadržaj" + +msgctxt "#35029" +msgid "Open anyway" +msgstr "Svejedno otvori" + +msgctxt "#35030" +msgid "Unlikely to be a subtitle" +msgstr "Malo vjerojatno da je podnaslov" + +msgctxt "#35031" +msgid "This file is quite large and unlikely to be a subtitle" +msgstr "Ova datoteka je prilično velika i malo je vjerojatno da je podnaslov" + +msgctxt "#35032" +msgid "Could not load subtitle" +msgstr "Nemoguće učitavanje podnaslova" + +msgctxt "#35033" +msgid "Could not find any subtitles in the file. Is it a valid subtitle?" +msgstr "Nemoguć pronalazak podnaslova u datoteci. Je li valjan podnaslov?" + +msgctxt "#35034" +msgid "Scanning..." +msgstr "Pretraživanje..." + +msgctxt "#35035" +msgid "Checking which encoding to use for this file." +msgstr "Provjeravanje koje enkôdiranje koristiti za ovu datoteku." + +msgctxt "#35036" +msgid "This does not seem to be a valid .sub file." +msgstr "Čini se da ovo nije valjana .sub datoteka." + +msgctxt "#35037" +msgid "This does not seem to be a valid .srt file." +msgstr "Čini se da ovo nije valjana .srt datoteka." + +msgctxt "#35038" +msgid "Results" +msgstr "Rezultati" + +msgctxt "#35039" +msgid "The encoding is: " +msgstr "Ovo enkôdiranje je: " + +msgctxt "#35040" +msgid "The following lines were skipped:" +msgstr "Sljedeći retci su preskočeni:" + +msgctxt "#35041" +msgid "Repair manually" +msgstr "Popravi ručno" + +msgctxt "#35042" +msgid "Jump to Specific subtitle" +msgstr "Idi na određeni podnaslov" + +msgctxt "#35043" +msgid "View or delete subtitle that is marked as first" +msgstr "Pogledaj ili obriši podnaslov koji je označen kao prvi" + +msgctxt "#35044" +msgid "View or delete subtitle that is marked as last" +msgstr "Pogledaj ili obriši podnaslov koji je označen kao posljednji" + +msgctxt "#35045" +msgid "Mark other subtitle as last to sync with" +msgstr "Označi drugi podnaslov kao posljednji za usklađivanje" + +msgctxt "#35046" +msgid "Mark other subtitle as first to sync with" +msgstr "Označi drugi podnaslov kao prvi za usklađivanje" + +msgctxt "#35047" +msgid "Change start time" +msgstr "Promijeni početno vrijeme" + +msgctxt "#35048" +msgid "Change end Time" +msgstr "Promijeni završno vrijeme" + +msgctxt "#35049" +msgid "Skip backward 100 milliseconds" +msgstr "Preskoči unatrag za 100 milisekundi" + +msgctxt "#35050" +msgid "Do you want: [CR]{}[CR]To appear at {}?" +msgstr "Želite li: [CR]{}[CR]Da se pojavi na {}?" From fc4c312a431474fb6a8a58ebab4017bfd89aba56 Mon Sep 17 00:00:00 2001 From: Alexander <6258737+alxndr42@users.noreply.github.com> Date: Wed, 15 Feb 2023 13:25:41 +0100 Subject: [PATCH 010/145] [script.radioparadise] 1.0.5 (#2382) --- script.radioparadise/CHANGELOG.md | 4 ++++ script.radioparadise/README.md | 2 +- script.radioparadise/addon.xml | 2 +- script.radioparadise/radioparadise.py | 6 +++--- .../resources/language/resource.language.en_gb/strings.po | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/script.radioparadise/CHANGELOG.md b/script.radioparadise/CHANGELOG.md index 740cb1d24..5b4de981a 100644 --- a/script.radioparadise/CHANGELOG.md +++ b/script.radioparadise/CHANGELOG.md @@ -1,3 +1,7 @@ +## v1.0.5 + +- Rename World/Etc mix to Global + ## v1.0.4 - Update logos diff --git a/script.radioparadise/README.md b/script.radioparadise/README.md index 20ccdf93a..f786be560 100644 --- a/script.radioparadise/README.md +++ b/script.radioparadise/README.md @@ -32,7 +32,7 @@ Mix parameter: | 0 | RP Main Mix | | 1 | RP Mellow Mix | | 2 | RP Rock Mix | -| 3 | RP World/Etc Mix | +| 3 | RP Global Mix | This can be used to add shortcuts for RP mixes in [favourites.xml][]. diff --git a/script.radioparadise/addon.xml b/script.radioparadise/addon.xml index af7f2ad5e..66511805f 100644 --- a/script.radioparadise/addon.xml +++ b/script.radioparadise/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/script.radioparadise/radioparadise.py b/script.radioparadise/radioparadise.py index 1310c967d..2696231c5 100644 --- a/script.radioparadise/radioparadise.py +++ b/script.radioparadise/radioparadise.py @@ -36,9 +36,9 @@ }, { 'channel': 3, - 'title': 'RP World/Etc Mix', - 'url_aac': 'http://stream.radioparadise.com/world-etc-128', - 'url_flac': 'http://stream.radioparadise.com/world-etc-flacm', + 'title': 'RP Global Mix', + 'url_aac': 'http://stream.radioparadise.com/global-128', + 'url_flac': 'http://stream.radioparadise.com/global-flacm', }, ] STREAM_INFO = {s['url_aac']: s for s in STREAMS} diff --git a/script.radioparadise/resources/language/resource.language.en_gb/strings.po b/script.radioparadise/resources/language/resource.language.en_gb/strings.po index bdb0db3e1..ca9085e18 100644 --- a/script.radioparadise/resources/language/resource.language.en_gb/strings.po +++ b/script.radioparadise/resources/language/resource.language.en_gb/strings.po @@ -38,7 +38,7 @@ msgid "RP Rock Mix" msgstr "" msgctxt "#30206" -msgid "RP World/Etc Mix" +msgid "RP Global Mix" msgstr "" msgctxt "#30207" From 6c90c3c2af91dc42539a855999372f07c3e04bec Mon Sep 17 00:00:00 2001 From: anxdpanic Date: Mon, 13 Feb 2023 12:17:27 -0500 Subject: [PATCH 011/145] [script.skinshortcuts] v2.0.3 --- script.skinshortcuts/addon.xml | 17 +- .../resource.language.af_za/strings.po | 15 +- .../resource.language.ar_sa/strings.po | 239 ++++---- .../resource.language.be_by/strings.po | 12 +- .../resource.language.bg_bg/strings.po | 8 +- .../resource.language.bs_ba/strings.po | 10 +- .../resource.language.ca_es/strings.po | 17 +- .../resource.language.cy_gb/strings.po | 15 +- .../resource.language.de_de/strings.po | 30 +- .../resource.language.el_gr/strings.po | 10 +- .../resource.language.en_au/strings.po | 15 +- .../resource.language.en_nz/strings.po | 15 +- .../resource.language.en_us/strings.po | 15 +- .../resource.language.es_ar/strings.po | 10 +- .../resource.language.es_mx/strings.po | 20 +- .../resource.language.et_ee/strings.po | 18 +- .../resource.language.eu_es/strings.po | 10 +- .../resource.language.fa_ir/strings.po | 13 +- .../resource.language.fi_fi/strings.po | 200 +++---- .../resource.language.fo_fo/strings.po | 15 +- .../resource.language.fr_ca/strings.po | 10 +- .../resource.language.fr_fr/strings.po | 24 +- .../resource.language.gl_es/strings.po | 10 +- .../resource.language.he_il/strings.po | 8 +- .../resource.language.hi_in/strings.po | 13 +- .../resource.language.hr_hr/strings.po | 157 +++--- .../resource.language.id_id/strings.po | 13 +- .../resource.language.is_is/strings.po | 13 +- .../resource.language.it_it/strings.po | 20 +- .../resource.language.ja_jp/strings.po | 13 +- .../resource.language.lt_lt/strings.po | 13 +- .../resource.language.lv_lv/strings.po | 15 +- .../resource.language.mk_mk/strings.po | 10 +- .../resource.language.ms_my/strings.po | 13 +- .../resource.language.mt_mt/strings.po | 15 +- .../resource.language.nb_no/strings.po | 10 +- .../resource.language.nl_nl/strings.po | 10 +- .../resource.language.pl_pl/strings.po | 10 +- .../resource.language.pt_br/strings.po | 10 +- .../resource.language.pt_pt/strings.po | 13 +- .../resource.language.ro_md/strings.po | 517 ------------------ .../resource.language.ro_ro/strings.po | 15 +- .../language/resource.language.scn/strings.po | 517 ------------------ .../resource.language.sk_sk/strings.po | 8 +- .../resource.language.sl_si/strings.po | 15 +- .../resource.language.sq_al/strings.po | 10 +- .../resource.language.sr_rs/strings.po | 10 +- .../resource.language.sr_rs@latin/strings.po | 10 +- .../resource.language.sv_se/strings.po | 12 +- .../resource.language.ta_in/strings.po | 15 +- .../resource.language.th_th/strings.po | 11 +- .../resource.language.tr_tr/strings.po | 37 +- .../resource.language.uk_ua/strings.po | 15 +- .../resource.language.vi_vn/strings.po | 13 +- .../resource.language.zh_tw/strings.po | 13 +- .../lib/skinshorcuts/datafunctions.py | 4 +- .../resources/lib/skinshorcuts/gui.py | 2 +- .../resources/lib/skinshorcuts/library.py | 8 +- .../lib/skinshorcuts/nodefunctions.py | 6 +- .../lib/skinshorcuts/xmlfunctions.py | 16 +- .../resources/shortcuts/livetv.DATA.xml | 4 +- 61 files changed, 683 insertions(+), 1679 deletions(-) delete mode 100644 script.skinshortcuts/resources/language/resource.language.ro_md/strings.po delete mode 100644 script.skinshortcuts/resources/language/resource.language.scn/strings.po diff --git a/script.skinshortcuts/addon.xml b/script.skinshortcuts/addon.xml index 51ee5638b..ba741944d 100644 --- a/script.skinshortcuts/addon.xml +++ b/script.skinshortcuts/addon.xml @@ -1,5 +1,5 @@ - + @@ -8,9 +8,9 @@ -[fix] some widgets not working |contrib: bumpaneer| -[fix] new widget properties not being properly saved and applied |contrib: bumpaneer| -[fix] fix configuration of widgets/actions on some skins |contrib: eXoterr| +[fix] translations in PVR |contrib: Dis90| +[fix] titles missing in some dialogs +[fix] handle missing profiles.xml gracefully (fixes Apple TV) [lang] update translations from Weblate all @@ -21,17 +21,20 @@ resources/media/icon.png resources/media/fanart.jpg + إضافة مخصصه للمظهر لتوفير إدارة بسيطة للودجيت "الأقسام" و الاختصارات على الشاشة (تتطلب دعم المظهر لها) Doplněk pro vzhledy poskytující jednoduchý management a seznamy uživatelských zkratek (vyžaduje podporu vzhledu) Add-on til skins der giver enkel styring og lister over brugergenveje (kræver skin-understøttelse) - Addon für Skins zum einfachen Bearbeiten und Auflisten von benutzerdefinierten Verknüpfungen (erfordert Skin-Unterstützung) + Addon für Skins zum einfachen Bearbeiten und Auflisten von benutzerdefinierten Verknüpfungen (erfordert Skinunterstützung) Πρόσθετο για κελύφη, το οποίο παρέχει έναν απλό τρόπο διαχείρισης και κατηγοριοποίησης των συντομεύσεων του χρήστη (πρέπει να υποστηρίζεται από το κέλυφος) Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support) Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support) Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support) Complemento para las pieles para proporcionar una gestión sencilla y lista de atajos de usuario (requiere que la piel lo soporte) - Lisäosa ulkoasuille joka tarjoaa helpon hallinnan ja käyttäjien pikakuvakkeiden luetteloimisen (vaatii tuen ulkoasulta) - Addiciel pour habillages qui fournit une gestion simple et un listage des raccourcis utilisateurs (exige la prise en charge de l'habillage) + Lisäosa, joka mahdollistaa ulkoasujen valikkokohteiden ja omien pikavalintojen lisäyksen ja niiden muokkauksen (vaatii tuen ulkoasulta) + Addiciel pour habillages qui fournit une gestion simple et un listage des raccourcis utilisateurs (exige la prise en charge de l'habillage) + Module complémentaire pour les skins pour fournir une gestion et une liste simples de raccourcis utilisateur (nécessite la prise en charge des skins) Complemento que fornece aos temas dunha xestión sinxela dos atallos dos usuarios (require soporte do tema) + Dodatak za presvlake koji omogućuje jednostavno upravljanje i prikaz prečaca korisnika (zahtijeva podršku presvlake) Felszín kiegészítő amely könnyen kezelhetővé és listázhatóvá teszi a felhasználói parancsikonokat (Felszín támogatás szükséges) Viðbót fyrir viðmót til að halda utan um flýtivísa og fá yfirlit yfir þá (þarfnast stuðnings frá viðmóti) Add-on per gli skin per consentire un facile gestione ed elenco delle scorciatoie utente (richiede che lo skin lo supporti) diff --git a/script.skinshortcuts/resources/language/resource.language.af_za/strings.po b/script.skinshortcuts/resources/language/resource.language.af_za/strings.po index d0b718203..36e1db346 100644 --- a/script.skinshortcuts/resources/language/resource.language.af_za/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.af_za/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Afrikaans\n" -"Language: af\n" +"PO-Revision-Date: 2022-03-01 17:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Afrikaans (South Africa) \n" +"Language: af_za\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.11\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Stel ontfout loghouding in staat" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.ar_sa/strings.po b/script.skinshortcuts/resources/language/resource.language.ar_sa/strings.po index 53063a055..12d8c696a 100644 --- a/script.skinshortcuts/resources/language/resource.language.ar_sa/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.ar_sa/strings.po @@ -1,20 +1,21 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Arabic\n" -"Language: ar\n" +"PO-Revision-Date: 2022-07-27 01:19+0000\n" +"Last-Translator: psp2111-ADSLGATE \n" +"Language-Team: Arabic (Saudi Arabia) \n" +"Language: ar_sa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" +"X-Generator: Weblate 4.13\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" -msgstr "" +msgstr "إضافة مخصصه للمظهر لتوفير إدارة بسيطة للودجيت \"الأقسام\" و الاختصارات على الشاشة (تتطلب دعم المظهر لها)" msgctxt "#32000" msgid "Add" @@ -26,47 +27,47 @@ msgstr "حذف" msgctxt "#32002" msgid "Move Up" -msgstr "" +msgstr "تحرك للأعلى" msgctxt "#32003" msgid "Move Down" -msgstr "" +msgstr "تحرك للأسفل" msgctxt "#32004" msgid "Video Playlist" -msgstr "" +msgstr "قائمة تشغيل الفيديو" msgctxt "#32005" msgid "Music Playlist" -msgstr "" +msgstr "قائمة تشغيل الموسيقى" msgctxt "#32006" msgid "Favourite" -msgstr "" +msgstr "المفضلة" msgctxt "#32007" msgid "Add-On" -msgstr "" +msgstr "الإضافات" msgctxt "#32008" msgid "Mixed Playlist" -msgstr "" +msgstr "قائمة تشغيل مختلطة" msgctxt "#32009" msgid "Program" -msgstr "" +msgstr "البرامج" msgctxt "#32010" msgid "Video Add-On" -msgstr "" +msgstr "إضافات الفيديو" msgctxt "#32011" msgid "Music Add-On" -msgstr "" +msgstr "إضافات الموسيقة" msgctxt "#32012" msgid "Picture Add-On" -msgstr "" +msgstr "إضافات الصور" msgctxt "#32013" msgid "" @@ -74,15 +75,15 @@ msgstr "" msgctxt "#32014" msgid "Videos" -msgstr "مقاطع مرئيه" +msgstr "مقاطع الفيديو" msgctxt "#32015" msgid "Movies" -msgstr "أفلام" +msgstr "الأفلام" msgctxt "#32016" msgid "TV Shows" -msgstr "" +msgstr "المسلسلات" msgctxt "#32017" msgid "Live TV" @@ -90,19 +91,19 @@ msgstr "تي في مباشر" msgctxt "#32018" msgid "Music Videos" -msgstr "" +msgstr "مقاطع الفيديو الموسيقية" msgctxt "#32019" msgid "Music" -msgstr "موسيقى" +msgstr "الموسيقى" msgctxt "#32020" msgid "Pictures" -msgstr "صور" +msgstr "الصور" msgctxt "#32021" msgid "Programs" -msgstr "برامج" +msgstr "البرامج" msgctxt "#32022" msgid "Live TV" @@ -110,71 +111,71 @@ msgstr "تي في مباشر" msgctxt "#32023" msgid "Timers" -msgstr "مؤقت" +msgstr "المؤقتات" msgctxt "#32024" msgid "Custom item" -msgstr "" +msgstr "عنصر مخصص" msgctxt "#32025" msgid "Set label" -msgstr "" +msgstr "تعيين التسمية" msgctxt "#32026" msgid "Set thumbnail" -msgstr "" +msgstr "تعيين الصورة المصغرة" msgctxt "#32027" msgid "Change action" -msgstr "" +msgstr "تغيير الإجراء" msgctxt "#32028" msgid "Restore menu items" -msgstr "" +msgstr "استعادة عناصر القائمة" msgctxt "#32029" msgid "Common" -msgstr "" +msgstr "الشائع" msgctxt "#32030" msgid "Video Library" -msgstr "" +msgstr "مكتبة الفيديو" msgctxt "#32031" msgid "Music Library" -msgstr "" +msgstr "مكتبة الموسيقى" msgctxt "#32032" msgid "Play DVD" -msgstr "" +msgstr "تشغيل القرص" msgctxt "#32033" msgid "Eject tray" -msgstr "" +msgstr "إخراج القرص" msgctxt "#32034" msgid "Common menu item" -msgstr "" +msgstr "عنصر قائمة شائع" msgctxt "#32035" msgid "Choose which items to display on the Main Menu" -msgstr "" +msgstr "اختر العناصر التي تريد عرضها في القائمة الرئيسية" msgctxt "#32036" msgid "Choose shortcuts for %s" -msgstr "" +msgstr "اختر اختصارات لـ%s" msgctxt "#32037" msgid "Reset all menu items" -msgstr "" +msgstr "إعادة تعيين كافة عناصر القائمة" msgctxt "#32038" msgid "Are you sure you want to reset all menu items back to default?" -msgstr "" +msgstr "هل أنت متأكد أنك تريد إعادة تعيين كافة عناصر القائمة إلى الوضع الافتراضي؟" msgctxt "#32039" msgid "Pick widget for %s" -msgstr "" +msgstr "اختر ودجيت \"قسم\" لـ%s" msgctxt "#32040" msgid "Playlist" @@ -182,7 +183,7 @@ msgstr "قائمة التشغيل" msgctxt "#32041" msgid "Action" -msgstr "" +msgstr "الإجراء" msgctxt "#32042" msgid "Unknown video node" @@ -190,31 +191,31 @@ msgstr "" msgctxt "#32043" msgid "Choose shortcut category" -msgstr "" +msgstr "اختر فئة الاختصار" msgctxt "#32044" msgid "Select widget" -msgstr "" +msgstr "اختر الودجيت \"القسم\"" msgctxt "#32045" msgid "Select background" -msgstr "" +msgstr "اختر الخلفية" msgctxt "#32046" msgid "Update video library" -msgstr "" +msgstr "تحديث مكتبة الفيديو" msgctxt "#32047" msgid "Update audio library" -msgstr "" +msgstr "تحديث مكتبة الصوت" msgctxt "#32048" msgid "Choose item for menu" -msgstr "" +msgstr "اختر عنصر لهذه القائمة" msgctxt "#32049" msgid "Building menu..." -msgstr "" +msgstr "جار ٍبناء القائمة..." msgctxt "#32050" msgid "Default" @@ -222,11 +223,11 @@ msgstr "الافتراضية" msgctxt "#32051" msgid "Single image" -msgstr "" +msgstr "صورة واحدة" msgctxt "#32052" msgid "Multi-image" -msgstr "" +msgstr "صور متعددة" msgctxt "#32053" msgid "None" @@ -234,31 +235,31 @@ msgstr "بلا" msgctxt "#32054" msgid "Kodi Command" -msgstr "" +msgstr "أوامر كودي" msgctxt "#32055" msgid "Clean video library" -msgstr "" +msgstr "تنظيف مكتبة الفيديو" msgctxt "#32056" msgid "Clean audio library" -msgstr "" +msgstr "تنظيف مكتبة الصوت" msgctxt "#32057" msgid "Kodi Commands" -msgstr "" +msgstr "أوامر كودي" msgctxt "#32058" msgid "Create menu item to here" -msgstr "" +msgstr "إنشاء عنصر القائمة هنا" msgctxt "#32059" msgid "Skin Playlist" -msgstr "" +msgstr "قائمة تشغيل المظهر" msgctxt "#32060" msgid "What do you want to do with the playlist?" -msgstr "" +msgstr "ماذا تريد أن تفعل بقائمة التشغيل؟" msgctxt "#32061" msgid "Display" @@ -270,31 +271,31 @@ msgstr "تشغيل" msgctxt "#32063" msgid "Getting directory listing..." -msgstr "" +msgstr "جار ٍ الحصول على قائمة الدليل..." msgctxt "#32064" msgid "No available items" -msgstr "" +msgstr "لا توجد عناصر متاحة" msgctxt "#32065" msgid "There are no available items to choose from for the category that you choose." -msgstr "" +msgstr "لا توجد عناصر متاحة للاختيار منها لهذه الفئة." msgctxt "#32066" msgid "Last TV channel" -msgstr "" +msgstr "آخر قناة تلفزيونية" msgctxt "#32067" msgid "Last radio channel" -msgstr "" +msgstr "آخر قناة إذاعية" msgctxt "#32068" msgid "Last channel" -msgstr "" +msgstr "آخر قناة" msgctxt "#32069" msgid "Video Source" -msgstr "" +msgstr "مصدر مقاطع الفيديو" msgctxt "#32070" msgid "UPnP" @@ -302,103 +303,103 @@ msgstr "UPnP" msgctxt "#32071" msgid "Customize Main Menu" -msgstr "" +msgstr "تخصيص القائمة الرئيسية" msgctxt "#32072" msgid "Customize Submenu" -msgstr "" +msgstr "تخصيص القائمة الفرعية" msgctxt "#32073" msgid "Music Source" -msgstr "" +msgstr "مصدر الموسيقى" msgctxt "#32074" msgid "Library Sources" -msgstr "" +msgstr "مصادر المكتبة" msgctxt "#32075" msgid "Sources" -msgstr "" +msgstr "المصادر" msgctxt "#32076" msgid "TV Channel" -msgstr "" +msgstr "قناة تلفزيونية" msgctxt "#32077" msgid "Radio Channel" -msgstr "" +msgstr "قناة الإذاعة" msgctxt "#32078" msgid "Display..." -msgstr "" +msgstr "عرض..." msgctxt "#32079" msgid "Files view" -msgstr "" +msgstr "عرض الملفات" msgctxt "#32080" msgid "Edit %s Submenu" -msgstr "" +msgstr "تحرير القائمة الفرعية لـ%s" msgctxt "#32081" msgid "Movies not in this source" -msgstr "" +msgstr "الأفلام غير متوفرة في هذا المصدر" msgctxt "#32082" msgid "TV Shows not in this source" -msgstr "" +msgstr "المسلسلات غير متوفرة في هذا المصدر" msgctxt "#32083" msgid "Music Videos not in this source" -msgstr "" +msgstr "مقاطع الفيديو الموسيقية غير متوفرة في هذا المصدر" msgctxt "#32084" msgid "Songs not in this source" -msgstr "" +msgstr "الأغاني غير متوفرة في هذا المصدر" msgctxt "#32085" msgid "Albums not in this source" -msgstr "" +msgstr "الألبومات غير متوفرة في هذا المصدر" msgctxt "#32086" msgid "Mixed content not in this source" -msgstr "" +msgstr "المحتوى المختلط غير متوفرة في هذا المصدر" msgctxt "#32087" msgid "Radio" -msgstr "إذاعة" +msgstr "الإذاعة" msgctxt "#32088" msgid "Channels" -msgstr "محطات" +msgstr "المحطات" msgctxt "#32089" msgid "Picture Source" -msgstr "" +msgstr "مصدر الصور" msgctxt "#32090" msgid "The item has been added to the menu" -msgstr "" +msgstr "تمت إضافة العنصر إلى القائمة" msgctxt "#32091" msgid "Unable to add item to the menu. Please check log for errors." -msgstr "" +msgstr "غير قادر على إضافة عنصر إلى القائمة. يرجى التحقق من السجل." msgctxt "#32092" msgid "Unable to build menu." -msgstr "" +msgstr "غير قادر على بناء القائمة." msgctxt "#32093" msgid "Upload debug log?" -msgstr "" +msgstr "رفع سجل الأخطاء؟" msgctxt "#32094" msgid "Install Kodi Log Uploader add-on to easily provide a debug log." -msgstr "" +msgstr "قم بتثبيت الإضافة Kodi Log Uploader لتوفير سجل تصحيح الأخطاء بسهولة." msgctxt "#32095" msgid "Choose default action for menu item" -msgstr "" +msgstr "اختر الإجراء الافتراضي لعنصر القائمة" msgctxt "#32096" msgid "Browse..." @@ -406,112 +407,112 @@ msgstr "استعراض..." msgctxt "#32097" msgid "Unable to save menu" -msgstr "" +msgstr "تعذر حفظ القائمة" msgctxt "#32098" msgid "Writing menu..." -msgstr "" +msgstr "جار ٍ كتابة القائمة..." msgctxt "#32099" msgid "Widget" -msgstr "" +msgstr "الودجيت \"القسم\"" msgctxt "#32100" msgid "Use as widget" -msgstr "" +msgstr "استخدامه كودجيت \"كقسم\"" msgctxt "#32101" msgid "Choose property" -msgstr "" +msgstr "اختر الميزة" msgctxt "#32102" msgid "Restore or reset?" -msgstr "" +msgstr "استعادة أو إعادة تعيين؟" msgctxt "#32103" msgid "Restore an original menu item" -msgstr "" +msgstr "استعادة عناصر القائمة للوضع الأصلي" msgctxt "#32104" msgid "Reset to skin defaults" -msgstr "" +msgstr "إعادة التعيين إلى الإعدادات الافتراضية للمظهر" msgctxt "#32105" msgid "There are no menu items to restore for this menu" -msgstr "" +msgstr "لا توجد عناصر قائمة من الأساس ليتم استعادتها" msgctxt "#32106" msgid "Install widget provider" -msgstr "" +msgstr "تثبيت موفر الودجيت" msgctxt "#32107" msgid "Enable default widgets" -msgstr "" +msgstr "تمكين الودجيت \"الأقسام\" الافتراضية" msgctxt "#32108" msgid "Party mode (music videos)" -msgstr "" +msgstr "وضع الحفلة (مقاطع فيديو موسيقية)" msgctxt "#32109" msgid "No menus from compatible skins found to import" -msgstr "" +msgstr "لم يتم العثور على قوائم من المظاهر المتوافقة ليتم استيرادها" msgctxt "#32110" msgid "Import menu from skin" -msgstr "" +msgstr "استيراد قائمة من مظهر اخر" msgctxt "#32111" msgid "Shared menu" -msgstr "" +msgstr "القوائم المشتركة" msgctxt "#32112" msgid "New item on the main menu" -msgstr "" +msgstr "عنصر جديد في القائمة الرئيسية" msgctxt "#32113" msgid "New item on the main menu (autofill submenu items)" -msgstr "" +msgstr "عنصر جديد في القائمة الرئيسية (مع الملء التلقائي لعناصر القائمة الفرعية)" msgctxt "#32114" msgid "Where should menu item be created" -msgstr "" +msgstr "أين يجب إنشاء عنصر القائمة هذه" msgctxt "#32115" msgid "Unable to get directory listings[CR][CR]See log for details" -msgstr "" +msgstr "تعذر الحصول على قوائم الدليل[CR][CR]انظر الى السجل للمزيد من التفاصيل" msgctxt "#32116" msgid "The skin you are using does not support adding items directly to the main menu" -msgstr "" +msgstr "لا يدعم المظهر الذي تستخدمه إضافة عناصر مباشرة إلى القائمة الرئيسية" msgctxt "#32117" msgid "Disable shortcut" -msgstr "" +msgstr "تعطيل الاختصار" msgctxt "#32118" msgid "Smart shortcuts" -msgstr "" +msgstr "اختصارات ذكية" msgctxt "#32119" msgid "Default widgets" -msgstr "" +msgstr "الودجيت \"الأقسام\" الافتراضية" msgctxt "#32120" msgid "Never hide PVR shortcuts" -msgstr "" +msgstr "لا تقم بإخفاء اختصارات الـPVR" msgctxt "#32121" msgid "Share menu between compatible skins" -msgstr "" +msgstr "مشاركة القائمة بين المظاهر المتوافقة" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "تمكين تسجيل الأخطاء" msgctxt "#32123" msgid "Games" -msgstr "" +msgstr "الألعاب" msgctxt "#32124" msgid "This addon is for skin developers, and requires skin support" -msgstr "" +msgstr "هذه الإضافة لمطوري المظاهر ، وتتطلب دعم المظهر لها" diff --git a/script.skinshortcuts/resources/language/resource.language.be_by/strings.po b/script.skinshortcuts/resources/language/resource.language.be_by/strings.po index da85cc606..ecebf71d2 100644 --- a/script.skinshortcuts/resources/language/resource.language.be_by/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.be_by/strings.po @@ -1,9 +1,9 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Belarusian \n" "Language: be_by\n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -23,7 +23,7 @@ msgstr "Add" msgctxt "#32001" msgid "Delete" -msgstr "Delete" +msgstr "Выдаліць" msgctxt "#32002" msgid "Move Up" @@ -231,7 +231,7 @@ msgstr "" msgctxt "#32053" msgid "None" -msgstr "None" +msgstr "Няма" msgctxt "#32054" msgid "Kodi Command" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Уключыць журнал адладкі" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.bg_bg/strings.po b/script.skinshortcuts/resources/language/resource.language.bg_bg/strings.po index ddc1c19ce..a12fcf9ee 100644 --- a/script.skinshortcuts/resources/language/resource.language.bg_bg/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.bg_bg/strings.po @@ -1,9 +1,9 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" +"PO-Revision-Date: 2022-03-01 17:13+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Bulgarian \n" "Language: bg_bg\n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Включи дебъг журнала" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.bs_ba/strings.po b/script.skinshortcuts/resources/language/resource.language.bs_ba/strings.po index 0976ff96d..8b89d8982 100644 --- a/script.skinshortcuts/resources/language/resource.language.bs_ba/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.bs_ba/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-01 17:13+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Bosnian (Bosnia and Herzegovina) \n" "Language: bs_ba\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Omogući bilježenje grešaka" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.ca_es/strings.po b/script.skinshortcuts/resources/language/resource.language.ca_es/strings.po index 52da490c6..6fec36b71 100644 --- a/script.skinshortcuts/resources/language/resource.language.ca_es/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.ca_es/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Catalan\n" -"Language: ca\n" +"PO-Revision-Date: 2022-08-15 22:34+0000\n" +"Last-Translator: Xean \n" +"Language-Team: Catalan (Spain) \n" +"Language: ca_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.13\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -242,7 +243,7 @@ msgstr "" msgctxt "#32056" msgid "Clean audio library" -msgstr "" +msgstr "Neteja la biblioteca d'àudio" msgctxt "#32057" msgid "Kodi Commands" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Habilita el registrament de depuració" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.cy_gb/strings.po b/script.skinshortcuts/resources/language/resource.language.cy_gb/strings.po index 876663d0e..b514596f5 100644 --- a/script.skinshortcuts/resources/language/resource.language.cy_gb/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.cy_gb/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Welsh\n" -"Language: cy\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Welsh (United Kingdom) \n" +"Language: cy_gb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -78,7 +79,7 @@ msgstr "Fideo" msgctxt "#32015" msgid "Movies" -msgstr "" +msgstr "Ffilmiau" msgctxt "#32016" msgid "TV Shows" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Galluogi cofnodi dadfygio" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.de_de/strings.po b/script.skinshortcuts/resources/language/resource.language.de_de/strings.po index f2dd1875b..754ab6b46 100644 --- a/script.skinshortcuts/resources/language/resource.language.de_de/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.de_de/strings.po @@ -3,19 +3,19 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-09-27 20:30+0000\n" -"Last-Translator: Chillbo \n" +"PO-Revision-Date: 2023-02-06 23:15+0000\n" +"Last-Translator: Demian \n" "Language-Team: German \n" "Language: de_de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" -msgstr "Addon für Skins zum einfachen Bearbeiten und Auflisten von benutzerdefinierten Verknüpfungen (erfordert Skin-Unterstützung)" +msgstr "Addon für Skins zum einfachen Bearbeiten und Auflisten von benutzerdefinierten Verknüpfungen (erfordert Skinunterstützung)" msgctxt "#32000" msgid "Add" @@ -259,7 +259,7 @@ msgstr "Skin-Wiedergabeliste" msgctxt "#32060" msgid "What do you want to do with the playlist?" -msgstr "Was soll mit Wiedergabeliste gemacht machen?" +msgstr "Was soll mit der Wiedergabeliste geschehen?" msgctxt "#32061" msgid "Display" @@ -283,7 +283,7 @@ msgstr "Es existieren keine zu passenden Einträge für diese Kategorie." msgctxt "#32066" msgid "Last TV channel" -msgstr "Letzter TV-Kanal" +msgstr "Letzter TV-Sender" msgctxt "#32067" msgid "Last radio channel" @@ -291,7 +291,7 @@ msgstr "Letzter Radiosender" msgctxt "#32068" msgid "Last channel" -msgstr "Letzter Kanal" +msgstr "Letzter Sender" msgctxt "#32069" msgid "Video Source" @@ -323,7 +323,7 @@ msgstr "Quellen" msgctxt "#32076" msgid "TV Channel" -msgstr "TV-Kanal" +msgstr "TV-Sender" msgctxt "#32077" msgid "Radio Channel" @@ -371,7 +371,7 @@ msgstr "Radio" msgctxt "#32088" msgid "Channels" -msgstr "Kanäle" +msgstr "Sender" msgctxt "#32089" msgid "Picture Source" @@ -427,7 +427,7 @@ msgstr "Eigenschaft auswählen" msgctxt "#32102" msgid "Restore or reset?" -msgstr "Wiederherstellen oder zurücksetzen ?" +msgstr "Wiederherstellen oder zurücksetzen?" msgctxt "#32103" msgid "Restore an original menu item" @@ -447,7 +447,7 @@ msgstr "Widget-Provider installieren" msgctxt "#32107" msgid "Enable default widgets" -msgstr "Standard-Widgets aktivieren" +msgstr "Standardwidgets aktivieren" msgctxt "#32108" msgid "Party mode (music videos)" @@ -483,7 +483,7 @@ msgstr "Verzeichniseinträge können nicht ermittelt werden[CR][CR]Protokoll fü msgctxt "#32116" msgid "The skin you are using does not support adding items directly to the main menu" -msgstr "Der verwendete Skin unterstützt nicht das Hinzufügen von Einträgen zum Hauptmenü" +msgstr "Der verwendete Skin unterstützt das Hinzufügen von Einträgen zum Hauptmenü nicht" msgctxt "#32117" msgid "Disable shortcut" @@ -495,11 +495,11 @@ msgstr "Smarte Lesezeichen" msgctxt "#32119" msgid "Default widgets" -msgstr "Standard-Widgets" +msgstr "Standardwidgets" msgctxt "#32120" msgid "Never hide PVR shortcuts" -msgstr "PVR-Lesezeichen niemals verstecken" +msgstr "PVR-Lesezeichen niemals ausblenden" msgctxt "#32121" msgid "Share menu between compatible skins" @@ -515,7 +515,7 @@ msgstr "Spiele" msgctxt "#32124" msgid "This addon is for skin developers, and requires skin support" -msgstr "Dieses Addon ist für Skin-Entwickler, und benötigt Skin-Unterstützung" +msgstr "Dieses Addon ist für Skinentwickler und benötigt Skinunterstützung" #~ msgctxt "#32024" #~ msgid "Custom shortcut" diff --git a/script.skinshortcuts/resources/language/resource.language.el_gr/strings.po b/script.skinshortcuts/resources/language/resource.language.el_gr/strings.po index efd2ccdfb..8bf9ded9f 100644 --- a/script.skinshortcuts/resources/language/resource.language.el_gr/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.el_gr/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Greek \n" "Language: el_gr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Καταγραφή σφαλμάτων" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.en_au/strings.po b/script.skinshortcuts/resources/language/resource.language.en_au/strings.po index 9d684e3fc..dd032e036 100644 --- a/script.skinshortcuts/resources/language/resource.language.en_au/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.en_au/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: English (Australia)\n" -"Language: en_AU\n" +"PO-Revision-Date: 2022-03-06 21:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: English (Australia) \n" +"Language: en_au\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Enable debug logging" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.en_nz/strings.po b/script.skinshortcuts/resources/language/resource.language.en_nz/strings.po index ccc4968b5..67c3f434a 100644 --- a/script.skinshortcuts/resources/language/resource.language.en_nz/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.en_nz/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: English (New Zealand)\n" -"Language: en_NZ\n" +"PO-Revision-Date: 2022-03-06 21:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: English (New Zealand) \n" +"Language: en_nz\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Enable debug logging" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.en_us/strings.po b/script.skinshortcuts/resources/language/resource.language.en_us/strings.po index 8d5b833d5..410939e3c 100644 --- a/script.skinshortcuts/resources/language/resource.language.en_us/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.en_us/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: English (US)\n" -"Language: en_US\n" +"PO-Revision-Date: 2022-03-11 02:27+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: English (United States) \n" +"Language: en_us\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Enable debug logging" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.es_ar/strings.po b/script.skinshortcuts/resources/language/resource.language.es_ar/strings.po index e9948d52b..03ee3e962 100644 --- a/script.skinshortcuts/resources/language/resource.language.es_ar/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.es_ar/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Spanish (Argentina) \n" "Language: es_ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Habilitar trazas de depuración" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.es_mx/strings.po b/script.skinshortcuts/resources/language/resource.language.es_mx/strings.po index ac68311d7..0fe000528 100644 --- a/script.skinshortcuts/resources/language/resource.language.es_mx/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.es_mx/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Spanish (Mexico) \n" "Language: es_mx\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -27,11 +27,11 @@ msgstr "Eliminar" msgctxt "#32002" msgid "Move Up" -msgstr "" +msgstr "Mover arriba" msgctxt "#32003" msgid "Move Down" -msgstr "" +msgstr "Mover abajo" msgctxt "#32004" msgid "Video Playlist" @@ -75,7 +75,7 @@ msgstr "" msgctxt "#32014" msgid "Videos" -msgstr "" +msgstr "Videos" msgctxt "#32015" msgid "Movies" @@ -91,7 +91,7 @@ msgstr "TV en Vivo" msgctxt "#32018" msgid "Music Videos" -msgstr "" +msgstr "Videoclips" msgctxt "#32019" msgid "Music" @@ -507,11 +507,11 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Activar registro de depuración" msgctxt "#32123" msgid "Games" -msgstr "" +msgstr "Juegos" msgctxt "#32124" msgid "This addon is for skin developers, and requires skin support" diff --git a/script.skinshortcuts/resources/language/resource.language.et_ee/strings.po b/script.skinshortcuts/resources/language/resource.language.et_ee/strings.po index 9059d008b..156c7db63 100644 --- a/script.skinshortcuts/resources/language/resource.language.et_ee/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.et_ee/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-11 02:27+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Estonian \n" "Language: et_ee\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -27,11 +27,11 @@ msgstr "Kustuta" msgctxt "#32002" msgid "Move Up" -msgstr "" +msgstr "Liigu üles" msgctxt "#32003" msgid "Move Down" -msgstr "" +msgstr "Liigu alla" msgctxt "#32004" msgid "Video Playlist" @@ -91,7 +91,7 @@ msgstr "" msgctxt "#32018" msgid "Music Videos" -msgstr "" +msgstr "Muusikavideod" msgctxt "#32019" msgid "Music" @@ -507,11 +507,11 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Luba silumise logimine" msgctxt "#32123" msgid "Games" -msgstr "" +msgstr "Mängud" msgctxt "#32124" msgid "This addon is for skin developers, and requires skin support" diff --git a/script.skinshortcuts/resources/language/resource.language.eu_es/strings.po b/script.skinshortcuts/resources/language/resource.language.eu_es/strings.po index 4ef9aa841..c755d4bd6 100644 --- a/script.skinshortcuts/resources/language/resource.language.eu_es/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.eu_es/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-01 17:13+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Basque (Spain) \n" "Language: eu_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Gaitu arazketa-erregistroa" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.fa_ir/strings.po b/script.skinshortcuts/resources/language/resource.language.fa_ir/strings.po index 7059bcc47..78585ccc7 100644 --- a/script.skinshortcuts/resources/language/resource.language.fa_ir/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.fa_ir/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Persian (Iran)\n" -"Language: fa_IR\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Persian (Iran) \n" +"Language: fa_ir\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "فعال‌کردن گزارش‌گیری اشکال‌زدایی" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.fi_fi/strings.po b/script.skinshortcuts/resources/language/resource.language.fi_fi/strings.po index 2e8e9f898..3f28f5903 100644 --- a/script.skinshortcuts/resources/language/resource.language.fi_fi/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.fi_fi/strings.po @@ -3,19 +3,19 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-11-29 19:13+0000\n" -"Last-Translator: G0mez82 \n" +"PO-Revision-Date: 2022-07-21 08:30+0000\n" +"Last-Translator: Oskari Lavinto \n" "Language-Team: Finnish \n" "Language: fi_fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.9.1\n" +"X-Generator: Weblate 4.13\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" -msgstr "Lisäosa ulkoasuille joka tarjoaa helpon hallinnan ja käyttäjien pikakuvakkeiden luetteloimisen (vaatii tuen ulkoasulta)" +msgstr "Lisäosa, joka mahdollistaa ulkoasujen valikkokohteiden ja omien pikavalintojen lisäyksen ja niiden muokkauksen (vaatii tuen ulkoasulta)" msgctxt "#32000" msgid "Add" @@ -27,11 +27,11 @@ msgstr "Poista" msgctxt "#32002" msgid "Move Up" -msgstr "Siirrä ylöspäin" +msgstr "Siirrä ylemmäs" msgctxt "#32003" msgid "Move Down" -msgstr "Siirrä alaspäin" +msgstr "Siirrä alemmas" msgctxt "#32004" msgid "Video Playlist" @@ -51,7 +51,7 @@ msgstr "Lisäosa" msgctxt "#32008" msgid "Mixed Playlist" -msgstr "Sekoitettu Toistolista" +msgstr "Sekalainen toistolista" msgctxt "#32009" msgid "Program" @@ -71,7 +71,7 @@ msgstr "Kuvalisäosa" msgctxt "#32013" msgid "" -msgstr "" +msgstr "" msgctxt "#32014" msgid "Videos" @@ -83,11 +83,11 @@ msgstr "Elokuvat" msgctxt "#32016" msgid "TV Shows" -msgstr "TV-Sarjat" +msgstr "Sarjat" msgctxt "#32017" msgid "Live TV" -msgstr "TV-lähetys" +msgstr "Televisio" msgctxt "#32018" msgid "Music Videos" @@ -107,7 +107,7 @@ msgstr "Ohjelmat" msgctxt "#32022" msgid "Live TV" -msgstr "TV-lähetys" +msgstr "Televisio" msgctxt "#32023" msgid "Timers" @@ -115,27 +115,27 @@ msgstr "Ajastukset" msgctxt "#32024" msgid "Custom item" -msgstr "Mukautettu kohde" +msgstr "Oma kohde" msgctxt "#32025" msgid "Set label" -msgstr "Aseta nimi" +msgstr "Syötä nimi" msgctxt "#32026" msgid "Set thumbnail" -msgstr "Aseta pienoiskuva" +msgstr "Valitse pienoiskuva" msgctxt "#32027" msgid "Change action" -msgstr "Muuta toimintoa" +msgstr "Vaihda toimintoa" msgctxt "#32028" msgid "Restore menu items" -msgstr "Palauta valikon kohdat" +msgstr "Palauta valikon kohteet" msgctxt "#32029" msgid "Common" -msgstr "Yleistä" +msgstr "Yleiset" msgctxt "#32030" msgid "Video Library" @@ -147,7 +147,7 @@ msgstr "Musiikkikirjasto" msgctxt "#32032" msgid "Play DVD" -msgstr "Toista DVD" +msgstr "Toista levy" msgctxt "#32033" msgid "Eject tray" @@ -155,27 +155,27 @@ msgstr "Poista levy" msgctxt "#32034" msgid "Common menu item" -msgstr "" +msgstr "Yleinen valikkokohde" msgctxt "#32035" msgid "Choose which items to display on the Main Menu" -msgstr "" +msgstr "Valitse päävalikossa näytettävät kohteet" msgctxt "#32036" msgid "Choose shortcuts for %s" -msgstr "" +msgstr "Valitse pikavalinnat kohteelle %s" msgctxt "#32037" msgid "Reset all menu items" -msgstr "" +msgstr "Palauta kaikki valikkokohteet" msgctxt "#32038" msgid "Are you sure you want to reset all menu items back to default?" -msgstr "" +msgstr "Haluatko varmasti palauttaa kaikki valikkokohteet oletuksiin?" msgctxt "#32039" msgid "Pick widget for %s" -msgstr "" +msgstr "Valitse widgetti kohteelle %s" msgctxt "#32040" msgid "Playlist" @@ -183,15 +183,15 @@ msgstr "Toistolista" msgctxt "#32041" msgid "Action" -msgstr "" +msgstr "Toiminto" msgctxt "#32042" msgid "Unknown video node" -msgstr "" +msgstr "Tuntematon videosolmu" msgctxt "#32043" msgid "Choose shortcut category" -msgstr "" +msgstr "Valitse pikavalinnan kategoria" msgctxt "#32044" msgid "Select widget" @@ -199,23 +199,23 @@ msgstr "Valitse widgetti" msgctxt "#32045" msgid "Select background" -msgstr "" +msgstr "Valitse tausta" msgctxt "#32046" msgid "Update video library" -msgstr "" +msgstr "Päivitä videokirjasto" msgctxt "#32047" msgid "Update audio library" -msgstr "" +msgstr "Päivitä äänikirjasto" msgctxt "#32048" msgid "Choose item for menu" -msgstr "" +msgstr "Valitse valikon kohde" msgctxt "#32049" msgid "Building menu..." -msgstr "" +msgstr "Rakennetaan valikkoa..." msgctxt "#32050" msgid "Default" @@ -227,43 +227,43 @@ msgstr "Yksittäinen kuva" msgctxt "#32052" msgid "Multi-image" -msgstr "" +msgstr "Monikuva" msgctxt "#32053" msgid "None" -msgstr "Pois" +msgstr "Ei mitään" msgctxt "#32054" msgid "Kodi Command" -msgstr "" +msgstr "Kodi-komento" msgctxt "#32055" msgid "Clean video library" -msgstr "" +msgstr "Siivoa videokirjasto" msgctxt "#32056" msgid "Clean audio library" -msgstr "" +msgstr "Siivoa äänikirjasto" msgctxt "#32057" msgid "Kodi Commands" -msgstr "" +msgstr "Kodi-komennot" msgctxt "#32058" msgid "Create menu item to here" -msgstr "" +msgstr "Luo valikkokohde tänne" msgctxt "#32059" msgid "Skin Playlist" -msgstr "" +msgstr "Ulkoasun toistolista" msgctxt "#32060" msgid "What do you want to do with the playlist?" -msgstr "" +msgstr "Mikä toiminto toistolistalle suoritetaan?" msgctxt "#32061" msgid "Display" -msgstr "Näyttö" +msgstr "Näytä" msgctxt "#32062" msgid "Play" @@ -271,31 +271,31 @@ msgstr "Toista" msgctxt "#32063" msgid "Getting directory listing..." -msgstr "" +msgstr "Noudetaan kansiolistausta..." msgctxt "#32064" msgid "No available items" -msgstr "" +msgstr "Ei kohteita" msgctxt "#32065" msgid "There are no available items to choose from for the category that you choose." -msgstr "" +msgstr "Valitussa kategoriassa ei ole valittavissa olevia kohteita." msgctxt "#32066" msgid "Last TV channel" -msgstr "" +msgstr "Edellinen televisiokanava" msgctxt "#32067" msgid "Last radio channel" -msgstr "" +msgstr "Edellinen radiokanava" msgctxt "#32068" msgid "Last channel" -msgstr "" +msgstr "Edellinen kanava" msgctxt "#32069" msgid "Video Source" -msgstr "" +msgstr "Videolähde" msgctxt "#32070" msgid "UPnP" @@ -303,67 +303,67 @@ msgstr "UPnP" msgctxt "#32071" msgid "Customize Main Menu" -msgstr "" +msgstr "Mukauta päävalikkoa" msgctxt "#32072" msgid "Customize Submenu" -msgstr "" +msgstr "Mukauta alivalikkoa" msgctxt "#32073" msgid "Music Source" -msgstr "" +msgstr "Musiikkilähde" msgctxt "#32074" msgid "Library Sources" -msgstr "" +msgstr "Kirjaston lähteet" msgctxt "#32075" msgid "Sources" -msgstr "" +msgstr "Lähteet" msgctxt "#32076" msgid "TV Channel" -msgstr "" +msgstr "Televisiokanava" msgctxt "#32077" msgid "Radio Channel" -msgstr "" +msgstr "Radiokanava" msgctxt "#32078" msgid "Display..." -msgstr "" +msgstr "Näyttö..." msgctxt "#32079" msgid "Files view" -msgstr "" +msgstr "Tiedostonäkymä" msgctxt "#32080" msgid "Edit %s Submenu" -msgstr "" +msgstr "Muokkaa valikon %s alivalikkoa" msgctxt "#32081" msgid "Movies not in this source" -msgstr "" +msgstr "Elokuvia ei ole tässä lähteessä" msgctxt "#32082" msgid "TV Shows not in this source" -msgstr "" +msgstr "Sarjoja ei ole tässä lähteessä" msgctxt "#32083" msgid "Music Videos not in this source" -msgstr "" +msgstr "Musiikkivideoita ei ole tässä lähteessä" msgctxt "#32084" msgid "Songs not in this source" -msgstr "" +msgstr "Kappaleita ei ole tässä lähteessä" msgctxt "#32085" msgid "Albums not in this source" -msgstr "" +msgstr "Albumeita ei ole tässä lähteessä" msgctxt "#32086" msgid "Mixed content not in this source" -msgstr "" +msgstr "Sekasisältöä ei ole tässä lähteessä" msgctxt "#32087" msgid "Radio" @@ -375,31 +375,31 @@ msgstr "Kanavat" msgctxt "#32089" msgid "Picture Source" -msgstr "" +msgstr "Kuvalähde" msgctxt "#32090" msgid "The item has been added to the menu" -msgstr "" +msgstr "Kohde lisättiin valikkoon" msgctxt "#32091" msgid "Unable to add item to the menu. Please check log for errors." -msgstr "" +msgstr "Kohdetta ei voitu lisätä valikkoon. Lokitiedostosta näet lisätietoja." msgctxt "#32092" msgid "Unable to build menu." -msgstr "" +msgstr "Valikkoa ei voitu rakentaa." msgctxt "#32093" msgid "Upload debug log?" -msgstr "" +msgstr "Lähetetäänkö vianselvitysloki?" msgctxt "#32094" msgid "Install Kodi Log Uploader add-on to easily provide a debug log." -msgstr "" +msgstr "Asenna Kodi Log Uploader -lisäosa vianselvityslokin helppoa lähetystä varten." msgctxt "#32095" msgid "Choose default action for menu item" -msgstr "" +msgstr "Valitse valikkokohteen oletustoiminto" msgctxt "#32096" msgid "Browse..." @@ -407,112 +407,112 @@ msgstr "Selaa..." msgctxt "#32097" msgid "Unable to save menu" -msgstr "" +msgstr "Valikkoa ei voitu tallentaa" msgctxt "#32098" msgid "Writing menu..." -msgstr "" +msgstr "Tallennetaan valikkoa..." msgctxt "#32099" msgid "Widget" -msgstr "" +msgstr "Widgetti" msgctxt "#32100" msgid "Use as widget" -msgstr "" +msgstr "Käytä widgettinä" msgctxt "#32101" msgid "Choose property" -msgstr "" +msgstr "Valitse tietue" msgctxt "#32102" msgid "Restore or reset?" -msgstr "" +msgstr "Palautetaanko alkuperäinen vai oletus?" msgctxt "#32103" msgid "Restore an original menu item" -msgstr "" +msgstr "Palauta alkuperäinen valikkokohde" msgctxt "#32104" msgid "Reset to skin defaults" -msgstr "" +msgstr "Palauta ulkoasun oletus" msgctxt "#32105" msgid "There are no menu items to restore for this menu" -msgstr "" +msgstr "Tälle valikolle ei ole palautettavia valikkokohteita" msgctxt "#32106" msgid "Install widget provider" -msgstr "" +msgstr "Asenna widgettilähde" msgctxt "#32107" msgid "Enable default widgets" -msgstr "" +msgstr "Käytä oletuswidgettejä" msgctxt "#32108" msgid "Party mode (music videos)" -msgstr "" +msgstr "Jukeboksi (musiikkivideot)" msgctxt "#32109" msgid "No menus from compatible skins found to import" -msgstr "" +msgstr "Yhteensopivista ulkoasuista tuotavia valikoita ei löytynyt" msgctxt "#32110" msgid "Import menu from skin" -msgstr "" +msgstr "Tuo valikko ulkoasusta" msgctxt "#32111" msgid "Shared menu" -msgstr "" +msgstr "Jaettu valikko" msgctxt "#32112" msgid "New item on the main menu" -msgstr "" +msgstr "Uusi kohde päävalikossa" msgctxt "#32113" msgid "New item on the main menu (autofill submenu items)" -msgstr "" +msgstr "Uusi kohde päävalikossa (täytä alivalikon kohteet automaattisesti)" msgctxt "#32114" msgid "Where should menu item be created" -msgstr "" +msgstr "Mihin valikkokohde tulisi luoda" msgctxt "#32115" msgid "Unable to get directory listings[CR][CR]See log for details" -msgstr "" +msgstr "Kansiolistauksen nouto ei onnistunut[CR][CR]Lokitiedostosta näet lisätietoja" msgctxt "#32116" msgid "The skin you are using does not support adding items directly to the main menu" -msgstr "" +msgstr "Käytössä oleva ulkoasu ei tue kohteiden lisäystä suoraan päävalikkoon" msgctxt "#32117" msgid "Disable shortcut" -msgstr "" +msgstr "Poista pikavalinta käytöstä" msgctxt "#32118" msgid "Smart shortcuts" -msgstr "" +msgstr "Älykkäät pikavalinnat" msgctxt "#32119" msgid "Default widgets" -msgstr "" +msgstr "Oletuswidgetit" msgctxt "#32120" msgid "Never hide PVR shortcuts" -msgstr "" +msgstr "Älä koskaan piilota tallentimen pikavalintoja" msgctxt "#32121" msgid "Share menu between compatible skins" -msgstr "" +msgstr "Jaa valikko yhteensopivien ulkoasujen välillä" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Käytä vianselvityslokia" msgctxt "#32123" msgid "Games" -msgstr "" +msgstr "Pelit" msgctxt "#32124" msgid "This addon is for skin developers, and requires skin support" -msgstr "" +msgstr "Tämä lisäosa on ulkoasujen kehittäjille ja vaatii tuen ulkoasulta" diff --git a/script.skinshortcuts/resources/language/resource.language.fo_fo/strings.po b/script.skinshortcuts/resources/language/resource.language.fo_fo/strings.po index c7eba3ef8..9b2371a3a 100644 --- a/script.skinshortcuts/resources/language/resource.language.fo_fo/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.fo_fo/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Faroese\n" -"Language: fo\n" +"PO-Revision-Date: 2022-03-11 02:27+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Faroese \n" +"Language: fo_fo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Tendra skráseting av handlingum" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.fr_ca/strings.po b/script.skinshortcuts/resources/language/resource.language.fr_ca/strings.po index a6421131a..459d63a3f 100644 --- a/script.skinshortcuts/resources/language/resource.language.fr_ca/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.fr_ca/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-19 06:51+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: French (Canada) \n" "Language: fr_ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Activer la journalisation de débogage" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.fr_fr/strings.po b/script.skinshortcuts/resources/language/resource.language.fr_fr/strings.po index 5b9174df7..93d05265f 100644 --- a/script.skinshortcuts/resources/language/resource.language.fr_fr/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.fr_fr/strings.po @@ -2,21 +2,21 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: Christian Gade \n" +"PO-Revision-Date: 2023-01-25 16:15+0000\n" +"Last-Translator: skypichat \n" "Language-Team: French (France) \n" "Language: fr_fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" -msgstr "" +msgstr "Module complémentaire pour les skins pour fournir une gestion et une liste simples de raccourcis utilisateur (nécessite la prise en charge des skins)" msgctxt "#32000" msgid "Add" @@ -320,7 +320,7 @@ msgstr "Sources de la Médiathèque" msgctxt "#32075" msgid "Sources" -msgstr "" +msgstr "Sources" msgctxt "#32076" msgid "TV Channel" @@ -396,7 +396,7 @@ msgstr "Uploader le fichier de débogage ?" msgctxt "#32094" msgid "Install Kodi Log Uploader add-on to easily provide a debug log." -msgstr "Installez le module Kodi journal Uploader pour fournir facilement un journal de débogage." +msgstr "Installer le module complémentaire Kodi Log Uploader pour fournir facilement un journal de débogage." msgctxt "#32095" msgid "Choose default action for menu item" @@ -500,20 +500,20 @@ msgstr "Widgets par défaut" msgctxt "#32120" msgid "Never hide PVR shortcuts" -msgstr "" +msgstr "Ne pas cacher les raccourcis PVR" msgctxt "#32121" msgid "Share menu between compatible skins" -msgstr "" +msgstr "Partager le menu entre skins compatibles" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Activer la journalisation de débogage" msgctxt "#32123" msgid "Games" -msgstr "" +msgstr "Jeux" msgctxt "#32124" msgid "This addon is for skin developers, and requires skin support" -msgstr "" +msgstr "Cet addon est destiné aux développeurs de skins et nécessite un support skin" diff --git a/script.skinshortcuts/resources/language/resource.language.gl_es/strings.po b/script.skinshortcuts/resources/language/resource.language.gl_es/strings.po index c2bb71bc3..0d0fd78c1 100644 --- a/script.skinshortcuts/resources/language/resource.language.gl_es/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.gl_es/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Galician (Spain) \n" "Language: gl_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Activar rexistro de depuración" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.he_il/strings.po b/script.skinshortcuts/resources/language/resource.language.he_il/strings.po index 2a928dd83..38d02a835 100644 --- a/script.skinshortcuts/resources/language/resource.language.he_il/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.he_il/strings.po @@ -1,9 +1,9 @@ msgid "" msgstr "" "Project-Id-Version: script.skinshortcuts\n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Hebrew (Israel) \n" "Language: he_il\n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "הפעל יומן רישום מורחב" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.hi_in/strings.po b/script.skinshortcuts/resources/language/resource.language.hi_in/strings.po index a3a0e798f..80b045b23 100644 --- a/script.skinshortcuts/resources/language/resource.language.hi_in/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.hi_in/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Hindi (Devanagiri)\n" -"Language: hi\n" +"PO-Revision-Date: 2022-03-09 14:06+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Hindi (India) \n" +"Language: hi_in\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "लॉगिंग डिबग सक्षम" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.hr_hr/strings.po b/script.skinshortcuts/resources/language/resource.language.hr_hr/strings.po index 3860da37c..da9b06933 100644 --- a/script.skinshortcuts/resources/language/resource.language.hr_hr/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.hr_hr/strings.po @@ -1,20 +1,21 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Croatian\n" -"Language: hr\n" +"PO-Revision-Date: 2023-01-11 15:15+0000\n" +"Last-Translator: gogogogi \n" +"Language-Team: Croatian \n" +"Language: hr_hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" -msgstr "" +msgstr "Dodatak za presvlake koji omogućuje jednostavno upravljanje i prikaz prečaca korisnika (zahtijeva podršku presvlake)" msgctxt "#32000" msgid "Add" @@ -74,7 +75,7 @@ msgstr "" msgctxt "#32014" msgid "Videos" -msgstr "Video snimke" +msgstr "Video" msgctxt "#32015" msgid "Movies" @@ -82,7 +83,7 @@ msgstr "Filmovi" msgctxt "#32016" msgid "TV Shows" -msgstr "TV emisije" +msgstr "TV serije" msgctxt "#32017" msgid "Live TV" @@ -114,7 +115,7 @@ msgstr "Zakazana snimanja" msgctxt "#32024" msgid "Custom item" -msgstr "" +msgstr "Prilagođena stavka" msgctxt "#32025" msgid "Set label" @@ -126,11 +127,11 @@ msgstr "Postavi minijaturu" msgctxt "#32027" msgid "Change action" -msgstr "Prilagođena radnja" +msgstr "Promijeni radnju" msgctxt "#32028" msgid "Restore menu items" -msgstr "" +msgstr "Vrati stavke izbornika" msgctxt "#32029" msgid "Common" @@ -154,7 +155,7 @@ msgstr "Izbaci optički pogon" msgctxt "#32034" msgid "Common menu item" -msgstr "" +msgstr "Uobičajena stavka izbornika" msgctxt "#32035" msgid "Choose which items to display on the Main Menu" @@ -166,11 +167,11 @@ msgstr "Odaberi prečac za %s" msgctxt "#32037" msgid "Reset all menu items" -msgstr "" +msgstr "Vrati izvorne sve stavke izbornika" msgctxt "#32038" msgid "Are you sure you want to reset all menu items back to default?" -msgstr "" +msgstr "Sigurno želite vratiti sve stavke izbornika na izvorno?" msgctxt "#32039" msgid "Pick widget for %s" @@ -202,15 +203,15 @@ msgstr "Odaberi pozadinu" msgctxt "#32046" msgid "Update video library" -msgstr "Ažuriraj videoteku" +msgstr "Nadopuni videoteku" msgctxt "#32047" msgid "Update audio library" -msgstr "Ažuriraj fonoteku" +msgstr "Nadopuni fonoteku" msgctxt "#32048" msgid "Choose item for menu" -msgstr "" +msgstr "Odaberi stavku za izbornik" msgctxt "#32049" msgid "Building menu..." @@ -250,7 +251,7 @@ msgstr "Kodi naredbe" msgctxt "#32058" msgid "Create menu item to here" -msgstr "" +msgstr "Stvori stavku izbornika do ovdje" msgctxt "#32059" msgid "Skin Playlist" @@ -258,7 +259,7 @@ msgstr "Popis izvođenja presvlake" msgctxt "#32060" msgid "What do you want to do with the playlist?" -msgstr "" +msgstr "Što želite učiniti s popisom izvođenja?" msgctxt "#32061" msgid "Display" @@ -270,31 +271,31 @@ msgstr "Reproduciraj" msgctxt "#32063" msgid "Getting directory listing..." -msgstr "" +msgstr "Dobivanje sadržaja direktorija..." msgctxt "#32064" msgid "No available items" -msgstr "" +msgstr "Nema dostupnih stavki" msgctxt "#32065" msgid "There are no available items to choose from for the category that you choose." -msgstr "" +msgstr "Nema dostupnih stavki za odabir iz kategorije po vašem izboru." msgctxt "#32066" msgid "Last TV channel" -msgstr "" +msgstr "Posljednji TV program" msgctxt "#32067" msgid "Last radio channel" -msgstr "" +msgstr "Posljednji radio program" msgctxt "#32068" msgid "Last channel" -msgstr "" +msgstr "Posljednji program" msgctxt "#32069" msgid "Video Source" -msgstr "" +msgstr "Video izvor" msgctxt "#32070" msgid "UPnP" @@ -302,67 +303,67 @@ msgstr "UPnP" msgctxt "#32071" msgid "Customize Main Menu" -msgstr "" +msgstr "Prilagodi glavni izbornik" msgctxt "#32072" msgid "Customize Submenu" -msgstr "" +msgstr "Prilagodi podizbornik" msgctxt "#32073" msgid "Music Source" -msgstr "" +msgstr "Glazbeni izvor" msgctxt "#32074" msgid "Library Sources" -msgstr "" +msgstr "Izvori zbirke" msgctxt "#32075" msgid "Sources" -msgstr "" +msgstr "Izvori" msgctxt "#32076" msgid "TV Channel" -msgstr "" +msgstr "TV programi" msgctxt "#32077" msgid "Radio Channel" -msgstr "" +msgstr "Radio programi" msgctxt "#32078" msgid "Display..." -msgstr "" +msgstr "Prikaz..." msgctxt "#32079" msgid "Files view" -msgstr "" +msgstr "Prikaz datoteka" msgctxt "#32080" msgid "Edit %s Submenu" -msgstr "" +msgstr "Uredi %s podizbornik" msgctxt "#32081" msgid "Movies not in this source" -msgstr "" +msgstr "Filmovi nisu u ovom izvoru" msgctxt "#32082" msgid "TV Shows not in this source" -msgstr "" +msgstr "Tv serije nisu u ovom izvoru" msgctxt "#32083" msgid "Music Videos not in this source" -msgstr "" +msgstr "Glazbeni spotovi nisu u ovom izvoru" msgctxt "#32084" msgid "Songs not in this source" -msgstr "" +msgstr "Pjesme nisu u ovom izvoru" msgctxt "#32085" msgid "Albums not in this source" -msgstr "" +msgstr "Albumi nisu u ovom izvoru" msgctxt "#32086" msgid "Mixed content not in this source" -msgstr "" +msgstr "Mješovit sadržaj nije u ovom izvoru" msgctxt "#32087" msgid "Radio" @@ -370,35 +371,35 @@ msgstr "Radio" msgctxt "#32088" msgid "Channels" -msgstr "Kanali" +msgstr "Programi" msgctxt "#32089" msgid "Picture Source" -msgstr "" +msgstr "Slikovni izvor" msgctxt "#32090" msgid "The item has been added to the menu" -msgstr "" +msgstr "Stavka je dodana u izbornik" msgctxt "#32091" msgid "Unable to add item to the menu. Please check log for errors." -msgstr "" +msgstr "Nemoguće dodavanje stavke u izbornik. Provjerite zapis za greške." msgctxt "#32092" msgid "Unable to build menu." -msgstr "" +msgstr "Nemoguća izgradnja izbornika." msgctxt "#32093" msgid "Upload debug log?" -msgstr "" +msgstr "Pošalji zapise otklanjanja grešaka?" msgctxt "#32094" msgid "Install Kodi Log Uploader add-on to easily provide a debug log." -msgstr "" +msgstr "Instaliraj dodatak pošiljatelja Kodi zapisa za lakše pružanje zapisa otklanjanja grešaka." msgctxt "#32095" msgid "Choose default action for menu item" -msgstr "" +msgstr "Odaberi zadanu radnju za stavku izbornika" msgctxt "#32096" msgid "Browse..." @@ -406,115 +407,115 @@ msgstr "Pregledaj..." msgctxt "#32097" msgid "Unable to save menu" -msgstr "" +msgstr "Nemoguće spremanje izbornika" msgctxt "#32098" msgid "Writing menu..." -msgstr "" +msgstr "Zapisivanje izbornika..." msgctxt "#32099" msgid "Widget" -msgstr "" +msgstr "Widget" msgctxt "#32100" msgid "Use as widget" -msgstr "" +msgstr "Koristi kao widget" msgctxt "#32101" msgid "Choose property" -msgstr "" +msgstr "Odaberi svojstvo" msgctxt "#32102" msgid "Restore or reset?" -msgstr "" +msgstr "Obnovi ili vrati izvorno?" msgctxt "#32103" msgid "Restore an original menu item" -msgstr "" +msgstr "Obnovi izvornu stavku izbornika" msgctxt "#32104" msgid "Reset to skin defaults" -msgstr "" +msgstr "Vrati presvlaku na izvorno" msgctxt "#32105" msgid "There are no menu items to restore for this menu" -msgstr "" +msgstr "Ne postoje stavke izbornika za vraćanje ne izvorno ovog izbornika" msgctxt "#32106" msgid "Install widget provider" -msgstr "" +msgstr "Instalorajl widget pružatelja" msgctxt "#32107" msgid "Enable default widgets" -msgstr "" +msgstr "Omogući zadane widgete" msgctxt "#32108" msgid "Party mode (music videos)" -msgstr "" +msgstr "Party način (glazbeni spotovi)" msgctxt "#32109" msgid "No menus from compatible skins found to import" -msgstr "" +msgstr "Nema izbornika iz kompatibilnih presvlaka pronađenih za uvažanje" msgctxt "#32110" msgid "Import menu from skin" -msgstr "" +msgstr "Uvezi izbornik iz presvlake" msgctxt "#32111" msgid "Shared menu" -msgstr "" +msgstr "Dijeljeni izbornik" msgctxt "#32112" msgid "New item on the main menu" -msgstr "" +msgstr "Nova stavka na glavnom izborniku" msgctxt "#32113" msgid "New item on the main menu (autofill submenu items)" -msgstr "" +msgstr "Nova stavka na glavnom izborniku (automatski popuni podizbornike)" msgctxt "#32114" msgid "Where should menu item be created" -msgstr "" +msgstr "Gdje treba stavku izbornika stvoriti" msgctxt "#32115" msgid "Unable to get directory listings[CR][CR]See log for details" -msgstr "" +msgstr "Nemoguć prikaz sadržaja direktorija[CR][CR]Pogledajte zapis za pojedinosti" msgctxt "#32116" msgid "The skin you are using does not support adding items directly to the main menu" -msgstr "" +msgstr "Presvlaka koju koristite ne podržava dodavanje stavki izravno u glavni izbornik" msgctxt "#32117" msgid "Disable shortcut" -msgstr "" +msgstr "Onemogući prečac" msgctxt "#32118" msgid "Smart shortcuts" -msgstr "" +msgstr "Pametni prečaci" msgctxt "#32119" msgid "Default widgets" -msgstr "" +msgstr "Zadani widget" msgctxt "#32120" msgid "Never hide PVR shortcuts" -msgstr "" +msgstr "Nikada ne sakrivaj PVR prečace" msgctxt "#32121" msgid "Share menu between compatible skins" -msgstr "" +msgstr "Dijeli izbornik između kompatibilnih presvlaka" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Omogući zapisivanje otklanjanja grešaka" msgctxt "#32123" msgid "Games" -msgstr "" +msgstr "Igre" msgctxt "#32124" msgid "This addon is for skin developers, and requires skin support" -msgstr "" +msgstr "Ovaj dodatak je za razvijatelje presvlaka i zahtijeva podršku presvlake" #~ msgctxt "#32024" #~ msgid "Custom shortcut" diff --git a/script.skinshortcuts/resources/language/resource.language.id_id/strings.po b/script.skinshortcuts/resources/language/resource.language.id_id/strings.po index d0b9e45c7..f896b6258 100644 --- a/script.skinshortcuts/resources/language/resource.language.id_id/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.id_id/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Indonesian\n" -"Language: id\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Indonesian \n" +"Language: id_id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Mendeteksi Nilai HDD" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.is_is/strings.po b/script.skinshortcuts/resources/language/resource.language.is_is/strings.po index c51e3e21b..1082e01f3 100644 --- a/script.skinshortcuts/resources/language/resource.language.is_is/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.is_is/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Icelandic\n" -"Language: is\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Icelandic \n" +"Language: is_is\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Virkja villuskráningu" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.it_it/strings.po b/script.skinshortcuts/resources/language/resource.language.it_it/strings.po index 63279c3b0..58a8b4034 100644 --- a/script.skinshortcuts/resources/language/resource.language.it_it/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.it_it/strings.po @@ -3,15 +3,15 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-11-11 02:30+0000\n" -"Last-Translator: nixxo \n" +"PO-Revision-Date: 2022-10-07 06:15+0000\n" +"Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8.1\n" +"X-Generator: Weblate 4.14.1\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -35,7 +35,7 @@ msgstr "Sposta giù" msgctxt "#32004" msgid "Video Playlist" -msgstr "Playlist Video" +msgstr "Playlist video" msgctxt "#32005" msgid "Music Playlist" @@ -83,7 +83,7 @@ msgstr "Film" msgctxt "#32016" msgid "TV Shows" -msgstr "Serie TV" +msgstr "Programmi TV" msgctxt "#32017" msgid "Live TV" @@ -147,7 +147,7 @@ msgstr "Libreria Musicale" msgctxt "#32032" msgid "Play DVD" -msgstr "" +msgstr "Play DVD" msgctxt "#32033" msgid "Eject tray" @@ -251,7 +251,7 @@ msgstr "Comandi Kodi" msgctxt "#32058" msgid "Create menu item to here" -msgstr "" +msgstr "Crea voce di menu qui" msgctxt "#32059" msgid "Skin Playlist" @@ -267,7 +267,7 @@ msgstr "Schermo" msgctxt "#32062" msgid "Play" -msgstr "Guarda" +msgstr "Play" msgctxt "#32063" msgid "Getting directory listing..." @@ -391,7 +391,7 @@ msgstr "Impossibile construire il menù." msgctxt "#32093" msgid "Upload debug log?" -msgstr "Carica il log di debug?" +msgstr "Caricare il log di debug?" msgctxt "#32094" msgid "Install Kodi Log Uploader add-on to easily provide a debug log." @@ -507,7 +507,7 @@ msgstr "Condividi menù tra le skin compatibili" msgctxt "#32122" msgid "Enable debug logging" -msgstr "Abilita logging debug" +msgstr "Registra eventi di debug" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.ja_jp/strings.po b/script.skinshortcuts/resources/language/resource.language.ja_jp/strings.po index f37100704..5eedfd0ec 100644 --- a/script.skinshortcuts/resources/language/resource.language.ja_jp/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.ja_jp/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Japanese\n" -"Language: ja\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Japanese \n" +"Language: ja_jp\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "デバッグ ロギングを有効にする" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.lt_lt/strings.po b/script.skinshortcuts/resources/language/resource.language.lt_lt/strings.po index c3651d957..96c51e5e0 100644 --- a/script.skinshortcuts/resources/language/resource.language.lt_lt/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.lt_lt/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Lithuanian\n" -"Language: lt\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Lithuanian \n" +"Language: lt_lt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Įjungti derinimo žurnalą" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.lv_lv/strings.po b/script.skinshortcuts/resources/language/resource.language.lv_lv/strings.po index fed40035c..07fbb8388 100644 --- a/script.skinshortcuts/resources/language/resource.language.lv_lv/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.lv_lv/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Latvian\n" -"Language: lv\n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Latvian \n" +"Language: lv_lv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Ieslēgt atkļūdošanas reģistrēšanu" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.mk_mk/strings.po b/script.skinshortcuts/resources/language/resource.language.mk_mk/strings.po index ffb5ec913..eae869ec7 100644 --- a/script.skinshortcuts/resources/language/resource.language.mk_mk/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.mk_mk/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-27 01:17+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Macedonian \n" "Language: mk_mk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Овозможи логирање на грешки" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.ms_my/strings.po b/script.skinshortcuts/resources/language/resource.language.ms_my/strings.po index de4a013d7..d2f0a38d5 100644 --- a/script.skinshortcuts/resources/language/resource.language.ms_my/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.ms_my/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Malay\n" -"Language: ms\n" +"PO-Revision-Date: 2022-03-27 01:18+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Malay \n" +"Language: ms_my\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Benarkan pengelogan nyahpepijat" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.mt_mt/strings.po b/script.skinshortcuts/resources/language/resource.language.mt_mt/strings.po index b0bb91720..65f15e79f 100644 --- a/script.skinshortcuts/resources/language/resource.language.mt_mt/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.mt_mt/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Maltese\n" -"Language: mt\n" +"PO-Revision-Date: 2022-03-27 01:18+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Maltese \n" +"Language: mt_mt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Attiva d-debug logging" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.nb_no/strings.po b/script.skinshortcuts/resources/language/resource.language.nb_no/strings.po index f6e0c96ff..773de2d12 100644 --- a/script.skinshortcuts/resources/language/resource.language.nb_no/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.nb_no/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-27 01:18+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Norwegian Bokmål \n" "Language: nb_no\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Aktiver feilsøkingslogg" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.nl_nl/strings.po b/script.skinshortcuts/resources/language/resource.language.nl_nl/strings.po index f7205373c..eded8eed3 100644 --- a/script.skinshortcuts/resources/language/resource.language.nl_nl/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.nl_nl/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-11 02:27+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Dutch \n" "Language: nl_nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Activeer foutregistratie" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.pl_pl/strings.po b/script.skinshortcuts/resources/language/resource.language.pl_pl/strings.po index c945a98b4..5e54d5b47 100644 --- a/script.skinshortcuts/resources/language/resource.language.pl_pl/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.pl_pl/strings.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-09-05 13:30+0000\n" +"PO-Revision-Date: 2022-10-18 14:15+0000\n" "Last-Translator: Marek Adamski \n" "Language-Team: Polish \n" "Language: pl_pl\n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.14.1\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -127,7 +127,7 @@ msgstr "Ustaw miniaturę" msgctxt "#32027" msgid "Change action" -msgstr "Ustaw akcję" +msgstr "Zmień czynność" msgctxt "#32028" msgid "Restore menu items" @@ -183,7 +183,7 @@ msgstr "Lista odtwarzania" msgctxt "#32041" msgid "Action" -msgstr "Akcja" +msgstr "Czynność" msgctxt "#32042" msgid "Unknown video node" @@ -399,7 +399,7 @@ msgstr "Zainstaluj dodatek Kodi Log Uploader, aby łatwo dostarczać plik dzienn msgctxt "#32095" msgid "Choose default action for menu item" -msgstr "Wybierz domyślną akcję dla pozycji menu" +msgstr "Wybierz domyślną czynność dla pozycji menu" msgctxt "#32096" msgid "Browse..." diff --git a/script.skinshortcuts/resources/language/resource.language.pt_br/strings.po b/script.skinshortcuts/resources/language/resource.language.pt_br/strings.po index 4dbae9cb2..f92c46ee8 100644 --- a/script.skinshortcuts/resources/language/resource.language.pt_br/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.pt_br/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-30 09:46+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Portuguese (Brazil) \n" "Language: pt_br\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Habilitar registro de depuração" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.pt_pt/strings.po b/script.skinshortcuts/resources/language/resource.language.pt_pt/strings.po index 9db05110f..403b57fa4 100644 --- a/script.skinshortcuts/resources/language/resource.language.pt_pt/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.pt_pt/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Portuguese\n" -"Language: pt\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Portuguese (Portugal) \n" +"Language: pt_pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Ativar registo de depuração" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.ro_md/strings.po b/script.skinshortcuts/resources/language/resource.language.ro_md/strings.po deleted file mode 100644 index e3ebcd88b..000000000 --- a/script.skinshortcuts/resources/language/resource.language.ro_md/strings.po +++ /dev/null @@ -1,517 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" -"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: ro_md\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n == 1) ? 0 : ((n == 0 || n % 100 >= 2 && n % 100 <= 19) ? 1 : 2);\n" - -msgctxt "Addon Description" -msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" -msgstr "" - -msgctxt "#32000" -msgid "Add" -msgstr "" - -msgctxt "#32001" -msgid "Delete" -msgstr "" - -msgctxt "#32002" -msgid "Move Up" -msgstr "" - -msgctxt "#32003" -msgid "Move Down" -msgstr "" - -msgctxt "#32004" -msgid "Video Playlist" -msgstr "" - -msgctxt "#32005" -msgid "Music Playlist" -msgstr "" - -msgctxt "#32006" -msgid "Favourite" -msgstr "" - -msgctxt "#32007" -msgid "Add-On" -msgstr "" - -msgctxt "#32008" -msgid "Mixed Playlist" -msgstr "" - -msgctxt "#32009" -msgid "Program" -msgstr "" - -msgctxt "#32010" -msgid "Video Add-On" -msgstr "" - -msgctxt "#32011" -msgid "Music Add-On" -msgstr "" - -msgctxt "#32012" -msgid "Picture Add-On" -msgstr "" - -msgctxt "#32013" -msgid "" -msgstr "" - -msgctxt "#32014" -msgid "Videos" -msgstr "" - -msgctxt "#32015" -msgid "Movies" -msgstr "" - -msgctxt "#32016" -msgid "TV Shows" -msgstr "" - -msgctxt "#32017" -msgid "Live TV" -msgstr "" - -msgctxt "#32018" -msgid "Music Videos" -msgstr "" - -msgctxt "#32019" -msgid "Music" -msgstr "" - -msgctxt "#32020" -msgid "Pictures" -msgstr "" - -msgctxt "#32021" -msgid "Programs" -msgstr "" - -msgctxt "#32022" -msgid "Live TV" -msgstr "" - -msgctxt "#32023" -msgid "Timers" -msgstr "" - -msgctxt "#32024" -msgid "Custom item" -msgstr "" - -msgctxt "#32025" -msgid "Set label" -msgstr "" - -msgctxt "#32026" -msgid "Set thumbnail" -msgstr "" - -msgctxt "#32027" -msgid "Change action" -msgstr "" - -msgctxt "#32028" -msgid "Restore menu items" -msgstr "" - -msgctxt "#32029" -msgid "Common" -msgstr "" - -msgctxt "#32030" -msgid "Video Library" -msgstr "" - -msgctxt "#32031" -msgid "Music Library" -msgstr "" - -msgctxt "#32032" -msgid "Play DVD" -msgstr "" - -msgctxt "#32033" -msgid "Eject tray" -msgstr "" - -msgctxt "#32034" -msgid "Common menu item" -msgstr "" - -msgctxt "#32035" -msgid "Choose which items to display on the Main Menu" -msgstr "" - -msgctxt "#32036" -msgid "Choose shortcuts for %s" -msgstr "" - -msgctxt "#32037" -msgid "Reset all menu items" -msgstr "" - -msgctxt "#32038" -msgid "Are you sure you want to reset all menu items back to default?" -msgstr "" - -msgctxt "#32039" -msgid "Pick widget for %s" -msgstr "" - -msgctxt "#32040" -msgid "Playlist" -msgstr "" - -msgctxt "#32041" -msgid "Action" -msgstr "" - -msgctxt "#32042" -msgid "Unknown video node" -msgstr "" - -msgctxt "#32043" -msgid "Choose shortcut category" -msgstr "" - -msgctxt "#32044" -msgid "Select widget" -msgstr "" - -msgctxt "#32045" -msgid "Select background" -msgstr "" - -msgctxt "#32046" -msgid "Update video library" -msgstr "" - -msgctxt "#32047" -msgid "Update audio library" -msgstr "" - -msgctxt "#32048" -msgid "Choose item for menu" -msgstr "" - -msgctxt "#32049" -msgid "Building menu..." -msgstr "" - -msgctxt "#32050" -msgid "Default" -msgstr "" - -msgctxt "#32051" -msgid "Single image" -msgstr "" - -msgctxt "#32052" -msgid "Multi-image" -msgstr "" - -msgctxt "#32053" -msgid "None" -msgstr "" - -msgctxt "#32054" -msgid "Kodi Command" -msgstr "" - -msgctxt "#32055" -msgid "Clean video library" -msgstr "" - -msgctxt "#32056" -msgid "Clean audio library" -msgstr "" - -msgctxt "#32057" -msgid "Kodi Commands" -msgstr "" - -msgctxt "#32058" -msgid "Create menu item to here" -msgstr "" - -msgctxt "#32059" -msgid "Skin Playlist" -msgstr "" - -msgctxt "#32060" -msgid "What do you want to do with the playlist?" -msgstr "" - -msgctxt "#32061" -msgid "Display" -msgstr "" - -msgctxt "#32062" -msgid "Play" -msgstr "" - -msgctxt "#32063" -msgid "Getting directory listing..." -msgstr "" - -msgctxt "#32064" -msgid "No available items" -msgstr "" - -msgctxt "#32065" -msgid "There are no available items to choose from for the category that you choose." -msgstr "" - -msgctxt "#32066" -msgid "Last TV channel" -msgstr "" - -msgctxt "#32067" -msgid "Last radio channel" -msgstr "" - -msgctxt "#32068" -msgid "Last channel" -msgstr "" - -msgctxt "#32069" -msgid "Video Source" -msgstr "" - -msgctxt "#32070" -msgid "UPnP" -msgstr "" - -msgctxt "#32071" -msgid "Customize Main Menu" -msgstr "" - -msgctxt "#32072" -msgid "Customize Submenu" -msgstr "" - -msgctxt "#32073" -msgid "Music Source" -msgstr "" - -msgctxt "#32074" -msgid "Library Sources" -msgstr "" - -msgctxt "#32075" -msgid "Sources" -msgstr "" - -msgctxt "#32076" -msgid "TV Channel" -msgstr "" - -msgctxt "#32077" -msgid "Radio Channel" -msgstr "" - -msgctxt "#32078" -msgid "Display..." -msgstr "" - -msgctxt "#32079" -msgid "Files view" -msgstr "" - -msgctxt "#32080" -msgid "Edit %s Submenu" -msgstr "" - -msgctxt "#32081" -msgid "Movies not in this source" -msgstr "" - -msgctxt "#32082" -msgid "TV Shows not in this source" -msgstr "" - -msgctxt "#32083" -msgid "Music Videos not in this source" -msgstr "" - -msgctxt "#32084" -msgid "Songs not in this source" -msgstr "" - -msgctxt "#32085" -msgid "Albums not in this source" -msgstr "" - -msgctxt "#32086" -msgid "Mixed content not in this source" -msgstr "" - -msgctxt "#32087" -msgid "Radio" -msgstr "" - -msgctxt "#32088" -msgid "Channels" -msgstr "" - -msgctxt "#32089" -msgid "Picture Source" -msgstr "" - -msgctxt "#32090" -msgid "The item has been added to the menu" -msgstr "" - -msgctxt "#32091" -msgid "Unable to add item to the menu. Please check log for errors." -msgstr "" - -msgctxt "#32092" -msgid "Unable to build menu." -msgstr "" - -msgctxt "#32093" -msgid "Upload debug log?" -msgstr "" - -msgctxt "#32094" -msgid "Install Kodi Log Uploader add-on to easily provide a debug log." -msgstr "" - -msgctxt "#32095" -msgid "Choose default action for menu item" -msgstr "" - -msgctxt "#32096" -msgid "Browse..." -msgstr "" - -msgctxt "#32097" -msgid "Unable to save menu" -msgstr "" - -msgctxt "#32098" -msgid "Writing menu..." -msgstr "" - -msgctxt "#32099" -msgid "Widget" -msgstr "" - -msgctxt "#32100" -msgid "Use as widget" -msgstr "" - -msgctxt "#32101" -msgid "Choose property" -msgstr "" - -msgctxt "#32102" -msgid "Restore or reset?" -msgstr "" - -msgctxt "#32103" -msgid "Restore an original menu item" -msgstr "" - -msgctxt "#32104" -msgid "Reset to skin defaults" -msgstr "" - -msgctxt "#32105" -msgid "There are no menu items to restore for this menu" -msgstr "" - -msgctxt "#32106" -msgid "Install widget provider" -msgstr "" - -msgctxt "#32107" -msgid "Enable default widgets" -msgstr "" - -msgctxt "#32108" -msgid "Party mode (music videos)" -msgstr "" - -msgctxt "#32109" -msgid "No menus from compatible skins found to import" -msgstr "" - -msgctxt "#32110" -msgid "Import menu from skin" -msgstr "" - -msgctxt "#32111" -msgid "Shared menu" -msgstr "" - -msgctxt "#32112" -msgid "New item on the main menu" -msgstr "" - -msgctxt "#32113" -msgid "New item on the main menu (autofill submenu items)" -msgstr "" - -msgctxt "#32114" -msgid "Where should menu item be created" -msgstr "" - -msgctxt "#32115" -msgid "Unable to get directory listings[CR][CR]See log for details" -msgstr "" - -msgctxt "#32116" -msgid "The skin you are using does not support adding items directly to the main menu" -msgstr "" - -msgctxt "#32117" -msgid "Disable shortcut" -msgstr "" - -msgctxt "#32118" -msgid "Smart shortcuts" -msgstr "" - -msgctxt "#32119" -msgid "Default widgets" -msgstr "" - -msgctxt "#32120" -msgid "Never hide PVR shortcuts" -msgstr "" - -msgctxt "#32121" -msgid "Share menu between compatible skins" -msgstr "" - -msgctxt "#32122" -msgid "Enable debug logging" -msgstr "" - -msgctxt "#32123" -msgid "Games" -msgstr "" - -msgctxt "#32124" -msgid "This addon is for skin developers, and requires skin support" -msgstr "" diff --git a/script.skinshortcuts/resources/language/resource.language.ro_ro/strings.po b/script.skinshortcuts/resources/language/resource.language.ro_ro/strings.po index 24712f100..c7921d6c7 100644 --- a/script.skinshortcuts/resources/language/resource.language.ro_ro/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.ro_ro/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Romanian\n" -"Language: ro\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Romanian \n" +"Language: ro_ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Activează jurnalizare depanare" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.scn/strings.po b/script.skinshortcuts/resources/language/resource.language.scn/strings.po deleted file mode 100644 index 601e1df0e..000000000 --- a/script.skinshortcuts/resources/language/resource.language.scn/strings.po +++ /dev/null @@ -1,517 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" -"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: scn\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" - -msgctxt "Addon Description" -msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" -msgstr "" - -msgctxt "#32000" -msgid "Add" -msgstr "" - -msgctxt "#32001" -msgid "Delete" -msgstr "" - -msgctxt "#32002" -msgid "Move Up" -msgstr "" - -msgctxt "#32003" -msgid "Move Down" -msgstr "" - -msgctxt "#32004" -msgid "Video Playlist" -msgstr "" - -msgctxt "#32005" -msgid "Music Playlist" -msgstr "" - -msgctxt "#32006" -msgid "Favourite" -msgstr "" - -msgctxt "#32007" -msgid "Add-On" -msgstr "" - -msgctxt "#32008" -msgid "Mixed Playlist" -msgstr "" - -msgctxt "#32009" -msgid "Program" -msgstr "" - -msgctxt "#32010" -msgid "Video Add-On" -msgstr "" - -msgctxt "#32011" -msgid "Music Add-On" -msgstr "" - -msgctxt "#32012" -msgid "Picture Add-On" -msgstr "" - -msgctxt "#32013" -msgid "" -msgstr "" - -msgctxt "#32014" -msgid "Videos" -msgstr "" - -msgctxt "#32015" -msgid "Movies" -msgstr "" - -msgctxt "#32016" -msgid "TV Shows" -msgstr "" - -msgctxt "#32017" -msgid "Live TV" -msgstr "" - -msgctxt "#32018" -msgid "Music Videos" -msgstr "" - -msgctxt "#32019" -msgid "Music" -msgstr "" - -msgctxt "#32020" -msgid "Pictures" -msgstr "" - -msgctxt "#32021" -msgid "Programs" -msgstr "" - -msgctxt "#32022" -msgid "Live TV" -msgstr "" - -msgctxt "#32023" -msgid "Timers" -msgstr "" - -msgctxt "#32024" -msgid "Custom item" -msgstr "" - -msgctxt "#32025" -msgid "Set label" -msgstr "" - -msgctxt "#32026" -msgid "Set thumbnail" -msgstr "" - -msgctxt "#32027" -msgid "Change action" -msgstr "" - -msgctxt "#32028" -msgid "Restore menu items" -msgstr "" - -msgctxt "#32029" -msgid "Common" -msgstr "" - -msgctxt "#32030" -msgid "Video Library" -msgstr "" - -msgctxt "#32031" -msgid "Music Library" -msgstr "" - -msgctxt "#32032" -msgid "Play DVD" -msgstr "" - -msgctxt "#32033" -msgid "Eject tray" -msgstr "" - -msgctxt "#32034" -msgid "Common menu item" -msgstr "" - -msgctxt "#32035" -msgid "Choose which items to display on the Main Menu" -msgstr "" - -msgctxt "#32036" -msgid "Choose shortcuts for %s" -msgstr "" - -msgctxt "#32037" -msgid "Reset all menu items" -msgstr "" - -msgctxt "#32038" -msgid "Are you sure you want to reset all menu items back to default?" -msgstr "" - -msgctxt "#32039" -msgid "Pick widget for %s" -msgstr "" - -msgctxt "#32040" -msgid "Playlist" -msgstr "" - -msgctxt "#32041" -msgid "Action" -msgstr "" - -msgctxt "#32042" -msgid "Unknown video node" -msgstr "" - -msgctxt "#32043" -msgid "Choose shortcut category" -msgstr "" - -msgctxt "#32044" -msgid "Select widget" -msgstr "" - -msgctxt "#32045" -msgid "Select background" -msgstr "" - -msgctxt "#32046" -msgid "Update video library" -msgstr "" - -msgctxt "#32047" -msgid "Update audio library" -msgstr "" - -msgctxt "#32048" -msgid "Choose item for menu" -msgstr "" - -msgctxt "#32049" -msgid "Building menu..." -msgstr "" - -msgctxt "#32050" -msgid "Default" -msgstr "" - -msgctxt "#32051" -msgid "Single image" -msgstr "" - -msgctxt "#32052" -msgid "Multi-image" -msgstr "" - -msgctxt "#32053" -msgid "None" -msgstr "" - -msgctxt "#32054" -msgid "Kodi Command" -msgstr "" - -msgctxt "#32055" -msgid "Clean video library" -msgstr "" - -msgctxt "#32056" -msgid "Clean audio library" -msgstr "" - -msgctxt "#32057" -msgid "Kodi Commands" -msgstr "" - -msgctxt "#32058" -msgid "Create menu item to here" -msgstr "" - -msgctxt "#32059" -msgid "Skin Playlist" -msgstr "" - -msgctxt "#32060" -msgid "What do you want to do with the playlist?" -msgstr "" - -msgctxt "#32061" -msgid "Display" -msgstr "" - -msgctxt "#32062" -msgid "Play" -msgstr "" - -msgctxt "#32063" -msgid "Getting directory listing..." -msgstr "" - -msgctxt "#32064" -msgid "No available items" -msgstr "" - -msgctxt "#32065" -msgid "There are no available items to choose from for the category that you choose." -msgstr "" - -msgctxt "#32066" -msgid "Last TV channel" -msgstr "" - -msgctxt "#32067" -msgid "Last radio channel" -msgstr "" - -msgctxt "#32068" -msgid "Last channel" -msgstr "" - -msgctxt "#32069" -msgid "Video Source" -msgstr "" - -msgctxt "#32070" -msgid "UPnP" -msgstr "" - -msgctxt "#32071" -msgid "Customize Main Menu" -msgstr "" - -msgctxt "#32072" -msgid "Customize Submenu" -msgstr "" - -msgctxt "#32073" -msgid "Music Source" -msgstr "" - -msgctxt "#32074" -msgid "Library Sources" -msgstr "" - -msgctxt "#32075" -msgid "Sources" -msgstr "" - -msgctxt "#32076" -msgid "TV Channel" -msgstr "" - -msgctxt "#32077" -msgid "Radio Channel" -msgstr "" - -msgctxt "#32078" -msgid "Display..." -msgstr "" - -msgctxt "#32079" -msgid "Files view" -msgstr "" - -msgctxt "#32080" -msgid "Edit %s Submenu" -msgstr "" - -msgctxt "#32081" -msgid "Movies not in this source" -msgstr "" - -msgctxt "#32082" -msgid "TV Shows not in this source" -msgstr "" - -msgctxt "#32083" -msgid "Music Videos not in this source" -msgstr "" - -msgctxt "#32084" -msgid "Songs not in this source" -msgstr "" - -msgctxt "#32085" -msgid "Albums not in this source" -msgstr "" - -msgctxt "#32086" -msgid "Mixed content not in this source" -msgstr "" - -msgctxt "#32087" -msgid "Radio" -msgstr "" - -msgctxt "#32088" -msgid "Channels" -msgstr "" - -msgctxt "#32089" -msgid "Picture Source" -msgstr "" - -msgctxt "#32090" -msgid "The item has been added to the menu" -msgstr "" - -msgctxt "#32091" -msgid "Unable to add item to the menu. Please check log for errors." -msgstr "" - -msgctxt "#32092" -msgid "Unable to build menu." -msgstr "" - -msgctxt "#32093" -msgid "Upload debug log?" -msgstr "" - -msgctxt "#32094" -msgid "Install Kodi Log Uploader add-on to easily provide a debug log." -msgstr "" - -msgctxt "#32095" -msgid "Choose default action for menu item" -msgstr "" - -msgctxt "#32096" -msgid "Browse..." -msgstr "" - -msgctxt "#32097" -msgid "Unable to save menu" -msgstr "" - -msgctxt "#32098" -msgid "Writing menu..." -msgstr "" - -msgctxt "#32099" -msgid "Widget" -msgstr "" - -msgctxt "#32100" -msgid "Use as widget" -msgstr "" - -msgctxt "#32101" -msgid "Choose property" -msgstr "" - -msgctxt "#32102" -msgid "Restore or reset?" -msgstr "" - -msgctxt "#32103" -msgid "Restore an original menu item" -msgstr "" - -msgctxt "#32104" -msgid "Reset to skin defaults" -msgstr "" - -msgctxt "#32105" -msgid "There are no menu items to restore for this menu" -msgstr "" - -msgctxt "#32106" -msgid "Install widget provider" -msgstr "" - -msgctxt "#32107" -msgid "Enable default widgets" -msgstr "" - -msgctxt "#32108" -msgid "Party mode (music videos)" -msgstr "" - -msgctxt "#32109" -msgid "No menus from compatible skins found to import" -msgstr "" - -msgctxt "#32110" -msgid "Import menu from skin" -msgstr "" - -msgctxt "#32111" -msgid "Shared menu" -msgstr "" - -msgctxt "#32112" -msgid "New item on the main menu" -msgstr "" - -msgctxt "#32113" -msgid "New item on the main menu (autofill submenu items)" -msgstr "" - -msgctxt "#32114" -msgid "Where should menu item be created" -msgstr "" - -msgctxt "#32115" -msgid "Unable to get directory listings[CR][CR]See log for details" -msgstr "" - -msgctxt "#32116" -msgid "The skin you are using does not support adding items directly to the main menu" -msgstr "" - -msgctxt "#32117" -msgid "Disable shortcut" -msgstr "" - -msgctxt "#32118" -msgid "Smart shortcuts" -msgstr "" - -msgctxt "#32119" -msgid "Default widgets" -msgstr "" - -msgctxt "#32120" -msgid "Never hide PVR shortcuts" -msgstr "" - -msgctxt "#32121" -msgid "Share menu between compatible skins" -msgstr "" - -msgctxt "#32122" -msgid "Enable debug logging" -msgstr "" - -msgctxt "#32123" -msgid "Games" -msgstr "" - -msgctxt "#32124" -msgid "This addon is for skin developers, and requires skin support" -msgstr "" diff --git a/script.skinshortcuts/resources/language/resource.language.sk_sk/strings.po b/script.skinshortcuts/resources/language/resource.language.sk_sk/strings.po index 54a60dad6..96c2dbd55 100644 --- a/script.skinshortcuts/resources/language/resource.language.sk_sk/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.sk_sk/strings.po @@ -1,9 +1,9 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Slovak \n" "Language: sk_sk\n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "Zdieľať ponuku medzi kompatibilným vzhľadmi" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Začať ukladať informácie / debug log" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.sl_si/strings.po b/script.skinshortcuts/resources/language/resource.language.sl_si/strings.po index cf70741c4..de273c01a 100644 --- a/script.skinshortcuts/resources/language/resource.language.sl_si/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.sl_si/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Slovenian\n" -"Language: sl\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Slovenian \n" +"Language: sl_si\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" +"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Omogoči zapisovanje razhroščevanja" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.sq_al/strings.po b/script.skinshortcuts/resources/language/resource.language.sq_al/strings.po index cf7ff61b2..31f6acd71 100644 --- a/script.skinshortcuts/resources/language/resource.language.sq_al/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.sq_al/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-01 17:13+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Albanian \n" "Language: sq_al\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Aktivoni debug logging" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.sr_rs/strings.po b/script.skinshortcuts/resources/language/resource.language.sr_rs/strings.po index 177113087..14d205625 100644 --- a/script.skinshortcuts/resources/language/resource.language.sr_rs/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.sr_rs/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-03-30 09:46+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Serbian \n" "Language: sr_rs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Омогући евиденцију грешака" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.sr_rs@latin/strings.po b/script.skinshortcuts/resources/language/resource.language.sr_rs@latin/strings.po index bd973c15e..b875df2a9 100644 --- a/script.skinshortcuts/resources/language/resource.language.sr_rs@latin/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.sr_rs@latin/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Serbian (latin) \n" "Language: sr_rs@latin\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Omogući evidenciju grešaka" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.sv_se/strings.po b/script.skinshortcuts/resources/language/resource.language.sv_se/strings.po index 87d4267c0..5e0882733 100644 --- a/script.skinshortcuts/resources/language/resource.language.sv_se/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.sv_se/strings.po @@ -1,17 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-08-22 19:29+0000\n" -"Last-Translator: anxdpanic \n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" "Language-Team: Swedish \n" "Language: sv_se\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -79,7 +79,7 @@ msgstr "VIDEO" msgctxt "#32015" msgid "Movies" -msgstr "" +msgstr "Filmer" msgctxt "#32016" msgid "TV Shows" @@ -507,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Aktivera felsökningsloggning" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.ta_in/strings.po b/script.skinshortcuts/resources/language/resource.language.ta_in/strings.po index 282c19276..c25756d59 100644 --- a/script.skinshortcuts/resources/language/resource.language.ta_in/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.ta_in/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Tamil (India)\n" -"Language: ta_IN\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Tamil (India) \n" +"Language: ta_in\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "பிழைநீக்கு பதிவை செயல்படுத்தவும்" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.th_th/strings.po b/script.skinshortcuts/resources/language/resource.language.th_th/strings.po index 7c3919b08..3a89daf4a 100644 --- a/script.skinshortcuts/resources/language/resource.language.th_th/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.th_th/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Thai\n" -"Language: th\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Thai \n" +"Language: th_th\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" diff --git a/script.skinshortcuts/resources/language/resource.language.tr_tr/strings.po b/script.skinshortcuts/resources/language/resource.language.tr_tr/strings.po index 9d5cf2e46..d8c3c397b 100644 --- a/script.skinshortcuts/resources/language/resource.language.tr_tr/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.tr_tr/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Turkish\n" -"Language: tr\n" +"PO-Revision-Date: 2022-04-19 17:53+0000\n" +"Last-Translator: queeup \n" +"Language-Team: Turkish \n" +"Language: tr_tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -26,11 +27,11 @@ msgstr "Sil" msgctxt "#32002" msgid "Move Up" -msgstr "" +msgstr "Yukarı Taşı" msgctxt "#32003" msgid "Move Down" -msgstr "" +msgstr "Aşağı Taşı" msgctxt "#32004" msgid "Video Playlist" @@ -46,11 +47,11 @@ msgstr "Sık Kullanılanlar" msgctxt "#32007" msgid "Add-On" -msgstr "" +msgstr "Eklenti" msgctxt "#32008" msgid "Mixed Playlist" -msgstr "" +msgstr "Karışık Oynatma Listesi" msgctxt "#32009" msgid "Program" @@ -58,15 +59,15 @@ msgstr "Program" msgctxt "#32010" msgid "Video Add-On" -msgstr "" +msgstr "Video Eklentisi" msgctxt "#32011" msgid "Music Add-On" -msgstr "" +msgstr "Müzik Eklentisi" msgctxt "#32012" msgid "Picture Add-On" -msgstr "" +msgstr "Resim Eklentisi" msgctxt "#32013" msgid "" @@ -114,23 +115,23 @@ msgstr "Zamanlayıcılar" msgctxt "#32024" msgid "Custom item" -msgstr "" +msgstr "Özel öğe" msgctxt "#32025" msgid "Set label" -msgstr "" +msgstr "Etiketi ayarla" msgctxt "#32026" msgid "Set thumbnail" -msgstr "" +msgstr "Küçük resmi ayarla" msgctxt "#32027" msgid "Change action" -msgstr "" +msgstr "Eylemi değiştir" msgctxt "#32028" msgid "Restore menu items" -msgstr "" +msgstr "Menü öğelerini geri yükle" msgctxt "#32029" msgid "Common" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Hata ayıklama günlüğünü etkinleştir" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.uk_ua/strings.po b/script.skinshortcuts/resources/language/resource.language.uk_ua/strings.po index aeb749812..42a2a1e64 100644 --- a/script.skinshortcuts/resources/language/resource.language.uk_ua/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.uk_ua/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Ukrainian\n" -"Language: uk\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Ukrainian \n" +"Language: uk_ua\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Увімкнути журнал налагодження" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.vi_vn/strings.po b/script.skinshortcuts/resources/language/resource.language.vi_vn/strings.po index 77d85d99e..e2e6e66c1 100644 --- a/script.skinshortcuts/resources/language/resource.language.vi_vn/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.vi_vn/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Vietnamese\n" -"Language: vi\n" +"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Vietnamese \n" +"Language: vi_vn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11.2\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "Cho phép ghi nhật ký gỡ lỗi" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/language/resource.language.zh_tw/strings.po b/script.skinshortcuts/resources/language/resource.language.zh_tw/strings.po index 0c028c845..e191166fd 100644 --- a/script.skinshortcuts/resources/language/resource.language.zh_tw/strings.po +++ b/script.skinshortcuts/resources/language/resource.language.zh_tw/strings.po @@ -1,16 +1,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"Report-Msgid-Bugs-To: noreply@noreply.com\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Chinese (Traditional)\n" -"Language: zh_TW\n" +"PO-Revision-Date: 2022-03-01 17:13+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Chinese (Taiwan) \n" +"Language: zh_tw\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.11\n" msgctxt "Addon Description" msgid "Add-on for skins to provide simple managing and listing of user shortcuts (requires skin support)" @@ -506,7 +507,7 @@ msgstr "" msgctxt "#32122" msgid "Enable debug logging" -msgstr "" +msgstr "啟用除錯記錄" msgctxt "#32123" msgid "Games" diff --git a/script.skinshortcuts/resources/lib/skinshorcuts/datafunctions.py b/script.skinshortcuts/resources/lib/skinshorcuts/datafunctions.py index 7fbf2306a..99e8fda1f 100644 --- a/script.skinshortcuts/resources/lib/skinshorcuts/datafunctions.py +++ b/script.skinshortcuts/resources/lib/skinshorcuts/datafunctions.py @@ -274,7 +274,7 @@ def _process_shortcuts(self, tree, group, profile_dir="special://profile", # If icon and thumbnail are in the additional properties, # overwrite anything in the .DATA.xml file # and remove them from the additional properties - for additional_property in additional_properties: + for additional_property in additional_properties.copy(): if additional_property[0] == "icon": node.find("icon").text = additional_property[1] additional_properties.remove(additional_property) @@ -283,7 +283,7 @@ def _process_shortcuts(self, tree, group, profile_dir="special://profile", if node.find("thumb") is None: ETree.SubElement(node, "thumb").text = "" - for additional_property in additional_properties: + for additional_property in additional_properties.copy(): if additional_property[0] == "thumb": node.find("thumb").text = additional_property[1] additional_properties.remove(additional_property) diff --git a/script.skinshortcuts/resources/lib/skinshorcuts/gui.py b/script.skinshortcuts/resources/lib/skinshorcuts/gui.py index 051b2a8d8..babbf8c0a 100644 --- a/script.skinshortcuts/resources/lib/skinshorcuts/gui.py +++ b/script.skinshortcuts/resources/lib/skinshorcuts/gui.py @@ -484,7 +484,7 @@ def _add_additional_properties(self, listitem=None): other_properties, requires, _ = self.data_func.get_property_requires() # Remove any properties whose requirements haven't been met - # pylint: disable=unsubscriptable-object + # pylint: disable=unsubscriptable-object,unsupported-membership-test for key in other_properties: if key in all_props and key in requires and requires[key] not in all_props: # This properties requirements aren't met diff --git a/script.skinshortcuts/resources/lib/skinshorcuts/library.py b/script.skinshortcuts/resources/lib/skinshorcuts/library.py index 91b971ae0..07b1b8724 100644 --- a/script.skinshortcuts/resources/lib/skinshorcuts/library.py +++ b/script.skinshortcuts/resources/lib/skinshorcuts/library.py @@ -1048,7 +1048,7 @@ def pvrlibrary(self): self.create(["ActivateWindow(TVGuide)", "22020", "32017", { "icon": "DefaultTVShows.png" }]), - self.create(["ActivateWindow(TVRecordings)", "19163", "32017", { + self.create(["ActivateWindow(TVRecordings)", "19017", "32017", { "icon": "DefaultTVShows.png" }]), self.create(["ActivateWindow(TVTimers)", "19040", "32017", { @@ -1115,7 +1115,7 @@ def radiolibrary(self): self.create(["ActivateWindow(RadioGuide)", "22020", "32087", { "icon": "DefaultAudio.png" }]), - self.create(["ActivateWindow(RadioRecordings)", "19163", "32087", { + self.create(["ActivateWindow(RadioRecordings)", "19017", "32087", { "icon": "DefaultAudio.png" }]), self.create(["ActivateWindow(RadioTimers)", "19040", "32087", { @@ -1393,7 +1393,7 @@ def favourites(self): for favourite in listing: name = favourite.attributes['name'].nodeValue path = favourite.childNodes[0].nodeValue - if ('RunScript' not in path) and ('StartAndroidActivity' not in path) and \ + if path.lower().startswith('activatewindow') and \ not path.endswith(',return)'): path = path.rstrip(')') path = '%s,return)' % path @@ -2475,7 +2475,7 @@ def select_shortcut(self, group="", custom=False, available_shortcuts=None, wind # Show select dialog _ = self._allow_install_widget_provider(None, is_widget, self.allow_widget_install) show_dialog = ShowDialog("DialogSelect.xml", CWD, listing=available_shortcuts, - windowtitle=window_title) + window_title=window_title) show_dialog.doModal() number = show_dialog.result del show_dialog diff --git a/script.skinshortcuts/resources/lib/skinshorcuts/nodefunctions.py b/script.skinshortcuts/resources/lib/skinshorcuts/nodefunctions.py index 2447c9840..a1b44130e 100644 --- a/script.skinshortcuts/resources/lib/skinshorcuts/nodefunctions.py +++ b/script.skinshortcuts/resources/lib/skinshorcuts/nodefunctions.py @@ -63,8 +63,10 @@ def parse_view(self, file, nodes, is_folder=False, orig_folder=None, orig_path=N try: # Load the xml file - tree = ETree.parse(file) - root = tree.getroot() + with open(file.encode('utf-8'), "rb") as infile: + filedata = infile.read().decode('utf-8') + + root = ETree.fromstring(filedata) # Get the item index if "order" in root.attrib: diff --git a/script.skinshortcuts/resources/lib/skinshorcuts/xmlfunctions.py b/script.skinshortcuts/resources/lib/skinshorcuts/xmlfunctions.py index 7d327cb26..91290ef15 100644 --- a/script.skinshortcuts/resources/lib/skinshorcuts/xmlfunctions.py +++ b/script.skinshortcuts/resources/lib/skinshorcuts/xmlfunctions.py @@ -66,8 +66,11 @@ def build_menu(self, mainmenu_id, groups, num_levels, build_mode, options, minit profiles_xml = xbmcvfs.translatePath('special://userdata/profiles.xml') tree = None if xbmcvfs.exists(profiles_xml): - contents = read_file(profiles_xml) - tree = ETree.fromstring(contents) + try: + contents = read_file(profiles_xml) + tree = ETree.fromstring(contents) + except FileNotFoundError: + pass profilelist = [] if tree is not None: @@ -86,7 +89,10 @@ def build_menu(self, mainmenu_id, groups, num_levels, build_mode, options, minit profilelist.append([path, "String.IsEqual(System.ProfileName,%s)" % name, name]) else: - profilelist = [["special://masterprofile", None]] + name = xbmc.getInfoLabel("System.ProfileName") + profilelist = [[xbmcvfs.translatePath("special://masterprofile/"), + "String.IsEqual(System.ProfileName,%s)" % name, + name]] if not self.shouldwerun(profilelist): log("Menu is up to date") @@ -455,7 +461,7 @@ def writexml(self, profilelist, mainmenu_id, groups, num_levels, build_mode, # Remove any template-only properties other_properties, _, template_only = self.data_func.get_property_requires() for key in other_properties: - if key in all_props and key in template_only: + if key in all_props and key in template_only: # pylint: disable=unsupported-membership-test # This key is template-only menuitem.remove(all_props[key]) all_props.pop(key) @@ -906,7 +912,7 @@ def build_element(self, item, group_name, visibility_condition, profile_visibili # Remove any properties whose requirements haven't been met for key in other_properties: - # pylint: disable=unsubscriptable-object + # pylint: disable=unsubscriptable-object,unsupported-membership-test if key in all_props and key in requires and requires[key] not in all_props: # This properties requirements aren't met newelement.remove(all_props[key]) diff --git a/script.skinshortcuts/resources/shortcuts/livetv.DATA.xml b/script.skinshortcuts/resources/shortcuts/livetv.DATA.xml index 957c49442..9f868f05e 100644 --- a/script.skinshortcuts/resources/shortcuts/livetv.DATA.xml +++ b/script.skinshortcuts/resources/shortcuts/livetv.DATA.xml @@ -9,7 +9,7 @@ 14 - + 32017 DefaultTVShows.png @@ -17,7 +17,7 @@ 13 - + 32017 DefaultTVShows.png From 284794f53338d2102f944121d84d8d23163dcf7e Mon Sep 17 00:00:00 2001 From: Jeremy Daalder Date: Mon, 20 Feb 2023 08:38:31 +1100 Subject: [PATCH 012/145] [weather.ozweather] 2.0.6 (#2411) --- weather.ozweather/addon.xml | 6 ++-- weather.ozweather/changelog.txt | 3 ++ .../lib/bom/bom_radar_scrape_latest.py | 35 +++++++++++++++---- weather.ozweather/resources/lib/store.py | 14 ++++++-- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/weather.ozweather/addon.xml b/weather.ozweather/addon.xml index deb78fa92..1a1dfc689 100644 --- a/weather.ozweather/addon.xml +++ b/weather.ozweather/addon.xml @@ -1,5 +1,5 @@ - + @@ -22,8 +22,8 @@ icon.png fanart.jpg - v2.0.5 - - Improve error handling if the BOM disappears for a bit... + v2.0.6 + - Update list of radars diff --git a/weather.ozweather/changelog.txt b/weather.ozweather/changelog.txt index 0e23e2a88..ce20ddbec 100644 --- a/weather.ozweather/changelog.txt +++ b/weather.ozweather/changelog.txt @@ -1,3 +1,6 @@ +2.0.6 +- Update list of radars + 2.0.5 - Improve error handling if the BOM disappears for a bit... diff --git a/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py b/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py index 41231095b..1358b7ded 100644 --- a/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py +++ b/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py @@ -16,20 +16,24 @@ content = soup.find(id="content") anchors = content.find_all("a") -print(f"# Automatically generated from {radar_page}") -print("BOM_RADAR_LOCATIONS = [") +# pprint(anchors) + +python_var = "" +javascript_var = "" -# The last anchor is not needed, but loop through the rest to scrape the actual radars... +# The last anchor is not a list of anchors, but loop through the rest to scrape the actual radars... for anchor in anchors[:-1]: href = anchor.get('href') radar_page = "http://www.bom.gov.au" + href - print("# " + radar_page) + python_var += f' # {radar_page}\n' + javascript_var += f' // {radar_page}\n' r = requests.get(radar_page, headers=headers) soup = BeautifulSoup(r.text, 'html.parser') site_infos = soup.find_all('div', class_='site-info') + for site_info in site_infos: # Get the radar name @@ -50,6 +54,25 @@ # bizarrely Mildura is the only one that has the '-' in the latitude, the rest all say 'south' if lat_lon_matches[0][0] == '-': lat_lon_matches[0] = lat_lon_matches[0][1:] - print(f'(-{lat_lon_matches[0]}, {lat_lon_matches[1]}, "{name}", "{radar_code}"),') -print("]") + python_var += f' (-{lat_lon_matches[0]}, {lat_lon_matches[1]}, "{name}", "{radar_code}"),\n' + javascript_var += f' [-{lat_lon_matches[0]}, {lat_lon_matches[1]}, "{name}", "{radar_code}"],\n' + +# Remove the final newline for neatness +python_var = python_var[:-2] +javascript_var = javascript_var[:-2] + +# Finally, print the Python + +print(f"\n\n# (Python) Automatically generated by bom_radar_scraper_latest.py from {radar_page}") +print("BOM_RADAR_LOCATIONS = [") +print(python_var) +print("]\n\n") + +# & print the Javascript version + +print(f"// (Javascript) Automatically generated by bom_radar_scraper_latest.py from {radar_page}") +print("const bomRadarLocations = [") +print(javascript_var) +print("]\n\n") + diff --git a/weather.ozweather/resources/lib/store.py b/weather.ozweather/resources/lib/store.py index a0ce376b7..ca906ae7a 100644 --- a/weather.ozweather/resources/lib/store.py +++ b/weather.ozweather/resources/lib/store.py @@ -20,15 +20,19 @@ class Store: BOM_RADAR_FTPSTUB = "ftp://anonymous:someone%40somewhere.com@ftp.bom.gov.au//anon/gen/radar/" BOM_RADAR_BACKGROUND_FTPSTUB = "ftp://anonymous:someone%40somewhere.com@ftp.bom.gov.au//anon/gen/radar_transparencies/" BOM_RADAR_HTTPSTUB = "http://www.bom.gov.au/products/radar_transparencies/" - # The below list is generated using the scraper: python3 resources/lib/bom/bom_radar_scrape_latest.py + + # The below list is generated using my scraper: python3 resources/lib/bom/bom_radar_scrape_latest.py # Just cut and paste the output of that below.... # The master URL is: http://www.bom.gov.au/australia/radar/about/radar_site_info.shtml # Can cross check with: https://github.com/theOzzieRat/bom-radar-card/blob/master/src/bom-radar-card.ts around line 130 + + # Automatically generated by bom_radar_scraper_latest.py from http://www.bom.gov.au/australia/radar/about/radar_site_info.shtml BOM_RADAR_LOCATIONS = [ # http://www.bom.gov.au/australia/radar/info/nsw_info.shtml (-29.96, 146.81, "Brewarrina", "IDR933"), (-35.66, 149.51, "Canberra (Captain's Flat)", "IDR403"), (-29.62, 152.97, "Grafton", "IDR283"), + (-33.55, 145.52, "Hillston", "IDR943"), (-29.50, 149.85, "Moree", "IDR533"), (-31.0240, 150.1915, "Namoi (Blackjack Mountain)", "IDR693"), (-32.730, 152.027, "Newcastle", "IDR043"), @@ -36,6 +40,7 @@ class Store: (-33.701, 151.210, "Sydney (Terrey Hills)", "IDR713"), (-35.17, 147.47, "Wagga Wagga", "IDR553"), (-34.264, 150.874, "Wollongong (Appin)", "IDR033"), + (-32.74, 148.70, "Yeoval", "IDR963"), # http://www.bom.gov.au/australia/radar/info/vic_info.shtml (-37.86, 144.76, "Melbourne", "IDR023"), (-34.28, 141.59, "Mildura", "IDR973"), @@ -44,16 +49,20 @@ class Store: (-36.03, 146.03, "Yarrawonga", "IDR493"), # http://www.bom.gov.au/australia/radar/info/qld_info.shtml (-19.88, 148.08, "Bowen", "IDR243"), + (-27.39, 153.13, "Brisbane Airport", "IDR1053"), (-27.718, 153.240, "Brisbane (Mt. Stapylton)", "IDR663"), (-16.82, 145.68, "Cairns", "IDR193"), (-23.5494, 148.2392, "Emerald (Central Highlands)", "IDR723"), (-23.86, 151.26, "Gladstone", "IDR233"), + (-18.99, 144.99, "Greenvale", "IDR743"), (-25.957, 152.577, "Gympie (Mt Kanigan)", "IDR083"), (-23.43, 144.29, "Longreach", "IDR563"), (-21.12, 149.22, "Mackay", "IDR223"), (-27.61, 152.54, "Marburg", "IDR503"), (-16.67, 139.17, "Mornington Island", "IDR363"), (-20.7114, 139.5553, "Mount Isa", "IDR753"), + (-20.75, 143.14, "Richmond", "IDR1073"), + (-25.696, 149.898, "Taroom", "IDR983"), (-19.42, 146.55, "Townsville (Hervey Range)", "IDR733"), (-26.44, 147.35, "Warrego", "IDR673"), (-12.67, 141.92, "Weipa", "IDR783"), @@ -72,6 +81,7 @@ class Store: (-22.10, 114.00, "Learmonth", "IDR293"), (-33.097, 119.009, "Newdegate", "IDR383"), (-32.39, 115.87, "Perth (Serpentine)", "IDR703"), + (-31.93, 115.98, "Perth Airport", "IDR263"), (-20.37, 118.63, "Port Hedland", "IDR163"), (-30.36, 116.29, "Watheroo", "IDR793"), (-15.45, 128.12, "Wyndham", "IDR073"), @@ -90,7 +100,7 @@ class Store: (-12.46, 130.93, "Darwin/Berrimah", "IDR633"), (-12.28, 136.82, "Gove", "IDR093"), (-14.51, 132.45, "Katherine/Tindal", "IDR423"), - (-11.6494, 133.38, "Warruwi", "IDR773"), + (-11.6494, 133.38, "Warruwi", "IDR773") ] DAYS = {"Mon": "Monday", From a9f3daca4a7abc36e67d57da1e8e14a589cf7da6 Mon Sep 17 00:00:00 2001 From: anxdpanic Date: Fri, 3 Mar 2023 04:10:15 -0500 Subject: [PATCH 013/145] [service.xbmc.versioncheck] 0.5.27+matrix.1 (#2417) --- service.xbmc.versioncheck/addon.xml | 10 +-- .../resource.language.de_de/strings.po | 10 +-- .../resource.language.lv_lv/strings.po | 67 ++++++++++--------- .../lib/version_check/distro/distro.py | 2 +- 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/service.xbmc.versioncheck/addon.xml b/service.xbmc.versioncheck/addon.xml index c4ae551a6..c63af34c8 100644 --- a/service.xbmc.versioncheck/addon.xml +++ b/service.xbmc.versioncheck/addon.xml @@ -1,13 +1,12 @@ - + -- add Kodi 20 release -- Update translations from Weblate +- Fix crash when lsb_release cannot be executed on linux icon.png @@ -44,6 +43,7 @@ Kodi Version Check controlla se stai utilizzando l'ultima versione disponibile. Kodi Version Checks는 최신 정식 릴리즈 버전을 사용중인지 검사해줍니다. Kodi Version Check patikrina ar naudojate naujausią versiją. + Kodi versijas pārbaude pārbauda, vai izmantojat jaunāko versiju. Kodi Versjonsettersyn sjekker om du kjører den sist utgitte versjonen. Kodi versie-check controleert of je de laatst beschikbare versie hebt. Kodi Version Check verifica s’executatz la darrièra version sortida. @@ -65,7 +65,7 @@ Kodi Version Check només és compatible amb una sèrie de plataformes / distribucions ja que les ultimes versions poden ser diferents entre elles. Per obtenir més informació, visiteu el lloc web kodi.tv. Kontrola verze Kodi podporuje pouze několik platforem/distribucí a verze mezi nimi se můžou lišit. Pro více informací navštivte webové stránky kodi.tv. Kodi Version Check kan kun undersøge for opdateringer for visse platforme/udgaver, da udgivelserne kan variere mellem dem. For mere information, besøg kodi.tv. - Kodi Version Check unterstützt nur ausgewählte Plattformen / Distributionen, da sich die jeweiligen Veröffentlichungen unterscheiden können. Mehr Informationen dazu gibt es auf der kodi.tv-Website. + Kodi Version Check unterstützt nur ausgewählte Plattformen/Distributionen, da sich die jeweiligen Veröffentlichungen unterscheiden können. Mehr Informationen dazu gibt es auf der kodi.tv-Website. Ο Έλεγχος Έκδοσης Kodi υποστηρίζει μόνο ορισμένα λειτουργικά συστήματα/διανομές, καθώς οι εκδόσεις διαφέρουν για το καθένα. Για περισσότερες πληροφορίες επισκεφθείτε το kodi.tv Kodi Version Check only supports a number of platforms/distros as releases may differ between them. For more information visit the kodi.tv website. Kodi Version Check only supports a number of platforms/distros as releases may differ between them. For more information visit the kodi.tv website. @@ -86,6 +86,7 @@ Kodi Version Check supporta solo un certo numero di piattaforme/distribuzioni poiché le versioni potrebbero differire tra loro. Per ulteriori informazioni, visita il sito Web kodi.tv. Kodi 버전 확인은 릴리스가 다를 수 있으므로 다수 플랫폼/배포판만 지원합니다. 자세한 내용은 kodi.tv 웹사이트를 방문하세요. Kodi Version Check palaiko tik kelias platformas/distribucijas, nes leidimai tarp jų gali skirtis. Norėdami gauti daugiau informacijos, apsilankykite Kodi.tv puslapyje. + Kodi versijas pārbaude tiek atbalstīta tikai dažās platformās/distributīvos, un tās var atšķirties viena no otras. Lai iegūtu vairāk informācijas, apmeklējiet kodi.tv vietni. Kodi Versjonsettersyn støtter kun noen plattformer/distribusjoner fordi utgivelser kan være forskjellige mellom dem. Besøk kodi.tv for mer informasjon. Kodi versie check ondersteunt alleen een aantal platforms/distro`s omdat uitgaven verschillen tussen hen. Voor meer informatie bezoek de kodi.tv website. Dodatek Version Check wspiera tylko część platform i dystrybucji. Więcej informacji na stronie kodi.tv. @@ -127,6 +128,7 @@ このスクリプトをお使いください。詳しくは kodi.tv を参照してください 이 스크립트를 자유롭게 사용하세요. 관련 정보는 kodi.tv를 방문하세요 Galite laisvai naudoti šį scenarijų. Apsilankykite kodi.tv, norėdami gauti daugiau informacijos. + Brīvi izmantojiet šo skriptu pēc saviem ieskatiem. Lai iegūtu vairāk informācijas, apmeklējiet kodi.tv vietni Du har fri tillatelse til å benytte dette skriptet. Besøk kodi.tv for informasjon Gebruik dit script vrijblijvend. Voor meer informatie bezoek kodi.tv Siatz liure d’utilizar aqueste script. Per d’informacions consultatz kodi.tv diff --git a/service.xbmc.versioncheck/resources/language/resource.language.de_de/strings.po b/service.xbmc.versioncheck/resources/language/resource.language.de_de/strings.po index e15f87c4c..8783c74ee 100644 --- a/service.xbmc.versioncheck/resources/language/resource.language.de_de/strings.po +++ b/service.xbmc.versioncheck/resources/language/resource.language.de_de/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-10-25 10:08+0000\n" +"PO-Revision-Date: 2023-02-05 23:15+0000\n" "Last-Translator: Kai Sommerfeld \n" "Language-Team: German \n" "Language: de_de\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Kodi Version Check checks if you are running latest released version." @@ -23,7 +23,7 @@ msgstr "Kodi Version Check prüft, ob die neuste Version von Kodi installiert is msgctxt "Addon Description" msgid "Kodi Version Check only supports a number of platforms/distros as releases may differ between them. For more information visit the kodi.tv website." -msgstr "Kodi Version Check unterstützt nur ausgewählte Plattformen / Distributionen, da sich die jeweiligen Veröffentlichungen unterscheiden können. Mehr Informationen dazu gibt es auf der kodi.tv-Website." +msgstr "Kodi Version Check unterstützt nur ausgewählte Plattformen/Distributionen, da sich die jeweiligen Veröffentlichungen unterscheiden können. Mehr Informationen dazu gibt es auf der kodi.tv-Website." msgctxt "Addon Disclaimer" msgid "Feel free to use this script. For information visit kodi.tv" @@ -47,7 +47,7 @@ msgstr "Dies kann in den Addon-Einstellungen aktiviert/deaktiviert werden." msgctxt "#32011" msgid "Use your package manager(apt) to upgrade." -msgstr "Bitte den System-Packetmanager (apt) zum Aktualisieren verwenden." +msgstr "Bitte den System-Paketmanager (apt) zum Aktualisieren verwenden." msgctxt "#32012" msgid "A new version is available, do you want to upgrade now?" @@ -122,7 +122,7 @@ msgstr "Ein Upgrade auf eine neuere Version wird empfohlen." # empty strings from id 32036 to 32039 msgctxt "#32040" msgid "Your version %s of the Python cryptography module is too old. You need at least version 1.7." -msgstr "Die installierte Version des Python-Kryptogaphie-Moduls ist zu alt. Es wird mindestens Version 1.7 benötigt." +msgstr "Die installierte Version des Python-Kryptogafiemoduls ist zu alt. Es wird mindestens Version 1.7 benötigt." msgctxt "#32041" msgid "Please upgrade your operating system." diff --git a/service.xbmc.versioncheck/resources/language/resource.language.lv_lv/strings.po b/service.xbmc.versioncheck/resources/language/resource.language.lv_lv/strings.po index 2656c8677..18982ba77 100644 --- a/service.xbmc.versioncheck/resources/language/resource.language.lv_lv/strings.po +++ b/service.xbmc.versioncheck/resources/language/resource.language.lv_lv/strings.po @@ -5,130 +5,131 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Kodi Translation Team\n" -"Language-Team: Latvian (http://www.transifex.com/projects/p/xbmc-addons/language/lv/)\n" -"Language: lv\n" +"PO-Revision-Date: 2023-02-24 00:15+0000\n" +"Last-Translator: Coool (github.com/Coool) \n" +"Language-Team: Latvian \n" +"Language: lv_lv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Kodi Version Check checks if you are running latest released version." -msgstr "" +msgstr "Kodi versijas pārbaude pārbauda, vai izmantojat jaunāko versiju." msgctxt "Addon Description" msgid "Kodi Version Check only supports a number of platforms/distros as releases may differ between them. For more information visit the kodi.tv website." -msgstr "" +msgstr "Kodi versijas pārbaude tiek atbalstīta tikai dažās platformās/distributīvos, un tās var atšķirties viena no otras. Lai iegūtu vairāk informācijas, apmeklējiet kodi.tv vietni." msgctxt "Addon Disclaimer" msgid "Feel free to use this script. For information visit kodi.tv" -msgstr "" +msgstr "Brīvi izmantojiet šo skriptu pēc saviem ieskatiem. Lai iegūtu vairāk informācijas, apmeklējiet kodi.tv vietni" msgctxt "#32001" msgid "We would like to recommend you to upgrade." -msgstr "" +msgstr "Mēs iesakām veikt atjaunināšanu." msgctxt "#32002" msgid "Visit Kodi.tv for more information." -msgstr "" +msgstr "Lai iegūtu vairāk informācijas, apmeklējiet kodi.tv vietni." # empty strings from id 32003 to 32008 msgctxt "#32009" msgid "Would you like to remove this reminder?" -msgstr "" +msgstr "Vai vēlaties aizvākt šo atgādinājumu?" msgctxt "#32010" msgid "You can enable/disable it through add-on settings." -msgstr "" +msgstr "Varat to iespējot/atspējot papildinājumu iestatījumu sadaļā." msgctxt "#32011" msgid "Use your package manager(apt) to upgrade." -msgstr "" +msgstr "Lai atjauninātu, izmantojiet pakotņu pārvaldnieku (apt)." msgctxt "#32012" msgid "A new version is available, do you want to upgrade now?" -msgstr "" +msgstr "Ir pieejama jauna versija. Vai vēlaties atjaunināt tūlīt?" msgctxt "#32013" msgid "Upgrade successful" -msgstr "" +msgstr "Atjaunināšana veiksmīgi pabeigta" msgctxt "#32014" msgid "Do you want to restart Kodi to finish the upgrade?" -msgstr "" +msgstr "Vai restartēt Kodi, lai pabeigtu atjaunināšanu?" msgctxt "#32015" msgid "Do you want to check the repository for a new version?" -msgstr "" +msgstr "Vai vēlaties pārbaudīt, vai repozitorijā nav jauna versija?" msgctxt "#32016" msgid "There is a newer stable Kodi version available." -msgstr "" +msgstr "Ir pieejama jauna stabila Kodi versija." msgctxt "#32020" msgid "General" -msgstr "Vispārīgi" +msgstr "Vispārīgie" msgctxt "#32021" msgid "Enable Kodi version check?" -msgstr "" +msgstr "Vai iespējot jaunu Kodi versijas pārbaudi?" msgctxt "#32022" msgid "Please enter your password" -msgstr "" +msgstr "Lūdzu, ievadiet savu paroli" msgctxt "#32023" msgid "Linux: Upgrade complete system" -msgstr "" +msgstr "Linux: Pilnīga sistēmas atjaunināšana" msgctxt "#32024" msgid "Linux: Upgrade using apt" -msgstr "" +msgstr "Linux: Atjaunināt, izmantojot apt" # empty strings from id 32025 to 32029 #. Used in OK dialog msgctxt "#32030" msgid "A new stable version of Kodi is available." -msgstr "" +msgstr "Ir pieejama jauna stabila Kodi versija." #. Direct people to the website. Used in OK dialog msgctxt "#32031" msgid "Visit http://kodi.tv for more information." -msgstr "" +msgstr "Lai iegūtu vairāk informācijas, apmeklējiet http://kodi.tv vietni." #. Used in OK dialog msgctxt "#32032" msgid "A new stable version of Kodi is available." -msgstr "" +msgstr "Ir pieejama jauna stabila Kodi versija." #. Direct people to the website. Used in OK dialog msgctxt "#32033" msgid "Visit http://kodi.tv for more information." -msgstr "" +msgstr "Lai iegūtu vairāk informācijas, apmeklējiet http://kodi.tv vietni." #. For example: "You are using 13.1 prealpha while 13.2 stable is available" msgctxt "#32034" msgid "Using %s while %s is available." -msgstr "" +msgstr "Jūs izmantojat %s, taču jau ir pieejama atjaunināta %s versija." #. Used in OK dialog msgctxt "#32035" msgid "It is recommended that you upgrade to a newer version." -msgstr "" +msgstr "Ieteicams veikt atjaunināšanu uz jauno versiju." # empty strings from id 32036 to 32039 msgctxt "#32040" msgid "Your version %s of the Python cryptography module is too old. You need at least version 1.7." -msgstr "" +msgstr "Jūsu Python kriptogrāfijas moduļa versija %s ir pārāk veca. Nepieciešama vismaz versija 1.7." msgctxt "#32041" msgid "Please upgrade your operating system." -msgstr "" +msgstr "Lūdzu, atjauniniet savu operētājsistēmu." msgctxt "#32042" msgid "For more information, see https://kodi.wiki/view/Linux" -msgstr "" +msgstr "Lai iegūtu vairāk informācijas, skatiet https://kodi.wiki/view/Linux vietni" diff --git a/service.xbmc.versioncheck/resources/lib/version_check/distro/distro.py b/service.xbmc.versioncheck/resources/lib/version_check/distro/distro.py index 06cdf6435..779eb71e8 100644 --- a/service.xbmc.versioncheck/resources/lib/version_check/distro/distro.py +++ b/service.xbmc.versioncheck/resources/lib/version_check/distro/distro.py @@ -1011,7 +1011,7 @@ def _lsb_release_info(self): try: cmd = ('lsb_release', '-a') stdout = subprocess.check_output(cmd, stderr=devnull) - except OSError: # Command not found + except (OSError, subprocess.CalledProcessError): # Command not found return {} content = stdout.decode(sys.getfilesystemencoding()).splitlines() return self._parse_lsb_release_content(content) From 1c31eb7e98943b727925556f40e7a0f8a6046d57 Mon Sep 17 00:00:00 2001 From: Rob <1572423+robweber@users.noreply.github.com> Date: Sun, 5 Mar 2023 09:11:34 -0600 Subject: [PATCH 014/145] [service.cronxbmc] 0.1.7 (#2418) --- service.cronxbmc/addon.xml | 5 ++++- service.cronxbmc/resources/lib/cron/main.py | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/service.cronxbmc/addon.xml b/service.cronxbmc/addon.xml index 496e5c145..e7d64fadc 100644 --- a/service.cronxbmc/addon.xml +++ b/service.cronxbmc/addon.xml @@ -1,6 +1,6 @@ + name="Cron For Kodi" version="0.1.7" provider-name="robweber"> @@ -20,6 +20,9 @@ resources/images/icon.png + Version 0.1.7 +- fixed bug of deprecated API in Nexus + Version 0.1.6 - fixed so it addon imports work properly - updated settings to new Kodi format diff --git a/service.cronxbmc/resources/lib/cron/main.py b/service.cronxbmc/resources/lib/cron/main.py index e9a44e88a..2abd9b4f3 100644 --- a/service.cronxbmc/resources/lib/cron/main.py +++ b/service.cronxbmc/resources/lib/cron/main.py @@ -137,8 +137,7 @@ def _refreshJobs(self): def _readCronFile(self): if(not xbmcvfs.exists(xbmcvfs.translatePath('special://profile/addon_data/service.cronxbmc/'))): - xbmcvfs.mkdir(xbmc.translatePath('special://profile/addon_data/service.cronxbmc/')) - + xbmcvfs.mkdir(xbmcvfs.translatePath('special://profile/addon_data/service.cronxbmc/')) adv_jobs = {} try: doc = xml.dom.minidom.parse(xbmcvfs.translatePath(self.CRONFILE)) From bf9413c8ddd65d1fc69e945368570c91581e0ef4 Mon Sep 17 00:00:00 2001 From: goggle Date: Wed, 8 Mar 2023 11:49:01 +0000 Subject: [PATCH 015/145] [script.module.srgssr] 2.2.3 --- script.module.srgssr/addon.xml | 2 +- script.module.srgssr/lib/srgssr.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/script.module.srgssr/addon.xml b/script.module.srgssr/addon.xml index 9d796798e..11236f1d6 100644 --- a/script.module.srgssr/addon.xml +++ b/script.module.srgssr/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/script.module.srgssr/lib/srgssr.py b/script.module.srgssr/lib/srgssr.py index 8752e3f67..d7260d6b0 100644 --- a/script.module.srgssr/lib/srgssr.py +++ b/script.module.srgssr/lib/srgssr.py @@ -654,6 +654,16 @@ def build_entry_apiv3(self, data, is_show=False, whitelist_ids=None): urn = data['urn'] self.log(f'build_entry_apiv3: urn = {urn}') title = utils.try_get(data, 'title') + + # Add the date & time to the title for upcoming livestreams: + if utils.try_get(data, 'type') == 'SCHEDULED_LIVESTREAM': + dt = utils.try_get(data, 'date') + if dt: + dt = utils.parse_datetime(dt) + if dt: + dts = dt.strftime('(%d.%m.%Y, %H:%M)') + title = dts + ' ' + title + media_id = utils.try_get(data, 'id') if whitelist_ids is not None and media_id not in whitelist_ids: return From 3f9908bfbe9c0bd2d9cf868738a70bf79a5f6d74 Mon Sep 17 00:00:00 2001 From: anxdpanic Date: Mon, 13 Mar 2023 16:26:02 -0400 Subject: [PATCH 016/145] [service.xbmc.versioncheck] 0.5.28+matrix.1 (#2422) --- service.xbmc.versioncheck/addon.xml | 5 +++-- service.xbmc.versioncheck/resources/versions.txt | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/service.xbmc.versioncheck/addon.xml b/service.xbmc.versioncheck/addon.xml index c63af34c8..e12d3fe7e 100644 --- a/service.xbmc.versioncheck/addon.xml +++ b/service.xbmc.versioncheck/addon.xml @@ -1,12 +1,13 @@ - + -- Fix crash when lsb_release cannot be executed on linux +- add Kodi 20.1 release +- Update translations from Weblate icon.png diff --git a/service.xbmc.versioncheck/resources/versions.txt b/service.xbmc.versioncheck/resources/versions.txt index 8e61d0b7c..bd0165d8c 100644 --- a/service.xbmc.versioncheck/resources/versions.txt +++ b/service.xbmc.versioncheck/resources/versions.txt @@ -2,6 +2,15 @@ "jsonrpc": "2.0", "releases": { "stable": [ + { + "major": "20", + "minor": "1", + "tag": "stable", + "tagversion":"", + "revision": "20230312-289ec664e3", + "extrainfo": "final", + "addon_support": "yes" + }, { "major": "20", "minor": "0", From d1e0b17f682806753516110c18bb5e63ec00a26d Mon Sep 17 00:00:00 2001 From: ronie Date: Mon, 27 Mar 2023 23:14:55 +0200 Subject: [PATCH 017/145] [weather.multi] 0.0.18 --- weather.multi/addon.xml | 2 +- weather.multi/changelog.txt | 3 + weather.multi/lib/weather.py | 5 +- .../resource.language.de_de/strings.po | 16 +- .../resource.language.fr_fr/strings.po | 4 +- .../resource.language.hr_hr/strings.po | 227 +++++++++--------- .../resource.language.it_it/strings.po | 24 +- .../resource.language.sv_se/strings.po | 114 ++++----- 8 files changed, 201 insertions(+), 194 deletions(-) diff --git a/weather.multi/addon.xml b/weather.multi/addon.xml index c776c03dd..f57516b60 100644 --- a/weather.multi/addon.xml +++ b/weather.multi/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/weather.multi/changelog.txt b/weather.multi/changelog.txt index 26f1a2c97..7b4ee9cff 100644 --- a/weather.multi/changelog.txt +++ b/weather.multi/changelog.txt @@ -1,3 +1,6 @@ +v0.0.18 +- fix yahoo weather again + v0.0.17 - fix yahoo weather again diff --git a/weather.multi/lib/weather.py b/weather.multi/lib/weather.py index bf1957215..30ab46efa 100644 --- a/weather.multi/lib/weather.py +++ b/weather.multi/lib/weather.py @@ -28,6 +28,8 @@ def __init__(self, *args, **kwargs): self.search_location(mode) else: location, locationid, locationlat, locationlon = self.get_location(mode) + log('location: %s' % (location)) + log('location id: %s' % (locationid)) if locationid > 0: ycookie, ycrumb = self.get_ycreds() if not ycookie: @@ -116,7 +118,8 @@ def get_ycreds(self): match = re.search('WeatherStore":{"crumb":"(.*?)","weathers', response.text, re.IGNORECASE) if not match: match = re.search("win.YAHOO.context.crumb = '(.*?)'", response.text, re.IGNORECASE) -# match = re.search('type="hidden" name="crumb" value="(.*?)"', response.text, re.IGNORECASE) + if not match: + match = re.search('window.YAHOO.context.*?"crumb": "(.*?)"', response.text, flags=re.DOTALL) ycrumb = codecs.decode(match.group(1), 'unicode-escape') ystamp = time.time() ADDON.setSettingString('ycookie', ycookie) diff --git a/weather.multi/resources/language/resource.language.de_de/strings.po b/weather.multi/resources/language/resource.language.de_de/strings.po index c4d30da84..d3951acad 100644 --- a/weather.multi/resources/language/resource.language.de_de/strings.po +++ b/weather.multi/resources/language/resource.language.de_de/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-02-21 14:46+0000\n" +"PO-Revision-Date: 2023-02-05 23:15+0000\n" "Last-Translator: Kai Sommerfeld \n" "Language-Team: German \n" "Language: de_de\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.10.1\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" @@ -43,7 +43,7 @@ msgstr "Protokollierung" msgctxt "#32110" msgid "API key" -msgstr "API-Key" +msgstr "API-Schlüssel" msgctxt "#32111" msgid "Location 1" @@ -67,7 +67,7 @@ msgstr "Ort 5" msgctxt "#32121" msgid "Show lat/lon when searching locations" -msgstr "Beim Suchen von Orten Längen- / Breitengrad anzeigen" +msgstr "Beim Suchen von Orten Längen-/Breitengrad anzeigen" msgctxt "#32125" msgid "Download additional weather data" @@ -87,11 +87,11 @@ msgstr "Wetterkarten herunterladen" msgctxt "#32131" msgid "To get additional weather data, get an api key at: https://weatherbit.io/" -msgstr "Für zusätzliche Wetterdaten wird ein API-Key benötigt: https://weatherbit.io/" +msgstr "Für zusätzliche Wetterdaten wird ein API-Schlüssel benötigt: https://weatherbit.io/" msgctxt "#32135" msgid "To use maps, get an api key at: http://openweathermap.org/appid" -msgstr "Für Karten wird ein API-Key benötigt: http://openweathermap.org/appid" +msgstr "Für Karten wird ein API-Schlüssel benötigt: http://openweathermap.org/appid" msgctxt "#32201" msgid "Thunderstorm with light rain" @@ -211,7 +211,7 @@ msgstr "Dunst" msgctxt "#32230" msgid "Sand/dust" -msgstr "Sand / Staub" +msgstr "Sand/Staub" msgctxt "#32231" msgid "Fog" @@ -379,7 +379,7 @@ msgstr "Regen und Hagel" msgctxt "#32284" msgid "Hot" -msgstr "Heiss" +msgstr "Heiß" msgctxt "#32285" msgid "Isolated Thunderstorms" diff --git a/weather.multi/resources/language/resource.language.fr_fr/strings.po b/weather.multi/resources/language/resource.language.fr_fr/strings.po index c1c0c2a32..9cd75665f 100644 --- a/weather.multi/resources/language/resource.language.fr_fr/strings.po +++ b/weather.multi/resources/language/resource.language.fr_fr/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-06-06 13:14+0000\n" +"PO-Revision-Date: 2023-01-01 16:16+0000\n" "Last-Translator: skypichat \n" "Language-Team: French (France) \n" "Language: fr_fr\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.12.2\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" diff --git a/weather.multi/resources/language/resource.language.hr_hr/strings.po b/weather.multi/resources/language/resource.language.hr_hr/strings.po index 6b08a95ff..06ae7f02c 100644 --- a/weather.multi/resources/language/resource.language.hr_hr/strings.po +++ b/weather.multi/resources/language/resource.language.hr_hr/strings.po @@ -7,451 +7,452 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" +"PO-Revision-Date: 2023-01-15 14:15+0000\n" +"Last-Translator: gogogogi \n" +"Language-Team: Croatian \n" "Language: hr_hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" -msgstr "" +msgstr "Vremenska prognoza iz nekoliko pružatelja usluge" msgctxt "Addon Description" msgid "Weather forecast provided by Yahoo, Weatherbit and Openweathermap" -msgstr "" +msgstr "Prognoza vremena pružana od strane Yahooa, Weatherbita i Openweathermapa" msgctxt "#32101" msgid "Location setup" -msgstr "" +msgstr "Postavljanje lokacije" msgctxt "#32102" msgid "Additional" -msgstr "" +msgstr "Dodatno" msgctxt "#32103" msgid "Maps" -msgstr "" +msgstr "Karte" msgctxt "#32104" msgid "Logging" -msgstr "" +msgstr "Prijavljivanje" msgctxt "#32110" msgid "API key" -msgstr "" +msgstr "API ključ" msgctxt "#32111" msgid "Location 1" -msgstr "" +msgstr "Lokacija 1" msgctxt "#32112" msgid "Location 2" -msgstr "" +msgstr "Lokacija 2" msgctxt "#32113" msgid "Location 3" -msgstr "" +msgstr "Lokacija 3" msgctxt "#32114" msgid "Location 4" -msgstr "" +msgstr "Lokacija 4" msgctxt "#32115" msgid "Location 5" -msgstr "" +msgstr "Lokacija 5" msgctxt "#32121" msgid "Show lat/lon when searching locations" -msgstr "" +msgstr "Prikaži zamljopisnu širinu/dužinu pri pretraživanju lokacija" msgctxt "#32125" msgid "Download additional weather data" -msgstr "" +msgstr "Preuzmi dodatne podatke vremena" msgctxt "#32128" msgid "Map zoom level" -msgstr "" +msgstr "Razina uvećanja karte" msgctxt "#32129" msgid "Enable logging" -msgstr "" +msgstr "Omogući zapisisvanje" msgctxt "#32130" msgid "Download weather maps" -msgstr "" +msgstr "Preuzmi mape prognoze" msgctxt "#32131" msgid "To get additional weather data, get an api key at: https://weatherbit.io/" -msgstr "" +msgstr "Kako bi dobili dodatne podatke vremena, nabavite api ključ na: https://weatherbit.io/" msgctxt "#32135" msgid "To use maps, get an api key at: http://openweathermap.org/appid" -msgstr "" +msgstr "Za korištenje karata, nabavite api ključ na: http://openweathermap.org/appid" msgctxt "#32201" msgid "Thunderstorm with light rain" -msgstr "" +msgstr "Grmljavinsko nevrijeme sa slabom kišom" msgctxt "#32202" msgid "Thunderstorm with rain" -msgstr "" +msgstr "Grmaljavinsko nevrijeme s kišom" msgctxt "#32203" msgid "Thunderstorm with heavy rain" -msgstr "" +msgstr "Grmaljivnosko nevrijeme s jakom kišom" msgctxt "#32204" msgid "Thunderstorm with light drizzle" -msgstr "" +msgstr "Grmljavinsko nevrijeme sa slabom rosuljom" msgctxt "#32205" msgid "Thunderstorm with drizzle" -msgstr "" +msgstr "Grmljavinsko nevrijeme sa rosuljom" msgctxt "#32206" msgid "Thunderstorm with heavy drizzle" -msgstr "" +msgstr "Grmaljvinsko nevrijeme s jakom rosuljom" msgctxt "#32207" msgid "Thunderstorm with Hail" -msgstr "" +msgstr "Grmaljvinsko nevrijeme s tučom" msgctxt "#32208" msgid "Light Drizzle" -msgstr "" +msgstr "Slaba rosulja" msgctxt "#32209" msgid "Drizzle" -msgstr "" +msgstr "Rosulja" msgctxt "#32210" msgid "Heavy Drizzle" -msgstr "" +msgstr "Jaka rosulja" msgctxt "#32211" msgid "Light Rain" -msgstr "" +msgstr "Slaba kiša" msgctxt "#32212" msgid "Moderate Rain" -msgstr "" +msgstr "Umjerena kiša" msgctxt "#32213" msgid "Heavy Rain" -msgstr "" +msgstr "Jaka kiša" msgctxt "#32214" msgid "Freezing rain" -msgstr "" +msgstr "Ledena kiša" msgctxt "#32215" msgid "Light shower rain" -msgstr "" +msgstr "Slab pljusak" msgctxt "#32216" msgid "Shower rain" -msgstr "" +msgstr "Pljusak" msgctxt "#32217" msgid "Heavy shower rain" -msgstr "" +msgstr "Jaki pljuskovi" msgctxt "#32218" msgid "Light snow" -msgstr "" +msgstr "Slab snijeg" msgctxt "#32219" msgid "Snow" -msgstr "" +msgstr "Snijeg" msgctxt "#32220" msgid "Heavy snow" -msgstr "" +msgstr "Jak snijeg" msgctxt "#32221" msgid "Mix snow/rain" -msgstr "" +msgstr "Mješoviti snijeg/kiša" msgctxt "#32222" msgid "Sleet" -msgstr "" +msgstr "Susnježica" msgctxt "#32223" msgid "Heavy sleet" -msgstr "" +msgstr "Jaka susnježica" msgctxt "#32224" msgid "Snow shower" -msgstr "" +msgstr "Snježni pljusak" msgctxt "#32225" msgid "Heavy snow shower" -msgstr "" +msgstr "Jak snježni pljusak" msgctxt "#32226" msgid "Flurries" -msgstr "" +msgstr "Nalet vjetra" msgctxt "#32227" msgid "Mist" -msgstr "" +msgstr "Magla" msgctxt "#32228" msgid "Smoke" -msgstr "" +msgstr "Dim" msgctxt "#32229" msgid "Haze" -msgstr "" +msgstr "Izmaglica" msgctxt "#32230" msgid "Sand/dust" -msgstr "" +msgstr "Pijesak/Prašina" msgctxt "#32231" msgid "Fog" -msgstr "" +msgstr "Magla" msgctxt "#32232" msgid "Freezing fog" -msgstr "" +msgstr "Smrznuta magla" msgctxt "#32233" msgid "Clear sky" -msgstr "" +msgstr "Vedro nebo" msgctxt "#32234" msgid "Few clouds" -msgstr "" +msgstr "Nekoliko oblaka" msgctxt "#32235" msgid "Scattered clouds" -msgstr "" +msgstr "Mjestimična naoblaka" msgctxt "#32236" msgid "Broken clouds" -msgstr "" +msgstr "Isprekidani oblaci" msgctxt "#32237" msgid "Overcast clouds" -msgstr "" +msgstr "Naoblačenje" msgctxt "#32238" msgid "Unknown Precipitation" -msgstr "" +msgstr "Nepoznata oborina" msgctxt "#32251" msgid "Tornado" -msgstr "" +msgstr "Tornado" msgctxt "#32252" msgid "Tropical Storm" -msgstr "" +msgstr "Tropska oluja" msgctxt "#32253" msgid "Hurricane" -msgstr "" +msgstr "Uragan" msgctxt "#32254" msgid "Severe Thunderstorms" -msgstr "" +msgstr "Jake grmljavinske oluje" msgctxt "#32255" msgid "Thunderstorms" -msgstr "" +msgstr "Grmljavinska nevremena" msgctxt "#32256" msgid "Mixed Rain and Snow" -msgstr "" +msgstr "Susnježica" msgctxt "#32257" msgid "Mixed Rain and Sleet" -msgstr "" +msgstr "Mješovita kiša i susnježica" msgctxt "#32258" msgid "Mixed Snow and Sleet" -msgstr "" +msgstr "Mješoviti snijeg i susnježica" msgctxt "#32259" msgid "Freezing Drizzle" -msgstr "" +msgstr "Ledena rosulja" msgctxt "#32260" msgid "Drizzle" -msgstr "" +msgstr "Rosulja" msgctxt "#32261" msgid "Freezing Rain" -msgstr "" +msgstr "Ledena kiša" msgctxt "#32262" msgid "Showers" -msgstr "" +msgstr "Pljuskovi" msgctxt "#32263" msgid "Rain" -msgstr "" +msgstr "Kiša" msgctxt "#32264" msgid "Snow Flurries" -msgstr "" +msgstr "Snježni naleti" msgctxt "#32265" msgid "Light Snow Showers" -msgstr "" +msgstr "Slabi snježni pljuskovi" msgctxt "#32266" msgid "Blowing Snow" -msgstr "" +msgstr "Snježni napuh" msgctxt "#32267" msgid "Snow" -msgstr "" +msgstr "Snijeg" msgctxt "#32268" msgid "Hail" -msgstr "" +msgstr "Tuča" msgctxt "#32269" msgid "Sleet" -msgstr "" +msgstr "Susnježica" msgctxt "#32270" msgid "Dust" -msgstr "" +msgstr "Prašina" msgctxt "#32271" msgid "Foggy" -msgstr "" +msgstr "Maglovito" msgctxt "#32272" msgid "Haze" -msgstr "" +msgstr "Izmaglica" msgctxt "#32273" msgid "Smoky" -msgstr "" +msgstr "Zadimljeno" msgctxt "#32274" msgid "Blustery" -msgstr "" +msgstr "Vjetrovito" msgctxt "#32275" msgid "Windy" -msgstr "" +msgstr "Vjetrovito" msgctxt "#32276" msgid "Cold" -msgstr "" +msgstr "Hladno" msgctxt "#32277" msgid "Cloudy" -msgstr "" +msgstr "Oblačno" msgctxt "#32278" msgid "Mostly Cloudy" -msgstr "" +msgstr "Pretežno oblačno" msgctxt "#32279" msgid "Partly Cloudy" -msgstr "" +msgstr "Djelomično oblačno" msgctxt "#32280" msgid "Clear" -msgstr "" +msgstr "Vedro" msgctxt "#32281" msgid "Sunny" -msgstr "" +msgstr "Sunčano" msgctxt "#32282" msgid "Fair" -msgstr "" +msgstr "Vedro" msgctxt "#32283" msgid "Mixed Rain and Hail" -msgstr "" +msgstr "Mješovita kiša i tuča" msgctxt "#32284" msgid "Hot" -msgstr "" +msgstr "Vrućina" msgctxt "#32285" msgid "Isolated Thunderstorms" -msgstr "" +msgstr "Izolirana grmljavinska nevremena" msgctxt "#32286" msgid "Scattered Thunderstorms" -msgstr "" +msgstr "Mjestimična grmljavinska nevremena" msgctxt "#32287" msgid "Scattered Showers" -msgstr "" +msgstr "Mjestimični pljuskovi" msgctxt "#32288" msgid "Heavy Rain" -msgstr "" +msgstr "Pljusak" msgctxt "#32289" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Mjestimice snježni pljuskovi" msgctxt "#32290" msgid "Heavy Snow" -msgstr "" +msgstr "Jak snijeg" msgctxt "#32291" msgid "Blizzard" -msgstr "" +msgstr "Mećava" msgctxt "#32292" msgid "Not Available" -msgstr "" +msgstr "Nedostupno" msgctxt "#32293" msgid "Scattered Showers" -msgstr "" +msgstr "Mjestimični pljuskovi" msgctxt "#32294" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Mjestimice snježni pljuskovi" msgctxt "#32295" msgid "Scattered Thundershowers" -msgstr "" +msgstr "Mjestimice pljuskovi s grmljavinom" msgctxt "#32300" msgid "New Moon" -msgstr "" +msgstr "Mladi mjesec" msgctxt "#32301" msgid "Waxing Crescent" -msgstr "" +msgstr "Rastući polumjesec" msgctxt "#32302" msgid "First Quarter" -msgstr "" +msgstr "Prva četvrtina" msgctxt "#32303" msgid "Waxing Gibbous" -msgstr "" +msgstr "Padajući polumjesec" msgctxt "#32304" msgid "Full Moon" -msgstr "" +msgstr "Pun mjesec" msgctxt "#32305" msgid "Waning Gibbous" -msgstr "" +msgstr "Opadajući polumjesec" msgctxt "#32306" msgid "Last Quarter" -msgstr "" +msgstr "Zadnja četvrtina" msgctxt "#32307" msgid "Waning Crescent" -msgstr "" +msgstr "Mlađak" diff --git a/weather.multi/resources/language/resource.language.it_it/strings.po b/weather.multi/resources/language/resource.language.it_it/strings.po index bedf0854e..f7cf4d550 100644 --- a/weather.multi/resources/language/resource.language.it_it/strings.po +++ b/weather.multi/resources/language/resource.language.it_it/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-10-25 17:57+0000\n" +"PO-Revision-Date: 2023-01-26 18:15+0000\n" "Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" @@ -15,15 +15,15 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.14.1\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" -msgstr "Previsioni meteo di diversi fornitori" +msgstr "Previsioni del tempo da diversi fornitori" msgctxt "Addon Description" msgid "Weather forecast provided by Yahoo, Weatherbit and Openweathermap" -msgstr "Previsioni meteo fornite da Yahoo, Weatherbit e Openweathermap" +msgstr "Previsioni del tempo fornite da Yahoo, Weatherbit e Openweathermap" msgctxt "#32101" msgid "Location setup" @@ -39,7 +39,7 @@ msgstr "Mappe" msgctxt "#32104" msgid "Logging" -msgstr "Logging" +msgstr "Registra log" msgctxt "#32110" msgid "API key" @@ -71,7 +71,7 @@ msgstr "Mostra lat/lon durante la ricerca della posizione" msgctxt "#32125" msgid "Download additional weather data" -msgstr "Scarica dati meteo aggiuntivi" +msgstr "Scarica ulteriori dati meteorologici" msgctxt "#32128" msgid "Map zoom level" @@ -79,7 +79,7 @@ msgstr "Livello di zoom della mappa" msgctxt "#32129" msgid "Enable logging" -msgstr "Abilita logging" +msgstr "Abilita registrazione log" msgctxt "#32130" msgid "Download weather maps" @@ -87,11 +87,11 @@ msgstr "Scarica mappe meteorologiche" msgctxt "#32131" msgid "To get additional weather data, get an api key at: https://weatherbit.io/" -msgstr "Per visualizzare dati extra, ottieni una chiave API su: https://weatherbit.io/" +msgstr "Per ottenere ulteriori dati meteorologici, ottieni una chiave API su: https://weatherbit.io/" msgctxt "#32135" msgid "To use maps, get an api key at: http://openweathermap.org/appid" -msgstr "Per utilizzare le mappe, ottieni una chiave API su: http://openweathermap.org/appid" +msgstr "Per usare le mappe, ottieni una chiave API su: http://openweathermap.org/appid" msgctxt "#32201" msgid "Thunderstorm with light rain" @@ -211,7 +211,7 @@ msgstr "Foschia" msgctxt "#32230" msgid "Sand/dust" -msgstr "Sabbia o polvere" +msgstr "Sabbia/polvere" msgctxt "#32231" msgid "Fog" @@ -431,7 +431,7 @@ msgstr "Luna nuova" msgctxt "#32301" msgid "Waxing Crescent" -msgstr "Luna crescente" +msgstr "Crescente" msgctxt "#32302" msgid "First Quarter" @@ -455,4 +455,4 @@ msgstr "Ultimo quarto" msgctxt "#32307" msgid "Waning Crescent" -msgstr "Luna calante" +msgstr "Calante" diff --git a/weather.multi/resources/language/resource.language.sv_se/strings.po b/weather.multi/resources/language/resource.language.sv_se/strings.po index a02a00e46..31b6c1fbe 100644 --- a/weather.multi/resources/language/resource.language.sv_se/strings.po +++ b/weather.multi/resources/language/resource.language.sv_se/strings.po @@ -7,15 +7,15 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-01-19 10:13+0000\n" -"Last-Translator: Luna Jernberg \n" +"PO-Revision-Date: 2023-03-23 20:16+0000\n" +"Last-Translator: Sopor \n" "Language-Team: Swedish \n" "Language: sv_se\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.10.1\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" @@ -43,7 +43,7 @@ msgstr "Loggning" msgctxt "#32110" msgid "API key" -msgstr "API nyckel" +msgstr "API-nyckel" msgctxt "#32111" msgid "Location 1" @@ -67,7 +67,7 @@ msgstr "Plats 5" msgctxt "#32121" msgid "Show lat/lon when searching locations" -msgstr "" +msgstr "Visa lat/lon när du söker efter platser" msgctxt "#32125" msgid "Download additional weather data" @@ -75,7 +75,7 @@ msgstr "Ladda ner ytterligare väderdata" msgctxt "#32128" msgid "Map zoom level" -msgstr "" +msgstr "Kartans zoomnivå" msgctxt "#32129" msgid "Enable logging" @@ -87,7 +87,7 @@ msgstr "Ladda ner väderkartor" msgctxt "#32131" msgid "To get additional weather data, get an api key at: https://weatherbit.io/" -msgstr "För att få ytterligare väderdata, skaffa en api-nyckel på: https://weatherbit.io/" +msgstr "För att få ytterligare väderdata, skaffa en api-nyckel på: https://weatherbit.io" msgctxt "#32135" msgid "To use maps, get an api key at: http://openweathermap.org/appid" @@ -247,183 +247,183 @@ msgstr "Okänd nederbörd" msgctxt "#32251" msgid "Tornado" -msgstr "" +msgstr "Tornado" msgctxt "#32252" msgid "Tropical Storm" -msgstr "" +msgstr "Tropisk storm" msgctxt "#32253" msgid "Hurricane" -msgstr "" +msgstr "Orkan" msgctxt "#32254" msgid "Severe Thunderstorms" -msgstr "" +msgstr "Kraftiga åskoväder" msgctxt "#32255" msgid "Thunderstorms" -msgstr "" +msgstr "Åska" msgctxt "#32256" msgid "Mixed Rain and Snow" -msgstr "" +msgstr "Blandat regn och snö" msgctxt "#32257" msgid "Mixed Rain and Sleet" -msgstr "" +msgstr "Blandat regn och snöslask" msgctxt "#32258" msgid "Mixed Snow and Sleet" -msgstr "" +msgstr "Blandat snö och slask" msgctxt "#32259" msgid "Freezing Drizzle" -msgstr "" +msgstr "Frysande duggregn" msgctxt "#32260" msgid "Drizzle" -msgstr "" +msgstr "Duggregn" msgctxt "#32261" msgid "Freezing Rain" -msgstr "" +msgstr "Frysande regn" msgctxt "#32262" msgid "Showers" -msgstr "" +msgstr "Duschar" msgctxt "#32263" msgid "Rain" -msgstr "" +msgstr "Regn" msgctxt "#32264" msgid "Snow Flurries" -msgstr "" +msgstr "Snöbyar" msgctxt "#32265" msgid "Light Snow Showers" -msgstr "" +msgstr "Lätta snöskurar" msgctxt "#32266" msgid "Blowing Snow" -msgstr "" +msgstr "Vinddriven snö" msgctxt "#32267" msgid "Snow" -msgstr "" +msgstr "Snö" msgctxt "#32268" msgid "Hail" -msgstr "" +msgstr "Hagel" msgctxt "#32269" msgid "Sleet" -msgstr "" +msgstr "Snöblandat regn" msgctxt "#32270" msgid "Dust" -msgstr "" +msgstr "Damm" msgctxt "#32271" msgid "Foggy" -msgstr "" +msgstr "Dimmig" msgctxt "#32272" msgid "Haze" -msgstr "" +msgstr "Dis" msgctxt "#32273" msgid "Smoky" -msgstr "" +msgstr "Rökig" msgctxt "#32274" msgid "Blustery" -msgstr "" +msgstr "Blåsigt" msgctxt "#32275" msgid "Windy" -msgstr "" +msgstr "Blåsigt" msgctxt "#32276" msgid "Cold" -msgstr "" +msgstr "Kallt" msgctxt "#32277" msgid "Cloudy" -msgstr "" +msgstr "Molnig" msgctxt "#32278" msgid "Mostly Cloudy" -msgstr "" +msgstr "Mestadels molnigt" msgctxt "#32279" msgid "Partly Cloudy" -msgstr "" +msgstr "Delvis molnigt" msgctxt "#32280" msgid "Clear" -msgstr "" +msgstr "Klart" msgctxt "#32281" msgid "Sunny" -msgstr "" +msgstr "Soligt" msgctxt "#32282" msgid "Fair" -msgstr "" +msgstr "Vackert" msgctxt "#32283" msgid "Mixed Rain and Hail" -msgstr "" +msgstr "Blandat regn och hagel" msgctxt "#32284" msgid "Hot" -msgstr "" +msgstr "Varmt" msgctxt "#32285" msgid "Isolated Thunderstorms" -msgstr "" +msgstr "Isolerade åskväder" msgctxt "#32286" msgid "Scattered Thunderstorms" -msgstr "" +msgstr "Spridda åskväder" msgctxt "#32287" msgid "Scattered Showers" -msgstr "" +msgstr "Spridda skurar" msgctxt "#32288" msgid "Heavy Rain" -msgstr "" +msgstr "Mycket regn" msgctxt "#32289" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Spridda snöskurar" msgctxt "#32290" msgid "Heavy Snow" -msgstr "" +msgstr "Kraftigt snöfall" msgctxt "#32291" msgid "Blizzard" -msgstr "" +msgstr "Snöstorm" msgctxt "#32292" msgid "Not Available" -msgstr "" +msgstr "Inte tillgänglig" msgctxt "#32293" msgid "Scattered Showers" -msgstr "" +msgstr "Spridda skurar" msgctxt "#32294" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Spridda snöskurar" msgctxt "#32295" msgid "Scattered Thundershowers" -msgstr "" +msgstr "Spridda åskskurar" msgctxt "#32300" msgid "New Moon" @@ -431,15 +431,15 @@ msgstr "Ny måne" msgctxt "#32301" msgid "Waxing Crescent" -msgstr "" +msgstr "Vaxande Crescent" msgctxt "#32302" msgid "First Quarter" -msgstr "Första kvartalet" +msgstr "Första kvarten" msgctxt "#32303" msgid "Waxing Gibbous" -msgstr "" +msgstr "Vaxande Gibbous" msgctxt "#32304" msgid "Full Moon" @@ -447,11 +447,11 @@ msgstr "Fullmåne" msgctxt "#32305" msgid "Waning Gibbous" -msgstr "" +msgstr "Avtagande Gibbous" msgctxt "#32306" msgid "Last Quarter" -msgstr "Sista kvartalet" +msgstr "Tredje kvartalet" msgctxt "#32307" msgid "Waning Crescent" From 9db6bfe3888e326a628fb19b4fca8c3d78775389 Mon Sep 17 00:00:00 2001 From: jbinkley60 <63779136+jbinkley60@users.noreply.github.com> Date: Tue, 28 Mar 2023 09:50:19 -0400 Subject: [PATCH 018/145] [service.autostop] 1.0.6 --- service.autostop/addon.xml | 2 +- service.autostop/changelog.txt | 5 +++++ service.autostop/common.py | 4 ++++ .../language/resource.language.en_gb/strings.po | 10 +++++++++- service.autostop/resources/settings.xml | 5 +++++ 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/service.autostop/addon.xml b/service.autostop/addon.xml index e2f58d4de..4068affdd 100644 --- a/service.autostop/addon.xml +++ b/service.autostop/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/service.autostop/changelog.txt b/service.autostop/changelog.txt index 0e53200fe..6a58a3837 100644 --- a/service.autostop/changelog.txt +++ b/service.autostop/changelog.txt @@ -1,3 +1,8 @@ +1.0.6 + +- Added option setting to reset sleep timer back to 0 after sleep + timer stops playback. + 1.0.5 - Added 300 and 600 second options for playback stop notification. diff --git a/service.autostop/common.py b/service.autostop/common.py index 239eaa510..eb6e74eae 100644 --- a/service.autostop/common.py +++ b/service.autostop/common.py @@ -156,6 +156,10 @@ def stopPlayback(notifymsg, logmsg): # Function to st dialog.notification(notifymsg, mgenlog, addon_icon, 5000) if settings('screensaver') == 'true': # Active screensaver if option selected xbmc.executebuiltin('ActivateScreensaver') + if settings('asreset') == 'true': # Reset sleep timer if option selected + settings('plstop', '0') + mgenlog = "Autosop sleep timer reset enabled. Sleep timer reset to 0." + xbmc.log(mgenlog, xbmc.LOGINFO) settings('notifyset', 'no') # Clear notification flag settings('varextnotify', 'no') # Clear notification flag except: diff --git a/service.autostop/resources/language/resource.language.en_gb/strings.po b/service.autostop/resources/language/resource.language.en_gb/strings.po index 0950278b8..22a8ffdd4 100644 --- a/service.autostop/resources/language/resource.language.en_gb/strings.po +++ b/service.autostop/resources/language/resource.language.en_gb/strings.po @@ -104,6 +104,10 @@ msgctxt "#30321" msgid "Autostop sleep timer and notification timer cannot be equal. Notification timer set to 300 seconds. " msgstr "" +msgctxt "#30322" +msgid "Sleep Timer Reset" +msgstr "" + msgctxt "#30501" msgid "Automatically stop paused video or music in minutes. 0 = never automatically stop paused playback." msgstr "" @@ -134,4 +138,8 @@ msgstr "" msgctxt "#30508" msgid "Adds option to stop playback when the sleep timer extension option is set to variable. Default is disabled." -msgstr "" \ No newline at end of file +msgstr "" + +msgctxt "#30509" +msgid "Enabling resets sleep timer back to 0 after playback stopped by sleep timer. Default is disabled." +msgstr "" diff --git a/service.autostop/resources/settings.xml b/service.autostop/resources/settings.xml index f09f8479b..d7da977f1 100644 --- a/service.autostop/resources/settings.xml +++ b/service.autostop/resources/settings.xml @@ -101,6 +101,11 @@ + + 0 + false + + 0 false From 878c734aaf575e25c6f5b4d1affc36847889c221 Mon Sep 17 00:00:00 2001 From: jbinkley60 <63779136+jbinkley60@users.noreply.github.com> Date: Tue, 28 Mar 2023 10:12:50 -0400 Subject: [PATCH 019/145] [service.autostop] 1.0.6 --- service.autostop/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service.autostop/common.py b/service.autostop/common.py index eb6e74eae..7882396ab 100644 --- a/service.autostop/common.py +++ b/service.autostop/common.py @@ -158,7 +158,7 @@ def stopPlayback(notifymsg, logmsg): # Function to st xbmc.executebuiltin('ActivateScreensaver') if settings('asreset') == 'true': # Reset sleep timer if option selected settings('plstop', '0') - mgenlog = "Autosop sleep timer reset enabled. Sleep timer reset to 0." + mgenlog = "Autostop sleep timer reset enabled. Sleep timer reset to 0." xbmc.log(mgenlog, xbmc.LOGINFO) settings('notifyset', 'no') # Clear notification flag settings('varextnotify', 'no') # Clear notification flag From 29c99845a40cbea9989fca7a203dffbf1a3886b1 Mon Sep 17 00:00:00 2001 From: "Paul J. Ghosh" Date: Sun, 2 Apr 2023 13:27:24 -0700 Subject: [PATCH 020/145] [script.wadeysay] 0.0.11 --- script.wadeysay/LICENSE.txt | 674 ++++++++++++++++++ script.wadeysay/addon.py | 27 + script.wadeysay/addon.xml | 25 + script.wadeysay/resources/icon-512x512.png | Bin 0 -> 31147 bytes .../resource.language.en_gb/strings.po | 82 +++ script.wadeysay/resources/settings.xml | 62 ++ script.wadeysay/wadeysay.py | 60 ++ script.wadeysay/wadeysay_conf.py | 52 ++ script.wadeysay/wadeysay_logic.py | 137 ++++ script.wadeysay/wadeysay_xbmc.py | 97 +++ 10 files changed, 1216 insertions(+) create mode 100644 script.wadeysay/LICENSE.txt create mode 100644 script.wadeysay/addon.py create mode 100644 script.wadeysay/addon.xml create mode 100644 script.wadeysay/resources/icon-512x512.png create mode 100644 script.wadeysay/resources/language/resource.language.en_gb/strings.po create mode 100644 script.wadeysay/resources/settings.xml create mode 100644 script.wadeysay/wadeysay.py create mode 100644 script.wadeysay/wadeysay_conf.py create mode 100644 script.wadeysay/wadeysay_logic.py create mode 100644 script.wadeysay/wadeysay_xbmc.py diff --git a/script.wadeysay/LICENSE.txt b/script.wadeysay/LICENSE.txt new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/script.wadeysay/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/script.wadeysay/addon.py b/script.wadeysay/addon.py new file mode 100644 index 000000000..77235750e --- /dev/null +++ b/script.wadeysay/addon.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Copyright (C) 2023 iCR8IONS LLC www.icr8ions.com +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# part of an addon called script.wadyasay for Kodi - https://kodi.tv + +# pylint: disable=C0103 + +""" entry point invoked by Kodi """ + +from wadeysay import wadeysay + +wadeysay() diff --git a/script.wadeysay/addon.xml b/script.wadeysay/addon.xml new file mode 100644 index 000000000..1079bb3df --- /dev/null +++ b/script.wadeysay/addon.xml @@ -0,0 +1,25 @@ + + + + + + + + video executable + + + wadeysay + What Did They Say? +This addon will rewind the video and play it with subtitles. Use it when you could not hear or understand what was just said. How much to rewind and which subtitle is selected is configurable. +NOTE: use Keymap Editor to map desired input or edit keymap file (fullscreenvideo -> runaddon) + GPL-3.0-or-later + all + https://forum.kodi.tv/showthread.php?tid=372702 + https://www.icr8ions.com/creations/wadeysay + support@icr8ions.com + + + resources/icon-512x512.png + + + diff --git a/script.wadeysay/resources/icon-512x512.png b/script.wadeysay/resources/icon-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..5166e2d06ea58c80ce5e083b5aa1912209edbb6e GIT binary patch literal 31147 zcmce8^kmASHRzN=mm%2#6w$sD#obAWA6R-QCT* zhx2^@h4+W^@f^?GGuK?P_u6Z%J+D-hWUpSKyn;fZuFA_vtD#UA;9oDGE@QzT+wR?m z@CS~AoQ@L;g?khE2gCL89pn-U=Lg!(>h>1SZpP2eQEqN-oKNj+oJ@@!%sK6!TPClH zQle0_D0%67kKI$2Q_=1u8og)AZlAuc;b2Hzqb2P9j1}`};L>C1L_e1FY}#;oP6_M> zsrRTbsLUIU;~zYE*^-5Snf}7B>R<0J)h9+rM=+X={qy$m<(_z8zR+Ez@#)8r*Sonb z(XHy|dDU~huIlDpMb!DfSrHJR$b*c@f8tDFpw9mnohZr(`5Wc{ z?DI>e0@hJ}#_%^Ogw!bbEq6F^Jthh+2y&EiN7W*KqjdTI_f4)N!|x`@?7IBo#f$N^ zHQy0GKh*l(9=4&Op@XC23-~Yi1A~T!W_^7f=6-LCqhV}}1`i7p=A52{jO=u^M(goo zNptgC@$vDJwzeE3BqZm5kdodrHl~9sr0(6T+c`U0?8!4K(dAph3^Hy+rfB{$Ji@9s zpMuw>7cWV`9{*7?e<0RXO38+xs~M`9GM(x7FfZfaU}UNq3asU8vOW3!{L*tLCpr<4 z8_%CVAODrW7M+-g#mdSWos@JXCnrbc$rDAY1mibn#wgSW{5tOTm!Cc{^V*NzgnOS> z;Chdo;p5?bh|IoyaB$FvjVX{68++k8mq9>i=#|9~yeVE}aURq2@{*XCn564hxOP^1 zdxpGv^@87aaDKJOO)MrM;gW0=bzozow48#%%S_p*`h|a=4(2Wesbau-hSU1^_;hC6 z4<6H>7jap~-`i}Ge>jN1$Uus!xx zuX-PDzbLgGGVo20?263KXYa3Y<60gnBiLOX!EKJBnG?B$r%r%ulCrvI{P&w9sfrBO zkM`CG>gwvci{B)xsHt5D#;5urPTOB*Pa~lY*S&yE=Y$EP;5Mp7&5zYcY%dQG|8QNo zV)6B@Fj=NwQWB-0$2QANK?ju2$&OZku_<k|#e z>*ICfv$HZ(uT)T`PxIdM=XYFg2B}_x6~TWXEqyWkrqDGLQ_~EsB7cRv!8#Q`JU%`i?~;nX<;l#@g;2 zb>sQ~9Q=bm9}NvsGc&W=rm*X0W}2F0W)>D|vLsBjv?zK8277B*gYxon71_suxw*IZ zCxU5=7XE%*Z{w<254a!BiHx1?_~gX+S3E1X`7e@?(9rjh41s_Ds>#X8`Kf@OT zL<<8^N)x~O{rmUsE;*j$Kb_y6s?T?3G`JuKjYIdFL$)##Gc$9;-;WO`zIKTFPfnV^ z>N-)u>i$UA`D(#!JIL!k`_{5{Y%EPU(q!Lrce4D)52?qGN#IqUoHaf#vl~f=kkj22 zz{1M(TTLEvK*O&5rb3ZEs%!y*@Sp#7a9 zL`?0qes58bzhNw`?>ZdR&hJihOa3oMt32;ZN}^oyJ&Nte#NF4b_Ke^h9jBl&g|McX@|MlzZF6_y2ii!c3aLH;RhVr44{f!qT6E)OfuO9oJt(_SwDd8`^-Q0YB zyznW_VfOdi{#*^VO&`-HXD6oyhzJwdG+utMUcKtBc>M_0dh++%yImtAsg-BipQ1%k zOX)v;{FsE@!Nb7de^}}9kn>5o-@`=qy8eFc?Trn(wY!>PH~6dr;+P)Qm)P`~z|`#& zy6OG>_YX~5YfXnn_0~DNxHLWemu2kXA-sd$R@P=G8-{2oes;V?PC+3*s>L2*@s$FC zUli_j&h8x)->qAh(!4h1ogE$F?!9!k2x^5xWHO0NO-(n3zdLo${gH@y^CrY;_V+}X z_z`o248tx2T{z((Z{NP{u2_5|FE5YmviGfK^lMzb8H@zAgWp}QpH5GkEpAP(Wmn9X zJsXIvjM6?@|5+yq8+?cJm^n5!*5U65c~L?mb9rjN64SMsGar31BbUu-d9R%wtphG^ zP3`N~uiq4P=jPNa#lyXFCEIOf%<*{N5dtnPnx@#53tko9wkMa=Zn!+=P&6bYq^YTi z{QC7^IFj^h*L!(fV7g(_hD&X4=oV-$>YoY^mD(b4G`bBctoxTc1N zYTD6yOALdc%i`nh-CZX5J^C5kyFE?9P@t$pQ%h^AJ`lI7qa&))Ub`Yr6lH_`qr7|^ zmT3d_zz61v`g*A+U(9e^SBKwLDr?X6_Vkd#{5e9z*4EQ|=<$S>es*SN0+#yV097gu z4|iD|uk+`jqkFME4S7I3h1>W-&GkQve_LAQy!J-iTCrO~LLgfHNgRiw@B(yn`D&nt7xUtRsksh^D>k7j-vL z`R%Z@b#RQ0A3V6!+L{L;@HM;6%L2VJrZwC|jrUzvjj%0aBv|we3?jc;{FzL<)UOAt z(i5Zq!?_OfbZkogm#<$P+f#(dNl2te3E0`%IQ4%RJ$Z7ox4S#~rdCLw!Hw`&ujtlr zHQkU`O9$WpGnY1PoCTZU-Cl}|dorI*(AHcBbFzARRu^s$y<*6%uDWYa}&<}e(V3>!Gk0kr;rf%Q8NZ6R`ecb9&Rh*U65BPM~T&H$?+z46B#Ds*W9>;VBo^srrocNfSn5{=IZY7AK9*$>5iRT`$ zJ)CP#ZFoh@ycw8gZqE&HAtVHwfVz>4LpQpwJ(m-%zs3A0Dd6MBk4Y)q?x&848p>K)S}8(KSy@H+ zWTd1Mu#;PDEHz-B*aiSYjt5=6!7C&`Jv+O3y+vD-0iF^LL8xo{zz+#J5MI$M`L|)M zZwUiB`u*#d+Q|nM9i3NOvwx<>4s;T0?M8k~Kp@tTXkU_p@US{k0V7m+4YzNFP+{WY zQnJYG524>Encuc$$y~>>*NA)kgM1t}7nkymDfPx+x-Ue|X_v2R5RR@auB=4Z^c8BH zTvXB44gokLo!KR4aJTJC-?RSDbU&M#a(s^ah~Vr~Q&S_qfe>_soRlv3$51quS?*yXjsH~44b9^`@rA1wr$!k`o$l*Omg}wG2dTQ8V_XI*{r7ub_9}rnu zS_(sAq*;4ZWu<84TJ=$jjYS~byjMN0^}}JKxC;#~&Xp_lMX${V4hH~CDJm$atsJY! z0*Y^cdpFpZ?3*F%)E#aXmdlVKa~JPJ~$`Rin%LD3hZ!gBh#&X}e6I*FeY5)Vb zbr`RGp{=c*Jy@p)a}y=DOO8%uZ~N8P+>8yU{QclTW+V)L`QIl3bXEQz_{G}zbZeZ3 zcggB^R;gDgQB_ zqk`LWDZ)zcL|+*j8&8*f@r@Nl9ZA6Y*;PKD3B8Ry4i71Q_?mN??+bgL#8oWJ>W!Z_ za+Np}lafML21^)<5>8SfHlZr_Mm>wm%e50Q*FL5B)YsNZZc@U_l${*yHA5+)(SAQ9 z1Y+$>$Cagrn<%BV&&Ca(D=VKI)>)M3I-VXM9LGzvec`_W!2*hlSRe7+%+H?*J$Du# z7%<~r7QQ^*jSt8j#{YrF43d|ibvMiAp>|@4#K_3V2H>zbAA{UXh}LkF6%Cjl($qes zlJKd#z2yvugc6e3Lj#(&FS{#nb~QXTK7aXgO*WkTo9`m~YiHX7qI4mHt6gAaR~^?N|$g*snl4$*iq*cj5W*bY}rO^F?~f`mun%VpI>PQGoJekFRQ1gXTS44K}_G=MR=q(r5KOP>QH_6FtJEFnvE2MSC4MFgOarl88jmJFQLRqsWWK<~pD)|%52X5Fx z&1GR`CMPxqX{P01)N}1tQOAp01mh0)l)Q3>+tqBE`QvWKuu}>EzBY$l=TZ<`qoap7 zYYbtaWywheraZpNW2Zhg_F4{hEpwXJOPS1=^P3M*5D~qAe3;;IdSCkYpFd5zD?@R8 zbAB)u@(SmLmyiwB+>X&(voU>5U)XK(GBPsWym`a20|4mF+qbXadCWx}b&Le#gh4?; zCc3&w-BdoX6Q^B@+1q;iV0JXbSySTU8|@`q6GZ(+mf*ZFE2Tu2#_1JkdTlgaZ(TCc zNz}+qOQTsGDpMXr7e_)Vp88M_O%FDy?Bay4ns(9n&&wK1-p z-fDAj83Kx{ITSO<*%(6CoF3Y|n+`VD`BV%A@tcH%TPrt1L);;9 z3Zxb#U`QZ|G$~plBM0B6ICA>VYA$o@NsmN0=FHxADn7+m@ z><<@!3MtOYk{SF?O5_NI>9os0%ru6x{n_cs$CVEh6chkKlnjXB(bQgt3!grw=q<5u zaLfc>uzfA+S9q0x00~g6A{LI0Jm;VknS3#1tI7*C_d4z_>r}T{C&LZ%2A=(_^4wDx zptG^Daok^@IG@wSM-Z>sv;b~LDeTOG))!6` z^;=yYEXn)!_7sZohO!K}(Dob5w%Xj~7TEJ4A(uCQINwI2^cQAkZrN5ZLcq;L4(lU0 zth>`@?zB9G%EaR)kRN!$1G$WIIibLz=5f#sL;}p z0$I3)&|Q}s%cXC@d`|7YX-zuVgrzhwSN5sIs%hPm}bvU$`^A^Mrh@DTUYWAr(M zdng-=P1^_1CQ9Oz#T;9&#F`W>2JaAQ0*~hr5YYN{Ktbf#8hdM+Z$WMoHC+uQvYKl? z)a@BiY5sTVG!zQOrKOs`(3C_x{QQZPOsR6ze%%lkOws7?>-ZW^o`l;DexoabE!#_U zGBkF|H1XFr0_Y07t5n`ilCVR>p7f(@)}ZRZ1EV7f)lzEq7&N z!;(%=S*?v$iPl|&?I82BvC#;yT|k?J2^uX_iqw5fw^N_f(+UU(0RFuT{K#dFPmt08 zUt$4|7#qt2tZf+s8yhYm5f&afZ6*8H0X!-Z*MRbJL7diQ;!V|%-s+RxAvKvOVkSk} zqCj}Z0ba_8a?@sf);UM%#@0CIxISq{H0n`AWMtx<=545oT5ODU5?wSK>g(5mG`+@o z77`d3*nX&qLZkk`Z`G;=Qs2Fc1jsSH^BE50SJR*2F%AbcKjGrmCAw%)Ka1-1dfa-E zS4}2$Q1r+3)qi1cyMUk?WTF^k!fA_SOGL zSO~54uBA9R?H4xhVH?exUPILZ~K6U+T7aWVPOfWq)vbUkOWwoWE2M>cQ%D# zZ|DqdZ*4WSz2)T(eger@2q!{C7JZz<<=j&T{pHD94}S6w^C$YiVaE1i|T$<{f~K;7X~gsNL~UL~#cT2e2oy>s;vS z>IxlVpbx(xfDa`zBM$^3y!%a1WoAIMgAk9MF#{B(A23buGNuH{LI@D@8xM0kdzf=XZt}~l~PrW zX?%?6DZuL7f;G=Dtnra*1IllFa`J*+>9ZJOMeOJ(De0Bog5-6>GyAF?GBg#ecD}HO zyStIKb?&;p9}xO@xVQ{OvO)Nc*yF%720$IjVwV;ZgE7?{6%54ps~ltss#Ns!aD{|~ zxIMP5GG>6JLpcXV51>F6P}>bXk`7}sC?Z=zlJ$ng-6KVc)|;=;#oKblfW zjT4Ja_#8-ZsT-RR=8)2V$p|)SPZ>;sRk3yeHU_}-TSX6EPGgX;P5Ddg4LcG1H(*zv ztv>?weUTs#golSS7Cn%zcz4-qZ*|0>Lu`-5t_Fy5Bo8!7hbO)HV*x_Qi|A-VZpw(7 zBYP;aRWvjp67oe2MnDIK8dCiU9G?UNy)@+B3g0xBOb2$@$ zjl=r*J^5GUI_@4GQc=`m>A-CFUB$)qhXEy9Y~AMI2>kYqx7>N*8Y3fPZC9r31c(U^ zkU}KCwT+BeczJtg0Br5dQD>g-FJ_RImAwxYYC2Fh{3TqsZ@=8$c7_uB#s2>OlK1PR zq+B}(Dnb&Hi(($ze)v?vk^rAG;K&hDQeJ_G$6rzd0>e(V2zrz8rid$EB(>NT2vfJ2 zE#uc`UK`d=MM-de!wYM=0A-N>SIZ6sg^yy>Wpwf7Hhr8KLjw4xuVgE}0wUZWv?-b> zsyPi!NJywJo3oPv(i7_NiT#Z!9znr3l@>a#D}$tGr+YP1Km#B^CZYPFvT`$QSfuPY zXVNSvDDkkCM=Au`Q$?=(9<2zl*5HnXL%}`nd%8vAwO)ta)z%hPX}6mc6BDDYug_8G zU9&%lyQzDTkwC?M?Z*;l##Jb^HVP|N>5Cc$b|4a2zC&XXP>Zs75%#`@jq#+$M+_;k z^q)LwIeK5sZ`Fx1bf35+ir)M%>#e1#`eMv$>ndRO%Rp+P4ZHi89wm)04}9ej64KeK zW@BZogM(@c*$pV9OTho+tn(KX7M9MTFwYL;Q+4J zG5i1it>`roc)b%LcI{UYY2b7#?W_@4;YGXq(v46OO#V}ru)Xe|{rNNZlS=pE_?knr zXrNhvG5p$gFFuo;h=^_`ata98RvT3ow4cX7zRul@p%k*POF-I78wB57oSb}#kl27) zacCT@qamfKXDN2gH2nr7f)Hm=Qg)9xtGB-s3yTun4B<4)+1c4?0@!H;JfMrfNIWsK z(l{o8sN|?}`{MftVF6_mJ$YJPLqo}xWS3&GvtPqfkPNCE*U?bI%QCN23|l)*HsUM; zm5)yA8OW3+0KVh>Dp_)Wm8ZaYuJ2exNRo9ZA-hLRh=JO9o=xzlKP=*gz|SvV?o6x* znEu4u)FqLluC>6taN+ZZ57HZ0xdjDH2r1h)p$OZ-YbHVKvFB%Hj@xW(fKmrOxM4nd z@?^bgZ?plFv&Gfy>qwyta>U;X3?O^T&04Qb*auiWva{n9-)v!+ZZ7!x-Kg%ugst1g zo)%ZnQ6UT* z%GHPZg^%ytx$_xH+1x$-j(1{#KJ?uTfC2hH$P;gx4pM}NhQ{8x9*|l!3H3CSa*80` zH`O3K3Mm8syW}@-hU4Ji)MLj`v);a4U$IuLS5h5@UY=Y3KQBN?h{Ky2gEKi-*V5dM zG3VueqOGm1oVLe-5EeEYUQmAbIq{fS**V!8i|bP*XvG}v0<45<8@<2pu3!Cb+UoG| za1w%9AOWqIx{8V)3^`%c4cQ8?`PE*3y1lTlkn1J-5vj4_;_mCe%VoTE3kvV6tx=A$ zd+$6~iAFVHv+I4cx@Qm;5sO`(`QFejNfdntCMCT}V%?H$U|^s>Tb1GIi3KmEBTRR< z`BN#7FAw+k<(5PMaEkgI3%cke0YQf0!>xiza8r=BvS8GEPk&SRS-fbi?bRz+t|iqn zh=>evTDX68lZ~Lf<<;3wTywmM3&@1kd++ZuJVZq zSzU**5zn=%T<==hA^;SXXQxN4QE1s-vpe$W5HvzRmki5~_~HxF(P0dh*%xKo0+^PT zmX`GKsh)oPJA&P?`sO% zy_@m={e^SEwXUII%3~}rIM{Hl0*LmWI~XX$nE;q)dS-^z+Mb(y9ORQup!-@|Poog| z5hVVAfQy3OhrH9%(}=wRBv6oIp{xNZ77^$`h+g&>J2*PZOTQ$ zVH}tHi|3b?@>ulXok8%VDzhIe9DL@15Q3A{OI?}4x8DMsMX0rgU}}%cVxpoX<~F01 zLP*(F?zU#obNY)+NE}$S423L+;K$Q(%Il!~-3PAx!NB0Rr~XA%yOh*I&!rRKEJOAa zJ}6#m@j#<-e7}AuEhPhKvDM}~L>#+?>xNz#r)y zkdw3US!T*atosv)*TQ_|poxf%wihy4{z1t2Fx%47Qv2G#L;g@;4%R0Uj?7P>PIJ(C zd3mH%nOOe!4*h*Wf~!Rm-pKIqhh2T(109<}N&jM}LxfbLkv2bD2C0apGIi8_>guNO zDlOVCd2w!z+4;+8iOqHN)kr&d`iIk<8n1)r0OHm8oB#oF>VA`3yt$#k^fnZ#snS!3 zxhYV8ED}@%1qV-slCpi6k&!-L%qv<J6qL#<`*gJK^tITTH17jCBxEZZ{uB3-7;jP0`!LjwpRp;q{# zTIP>nEiAl(N>^$qJ2zLMgT{rPV4e8^ zO*MiVk?C%HMI2a4M30EetxKr#-IJHF$0t0Vos9osE2^ZgEQA6gcJD@Q$=n6$Ils@k z1)%ns{X0B8=bsE=Nusr$-meKRyXMA+u!i`S4Qf| zQIESp8qbK?sPo5ewQ<0LP0Hddd3?B3^y5&x0SNK{nte2og0{MSNqjZ|y$nuFVie-1 z`%_XowD14K4Z;1@t;Eg_`)XQ_mSimdB;6Wz19EoSMeqyI0wkj{6>e)xMN?$4*!!ta zJd-WX1Nj>Y2y7j=xS~$izf;dF-WSbq=#~D?+6igrEBx6UB2DT&cLH>D@l!E+8pSW# z?9&p-$EtwY6_u5*FILRG^Ng&-m(_AUD}{F^BD!bLOvCrGom|852RLr(=q>7L%dMIARAd*Y}!mxrWFRpo5$HzWZrv# z@#;Q4d<}o+4@XHGa9-z~XDcEyLTTQ+Z&f_~>rikAW8-D0!P!C{Aww?a@ojP!3c8m- z48MByM(;&P=nyC~{!Jz^Z)EV1NDV@B(+Ys6XNPX|-mjCB^U4d7@_|;jO1AED(<*$T zI;{Dq`e61(#%}2@Rc4BP^#RteU%vtpiEi9rV~r4X=0nYc3c&mHue9S4pdfg!A-X#R zXh1=XOfkV=xBz=r(~7Mak%-AyLSmwnfP$K_oIz11=uVv*7wpD+PZ%rfb@0FI{zaJ0tv$HFfm2u?d=8}}{?CzE> zjJ?{{2P)Cov%aXXP;nD7>=Y^cBox7VZ(+s*Fam_NpanFVG%bjYU5 z&A`9_>Y)$iRl42Y8Y-+XEet;)#-?Xy%UMy-`%dQ~w?8@DAwKk40`iD4%XqbMW2!lD zupZeIMI$Kg%4Cb}r9MY?%1sLUw+joFD1AIsxC{fhvD6%okjg`h>UVb<7~L|) z+PuBI7_*3)jks$;aSKc&qM@;e4e3q#$llwMKN)cbNwt9+=<~vuknR|eZgl}T!~u!M zHe)=K&qjV|%s-+-d7t2=hhfy}yNz6;qoWHQDuNwlLiv-7P<7r6@Hab8gdhy^<(oI; z8Rk$R!AraCENWyNKJX2W{}a!u9*|}SWnS5%GfobUNAo%~RXZb)@YuKi;m{9O!gC&L zX*C?~EWzL)3~pD3KWnjMNV;noIZ2VoX;7J+$7-J13P6x`)DDPJLG-CGXjU6Y+_$+W zonKfe!^Opw+{b$7;|k2A?5L#+|FeFTeLWNif;+-N52~fesi+>oU&}mr03L@xl`$Yc zV)`bY;osm_v`VI<2PN=rB|a+k_eJpDsWjOh>`G86FmtnVaRoy}R((!6gJ7_F`&(cx zNjD%4gc?A%%j3(JFGj%KhYse}L2jWx)}7?4IaVt&)qXnG)ZC2wXN#5?Vu*INmr!{{ z1ulmrK+xE0Jf&Z}k6ghhc3n59g-@CP14A_6rTl^d4bj-YQp_s&*W3aTdz1;|ntGCve2qpLw0VS)i?aa^MhNAqS z$|{VnUh2*vMsu{!15p=HI)v12O-+H7`04oT^O;e%SCLe@*zV*3u8~ETJL2Fv{PF#J z%p6wvu23(;m!=~_D%cI+98q1{*_-deeE9I8tw9GYlgpNq7U&Ft66Rs&R5oy?I|h)_ z$D%+@<1eyA_-b!W%V*En5&pMY#929eRQmDz!HIOl~L$#Hv`EaYqEXlyA!iZ zbFr%h)LM{PRp-;IVn8eUPp`m5EJm9%ZGR6}K~b{;(s=1_JusKU+wE`EcGt#=k}dD0 z3;?%-W8c)azI9I z69=?W=xA9D)oU)ppXuqen}gl_OiVKKbR)@NXv>~YkoWuw^r-gZ$BZRwz%^thmr?ZF zL_&yluW+63eDMWF){!cr`r3rpt+W(j+GR8-Wu7dZgQ%={M?O`uq*4I6{eY5K;yo-*s> zOF<#~^|)NoeOaX-EfBuTJdJ{)Fh$Uj9&KxV1REUjhjdrx0Z#(X!RSi<-PzUt;`>%d z*CephPZVIQfN6zwkv**GB_e6uNbM;C16kU3O)X*SRN0a&HClRpAVqHjY)rB648V$& z+dlWDQ|_2wLEA1Dq>6c#cJ5X=Ok6PcS9sm90tOXdLo2TAqAb!Zb9Xg8wQ*bDaYbhpF zXaP~FJf=TYX8L?Sp4V}a&lBB>1`dI=WIcK1(r8mQN6BX`ZIG4(o3g}!=GK=4P|p@- zhX||(iVP(*u#~_R(D|o~re7p)Ixky*ep8I-UWwsT3yZADNb9cmmkxef?3n+jQQ}hh z2`~r=#m&!|k0a#=(w6-j%tJ~Y#het)d9(8;A^y#@J^st+k zk?|rI$O2VsP;xu(UA?^99@>trqOTwE?%g|*ffD@*!0e=Mf8EBsWverEyb)?E19J_$ z2WBeD?HR8e9UcE3aYCtnUU{mkXLf~1oE?ANt`_my|GX-0(l}@#Cl|85y9P1jfvc_7 zJ~&cuuckv_c!IUxOU&Q2N+mhDT3{jJc(@*JFQ^?|C31vfL}?>*6%1k@_C_Ej zhX9D0E-C&c=C+#BDb5WfN9gciA=ujeLq)Oy|4rX`+Y@}1lD8JDMj4o^QOjdBGyqat zY}AK9J1_#Bvb*|dqnReh&e(bpP{u9qcLAhqnu5p4*V@NnIIQ1jz{&N3zRZ>FE@eb$ z8h>GSwj@;Dn-RYk8{l+bp?cvf#tCPV%STnaKS!&a#WaSGb5JD%o*sW;tLriT--74}u2}5q=0O=8K6aj;- zo3Px^``6TT3HUd*g0)00!&Tnv+|cilv!(buRpfOglV%~kTlvy_Pu}a&xA*P~JI|+= z+j@CbHZq1+ZLT*E+=m~2WVeC0+Q94cc7T55?+^VoSkS0JlNwGn=ox&7d4*U!B%-y(OjZg5X+5>Y=a z${#aA==IPcTQhL2%6Zy*gWF$eD-H*hUR16%VT;_%|K)*XWN`W9(lK zw*WtO@YEMuYg;G=&VWs-PBJOLG}cq2pKtG4wg|94T+4ct9DvU$-FSTL^`CNMgN$yX z8t_L0NFtlM-@0Ks)z#DjjyQREx)!jM+N}^cvKt2{uplk3%i;lu8!E%Bpb^~~`^;Vd zCa-$KCtr07+ySJ-^}R0vu90+6pwUJ>!F6pkwUVr$3gBJfQQ?OVjT4__EQ%;dNEj3@G5vVy_JlfUoERc+oS=VfS5U zCky)^9WLgu*v*=;3u0t!>@dY2EEL3Zt?oh)x&VE%2wgQ*-d^e>z{B#N+=ZL01B;`e zXeP0}HfEUZZD2snZcwSMMtLOlZ4F$#1W=yF#s?K&mp(JH9r*I`1EZTv90sCbg16>@ zEio~1s>K(g*;(h+VV&#~@EBeNo;LPx|MmCYW$qg$U{Xnl|5;7AQV}J7*z%O=t;uN= z@Prw=3TN7yFPSj?AQB;p>!3lo!@cK}KS!ZlBC)OkB1K+)nV_p$ugat31LJP6+!#0+ z_7Sl-%Xs-xmyIT{SMF%Eyn>S_F9pIaDmo5zcRzkAM1CY~CY|#7H8$kk*f;Rxg$ght zN}8CwZ{*$e@3JBhwqF^ox&dH+`jW|V5F~OI78XKX8A#W+K7JQV!b3?bNkQX)?l-H9 z@)fWfr0(+PgC8m&Fp$;G7i8gAPnW|wJ5?Oq+_Z*A-yTI`fEq_+&2?u#pTG;-uZyp` zy86HRb6({8t|Htva8}7-wwm~asu!*%ss>cjK>Rm+>M2U z>F!-(Xo_L{WW4-JCV~>D1fj!V#;~EFq~w3b(v6Ifhz2G2`z{Ll0Frp0zR%`3JM9QD zXavU$%|X)crYVK*q-=tE8~j&r-A>KhvB%8jbF-|{o1yeWl;pIV9JG;u2^xOpf+dM6MvzP(le}A$E!`HTie=*t=9-KQ8Dz=G85sZpPlBEnhgD+LGI%;?`{)RK%~m@hdX_S z50y*}^PhabmJ6(FiOX)aX(633iqJc#nao)XMYtmQ^R!sEVEq?cQFp}%m{E;^f4$B4 zg$6YGi3owwY_|$2>P-TT9 zo@-&c(hR)bK;;+^>&D=QY`MF156oB)>q@?_si~{;(9^#ZEu%)7JfN|tXSO;lDykVl zx5N43ULc9vj=I_X1O#8wlCydRtY10V?s+|-kSC{a#PkG1Uxx&kH@@i>l#SS5BPK3} zCa7uj&WF4_HXrD_a1)&ckl%6rOad{|!j%nFM|MDdcx_nv&H=k%TRl1wju=_OQWgsl zA8}|X=*hPau*`NW!IZjwv{us$P-f{U6o5bAunADgI{*BM5Y058;(tbN2Te9$cP-r0 z2ZuCxE-oW345%)rDR!)(np_<$!3Bc5Xipym3gkbag`#z<_|OS>{a;0=A?21G)IE18 zPxmAqPr)uABqCB>bA`grU$a0rCpyIOB6NPiv3vos2yh4sCudfqnE)dGr?3LQr2i6j(vfNT@Q9D(lTY}nSyO2r?_qTq>t=ft zcUgl;@wzAx(k3}k^z8Nr;8!>FSi_y@4hbv%+E{w4>~Nrf!EqP9?}Lf7s1|EUpM_k# zd^tLPx;I-GwZ5}+$-gc=yWnoe_)q9l?H72Di2_ao0$uFi;hP%RD8N^tL$_0F1CajK z>>O}&fD0qT99qm26r7wMQ=z~+aNCY;&=K)=+a1g7x?7z$X}*fL@6ctJ3Sm~k1(e#ATnT7P#8dFuN;48L4A)RQOiQC#jp9J3a0 z6q(+DFn3eji@eaF3V|YEw*j}rCB*nZ4wmIfEoCYyP~_f#tdk;&z6K%;>~##JCk-@B z_ZyYV&md6va>IPzI*{}3?Cy~<_Wtb%)lXi>(+O^ z+&_0kEq;?XZP7{`Ovg<-34J~M0uc%}$~%!&5l|nb;D(!(9-xw5o0^(h>vsdlJioZ8 z@J>q^@;(uOjMaWOTr&3YHP+8HTYzUvpRC%oh7d7yw`Y&mH%Hv~RKAYXxn5Jnhh1Q) zS56f+-#P^al-k+Njk%)$`~Lm=8*tkA_eLOWbeY|Wnd|ij<4!$5m1L-P{(hW(t8;?5 zCzAJ4lX<}5t+ACOPWoAGp8_>2L&o_;yNJLPX<`*WoM#{<9w0FEIhffY=zaka)=M~tj4gW*?O%Y8FUY+4kHz}$$!~w*e#spy>DHfH`Qa81+uUQj(R2b-rT$Q zjf~PKOM&3J7S~ThpGGoMJymVmNO+QDXlq;Wfl)xV2g6U!{l810+f80i7NKq(^(@cm znfIs|LgyjJL|Oee4G?=s%EY`6zcnHd;e`HV^|Hel&wKFqTq!AA!a$u}tZgv@-h}#T46l*N1FgLd zSpLNkyPjN)=#-Rvm>D`~G=j*yG-3ye00PY<2ujyCU`!`V0Rh89 zi)E#Y48ct3cm5%V@ULAU7iH|yyLH$;fC~{SrW6o1JbL+RTq~p32`E;v@w3Py0E?>} zKVa~|I=_topw$ZiWkQGgy1Q$^oOO%ohY(;sRQ%W__!7d~&SsMH@!Np3$kZ(ko&uv%}`^qVRW!k=;*Hh7?7OjORI-6Phrk zRu1rM&#Xp%l>F~6sX@weN2T{r0Rl{4WaA-EhdK;~wlq=-{p?;|UbWUGxzXXsD5fEv z;6guO<>W5p-tn24kF9*laU!UYY%&QIA5d+VH0C3@O+;7A1W3tCUp#a6-d-^ozJr^UirM?780RmX| ze{azEDl(GnhaYU}^^J|LW!+B$RDKZUnzk^&FS@Ree7!@aFJ$yo0=m4ieCMtCQ7FPA z3fl9e0sk*3CTt!>OGkH4?b=YMGYYZeHrf7%Z00GtFlwQf5Gt0dkFZhTkkl9k+NSVY z-1+K05q4c>={9J?Mq%)JT_!{!(E(5ZNl8IY4hEdh?EL)rlu%^q8m*v*5I(Vh%aIAd zTWYL5hbw6m<6OAB2L%#Hf=oh0$eV}!gBHJxUC@@2+AmyA-+)OThaep~6za--J~Q_a z3)WzBb2H|93xR2j|8_ebL-;&u9DI?nvHg*=P;+2ofRP&qEF313$Qu$h^z>-#KPrJ- zEw5lIl0<-lFCzd$1eQT)PuKn5MGU|^508ulCKiKDMgHkC*)0r7uv|WYBH7XNlma;& zUBtkO5L&0bdxsC!DyX=Tr=k2nSYWdoDzi8I-`U3Nl2Bx|JHzasKp8>n;QywJ{Jk5> z9c9D-6=!GGqZ_ZDo}VKMh>`wq`Y&_%Pwx4m-eX8gNnHSMI;))oC=>s85u%-18|v!j z9?1GF(o&#+z0N4Z*ta}iTmn3bJJQ)FfI{G#4Vr36hxhKlyuq{uPnN%51q%hOOMZZ~ znpTkh@&Cq?b`Il*vODVsQd&`sJM`m+0ac4yQkXwC>=bAFsLc1 zQVY~RRD8xjiG~g$qD*~#{Wt)-SaqIoQTXOVEyy{-LHcU?`d7`(&AWNXXR`pDUpXVG zGH)Z3e;R*J9HkOkXXFP?syfi)7@17Shc zv>Y5)p&%zM8To9CDGC)@EHTgTKO5WI0bq@~2Sr%A+uCR+toH;liXjN#JXlANH#Gtu z>-tuQ#Fn35R{(et>VYREDeL(CI{-4OBxBV@Otl}t&pcLm`ji#C;L)>|RC;l(0f@i^ zJ^^+}ag{}P29YLTq@NZV>k&)j5y4Wq!4GG7D?@#dLD5$wsm3#csjn?If|W$gjdsZo zVEZ)*fVN1t!k`3&Fw#d}_wo|*A%bd&;z)C6=Wpw$6gO@>L?pxY&CPl!dzw;_l~9MD zOM-G}`d^#*Wt#DD@z2`qlY%aM~ms1orjBPH`PQy|5Rce7N}GUl<2vpTx}! zx}JViRK)ew4weCf)&yj6W{)+g@Mnq>lVa`lA^Vyph+r{m_W9n)@$rn`xK@E6uEat~ zenF$`%%F)mbO>C8>&-97o4}o43yXprU~ZGf%aEd>1WEuOIpTUpzOex@|7BU3fD7YK ze28^HAY@$O@IPEQ6L#i7fq5-X~MXZE;r= zKFomdbME6Wu(PMQU4OpeF%5W~@fuPzzTJHk>YbpY)W%9Yu%%G*-zs`hLIA~&BXqw> zm93LEBiIvY#MZrsz2b_BiX?+$Ku2~NaYy%Iq{pSfQ3Gr)(qs#L@WxB1?GtJUD_uE|uQso(^{+1fxl1I2bkL@mnMxzW7^rer8)??n z)zxEeS|@djKS`G$IbXGGw)v}b1nS(cH zQhY{mAr=|F=tAEmmLp*5N+BOt_61QPHTuZRa+w9gG!IBgnOZ+ z;C-t&?ef_fX}ODI^?sKR4(>*-NvPuZ4x}=g;-p+P_Hac7A?7iMY0XAdopLLuFGi)J{aV zGdNe&;rlJ&0MH-1bRtfAfacH#-!lqK)P&P7I26uqM`ymsUH^RolhyLMpj&HQR905j zd6yC4Q^sLLJWNbMl}fv_NG(1!Ir$k|H!XhlQO{0E3oO!ClXh&{|N^VF+xx86qh2sm~f9zw~y+<6$-u2C42xO z+-snx5)+(&(clEsukoo;39i}v#Ri*l@Bq{n9GVZlj8L>7n!mvfJzwYwf_Wu!a&r2( zcKzIy;+@YAb&$HduaNsX?f)EwRN`LcDxW@OWo_QqQ8H0ciQXnY0iVNpiw?i$Z^)hF z;Pd{tdIP)%V7XQ_xRFR*o|$n!CM z&#~c^dO@YTV(WKyJSTw+WPjYB;0jH8NZ;vZ-@%%5zH}NWTC7J`=_jM32neHxCd3esKd6-`fHeR{YwUGjPGuvgDse!vZu#c{)LMNDd;V608#=1E-zq{>`2PGBob>x@^gj&-;4?SyEfP&D3aF0||Br$~qskrd z4^4DDN(0Ibriy_z<`8gTP|q z;o)IoVDPTf$1h}ecfo2C#m{#5b{vR<*uL7(f$vV16PV7Um1wy1@c%XU9&Mi4}SuAtWV`h=&KSE6FJ80QTQp~UlgFBmM0{U`R;E!v>_OQM27$c zF3dmwrObN+lh*BC0=*Imk$xN2BwSr(feSy47<@KI0W1FN0?{4x_L)FAePw>%(9nK% zLte`ZV{Po|(PDtiKTeloJSkZmLcfiH8FyD19>Unzlq^TksZ*yc9M}Q?Y`i|P7p!T& z(}f^3W^(=pqb=rr^}9asZH!!=!Y>Q;#Yi^-duG5@E!vR_pup<6{3j{`x1hr?0mI*= zkM~9rTnXXB#$^L|B0+>6VIg9;`N_G7tsQ}Q)BfgD%=aZb{$MPSa3i#B8RTY3+fF3> z@Pz3ACrWv4?&A$hrza|Ev!1lG{%Mv|{KZ|RyO&Goqo2)Do(+-=OE^Es{dBbcm z?lmgT=h~FKvn33hfim3RI$1)(4Z)G1Gtg!o?LmctRigwhSNAM^)SnsV2Wu0_oUL#kRV*y znfob?qf7a8&*MXkO0!+NJ_~5M3Z!ZHwhsncBT8rnmbgKEoK%rM@$zOEk4l3P?g1=i zfIEBWhK`OxTWlYM?$r;EAzDA6pQa9QMVMTbt+QoAO64b1<#=uIf1y=vZCt&6qcS7j z78Vwbe#RaTWpE*~60nW1a;w1bruF_|BSS7>-GOi4OiDF)DaQ8YV9(GQs8z0t=!A-> zsio9=ECE|RMB~(Id_u_snvV+9vUFf%WTm2WqazQO2#=YWnN`EV%Ja#)g~DH0T3P9r zYVo8h z{QZ#4%>%SUL>Y;66Z<3;4O0z74Lb#C#~Ldsl$p;*cUTICIx;!3e(3JDlgtPo#n?~mm>pab)9}sAKa>{vc#iE}&@$~z^D3x+cRN%9))*Nb-C!8X z&NQZz{3uAfkj==*s9@;$ytK$F%t1pW(|m%T5Ei#CT){%ZXAVy-*TyTFPaVhXfGkGV z-Mdk)z7;Z&C2P<3)iLgsmR`EBIC`*S3|#3*K7)6-KQu1|Ly8It>kWe0SB!btf;3_n zE0jQWJD4eB%{5hlgh8Xxv_CeN^#yW(h_FiJI;-*{U}zg3XSOj-I8%m#*Rh%0 z+t2Cg+jasI6yr$jOods8=lS{dPHBrOxg6w9$*sx`Mjw zKs@BGvStne8b6|-TniS3bFA!DFTv;!R&H)?CWjAa*B@3*jF0zdVRCy41VLhA6tJ*I zwBWYY@ThR})Ow0B+Vo7@(ss{5V<#oP-M#5eJr%xj*sY!|VWrLiY@}ItghvB|F|*KD zk+C6bo0wSW+}No)hKHwTFgT`hiLZoj=Y|v&$q>_*BMKYN+FzLO?t`CPijGx#O(6%R zV)699tvnRz_?2iNHyDQ4hyV(v=BQ%KkUz>q0gZ zA!p_>Ivq9t27_Q5Y1E@u4TqV8IH4nbapaL!kXEG-+9A`f>mohrdP%NO;?ceMF?Jc> zp5b=xb&Rmp{5<+-eTg`a7UuX{p5-@r)~&PreIFz9abKIK`2U=o9P_bP&fMJGkH3iC zBQHK18(Y@fZ>GKX!M^YD((b;kn<<1Dl$F+3^p&3EGH@lkHDV7?tnTH@%l-oI#!)io zPaRgYD@vG|o%LujGH#mU(gr6$if3h9q83z0wJtRI*3sVpfpzIGcga4hlj5su&qx&; zM*HI^xBdf5NK$BG;yNNbHSL<4`5Y}1$VXm&cZ$&HAa35O0qD*~pg}M3L5r_lrJEZe zc__GsZ=w*vDjyGC-KL(Np1f}8;?x%A`<9$(u_f}|%YwYw9nUkhYM7Xs=GZypTj`pb zuF7_y?K%WFJi{VCuM0{kCmv3xm0&9p2S*7v10y5*rkG~(G(XKwe#uXpfcP%fpPC2K znzO~&{N>B6kry6?Jt9uC1xzp4t1sU2fsczG#?JXuhZNx!G?*4`lQP6l0X><0)hZ?5 zSy*{gp(0yv7#d!Wot>9}GCT|_g&TX7!pk3?`lyEMP$)2>YnI~6dG>n9^8?BWw7%wL z`=Br*MN~*$Bir~sWB=R$`*RRkV^wyS0XrW=vD*><2hXtlOEBZ?NJoChB9QGX_^f-& z3%hGqu4MLxHC3R_?wRDW9cL=(h5~r+*dSt@R|`|F7kE7#T2nw2Xc&i{+ODdqN`tq- z`AsiOz@YLReJ3*#Sb|~Oc)86T0A%7=UOz!@U1L}q#x@M~cya%|B={o*{F-R#u;tD` zsH8aCCaCFW_3LyQDdus%?_4)U;t|Av3i+Vmxk@An#Z?$#Q0OjrZ8rfm~esH7{IskFG20#-0qdo`U3`j1b6X)t&*4+&FUR4 zhj#lLICj%+C%)Z1_&m*|&&14ZI4!dD2_CJ)d<;#O$PUM6-LK=C?a&0f`n`gX17G(f zgk+B16w)}dL{B4noV45meCY^Y_MWoh+_`4;3As@f)dymNm_@!il5$X&y}qeQTsl6& z-|Xg~fc8_;2IqTELCy5|OV9&F8JTPKI#n)8*CF#|=RJm;-8TB$Es8CYa_Bs0OG&A! ze^ajDiH^5#IGksT+6b^x@@#=PU_RAPb^owP=t;} z4Pi>IUu5mo_cGxVK$ND!^si^swzR5BB{rA@5bamV^o+`M7uYNZ~4)(bDkB`<(}SE;Lu+FX>xG&F8XKSDnRehdL~PhZ7ZL9Ob+jEN0mOl-NYD| z>?DS_V+-i-JzJR8zJp*R?#UB1!?4KtxcGPj+~qZIL1Tx2-}@v+WjAjYMY-BvS(KXr zaLX5skO=~NoZGw*xa-C!r>4&rHKEH_=mw=E)-*}(BA!AVp2DM&l8(XD;`gIhLPD6Q zH<|x+@k$Eho4L0mJ|$%*U^fGFI`muXYHgmqI9X&61m?*G%shQT-81p?dm=SIi;yyy zd@OAs?P=+Dz|14ZQznK{=?|sFb=+8761;vJ{R_;hPcj%Vw3T!3*S^dpY~hSPrgNaoOzA|NB!bKiE@|36JFZtJZ57V~^7Ib`0i zAD^lq2AP-UnoCu6c5XmGud1(Kfsv~)Jp2FyuQ%vcW*7cJ0F^V(MLv&?a=O z;_(SU4m4g~)@#?03?GU;-Y@LtfpNVRy${82J@(lFTk5Rzz8rVSDlB;+sP9(R){Ndw zjkb?YZkP@{>87Txt{9MbyRtG3Y`kcH2kv-0&j&@H^R(E7!+Z^LPXGzct_?pkV9NqQ z@0FWsXCtO1Xrb_^i}qhCRdzdh@->(&N#n29Irv<}$MF`rF`zEb8esvfk4-tde$ATN zlMCnap?8p&J97(VIIk~5W&NrnP;~Un7j1jvn()&3NBNTIkU*7aeEkut5N)Mx+qmrQ z?NP)p5SK~_8>qE< zC45`QkL+Iuyvg6eVn5Yc+s0=7|E<5^3^{m&6t2L)dNbKy5_ZGhcZ%m{+`+mAcp?*?djF{h{$Hc@?l$DiDyWV~~^CR*3!g6>{CzTwlPcmT2u)dR@@ZLoU zg55(jevB=k}(R05b2 zaYF*^n(=$AT+#Ykmq8w>l_${7*ScO;ZF$fS2c~y+o;mG?EexGOjoViD>u~)ReA- z0pQiUyo$@szAdUrm={qDBI_Nn%HGj4pICawBH!4_N#yNfcWZ0VnrF#d$>ngNJhfMN zyATXh($OJF5Ll@m9*!IMZ-p9tj~xXS(b&>*%|wadYZOfN*jmQGbIPYBe?{;80}61{ z8NrRKSQTLIJ6@iAzlYf;4{)0mzy9~OHuDAxiMUuyZDI+AgE^U^+R6K0B4sOSL!C?M z0kCut|1FgPx0kwCuOj^u@atLeK6KRG+FKrkJ?6!wd#w)FehB+Pz*fmyU0Jcx(?y<@?F(gSh)d zMMc46p0&BTIm29vB@(y9c@Ji2LZK5aA7Dp3+>*XJPIAv>EW1Pq%g1srHZ*6%0c~Vt zBm?4gR6>|3aJa+g4ije$OuV_Y2IAxtl2^UE`!5F(yTA2b&9BCSYnyv zJ8a$xR(hZ~KzM0;3JVrd5V{)g2K|Uw7hj-|e07fh?tEsOi+<{4O$~wyGZ|X#Ga~YS zhb)492i2cCLg!-x&(Hh2)91gl4B-!ahC2Gf`$ zmM#3`=DCya^>Z+Kr){o<33`X5U%#K`7Z!?P-uWdh{ZhSV(0l=Q6Y0ECb0NiCeLe38 zLZ)Rj3c`>H5oSxKr+tHz)22^i+);6o=S(@nzGp4IH+~{O)*#!cc`T=(wj|<&`I^$t+ zacdwdq(Bo?Tk>zJ85`+)5xj1ViChrsTt>M~G2F5u+0>cwz+$#zHGUtI73_){*!v_s zIw7~-5!NN{Ut5Lo`$YqR8$SgO4-T4tR33R(w2?f(PW;J~j_99{w4{$h7;Ux^KG{+9 z=~@(kkmKXqUF>0gZ1lf&YFq=A<==JMcGO}sxg&3A_y+;QO9phi>|g`jk3*3{aJl6D%|z^Q;LHdW{%)x`@J z13hVJX@SlQVBC=fdI#Me?U}=#vsVLYsKN)+(&Mo@{ymie>iZh<*R!%m%+qsQwdRoO{-VKVet2TrD=4+@_HQ8(3dZk0m?(4KQkl4uM*Xz zJzB-D#`7|Yp966ugYGIUD#}cxw}^qm{CvSZf1Bd&N1V6zq&HW%>9P|8en>iND%=L! z+>3R`-*t8-V@ecv=QXCW2!~P;b`d1b0DSwt_4kBs@%uRFn>#4tMl7?hYo4U4$>4(K0>itvA}46&zbkIo2XmuFU2BlFfA=)qD3hp?7^+1 z0xg}AAE0jh#BX;+INyj;Qnmy)gjy+XeBp*yIJBa2fw3z|>G*ZWQF11R z>3_F|^b&ip&}uTr`|)Dk!5|Da97jR_2t_Sl1A6#! zd$t;CJr9;O#nt!xQyv}Kpo4~nh9ll%(vR!B_xjc@o&-4_3{2Rc2!!%q_gz6VqUh6D z4mE%QEesdOA8|{7c-ay1eHbcwkF~-m6rhJr3`NP1YHjGJkq2>0e~p_+kNuxisT|f$18K6ZPpVcjm zCAox@tOJBPZ9#@&(!*4>j>5&F)3pbT6P$u@X>NTN?-@0I@{WMgy8Pfe5do}Gt44AA zw=;DJfq!?B6J8AysIawv`DxbPo?AT(@5Cc$M0zF-lN(ehaEvU7N={8}@@LMH!jTlf zZy;=5cc!aX>mdj%p9Ti1HP796*3-vS)lF6>T0%r*8PQuKJO=OX_E)hh;w9FGNy=_~ zs1MmIcj%vg{G2&xIVD)=bqMMCh!T-7u)5R${yAd0L8kgw9+~N%2Xuk&GtqOFK*q77u6UU>fC;N<$+nK z>_VE>>miW6-wYnJ+`W5u-Me=Q^IkkBEORYl0bf0U8V^(t-s|X|&ZvE4p0V0OS)NN8jtDn?7**A_7z_VXL%T7S?f`O8zgVIx*Xr<2>fyh-q?3p>Wv+m7X{Er zPe}%*ni*j%X|#!-zx*_Zl>)=o1L#w}nis&N2~NosOXnY~n{PTK3-4n)Jnr zfBw=shyG^+EOgl4k=7c&a2>sSEG8s|VJwp{mWY7m$7QG!y!vFN=A?)}II3KkE`80_ zA~;gw%;>votRUFF@oRMH|l z%E?8U`T!!+DYDjcadC-6fEnUX=!}Kz3QXQ$IJXc7s0nx4=A$TQ!8BQpt1|)1xqBZd z_Zo6!5IGA7u>RfqLc<|n_l4ON-70X87Sw8f=II)VnwA6?F-%rY_En}r8N-#`_ByZG zh+R16{{7g6>E}!0X!TwcvzhNLdH7HiQ0gEQ_Z3gIghOM%QHTNifD4m>@ov^_vgM|% zIi%y$0(z8f`~h>6RS+Y{?Ej6tzKoe!MAs(^&yPDnAN=~& z7;WA=&!g$->3eYeSGJ!(rU42I_^l{FPy4CAzv|f=!zNe2LYWb$#k5AUZU`#ba zVy8^vISMYsjBhF-+lR`(Z8-nY!-paL{r%Q0V<2vDqPfi~6wJ)Vk|4sd5obgA`tu+@ zPk`6^7FtkpFHk92?%Cg*0ya_jwQHBa0iXzH2|nTC(EGKls<&4FN++FstCW)SIFyLE zTC~sZlU}=Oy<7&}Z6R=R?xJq>kjWKWU3R8aGs&)np)q0*Mi@rqye(pjquRHr;)8+lX#;Xh6^|&hn&GgemFZz ze8WP+O<^vkG1;g{2u`)w20B|4C#l~AA|fIj!P&nD=imzeOYFgUEt_~{9ZY|JAH~5S zuG4D3PmIZc7>%aAbL9ya7ssDc%>^hF#4wVSKoLs9N)7_)>W|})XN$p#8MY>q)Wu9C zC8Zb~*%b$iH)P&*<1ItxhsZX>mK2BHL`+dJ?p&F_6zrbJ4n~3J*>@^$NP3Px2yGRg z1B~P15~Hy=SPhLI7ZMwWpcm}$L0 z?dYge-&9w_^^8IQiC<&g?+1s_Lr~$Cz)GPco3i5ToIJZx3mWyCH*c;tIKkgRr&mM7 zYnS@t(oA6>z)n#-eUKdurLeg8au{PABR0o4J>-+3%?g-d99s|Zmj(_H z_WZ42hSzsoXyxLIM&^Ru+-Sh>}A;;R~uI;Wxc!;3u<>+r=sQ&0OvU7tlWD4 z6!=^5jVpHLTh$=!5>ZYlUWK33S7If0GRV~0u!KTqxl)Ob6NaOy=WKYdp!Pt?Ujw@< zN3iZ_0s>S>vnpy`Rn$_c=vB#m$DlgG^N+w^wE<>EJe&&Ywre5KL;7qTIg*~5>c)Gz ztl@|Pk%VA+%|iHW^=0?FYa#jVhdW0`n~QdK8#z%46SYZdL*Z9+g+%KCBkfivsA_C4 zT(<}ANo=Fg9W)M3AE$+iXYo=H5ks+#5v6L8!;p%fKD+TCt^-Nl#JxOBK*K-un1z4z`v(S?$OhS7uaf=?DbhFWC9!TLYR5x>zJa&a zs&8UBuG6tB=aLfu5uHL{ zEAu#DUKvHFHmYy(!`3!gYJcL+Ty8W4RX98hRDJtDZhxM30;diEzXZy>l>%`$AcnYz zLazq%l?){4bE@nNbN$T}^gP5F(W&swNzBEVt{J}dtZ8}u+GVzmt9%_eBuP60)X?iy zg9qgkCTfBzNaqe+_uqf{J32aotnXZ!oAaYkkWyWKyOo>WW-dQKMW6@3V;8X*!*syb zLWvFbr(Se-cZXzWiw2(c62v72Pzw|96mr0#Z&-+sn_<7B>OJfkx~p zolfK=ftII403%$+*rgT^vl@q7ol^~uKcvJb45~3YHCFh90!DwOF2-_PC2K7O^!1B4 zU+l_#>G7|>{Xl0t>C15d8wf!<>bp1%X>_PGcFrLT4M|Hp0~;ao zm8`<8DPWS@4#uZ|H4QQ}-ZQ-2J`cVG?aU1ZYR#7hqdl};Sq1?HK|jz9F_RYuSDD!^ z>9jZ8f4C0L;J zg9q@LpBl^_EVaA}G^YXBf%EunYlNLy<(EnI^AF!Im`m}~@ zot>Y*0$m+(#>Ak?U*nso^+jBR98L!!R&MK^%q+l6&{+v>+qM?uCn0?0zxBcveF{0D z4@@mNk5BqO7})9LTKuH07|_NEgG4k5%b8^mZK)csb~=k2BX|*rgJQp2yG%iJymM#n z>eW?u1Y?`*kW4NT;2B*!u>%DnjeN%*ifsatw>Eqk03GRKNs;kGH)rus@W!!W5}&!> z>mX1*q0O5|)ACPw49g4#0zS~iRZ#G;VuwPm{WoEtf7U^c1&ly6ZvB|*I?JoD28Unj zUmk>svCG43$f!Ol(%p1)F6LQ&6iF~ZEXQGoWgjpyeVAVO+JabW0Taf_e<8r;A)=@& z_Mi<4vpY~=akT=o~gfj`{e116kEc|>0w1HYt z`(P)6AqBlAIinOmh$}YMBHUJZrY8mMc842EMzRCXK4^LKrl#9B{3{7qzq1-YpP8-4&Ae#U?rY%VgxAC!|L<};FiyQ{P@{dp;1 zkFuH030gx9j!sy%Y*_|M=vJU32^Wwfqt-ZSQbMXJ@Y}nHN~+aGDF&4;D4y^W57KiM z4X5CSd(bFlmKlSUJD$9F7b?5gSe1?BfF_ccaY>w}_?-S6h!yWrU^U)WA~$fKWgL}~ zmVWZ(^m*rKp-;jtO#NTJumMw*St`%U`h-YU7*Jr(a{T4Hcf6QNRYQ+Qe&7HW*o0R% zG;lmQ^KBV&P5<~fNjVu-(!OEcD}g%#`g6xP9rg>Cz(IcOJ1KGCncrH}M0RFBniSWF zu-6Fca0H>NML_avSRp9cqD@nVMkfeoF(JYcDIF@^5Wtxr1NBX+R6#S>8*r|=xtaQX zY>cTtdL81<3H#E6n71Lx0shf0ey_KCH>Z-avMy2!xJx={0q~=AZlexuQn#c&hz9tG zC6=17SjC0^K + +
+ + + + 0 + 20 + + 0 + 1 + 60 + + + false + + + + 0 + 2 + + 0 + 1 + 60 + + + false + + + + + + 0 + false + + + + 0 + 0 + + + + + + + + + + 0 + 0 + + + + + + + + + + +
+
diff --git a/script.wadeysay/wadeysay.py b/script.wadeysay/wadeysay.py new file mode 100644 index 000000000..86cd4efc0 --- /dev/null +++ b/script.wadeysay/wadeysay.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Copyright (C) 2023 iCR8IONS LLC www.icr8ions.com +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# part of an addon called script.wadyasay for Kodi - https://kodi.tv + +# pylint: disable=C0103 + +""" entry point invoked by Kodi """ + +from wadeysay_xbmc import get_conf +from wadeysay_xbmc import is_playing_video +from wadeysay_xbmc import media_has_streams +from wadeysay_xbmc import get_player_properties +from wadeysay_xbmc import enable_subtitle +from wadeysay_xbmc import enable_subtitle_index +from wadeysay_xbmc import set_subtitle +from wadeysay_xbmc import rewind_wait +from wadeysay_logic import wadeysay_logic + +#import web_pdb + +#web_pdb.set_trace() + +def wadeysay(): + if (is_playing_video()): + # video is playing + _conf = get_conf() + _dirty = False + if (media_has_streams()): + # at least one subtitle and one audio available + # obtain current media properties + _media_properties = get_player_properties() + result = wadeysay_logic(_media_properties, _conf) + if (result.action != None): + if ((result.action.index == -1) and (result.action.enabled == True)): + enable_subtitle() + elif ((result.action.index != -1) and (result.action.enabled == True)): + enable_subtitle_index(result.action.index) + _dirty = True + # skip now + # non forced subtitle was enabled or subtitle set and enabled as preferred + rewind_wait(_conf.rewind_time, _conf.longer_time) + if ((_dirty == True) and (result.initial != None)): + # there was a change to subtitle so restore along with enabled state + set_subtitle(result.initial.index, result.initial.enabled) diff --git a/script.wadeysay/wadeysay_conf.py b/script.wadeysay/wadeysay_conf.py new file mode 100644 index 000000000..6c67ad1f0 --- /dev/null +++ b/script.wadeysay/wadeysay_conf.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Copyright (C) 2023 iCR8IONS LLC www.icr8ions.com +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# part of an addon called script.wadeysay for Kodi - https://kodi.tv + +# pylint: disable=C0103 + +""" provides configuration class definition """ + +from enum import Enum +from dataclasses import dataclass + +class SUBTITLE_FORCED(Enum): + """ enum for subtitle forced options """ + FORCED_LANGUAGE=0 + AUDIO_LANGUAGE=1 + +class SUBTITLE_DISABLED(Enum): + """ enum for subtitle selected options """ + SELECTED_SUBTITLE=0 + AUDIO_LANGUAGE=1 + +@dataclass(frozen=True) +class CONF: + """ immutable class for configuration """ + rewind_time: int + longer_time: int + p_sdh: bool + p_subtitle_forced: SUBTITLE_FORCED + p_subtitle_disabled: SUBTITLE_DISABLED + + def __init__(self, rewind_time, longer_time, p_sdh, p_subtitle_forced, p_subtitle_disabled): + object.__setattr__(self, "rewind_time", rewind_time) + object.__setattr__(self, "longer_time", longer_time) + object.__setattr__(self, "p_sdh", p_sdh) + object.__setattr__(self, "p_subtitle_forced", p_subtitle_forced) + object.__setattr__(self, "p_subtitle_disabled", p_subtitle_disabled) diff --git a/script.wadeysay/wadeysay_logic.py b/script.wadeysay/wadeysay_logic.py new file mode 100644 index 000000000..31df8fcef --- /dev/null +++ b/script.wadeysay/wadeysay_logic.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Copyright (C) 2023 iCR8IONS LLC www.icr8ions.com +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# part of an addon called script.wadeysay for Kodi - https://kodi.tv + +# pylint: disable=C0103 + +""" core logic that returns result """ + +import re +import json +from dataclasses import dataclass +from wadeysay_conf import CONF +from wadeysay_conf import SUBTITLE_DISABLED +from wadeysay_conf import SUBTITLE_FORCED + +@dataclass +class SUBTITLE_STATE: + """ subtitle state represented as a data class """ + index: int = -1 + enabled: bool = False + +@dataclass +class RESULT: + """ result represented as a data class """ + initial: SUBTITLE_STATE = None + action: SUBTITLE_STATE = None + +def is_forced(subtitle): + """ returns bool of whether subtitle is forced or not """ + return ((subtitle.get("isforced") == True) + or (re.search('forced', subtitle.get("name"), re.IGNORECASE) != None)) + +def is_sdh(subtitle): + """ returns bool of whether subtitle is SDH or not """ + return ((subtitle.get("isimpaired") == True) + or (re.search('SDH', subtitle.get("name"), re.IGNORECASE) != None)) + +def wadeysay_logic(media_properties: json, conf: CONF) -> RESULT: + """ parses json and populates initial and action states """ + + # inital state is what needs to be restored + # action state is what needs to be done + + result = RESULT() + + _json_properties = json.loads(media_properties) + + _current_audio_language = _json_properties.get("result", {}).get("currentaudiostream", {}).get("language") + _current_subtitle_state = _json_properties.get("result", {}).get("subtitleenabled") + _subtitles = _json_properties.get("result", {}).get("subtitles") + + + _current_subtitle = _json_properties.get("result", {}).get("currentsubtitle") + _current_subtitle_index = None + _current_subtitle_isforced = None + _current_subtitle_language = None + _current_subtitle_isimpaired = None + _current_subtitle_isdefault = None + if ((_current_subtitle != None) and (len(_current_subtitle)>0)): + _current_subtitle_index = _current_subtitle.get("index") + _current_subtitle_isforced = is_forced(_current_subtitle) + _current_subtitle_language = _current_subtitle.get("language") + _current_subtitle_isimpaired = is_sdh(_current_subtitle) + _current_subtitle_isdefault = _current_subtitle.get("isdefault") + + initial = SUBTITLE_STATE(_current_subtitle_index, _current_subtitle_state) + result.initial = initial + + if ((_current_subtitle_state == True and (_current_subtitle_isforced == True)) + or (_current_subtitle_state == False)): + # subtitle enabled and is forced or subtitle is disabled so determine subtitle + + _prefer_language = _current_audio_language + + if (((_current_subtitle_state == False) and (_current_subtitle_isforced == False)) + and ((conf.p_subtitle_disabled == SUBTITLE_DISABLED.SELECTED_SUBTITLE) + or ((conf.p_subtitle_disabled == SUBTITLE_DISABLED.AUDIO_LANGUAGE) + and (_current_subtitle_language == _current_audio_language) + and (_current_subtitle_isimpaired == conf.p_sdh)))): + # subtitle disabled and current is not forced + # preference is enable selected or audio language and current subtitle is a match including sdh preference + + # index of -1 implies don't touch subtitle but just enable + action = SUBTITLE_STATE(-1, True) + result.action = action + + else: + # figure out preferred language for subtitle + if ((_current_subtitle_state == False) + and (conf.p_subtitle_disabled == SUBTITLE_DISABLED.AUDIO_LANGUAGE)): + _prefer_language = _current_audio_language + elif (_current_subtitle_isforced == True): + if (conf.p_subtitle_forced == SUBTITLE_FORCED.FORCED_LANGUAGE): + _prefer_language = _current_subtitle_language + elif (conf.p_subtitle_forced == SUBTITLE_FORCED.AUDIO_LANGUAGE): + _prefer_language = _current_audio_language + + # determine subtitle based on preferred language and preferences + _preferred_subtitle_index = -1 + _subtitle_other = [] + for _subtitle in _subtitles: + if (_prefer_language == _subtitle['language'] and is_forced(_subtitle) == False): + if (is_sdh(_subtitle) == conf.p_sdh): + _preferred_subtitle_index = _subtitle['index'] + break + _subtitle_other.append(_subtitle['index']) + + if ((_preferred_subtitle_index == -1) and (len(_subtitle_other) > 0)): + # fallback - could not find exact match per preferences + _preferred_subtitle_index = _subtitle_other[0] + + if (_preferred_subtitle_index != -1): + # set determined subtitle and enable + if (_preferred_subtitle_index == _current_subtitle_index): + # determinded subtitle is the same as current so just enable + # probably sdh mismatch only + _preferred_subtitle_index = -1 + action = SUBTITLE_STATE(_preferred_subtitle_index, True) + result.action = action + + return result diff --git a/script.wadeysay/wadeysay_xbmc.py b/script.wadeysay/wadeysay_xbmc.py new file mode 100644 index 000000000..44359628e --- /dev/null +++ b/script.wadeysay/wadeysay_xbmc.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Copyright (C) 2023 iCR8IONS LLC www.icr8ions.com +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# part of an addon called script.wadeysay for Kodi - https://kodi.tv + +# pylint: disable=C0103 + +""" this module contains all xbmc/kodi specific code """ + +import sys +import json +import xbmc +import xbmcaddon +from wadeysay_conf import CONF, SUBTITLE_FORCED, SUBTITLE_DISABLED + +# this is a pointer to the module object instance itself +this = sys.modules[__name__] +this._player_id = None + +def get_conf() -> CONF: + """ instantiation of immutatable configuration object using addon settings """ + _addon = xbmcaddon.Addon() + + _rewind_time = _addon.getSettingInt('rewind') + _longer_time = _addon.getSettingInt('longer') + _p_sdh = _addon.getSettingBool('p_sdh') + _p_subtitle_forced = SUBTITLE_FORCED(_addon.getSettingInt('p_subtitle_forced')) + _p_subtitle_disabled = SUBTITLE_DISABLED(_addon.getSettingInt('p_subtitle_disabled')) + + return CONF(_rewind_time,_longer_time,_p_sdh,_p_subtitle_forced,_p_subtitle_disabled) + +def is_playing_video() -> bool: + """ return true if video is playing """ + return xbmc.Player().isPlayingVideo() + +def rewind_wait(rewind_time: int, longer_time: int): + """ rewind video for rewind_time and wait for rewind_time + longer_time """ + + xbmc.executebuiltin('Seek(-%d)' %(rewind_time)) + xbmc.Monitor().waitForAbort(rewind_time + longer_time) + +def media_has_streams() -> bool: + """ check current media for at least one subtitle and one audio stream """ + # at least one subtitle and one audio available + return ((len(xbmc.Player().getAvailableSubtitleStreams()) > 0) + and (len(xbmc.Player().getAvailableAudioStreams()) > 0)) + +def _get_active_player_id() -> int: + """ determine and return active player id """ + if (this._player_id == None): + _json_query = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetActivePlayers","id":1}') + _json_properties = json.loads(_json_query) + _players = _json_properties["result"] + for _player in _players: + if (_player["type"] == "video"): + this._player_id = _player["playerid"] + break + return this._player_id + +def get_player_properties() -> json: + """ get playing media properties as json """ + _player_id = _get_active_player_id() + return xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetProperties","params":{"playerid":%d,"properties":["subtitles","subtitleenabled","currentsubtitle","audiostreams","currentaudiostream"]},"id":1}' %(_player_id)) + +def enable_subtitle(): + """ just enable subtitle that is currently selected """ + xbmc.Player().showSubtitles(True) + +def disable_subtitle(): + """ just disable subtitle that is currently selected """ + xbmc.Player().showSubtitles(False) + +def enable_subtitle_index(index): + """ enable subtitle by index """ + set_subtitle(index, True) + +def set_subtitle(index: int, subtitle_state: bool): + """ set subtitle by index and set subtitle state """ + _player_id = _get_active_player_id() + xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.SetSubtitle","params":{"playerid":%d,"subtitle":%d,"enable":%s},"id":1}' %(_player_id, index, ("%r" %(subtitle_state)).lower())) + # TODO: workaround since enable:false params does not disable subtitles + xbmc.Player().showSubtitles(subtitle_state) From 4c87191c02ccf5eab391671ca4ea8a4d0cc2bd2d Mon Sep 17 00:00:00 2001 From: Rob Weber Date: Thu, 6 Apr 2023 12:51:41 -0500 Subject: [PATCH 021/145] [script.module.dropbox] 10.3.1 --- script.module.dropbox/addon.xml | 35 +- script.module.dropbox/lib/dropbox/account.py | 323 + script.module.dropbox/lib/dropbox/auth.py | 15 + script.module.dropbox/lib/dropbox/base.py | 833 +- .../lib/dropbox/base_team.py | 370 +- script.module.dropbox/lib/dropbox/check.py | 158 + .../lib/dropbox/cloud_docs.py | 2316 + script.module.dropbox/lib/dropbox/dropbox.py | 184 +- .../lib/dropbox/file_properties.py | 28 +- .../lib/dropbox/file_requests.py | 4 +- script.module.dropbox/lib/dropbox/files.py | 5020 +- script.module.dropbox/lib/dropbox/oauth.py | 285 +- script.module.dropbox/lib/dropbox/paper.py | 330 +- .../lib/dropbox/secondary_emails.py | 121 + script.module.dropbox/lib/dropbox/session.py | 3 + script.module.dropbox/lib/dropbox/sharing.py | 57 +- .../lib/dropbox/stone_base.py | 30 +- .../lib/dropbox/stone_fixtures.py | 139 + .../lib/dropbox/stone_serializers.py | 16 +- .../lib/dropbox/stone_validators.py | 5 +- script.module.dropbox/lib/dropbox/team.py | 26725 +++-- script.module.dropbox/lib/dropbox/team_log.py | 83255 ++++++++++------ .../lib/dropbox/team_policies.py | 208 + script.module.dropbox/lib/dropbox/users.py | 534 +- 24 files changed, 79979 insertions(+), 41015 deletions(-) create mode 100644 script.module.dropbox/lib/dropbox/account.py create mode 100644 script.module.dropbox/lib/dropbox/check.py create mode 100644 script.module.dropbox/lib/dropbox/cloud_docs.py create mode 100644 script.module.dropbox/lib/dropbox/secondary_emails.py create mode 100644 script.module.dropbox/lib/dropbox/stone_fixtures.py diff --git a/script.module.dropbox/addon.xml b/script.module.dropbox/addon.xml index 50734f264..489718bcb 100644 --- a/script.module.dropbox/addon.xml +++ b/script.module.dropbox/addon.xml @@ -1,12 +1,12 @@ - - + + @@ -18,16 +18,25 @@ https://www.dropbox.com/developers/documentation/python https://github.com/dropbox/dropbox-sdk-python -v9.4.0 (2019-11-26) -- support for Python 3 -v8.4.2 (2019-08-23) -- Fix Windows import errors (github.com/robweber) -- Make qrcode module an optional dependency (github.com/robweber) -v8.4.1 (2017-11-28) -- Update to API version 8.4.0 -- Switch strings to po format -- Add Hebrew (github.com/Eng2Heb) -- Fix for UI lib issues (github.com/SchapplM) +v10.3.1 (2020-08-10) +- remove beta feature comments +v10.3.0 (2020-07-15) +- Update Readme +- Fix error message for non-UTF8 strings +- Make with_path_root() update existing headers rather than overwrite them +- Add Close() method to _DropboxTransport to cleanup any network resources +- Add default timeout to oauth flow finish calls +v10.2.0 (2020-05-27) +- support additional properties for Dropbox Teams +v10.1.0 (2020-04-16) +- support additional properties for Dropbox Teams +v10.0.0 (2020-04-16) +- support for PKCE +- Added support for short lived access tokens +- added support for scopes +- requirements update +v9.5.0 (2020-04-02) +- support additional properties for Dropbox Teams diff --git a/script.module.dropbox/lib/dropbox/account.py b/script.module.dropbox/lib/dropbox/account.py new file mode 100644 index 000000000..83aa7ae35 --- /dev/null +++ b/script.module.dropbox/lib/dropbox/account.py @@ -0,0 +1,323 @@ +# -*- coding: utf-8 -*- +# Auto-generated by Stone, do not modify. +# @generated +# flake8: noqa +# pylint: skip-file +try: + from . import stone_validators as bv + from . import stone_base as bb +except (ImportError, SystemError, ValueError): + # Catch errors raised when importing a relative module when not in a package. + # This makes testing this file directly (outside of a package) easier. + import stone_validators as bv + import stone_base as bb + +class PhotoSourceArg(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar str account.PhotoSourceArg.base64_data: Image data in base64-encoded + bytes. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def base64_data(cls, val): + """ + Create an instance of this class set to the ``base64_data`` tag with + value ``val``. + + :param str val: + :rtype: PhotoSourceArg + """ + return cls('base64_data', val) + + def is_base64_data(self): + """ + Check if the union tag is ``base64_data``. + + :rtype: bool + """ + return self._tag == 'base64_data' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_base64_data(self): + """ + Image data in base64-encoded bytes. + + Only call this if :meth:`is_base64_data` is true. + + :rtype: str + """ + if not self.is_base64_data(): + raise AttributeError("tag 'base64_data' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PhotoSourceArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PhotoSourceArg(%r, %r)' % (self._tag, self._value) + +PhotoSourceArg_validator = bv.Union(PhotoSourceArg) + +class SetProfilePhotoArg(bb.Struct): + """ + :ivar account.SetProfilePhotoArg.photo: Image to set as the user's new + profile photo. + """ + + __slots__ = [ + '_photo_value', + '_photo_present', + ] + + _has_required_fields = True + + def __init__(self, + photo=None): + self._photo_value = None + self._photo_present = False + if photo is not None: + self.photo = photo + + @property + def photo(self): + """ + Image to set as the user's new profile photo. + + :rtype: PhotoSourceArg + """ + if self._photo_present: + return self._photo_value + else: + raise AttributeError("missing required field 'photo'") + + @photo.setter + def photo(self, val): + self._photo_validator.validate_type_only(val) + self._photo_value = val + self._photo_present = True + + @photo.deleter + def photo(self): + self._photo_value = None + self._photo_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SetProfilePhotoArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SetProfilePhotoArg(photo={!r})'.format( + self._photo_value, + ) + +SetProfilePhotoArg_validator = bv.Struct(SetProfilePhotoArg) + +class SetProfilePhotoError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar account.SetProfilePhotoError.file_type_error: File cannot be set as + profile photo. + :ivar account.SetProfilePhotoError.file_size_error: File cannot exceed 10 + MB. + :ivar account.SetProfilePhotoError.dimension_error: Image must be larger + than 128 x 128. + :ivar account.SetProfilePhotoError.thumbnail_error: Image could not be + thumbnailed. + :ivar account.SetProfilePhotoError.transient_error: Temporary infrastructure + failure, please retry. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + file_type_error = None + # Attribute is overwritten below the class definition + file_size_error = None + # Attribute is overwritten below the class definition + dimension_error = None + # Attribute is overwritten below the class definition + thumbnail_error = None + # Attribute is overwritten below the class definition + transient_error = None + # Attribute is overwritten below the class definition + other = None + + def is_file_type_error(self): + """ + Check if the union tag is ``file_type_error``. + + :rtype: bool + """ + return self._tag == 'file_type_error' + + def is_file_size_error(self): + """ + Check if the union tag is ``file_size_error``. + + :rtype: bool + """ + return self._tag == 'file_size_error' + + def is_dimension_error(self): + """ + Check if the union tag is ``dimension_error``. + + :rtype: bool + """ + return self._tag == 'dimension_error' + + def is_thumbnail_error(self): + """ + Check if the union tag is ``thumbnail_error``. + + :rtype: bool + """ + return self._tag == 'thumbnail_error' + + def is_transient_error(self): + """ + Check if the union tag is ``transient_error``. + + :rtype: bool + """ + return self._tag == 'transient_error' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SetProfilePhotoError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SetProfilePhotoError(%r, %r)' % (self._tag, self._value) + +SetProfilePhotoError_validator = bv.Union(SetProfilePhotoError) + +class SetProfilePhotoResult(bb.Struct): + """ + :ivar account.SetProfilePhotoResult.profile_photo_url: URL for the photo + representing the user, if one is set. + """ + + __slots__ = [ + '_profile_photo_url_value', + '_profile_photo_url_present', + ] + + _has_required_fields = True + + def __init__(self, + profile_photo_url=None): + self._profile_photo_url_value = None + self._profile_photo_url_present = False + if profile_photo_url is not None: + self.profile_photo_url = profile_photo_url + + @property + def profile_photo_url(self): + """ + URL for the photo representing the user, if one is set. + + :rtype: str + """ + if self._profile_photo_url_present: + return self._profile_photo_url_value + else: + raise AttributeError("missing required field 'profile_photo_url'") + + @profile_photo_url.setter + def profile_photo_url(self, val): + val = self._profile_photo_url_validator.validate(val) + self._profile_photo_url_value = val + self._profile_photo_url_present = True + + @profile_photo_url.deleter + def profile_photo_url(self): + self._profile_photo_url_value = None + self._profile_photo_url_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SetProfilePhotoResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SetProfilePhotoResult(profile_photo_url={!r})'.format( + self._profile_photo_url_value, + ) + +SetProfilePhotoResult_validator = bv.Struct(SetProfilePhotoResult) + +PhotoSourceArg._base64_data_validator = bv.String() +PhotoSourceArg._other_validator = bv.Void() +PhotoSourceArg._tagmap = { + 'base64_data': PhotoSourceArg._base64_data_validator, + 'other': PhotoSourceArg._other_validator, +} + +PhotoSourceArg.other = PhotoSourceArg('other') + +SetProfilePhotoArg._photo_validator = PhotoSourceArg_validator +SetProfilePhotoArg._all_field_names_ = set(['photo']) +SetProfilePhotoArg._all_fields_ = [('photo', SetProfilePhotoArg._photo_validator)] + +SetProfilePhotoError._file_type_error_validator = bv.Void() +SetProfilePhotoError._file_size_error_validator = bv.Void() +SetProfilePhotoError._dimension_error_validator = bv.Void() +SetProfilePhotoError._thumbnail_error_validator = bv.Void() +SetProfilePhotoError._transient_error_validator = bv.Void() +SetProfilePhotoError._other_validator = bv.Void() +SetProfilePhotoError._tagmap = { + 'file_type_error': SetProfilePhotoError._file_type_error_validator, + 'file_size_error': SetProfilePhotoError._file_size_error_validator, + 'dimension_error': SetProfilePhotoError._dimension_error_validator, + 'thumbnail_error': SetProfilePhotoError._thumbnail_error_validator, + 'transient_error': SetProfilePhotoError._transient_error_validator, + 'other': SetProfilePhotoError._other_validator, +} + +SetProfilePhotoError.file_type_error = SetProfilePhotoError('file_type_error') +SetProfilePhotoError.file_size_error = SetProfilePhotoError('file_size_error') +SetProfilePhotoError.dimension_error = SetProfilePhotoError('dimension_error') +SetProfilePhotoError.thumbnail_error = SetProfilePhotoError('thumbnail_error') +SetProfilePhotoError.transient_error = SetProfilePhotoError('transient_error') +SetProfilePhotoError.other = SetProfilePhotoError('other') + +SetProfilePhotoResult._profile_photo_url_validator = bv.String() +SetProfilePhotoResult._all_field_names_ = set(['profile_photo_url']) +SetProfilePhotoResult._all_fields_ = [('profile_photo_url', SetProfilePhotoResult._profile_photo_url_validator)] + +set_profile_photo = bb.Route( + 'set_profile_photo', + 1, + False, + SetProfilePhotoArg_validator, + SetProfilePhotoResult_validator, + SetProfilePhotoError_validator, + {'host': u'api', + 'style': u'rpc'}, +) + +ROUTES = { + 'set_profile_photo': set_profile_photo, +} + diff --git a/script.module.dropbox/lib/dropbox/auth.py b/script.module.dropbox/lib/dropbox/auth.py index 1862571f1..83dac32ab 100644 --- a/script.module.dropbox/lib/dropbox/auth.py +++ b/script.module.dropbox/lib/dropbox/auth.py @@ -126,6 +126,8 @@ class AuthError(bb.Union): :ivar auth.AuthError.expired_access_token: The access token has expired. :ivar TokenScopeError AuthError.missing_scope: The access token does not have the required scope to access the route. + :ivar auth.AuthError.route_access_denied: The route is not available to + public. """ _catch_all = 'other' @@ -140,6 +142,8 @@ class AuthError(bb.Union): # Attribute is overwritten below the class definition expired_access_token = None # Attribute is overwritten below the class definition + route_access_denied = None + # Attribute is overwritten below the class definition other = None @classmethod @@ -201,6 +205,14 @@ def is_missing_scope(self): """ return self._tag == 'missing_scope' + def is_route_access_denied(self): + """ + Check if the union tag is ``route_access_denied``. + + :rtype: bool + """ + return self._tag == 'route_access_denied' + def is_other(self): """ Check if the union tag is ``other``. @@ -734,6 +746,7 @@ def __repr__(self): AuthError._user_suspended_validator = bv.Void() AuthError._expired_access_token_validator = bv.Void() AuthError._missing_scope_validator = TokenScopeError_validator +AuthError._route_access_denied_validator = bv.Void() AuthError._other_validator = bv.Void() AuthError._tagmap = { 'invalid_access_token': AuthError._invalid_access_token_validator, @@ -742,6 +755,7 @@ def __repr__(self): 'user_suspended': AuthError._user_suspended_validator, 'expired_access_token': AuthError._expired_access_token_validator, 'missing_scope': AuthError._missing_scope_validator, + 'route_access_denied': AuthError._route_access_denied_validator, 'other': AuthError._other_validator, } @@ -750,6 +764,7 @@ def __repr__(self): AuthError.invalid_select_admin = AuthError('invalid_select_admin') AuthError.user_suspended = AuthError('user_suspended') AuthError.expired_access_token = AuthError('expired_access_token') +AuthError.route_access_denied = AuthError('route_access_denied') AuthError.other = AuthError('other') InvalidAccountTypeError._endpoint_validator = bv.Void() diff --git a/script.module.dropbox/lib/dropbox/base.py b/script.module.dropbox/lib/dropbox/base.py index a4a5fce59..f848fb283 100644 --- a/script.module.dropbox/lib/dropbox/base.py +++ b/script.module.dropbox/lib/dropbox/base.py @@ -7,16 +7,21 @@ import warnings from . import ( + account, async_, auth, + check, + cloud_docs, common, contacts, file_properties, file_requests, files, paper, + secondary_emails, seen_state, sharing, + stone_fixtures, team, team_common, team_log, @@ -33,6 +38,31 @@ class DropboxBase(object): def request(self, route, namespace, arg, arg_binary=None): pass + # ------------------------------------------ + # Routes in account namespace + + def account_set_profile_photo(self, + photo): + """ + Sets a user's profile photo. + + :param photo: Image to set as the user's new profile photo. + :type photo: :class:`dropbox.account.PhotoSourceArg` + :rtype: :class:`dropbox.account.SetProfilePhotoResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.account.SetProfilePhotoError` + """ + arg = account.SetProfilePhotoArg(photo) + r = self.request( + account.set_profile_photo, + 'account', + arg, + None, + ) + return r + # ------------------------------------------ # Routes in auth namespace @@ -77,6 +107,241 @@ def auth_token_revoke(self): ) return None + # ------------------------------------------ + # Routes in check namespace + + def check_app(self, + query=u''): + """ + This endpoint performs App Authentication, validating the supplied app + key and secret, and returns the supplied string, to allow you to test + your code and connection to the Dropbox API. It has no other effect. If + you receive an HTTP 200 response with the supplied query, it indicates + at least part of the Dropbox API infrastructure is working and that the + app key and secret valid. + + :param str query: The string that you'd like to be echoed back to you. + :rtype: :class:`dropbox.check.EchoResult` + """ + arg = check.EchoArg(query) + r = self.request( + check.app, + 'check', + arg, + None, + ) + return r + + def check_user(self, + query=u''): + """ + This endpoint performs User Authentication, validating the supplied + access token, and returns the supplied string, to allow you to test your + code and connection to the Dropbox API. It has no other effect. If you + receive an HTTP 200 response with the supplied query, it indicates at + least part of the Dropbox API infrastructure is working and that the + access token is valid. + + :param str query: The string that you'd like to be echoed back to you. + :rtype: :class:`dropbox.check.EchoResult` + """ + arg = check.EchoArg(query) + r = self.request( + check.user, + 'check', + arg, + None, + ) + return r + + # ------------------------------------------ + # Routes in cloud_docs namespace + + def cloud_docs_get_content(self, + file_id): + """ + Fetch the binary content of the requested document. This route requires + Cloud Docs auth. Please make a request to cloud_docs/authorize and + supply that token in the Authorization header. + + :type file_id: str + :rtype: (None, + :class:`requests.models.Response`) + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.cloud_docs.CloudDocsAccessError` + + If you do not consume the entire response body, then you must call close + on the response object, otherwise you will max out your available + connections. We recommend using the `contextlib.closing + `_ + context manager to ensure this. + """ + arg = cloud_docs.GetContentArg(file_id) + r = self.request( + cloud_docs.get_content, + 'cloud_docs', + arg, + None, + ) + return None + + def cloud_docs_get_content_to_file(self, + download_path, + file_id): + """ + Fetch the binary content of the requested document. This route requires + Cloud Docs auth. Please make a request to cloud_docs/authorize and + supply that token in the Authorization header. + + :param str download_path: Path on local machine to save file. + :type file_id: str + :rtype: None + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.cloud_docs.CloudDocsAccessError` + """ + arg = cloud_docs.GetContentArg(file_id) + r = self.request( + cloud_docs.get_content, + 'cloud_docs', + arg, + None, + ) + self._save_body_to_file(download_path, r[1]) + return None + + def cloud_docs_get_metadata(self, + file_id=u''): + """ + Fetches metadata associated with a Cloud Doc and user. This route + requires Cloud Docs auth. Please make a request to cloud_docs/authorize + and supply that token in the Authorization header. + + :param str file_id: API ID ("id:...") associated with the Cloud Doc. + :rtype: :class:`dropbox.cloud_docs.GetMetadataResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.cloud_docs.GetMetadataError` + """ + arg = cloud_docs.GetMetadataArg(file_id) + r = self.request( + cloud_docs.get_metadata, + 'cloud_docs', + arg, + None, + ) + return r + + def cloud_docs_lock(self, + file_id=u''): + """ + Lock a Cloud Doc. This route requires Cloud Docs auth. Please make a + request to cloud_docs/authorize and supply that token in the + Authorization header. + + :param str file_id: The API ID ("id:...") associated with the Cloud Doc + :rtype: :class:`dropbox.cloud_docs.LockResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.cloud_docs.LockingError` + """ + arg = cloud_docs.LockArg(file_id) + r = self.request( + cloud_docs.lock, + 'cloud_docs', + arg, + None, + ) + return r + + def cloud_docs_rename(self, + file_id=u'', + title=u''): + """ + Update the title of a Cloud Doc. This route requires Cloud Docs auth. + Please make a request to cloud_docs/authorize and supply that token in + the Authorization header. + + :param str file_id: The API ID ("id:...") associated with the Cloud Doc + :param str title: The new title of the doc, excluding extension + :rtype: :class:`dropbox.cloud_docs.RenameResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.cloud_docs.RenameError` + """ + arg = cloud_docs.RenameArg(file_id, + title) + r = self.request( + cloud_docs.rename, + 'cloud_docs', + arg, + None, + ) + return r + + def cloud_docs_unlock(self, + file_id=u''): + """ + Unlock a Cloud Doc. This route requires Cloud Docs auth. Please make a + request to cloud_docs/authorize and supply that token in the + Authorization header. + + :param str file_id: The API ID ("id:...") associated with the Cloud Doc + :rtype: :class:`dropbox.cloud_docs.UnlockResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.cloud_docs.LockingError` + """ + arg = cloud_docs.UnlockArg(file_id) + r = self.request( + cloud_docs.unlock, + 'cloud_docs', + arg, + None, + ) + return r + + def cloud_docs_update_content(self, + f, + file_id, + actor_tokens, + additional_contents=None): + """ + Update the contents of a Cloud Doc. This should be called for files with + a max size of 150MB. This route requires Cloud Docs auth. Please make a + request to cloud_docs/authorize and supply that token in the + Authorization header. + + :param bytes f: Contents to upload. + :type file_id: str + :param list actor_tokens: A list of auth_tokens, one for each editor who + made changes to the document since the last call to update_content. + :param Nullable additional_contents: Currently, this will always be + empty until we implement upload_additional_content. + :rtype: :class:`dropbox.cloud_docs.UpdateContentResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.cloud_docs.UpdateContentError` + """ + arg = cloud_docs.UpdateContentArg(file_id, + actor_tokens, + additional_contents) + r = self.request( + cloud_docs.update_content, + 'cloud_docs', + arg, + f, + ) + return r + # ------------------------------------------ # Routes in contacts namespace @@ -132,7 +397,8 @@ def file_properties_properties_add(self, :param str path: A unique identifier for the file or folder. :param list property_groups: The property groups which are to be added - to a Dropbox file. + to a Dropbox file. No two groups in the input should refer to the + same template. :rtype: None :raises: :class:`.exceptions.ApiError` @@ -162,7 +428,8 @@ def file_properties_properties_overwrite(self, :param str path: A unique identifier for the file or folder. :param list property_groups: The property groups "snapshot" updates to - force apply. + force apply. No two groups in the input should refer to the same + template. :rtype: None :raises: :class:`.exceptions.ApiError` @@ -1354,6 +1621,29 @@ def files_export_to_file(self, self._save_body_to_file(download_path, r[1]) return r[0] + def files_get_file_lock_batch(self, + entries): + """ + Return the lock metadata for the given list of paths. + + :param list entries: List of 'entries'. Each 'entry' contains a path of + the file which will be locked or queried. Duplicate path arguments + in the batch are considered only once. + :rtype: :class:`dropbox.files.LockFileBatchResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.files.LockFileError` + """ + arg = files.LockFileBatchArg(entries) + r = self.request( + files.get_file_lock_batch, + 'files', + arg, + None, + ) + return r + def files_get_metadata(self, path, include_media_info=False, @@ -1631,6 +1921,94 @@ def files_get_thumbnail_to_file(self, self._save_body_to_file(download_path, r[1]) return r[0] + def files_get_thumbnail_v2(self, + resource, + format=files.ThumbnailFormat.jpeg, + size=files.ThumbnailSize.w64h64, + mode=files.ThumbnailMode.strict): + """ + Get a thumbnail for a file. + + :param resource: Information specifying which file to preview. This + could be a path to a file, a shared link pointing to a file, or a + shared link pointing to a folder, with a relative path. + :type resource: :class:`dropbox.files.PathOrLink` + :param format: The format for the thumbnail image, jpeg (default) or + png. For images that are photos, jpeg should be preferred, while + png is better for screenshots and digital arts. + :type format: :class:`dropbox.files.ThumbnailFormat` + :param size: The size for the thumbnail image. + :type size: :class:`dropbox.files.ThumbnailSize` + :param mode: How to resize and crop the image to achieve the desired + size. + :type mode: :class:`dropbox.files.ThumbnailMode` + :rtype: (:class:`dropbox.files.PreviewResult`, + :class:`requests.models.Response`) + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.files.ThumbnailV2Error` + + If you do not consume the entire response body, then you must call close + on the response object, otherwise you will max out your available + connections. We recommend using the `contextlib.closing + `_ + context manager to ensure this. + """ + arg = files.ThumbnailV2Arg(resource, + format, + size, + mode) + r = self.request( + files.get_thumbnail_v2, + 'files', + arg, + None, + ) + return r + + def files_get_thumbnail_to_file_v2(self, + download_path, + resource, + format=files.ThumbnailFormat.jpeg, + size=files.ThumbnailSize.w64h64, + mode=files.ThumbnailMode.strict): + """ + Get a thumbnail for a file. + + :param str download_path: Path on local machine to save file. + :param resource: Information specifying which file to preview. This + could be a path to a file, a shared link pointing to a file, or a + shared link pointing to a folder, with a relative path. + :type resource: :class:`dropbox.files.PathOrLink` + :param format: The format for the thumbnail image, jpeg (default) or + png. For images that are photos, jpeg should be preferred, while + png is better for screenshots and digital arts. + :type format: :class:`dropbox.files.ThumbnailFormat` + :param size: The size for the thumbnail image. + :type size: :class:`dropbox.files.ThumbnailSize` + :param mode: How to resize and crop the image to achieve the desired + size. + :type mode: :class:`dropbox.files.ThumbnailMode` + :rtype: :class:`dropbox.files.PreviewResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.files.ThumbnailV2Error` + """ + arg = files.ThumbnailV2Arg(resource, + format, + size, + mode) + r = self.request( + files.get_thumbnail_v2, + 'files', + arg, + None, + ) + self._save_body_to_file(download_path, r[1]) + return r[0] + def files_get_thumbnail_batch(self, entries): """ @@ -1913,6 +2291,32 @@ def files_list_revisions(self, ) return r + def files_lock_file_batch(self, + entries): + """ + Lock the files at the given paths. A locked file will be writable only + by the lock holder. A successful response indicates that the file has + been locked. Returns a list of the locked file paths and their metadata + after this operation. + + :param list entries: List of 'entries'. Each 'entry' contains a path of + the file which will be locked or queried. Duplicate path arguments + in the batch are considered only once. + :rtype: :class:`dropbox.files.LockFileBatchResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.files.LockFileError` + """ + arg = files.LockFileBatchArg(entries) + r = self.request( + files.lock_file_batch, + 'files', + arg, + None, + ) + return r + def files_move_v2(self, from_path, to_path, @@ -1921,7 +2325,8 @@ def files_move_v2(self, allow_ownership_transfer=False): """ Move a file or folder to a different location in the user's Dropbox. If - the source path is a folder all its contents will be moved. + the source path is a folder all its contents will be moved. Note that we + do not currently support case-only renaming. :param bool allow_shared_folder: If true, :meth:`files_copy` will copy contents in shared folder, otherwise @@ -2001,8 +2406,9 @@ def files_move_batch_v2(self, allow_ownership_transfer=False): """ Move multiple files or folders to different locations at once in the - user's Dropbox. This route will replace :meth:`files_move_batch`. The - main difference is this route will return status for each entry, while + user's Dropbox. Note that we do not currently support case-only + renaming. This route will replace :meth:`files_move_batch`. The main + difference is this route will return status for each entry, while :meth:`files_move_batch` raises failure if any entry fails. This route will either finish synchronously, or return a job ID and do the async move job in background. Please use :meth:`files_move_batch_check_v2` to @@ -2031,9 +2437,8 @@ def files_move_batch(self, allow_ownership_transfer=False): """ Move multiple files or folders to different locations at once in the - user's Dropbox. This route is 'all or nothing', which means if one entry - fails, the whole transaction will abort. This route will return job ID - immediately and do the async moving job in background. Please use + user's Dropbox. This route will return job ID immediately and do the + async moving job in background. Please use :meth:`files_move_batch_check` to check the job status. :param bool allow_shared_folder: If true, :meth:`files_copy_batch` will @@ -2046,6 +2451,10 @@ def files_move_batch(self, This does not apply to copies. :rtype: :class:`dropbox.files.RelocationBatchLaunch` """ + warnings.warn( + 'move_batch is deprecated. Use move_batch.', + DeprecationWarning, + ) arg = files.RelocationBatchArg(entries, autorename, allow_shared_folder, @@ -2095,6 +2504,10 @@ def files_move_batch_check(self, If this raises, ApiError will contain: :class:`dropbox.files.PollError` """ + warnings.warn( + 'move_batch/check is deprecated. Use move_batch/check.', + DeprecationWarning, + ) arg = async_.PollArg(async_job_id) r = self.request( files.move_batch_check, @@ -2138,7 +2551,8 @@ def files_properties_add(self, """ :param str path: A unique identifier for the file or folder. :param list property_groups: The property groups which are to be added - to a Dropbox file. + to a Dropbox file. No two groups in the input should refer to the + same template. :rtype: None :raises: :class:`.exceptions.ApiError` @@ -2165,7 +2579,8 @@ def files_properties_overwrite(self, """ :param str path: A unique identifier for the file or folder. :param list property_groups: The property groups "snapshot" updates to - force apply. + force apply. No two groups in the input should refer to the same + template. :rtype: None :raises: :class:`.exceptions.ApiError` @@ -2366,10 +2781,11 @@ def files_search(self, :param str path: The path in the user's Dropbox to search. Should probably be a folder. - :param str query: The string to search for. The search string is split - on spaces into multiple tokens. For file name searching, the last - token is used for prefix matching (i.e. "bat c" matches "bat cave" - but not "batman car"). + :param str query: The string to search for. Query string may be + rewritten to improve relevance of results. The string is split on + spaces into multiple tokens. For file name searching, the last token + is used for prefix matching (i.e. "bat c" matches "bat cave" but not + "batman car"). :param int start: The starting index within the search results (used for paging). :param int max_results: The maximum number of search results to return. @@ -2383,6 +2799,10 @@ def files_search(self, If this raises, ApiError will contain: :class:`dropbox.files.SearchError` """ + warnings.warn( + 'search is deprecated. Use search.', + DeprecationWarning, + ) arg = files.SearchArg(path, query, start, @@ -2396,6 +2816,92 @@ def files_search(self, ) return r + def files_search_v2(self, + query, + options=None, + include_highlights=False): + """ + Searches for files and folders. Note: :meth:`files_search_v2` along with + :meth:`files_search_continue_v2` can only be used to retrieve a maximum + of 10,000 matches. Recent changes may not immediately be reflected in + search results due to a short delay in indexing. Duplicate results may + be returned across pages. Some results may not be returned. + + :param str query: The string to search for. May match across multiple + fields based on the request arguments. Query string may be rewritten + to improve relevance of results. + :param Nullable options: Options for more targeted search results. + :type include_highlights: bool + :rtype: :class:`dropbox.files.SearchV2Result` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.files.SearchError` + """ + arg = files.SearchV2Arg(query, + options, + include_highlights) + r = self.request( + files.search_v2, + 'files', + arg, + None, + ) + return r + + def files_search_continue_v2(self, + cursor): + """ + Fetches the next page of search results returned from + :meth:`files_search_v2`. Note: :meth:`files_search_v2` along with + :meth:`files_search_continue_v2` can only be used to retrieve a maximum + of 10,000 matches. Recent changes may not immediately be reflected in + search results due to a short delay in indexing. Duplicate results may + be returned across pages. Some results may not be returned. + + :param str cursor: The cursor returned by your last call to + :meth:`files_search_v2`. Used to fetch the next page of results. + :rtype: :class:`dropbox.files.SearchV2Result` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.files.SearchError` + """ + arg = files.SearchV2ContinueArg(cursor) + r = self.request( + files.search_continue_v2, + 'files', + arg, + None, + ) + return r + + def files_unlock_file_batch(self, + entries): + """ + Unlock the files at the given paths. A locked file can only be unlocked + by the lock holder or, if a business account, a team admin. A successful + response indicates that the file has been unlocked. Returns a list of + the unlocked file paths and their metadata after this operation. + + :param list entries: List of 'entries'. Each 'entry' contains a path of + the file which will be unlocked. Duplicate path arguments in the + batch are considered only once. + :rtype: :class:`dropbox.files.LockFileBatchResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.files.LockFileError` + """ + arg = files.UnlockFileBatchArg(entries) + r = self.request( + files.unlock_file_batch, + 'files', + arg, + None, + ) + return r + def files_upload(self, f, path, @@ -2675,8 +3181,15 @@ def files_upload_session_start(self, def paper_docs_archive(self, doc_id): """ - Marks the given Paper doc as archived. Note: This action can be - performed or undone by anyone with edit permissions to the doc. + Marks the given Paper doc as archived. This action can be performed or + undone by anyone with edit permissions to the doc. Note that this + endpoint will continue to work for content created by users on the older + version of Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. This endpoint will be + retired in September 2020. Refer to the `Paper Migration Guide + `_ + for more information. :param str doc_id: The Paper doc ID. :rtype: None @@ -2685,6 +3198,10 @@ def paper_docs_archive(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/archive is deprecated.', + DeprecationWarning, + ) arg = paper.RefPaperDoc(doc_id) r = self.request( paper.docs_archive, @@ -2699,7 +3216,14 @@ def paper_docs_create(self, import_format, parent_folder_id=None): """ - Creates a new Paper doc with the provided content. + Creates a new Paper doc with the provided content. Note that this + endpoint will continue to work for content created by users on the older + version of Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. This endpoint will be + retired in September 2020. Refer to the `Paper Migration Guide + `_ + for more information. :param bytes f: Contents to upload. :param Nullable parent_folder_id: The Paper folder ID where the Paper @@ -2713,6 +3237,10 @@ def paper_docs_create(self, If this raises, ApiError will contain: :class:`dropbox.paper.PaperDocCreateError` """ + warnings.warn( + 'docs/create is deprecated.', + DeprecationWarning, + ) arg = paper.PaperDocCreateArgs(import_format, parent_folder_id) r = self.request( @@ -2727,7 +3255,14 @@ def paper_docs_download(self, doc_id, export_format): """ - Exports and downloads Paper doc either as HTML or markdown. + Exports and downloads Paper doc either as HTML or markdown. Note that + this endpoint will continue to work for content created by users on the + older version of Paper. To check which version of Paper a user is on, + use /users/features/get_values. If the paper_as_files feature is + enabled, then the user is running the new version of Paper. Refer to the + `Paper Migration Guide + `_ + for migration information. :type export_format: :class:`dropbox.paper.ExportFormat` :rtype: (:class:`dropbox.paper.PaperDocExportResult`, @@ -2743,6 +3278,10 @@ def paper_docs_download(self, `_ context manager to ensure this. """ + warnings.warn( + 'docs/download is deprecated.', + DeprecationWarning, + ) arg = paper.PaperDocExport(doc_id, export_format) r = self.request( @@ -2758,7 +3297,14 @@ def paper_docs_download_to_file(self, doc_id, export_format): """ - Exports and downloads Paper doc either as HTML or markdown. + Exports and downloads Paper doc either as HTML or markdown. Note that + this endpoint will continue to work for content created by users on the + older version of Paper. To check which version of Paper a user is on, + use /users/features/get_values. If the paper_as_files feature is + enabled, then the user is running the new version of Paper. Refer to the + `Paper Migration Guide + `_ + for migration information. :param str download_path: Path on local machine to save file. :type export_format: :class:`dropbox.paper.ExportFormat` @@ -2768,6 +3314,10 @@ def paper_docs_download_to_file(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/download is deprecated.', + DeprecationWarning, + ) arg = paper.PaperDocExport(doc_id, export_format) r = self.request( @@ -2786,7 +3336,14 @@ def paper_docs_folder_users_list(self, Lists the users who are explicitly invited to the Paper folder in which the Paper doc is contained. For private folders all users (including owner) shared on the folder are listed and for team folders all non-team - users shared on the folder are returned. + users shared on the folder are returned. Note that this endpoint will + continue to work for content created by users on the older version of + Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. :param int limit: Size limit per batch. The maximum number of users that can be retrieved per batch is 1000. Higher value results in invalid @@ -2797,6 +3354,10 @@ def paper_docs_folder_users_list(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/folder_users/list is deprecated.', + DeprecationWarning, + ) arg = paper.ListUsersOnFolderArgs(doc_id, limit) r = self.request( @@ -2813,7 +3374,13 @@ def paper_docs_folder_users_list_continue(self, """ Once a cursor has been retrieved from :meth:`paper_docs_folder_users_list`, use this to paginate through all - users on the Paper folder. + users on the Paper folder. Note that this endpoint will continue to work + for content created by users on the older version of Paper. To check + which version of Paper a user is on, use /users/features/get_values. If + the paper_as_files feature is enabled, then the user is running the new + version of Paper. Refer to the `Paper Migration Guide + `_ + for migration information. :param str cursor: The cursor obtained from :meth:`paper_docs_folder_users_list` or @@ -2825,6 +3392,10 @@ def paper_docs_folder_users_list_continue(self, If this raises, ApiError will contain: :class:`dropbox.paper.ListUsersCursorError` """ + warnings.warn( + 'docs/folder_users/list/continue is deprecated.', + DeprecationWarning, + ) arg = paper.ListUsersOnFolderContinueArgs(doc_id, cursor) r = self.request( @@ -2842,8 +3413,15 @@ def paper_docs_get_folder_info(self, folder sharing policy; permissions for subfolders are set by the top-level folder. - full 'filepath', i.e. the list of folders (both folderId and folderName) from the root folder to the folder directly - containing the Paper doc. Note: If the Paper doc is not in any folder - (aka unfiled) the response will be empty. + containing the Paper doc. If the Paper doc is not in any folder (aka + unfiled) the response will be empty. Note that this endpoint will + continue to work for content created by users on the older version of + Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. :param str doc_id: The Paper doc ID. :rtype: :class:`dropbox.paper.FoldersContainingPaperDoc` @@ -2852,6 +3430,10 @@ def paper_docs_get_folder_info(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/get_folder_info is deprecated.', + DeprecationWarning, + ) arg = paper.RefPaperDoc(doc_id) r = self.request( paper.docs_get_folder_info, @@ -2869,7 +3451,14 @@ def paper_docs_list(self, """ Return the list of all Paper docs according to the argument specifications. To iterate over through the full pagination, pass the - cursor to :meth:`paper_docs_list_continue`. + cursor to :meth:`paper_docs_list_continue`. Note that this endpoint will + continue to work for content created by users on the older version of + Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. :param filter_by: Allows user to specify how the Paper docs should be filtered. @@ -2884,6 +3473,10 @@ def paper_docs_list(self, arguments error. :rtype: :class:`dropbox.paper.ListPaperDocsResponse` """ + warnings.warn( + 'docs/list is deprecated.', + DeprecationWarning, + ) arg = paper.ListPaperDocsArgs(filter_by, sort_by, sort_order, @@ -2900,7 +3493,14 @@ def paper_docs_list_continue(self, cursor): """ Once a cursor has been retrieved from :meth:`paper_docs_list`, use this - to paginate through all Paper doc. + to paginate through all Paper doc. Note that this endpoint will continue + to work for content created by users on the older version of Paper. To + check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. :param str cursor: The cursor obtained from :meth:`paper_docs_list` or :meth:`paper_docs_list_continue`. Allows for pagination. @@ -2910,6 +3510,10 @@ def paper_docs_list_continue(self, If this raises, ApiError will contain: :class:`dropbox.paper.ListDocsCursorError` """ + warnings.warn( + 'docs/list/continue is deprecated.', + DeprecationWarning, + ) arg = paper.ListPaperDocsContinueArgs(cursor) r = self.request( paper.docs_list_continue, @@ -2923,8 +3527,14 @@ def paper_docs_permanently_delete(self, doc_id): """ Permanently deletes the given Paper doc. This operation is final as the - doc cannot be recovered. Note: This action can be performed only by the - doc owner. + doc cannot be recovered. This action can be performed only by the doc + owner. Note that this endpoint will continue to work for content created + by users on the older version of Paper. To check which version of Paper + a user is on, use /users/features/get_values. If the paper_as_files + feature is enabled, then the user is running the new version of Paper. + Refer to the `Paper Migration Guide + `_ + for migration information. :param str doc_id: The Paper doc ID. :rtype: None @@ -2933,6 +3543,10 @@ def paper_docs_permanently_delete(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/permanently_delete is deprecated.', + DeprecationWarning, + ) arg = paper.RefPaperDoc(doc_id) r = self.request( paper.docs_permanently_delete, @@ -2945,7 +3559,14 @@ def paper_docs_permanently_delete(self, def paper_docs_sharing_policy_get(self, doc_id): """ - Gets the default sharing policy for the given Paper doc. + Gets the default sharing policy for the given Paper doc. Note that this + endpoint will continue to work for content created by users on the older + version of Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. :param str doc_id: The Paper doc ID. :rtype: :class:`dropbox.paper.SharingPolicy` @@ -2954,6 +3575,10 @@ def paper_docs_sharing_policy_get(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/sharing_policy/get is deprecated.', + DeprecationWarning, + ) arg = paper.RefPaperDoc(doc_id) r = self.request( paper.docs_sharing_policy_get, @@ -2969,9 +3594,15 @@ def paper_docs_sharing_policy_set(self, """ Sets the default sharing policy for the given Paper doc. The default 'team_sharing_policy' can be changed only by teams, omit this field for - personal accounts. Note: 'public_sharing_policy' cannot be set to the - value 'disabled' because this setting can be changed only via the team - admin console. + personal accounts. The 'public_sharing_policy' policy can't be set to + the value 'disabled' because this setting can be changed only via the + team admin console. Note that this endpoint will continue to work for + content created by users on the older version of Paper. To check which + version of Paper a user is on, use /users/features/get_values. If the + paper_as_files feature is enabled, then the user is running the new + version of Paper. Refer to the `Paper Migration Guide + `_ + for migration information. :param sharing_policy: The default sharing policy to be set for the Paper doc. @@ -2982,6 +3613,10 @@ def paper_docs_sharing_policy_set(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/sharing_policy/set is deprecated.', + DeprecationWarning, + ) arg = paper.PaperDocSharingPolicy(doc_id, sharing_policy) r = self.request( @@ -2999,7 +3634,14 @@ def paper_docs_update(self, revision, import_format): """ - Updates an existing Paper doc with the provided content. + Updates an existing Paper doc with the provided content. Note that this + endpoint will continue to work for content created by users on the older + version of Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. This endpoint will be + retired in September 2020. Refer to the `Paper Migration Guide + `_ + for more information. :param bytes f: Contents to upload. :param doc_update_policy: The policy used for the current update call. @@ -3015,6 +3657,10 @@ def paper_docs_update(self, If this raises, ApiError will contain: :class:`dropbox.paper.PaperDocUpdateError` """ + warnings.warn( + 'docs/update is deprecated.', + DeprecationWarning, + ) arg = paper.PaperDocUpdateArgs(doc_id, doc_update_policy, revision, @@ -3034,8 +3680,15 @@ def paper_docs_users_add(self, quiet=False): """ Allows an owner or editor to add users to a Paper doc or change their - permissions using their email address or Dropbox account ID. Note: The - Doc owner's permissions cannot be changed. + permissions using their email address or Dropbox account ID. The doc + owner's permissions cannot be changed. Note that this endpoint will + continue to work for content created by users on the older version of + Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. :param list members: User which should be added to the Paper doc. Specify only email address or Dropbox account ID. @@ -3049,6 +3702,10 @@ def paper_docs_users_add(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/users/add is deprecated.', + DeprecationWarning, + ) arg = paper.AddPaperDocUser(doc_id, members, custom_message, @@ -3070,7 +3727,13 @@ def paper_docs_users_list(self, This call excludes users who have been removed. The list is sorted by the date of the visit or the share date. The list will include both users, the explicitly shared ones as well as those who came in using the - Paper url link. + Paper url link. Note that this endpoint will continue to work for + content created by users on the older version of Paper. To check which + version of Paper a user is on, use /users/features/get_values. If the + paper_as_files feature is enabled, then the user is running the new + version of Paper. Refer to the `Paper Migration Guide + `_ + for migration information. :param int limit: Size limit per batch. The maximum number of users that can be retrieved per batch is 1000. Higher value results in invalid @@ -3084,6 +3747,10 @@ def paper_docs_users_list(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/users/list is deprecated.', + DeprecationWarning, + ) arg = paper.ListUsersOnPaperDocArgs(doc_id, limit, filter_by) @@ -3100,7 +3767,14 @@ def paper_docs_users_list_continue(self, cursor): """ Once a cursor has been retrieved from :meth:`paper_docs_users_list`, use - this to paginate through all users on the Paper doc. + this to paginate through all users on the Paper doc. Note that this + endpoint will continue to work for content created by users on the older + version of Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. :param str cursor: The cursor obtained from :meth:`paper_docs_users_list` or @@ -3111,6 +3785,10 @@ def paper_docs_users_list_continue(self, If this raises, ApiError will contain: :class:`dropbox.paper.ListUsersCursorError` """ + warnings.warn( + 'docs/users/list/continue is deprecated.', + DeprecationWarning, + ) arg = paper.ListUsersOnPaperDocContinueArgs(doc_id, cursor) r = self.request( @@ -3126,7 +3804,14 @@ def paper_docs_users_remove(self, member): """ Allows an owner or editor to remove users from a Paper doc using their - email address or Dropbox account ID. Note: Doc owner cannot be removed. + email address or Dropbox account ID. The doc owner cannot be removed. + Note that this endpoint will continue to work for content created by + users on the older version of Paper. To check which version of Paper a + user is on, use /users/features/get_values. If the paper_as_files + feature is enabled, then the user is running the new version of Paper. + Refer to the `Paper Migration Guide + `_ + for migration information. :param member: User which should be removed from the Paper doc. Specify only email address or Dropbox account ID. @@ -3137,6 +3822,10 @@ def paper_docs_users_remove(self, If this raises, ApiError will contain: :class:`dropbox.paper.DocLookupError` """ + warnings.warn( + 'docs/users/remove is deprecated.', + DeprecationWarning, + ) arg = paper.RemovePaperDocUser(doc_id, member) r = self.request( @@ -3147,6 +3836,52 @@ def paper_docs_users_remove(self, ) return None + def paper_folders_create(self, + name, + parent_folder_id=None, + is_team_folder=None): + """ + Create a new Paper folder with the provided info. Note that this + endpoint will continue to work for content created by users on the older + version of Paper. To check which version of Paper a user is on, use + /users/features/get_values. If the paper_as_files feature is enabled, + then the user is running the new version of Paper. Refer to the `Paper + Migration Guide + `_ + for migration information. + + :param str name: The name of the new Paper folder. + :param Nullable parent_folder_id: The encrypted Paper folder Id where + the new Paper folder should be created. The API user has to have + write access to this folder or error is thrown. If not supplied, the + new folder will be created at top level. + :param Nullable is_team_folder: Whether the folder to be created should + be a team folder. This value will be ignored if parent_folder_id is + supplied, as the new folder will inherit the type (private or team + folder) from its parent. We will by default create a top-level + private folder if both parent_folder_id and is_team_folder are not + supplied. + :rtype: :class:`dropbox.paper.PaperFolderCreateResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.paper.PaperFolderCreateError` + """ + warnings.warn( + 'folders/create is deprecated.', + DeprecationWarning, + ) + arg = paper.PaperFolderCreateArg(name, + parent_folder_id, + is_team_folder) + r = self.request( + paper.folders_create, + 'paper', + arg, + None, + ) + return r + # ------------------------------------------ # Routes in sharing namespace @@ -4450,6 +5185,30 @@ def sharing_update_folder_policy(self, # ------------------------------------------ # Routes in users namespace + def users_features_get_values(self, + features): + """ + Get a list of feature values that may be configured for the current + account. + + :param list features: A list of features in + :class:`dropbox.users.UserFeature`. If the list is empty, this route + will return :class:`dropbox.users.UserFeaturesGetValuesBatchError`. + :rtype: :class:`dropbox.users.UserFeaturesGetValuesBatchResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.users.UserFeaturesGetValuesBatchError` + """ + arg = users.UserFeaturesGetValuesBatchArg(features) + r = self.request( + users.features_get_values, + 'users', + arg, + None, + ) + return r + def users_get_account(self, account_id): """ diff --git a/script.module.dropbox/lib/dropbox/base_team.py b/script.module.dropbox/lib/dropbox/base_team.py index cb01060dc..d5440b958 100644 --- a/script.module.dropbox/lib/dropbox/base_team.py +++ b/script.module.dropbox/lib/dropbox/base_team.py @@ -7,16 +7,21 @@ import warnings from . import ( + account, async_, auth, + check, + cloud_docs, common, contacts, file_properties, file_requests, files, paper, + secondary_emails, seen_state, sharing, + stone_fixtures, team, team_common, team_log, @@ -33,9 +38,18 @@ class DropboxTeamBase(object): def request(self, route, namespace, arg, arg_binary=None): pass + # ------------------------------------------ + # Routes in account namespace + # ------------------------------------------ # Routes in auth namespace + # ------------------------------------------ + # Routes in check namespace + + # ------------------------------------------ + # Routes in cloud_docs namespace + # ------------------------------------------ # Routes in contacts namespace @@ -386,6 +400,7 @@ def team_get_info(self): def team_groups_create(self, group_name, + add_creator_as_owner=False, group_external_id=None, group_management_type=None): """ @@ -393,6 +408,8 @@ def team_groups_create(self, member management. :param str group_name: Group name. + :param bool add_creator_as_owner: Automatically add the creator of the + group. :param Nullable group_external_id: The creator of a team can associate an arbitrary external ID to the group. :param Nullable group_management_type: Whether the team can be managed @@ -404,6 +421,7 @@ def team_groups_create(self, :class:`dropbox.team.GroupCreateError` """ arg = team.GroupCreateArg(group_name, + add_creator_as_owner, group_external_id, group_management_type) r = self.request( @@ -711,6 +729,182 @@ def team_groups_update(self, ) return r + def team_legal_holds_create_policy(self, + name, + members, + description=None, + start_date=None, + end_date=None): + """ + Creates new legal hold policy. Permission : Team member file access. + + :param str name: Policy name. + :param Nullable description: A description of the legal hold policy. + :param list members: List of team members added to the hold. + :param Nullable start_date: start date of the legal hold policy. + :param Nullable end_date: end date of the legal hold policy. + :rtype: :class:`dropbox.team.LegalHoldPolicy` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.LegalHoldsPolicyCreateError` + """ + arg = team.LegalHoldsPolicyCreateArg(name, + members, + description, + start_date, + end_date) + r = self.request( + team.legal_holds_create_policy, + 'team', + arg, + None, + ) + return r + + def team_legal_holds_get_policy(self, + id): + """ + Gets a legal hold by Id. Permission : Team member file access. + + :param str id: The legal hold Id. + :rtype: :class:`dropbox.team.LegalHoldPolicy` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.LegalHoldsGetPolicyError` + """ + arg = team.LegalHoldsGetPolicyArg(id) + r = self.request( + team.legal_holds_get_policy, + 'team', + arg, + None, + ) + return r + + def team_legal_holds_list_held_revisions(self, + id): + """ + List the file metadata that's under the hold. Permission : Team member + file access. + + :param str id: The legal hold Id. + :rtype: :class:`dropbox.team.LegalHoldsListHeldRevisionResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.LegalHoldsListHeldRevisionsError` + """ + arg = team.LegalHoldsListHeldRevisionsArg(id) + r = self.request( + team.legal_holds_list_held_revisions, + 'team', + arg, + None, + ) + return r + + def team_legal_holds_list_held_revisions_continue(self, + id, + cursor=None): + """ + Continue listing the file metadata that's under the hold. Permission : + Team member file access. + + :param str id: The legal hold Id. + :param Nullable cursor: The cursor idicates where to continue reading + file metadata entries for the next API call. When there are no more + entries, the cursor will return none. + :rtype: :class:`dropbox.team.LegalHoldsListHeldRevisionResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.LegalHoldsListHeldRevisionsError` + """ + arg = team.LegalHoldsListHeldRevisionsContinueArg(id, + cursor) + r = self.request( + team.legal_holds_list_held_revisions_continue, + 'team', + arg, + None, + ) + return r + + def team_legal_holds_list_policies(self, + include_released=False): + """ + Lists legal holds on a team. Permission : Team member file access. + + :param bool include_released: Whether to return holds that were + released. + :rtype: :class:`dropbox.team.LegalHoldsListPoliciesResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.LegalHoldsListPoliciesError` + """ + arg = team.LegalHoldsListPoliciesArg(include_released) + r = self.request( + team.legal_holds_list_policies, + 'team', + arg, + None, + ) + return r + + def team_legal_holds_release_policy(self, + id): + """ + Releases a legal hold by Id. Permission : Team member file access. + + :param str id: The legal hold Id. + :rtype: None + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.LegalHoldsPolicyReleaseError` + """ + arg = team.LegalHoldsPolicyReleaseArg(id) + r = self.request( + team.legal_holds_release_policy, + 'team', + arg, + None, + ) + return None + + def team_legal_holds_update_policy(self, + id, + members, + name=None, + description=None): + """ + Updates a legal hold. Permission : Team member file access. + + :param str id: The legal hold Id. + :param Nullable name: Policy new name. + :param Nullable description: Policy new description. + :param list members: List of team members to apply the policy on. + :rtype: :class:`dropbox.team.LegalHoldPolicy` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.LegalHoldsPolicyUpdateError` + """ + arg = team.LegalHoldsPolicyUpdateArg(id, + members, + name, + description) + r = self.request( + team.legal_holds_update_policy, + 'team', + arg, + None, + ) + return r + def team_linked_apps_list_member_linked_apps(self, team_member_id): """ @@ -1045,6 +1239,29 @@ def team_members_add_job_status_get(self, ) return r + def team_members_delete_profile_photo(self, + user): + """ + Deletes a team member's profile photo. Permission : Team member + management. + + :param user: Identity of the user whose profile photo will be deleted. + :type user: :class:`dropbox.team.UserSelectorArg` + :rtype: :class:`dropbox.team.TeamMemberInfo` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.MembersDeleteProfilePhotoError` + """ + arg = team.MembersDeleteProfilePhotoArg(user) + r = self.request( + team.members_delete_profile_photo, + 'team', + arg, + None, + ) + return r + def team_members_get_info(self, members): """ @@ -1204,7 +1421,8 @@ def team_members_remove(self, wipe_data=True, transfer_dest_id=None, transfer_admin_id=None, - keep_account=False): + keep_account=False, + retain_team_shares=False): """ Removes a member from a team. Permission : Team member management Exactly one of team_member_id, email, or external_id must be provided to @@ -1215,7 +1433,7 @@ def team_members_remove(self, recoverable on your team will return with ``MemberAddResult.user_already_on_team``. Accounts can have their files transferred via the admin console for a limited time, based on the - version history length associated with the team (120 days for most + version history length associated with the team (180 days for most teams). This endpoint may initiate an asynchronous job. To obtain the final result of the job, the client should periodically poll :meth:`team_members_remove_job_status_get`. @@ -1229,8 +1447,15 @@ def team_members_remove(self, :param bool keep_account: Downgrade the member to a Basic account. The user will retain the email address associated with their Dropbox account and data in their account that is not restricted to team - members. In order to keep the account the argument wipe_data should - be set to False. + members. In order to keep the account the argument ``wipe_data`` + should be set to ``False``. + :param bool retain_team_shares: If provided, allows removed users to + keep access to Dropbox folders (not Dropbox Paper folders) already + explicitly shared with them (not via a group) when they are + downgraded to a Basic account. Users will not retain access to + folders that do not allow external sharing. In order to keep the + sharing relationships, the arguments ``wipe_data`` should be set to + ``False`` and ``keep_account`` should be set to ``True``. :rtype: :class:`dropbox.team.LaunchEmptyResult` :raises: :class:`.exceptions.ApiError` @@ -1241,7 +1466,8 @@ def team_members_remove(self, wipe_data, transfer_dest_id, transfer_admin_id, - keep_account) + keep_account, + retain_team_shares) r = self.request( team.members_remove, 'team', @@ -1274,6 +1500,70 @@ def team_members_remove_job_status_get(self, ) return r + def team_members_secondary_emails_add(self, + new_secondary_emails): + """ + Add secondary emails to users. Permission : Team member management. + Emails that are on verified domains will be verified automatically. For + each email address not on a verified domain a verification email will be + sent. + + :param list new_secondary_emails: List of users and secondary emails to + add. + :rtype: :class:`dropbox.team.AddSecondaryEmailsResult` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.AddSecondaryEmailsError` + """ + arg = team.AddSecondaryEmailsArg(new_secondary_emails) + r = self.request( + team.members_secondary_emails_add, + 'team', + arg, + None, + ) + return r + + def team_members_secondary_emails_delete(self, + emails_to_delete): + """ + Delete secondary emails from users Permission : Team member management. + Users will be notified of deletions of verified secondary emails at both + the secondary email and their primary email. + + :param list emails_to_delete: List of users and their secondary emails + to delete. + :rtype: :class:`dropbox.team.DeleteSecondaryEmailsResult` + """ + arg = team.DeleteSecondaryEmailsArg(emails_to_delete) + r = self.request( + team.members_secondary_emails_delete, + 'team', + arg, + None, + ) + return r + + def team_members_secondary_emails_resend_verification_emails(self, + emails_to_resend): + """ + Resend secondary email verification emails. Permission : Team member + management. + + :param list emails_to_resend: List of users and secondary emails to + resend verification emails to. + :rtype: :class:`dropbox.team.ResendVerificationEmailResult` + """ + arg = team.ResendVerificationEmailArg(emails_to_resend) + r = self.request( + team.members_secondary_emails_resend_verification_emails, + 'team', + arg, + None, + ) + return r + def team_members_send_welcome_email(self, arg): """ @@ -1368,6 +1658,33 @@ def team_members_set_profile(self, ) return r + def team_members_set_profile_photo(self, + user, + photo): + """ + Updates a team member's profile photo. Permission : Team member + management. + + :param user: Identity of the user whose profile photo will be set. + :type user: :class:`dropbox.team.UserSelectorArg` + :param photo: Image to set as the member's new profile photo. + :type photo: :class:`dropbox.team.PhotoSourceArg` + :rtype: :class:`dropbox.team.TeamMemberInfo` + :raises: :class:`.exceptions.ApiError` + + If this raises, ApiError will contain: + :class:`dropbox.team.MembersSetProfilePhotoError` + """ + arg = team.MembersSetProfilePhotoArg(user, + photo) + r = self.request( + team.members_set_profile_photo, + 'team', + arg, + None, + ) + return r + def team_members_suspend(self, user, wipe_data=True): @@ -1592,7 +1909,9 @@ def team_reports_get_activity(self, """ Retrieves reporting data about a team's user activity. - :param Nullable start_date: Optional starting date (inclusive). + :param Nullable start_date: Optional starting date (inclusive). If + start_date is None or too long ago, this field will be set to 6 + months ago. :param Nullable end_date: Optional ending date (exclusive). :rtype: :class:`dropbox.team.GetActivityReport` :raises: :class:`.exceptions.ApiError` @@ -1616,7 +1935,9 @@ def team_reports_get_devices(self, """ Retrieves reporting data about a team's linked devices. - :param Nullable start_date: Optional starting date (inclusive). + :param Nullable start_date: Optional starting date (inclusive). If + start_date is None or too long ago, this field will be set to 6 + months ago. :param Nullable end_date: Optional ending date (exclusive). :rtype: :class:`dropbox.team.GetDevicesReport` :raises: :class:`.exceptions.ApiError` @@ -1640,7 +1961,9 @@ def team_reports_get_membership(self, """ Retrieves reporting data about a team's membership. - :param Nullable start_date: Optional starting date (inclusive). + :param Nullable start_date: Optional starting date (inclusive). If + start_date is None or too long ago, this field will be set to 6 + months ago. :param Nullable end_date: Optional ending date (exclusive). :rtype: :class:`dropbox.team.GetMembershipReport` :raises: :class:`.exceptions.ApiError` @@ -1664,7 +1987,9 @@ def team_reports_get_storage(self, """ Retrieves reporting data about a team's storage usage. - :param Nullable start_date: Optional starting date (inclusive). + :param Nullable start_date: Optional starting date (inclusive). If + start_date is None or too long ago, this field will be set to 6 + months ago. :param Nullable end_date: Optional ending date (exclusive). :rtype: :class:`dropbox.team.GetStorageReport` :raises: :class:`.exceptions.ApiError` @@ -1932,13 +2257,18 @@ def team_log_get_events(self, limit=1000, account_id=None, time=None, - category=None): - """ - Retrieves team events. Events have a lifespan of two years. Events older - than two years will not be returned. Many attributes note 'may be - missing due to historical data gap'. Note that the file_operations - category and & analogous paper events are not available on all Dropbox - Business `plans `_. Use `features/get_values + category=None, + event_type=None): + """ + Retrieves team events. If the result's ``GetTeamEventsResult.has_more`` + field is ``True``, call :meth:`team_log_get_events_continue` with the + returned cursor to retrieve more entries. If end_time is not specified + in your request, you may use the returned cursor to poll + :meth:`team_log_get_events_continue` for new events. Many attributes + note 'may be missing due to historical data gap'. Note that the + file_operations category and & analogous paper events are not available + on all Dropbox Business `plans `_. Use + `features/get_values `_ to check for this feature. Permission : Team Auditing. @@ -1947,12 +2277,15 @@ def team_log_get_events(self, even return no events, even with `has_more` set to true. In this case, callers should fetch again using :meth:`team_log_get_events_continue`. - :param Nullable account_id: Filter the events by account ID. Return ony + :param Nullable account_id: Filter the events by account ID. Return only events with this account_id as either Actor, Context, or Participants. :param Nullable time: Filter by time range. :param Nullable category: Filter the returned events to a single category. + :param Nullable event_type: Filter the returned events to a single event + type. Note that event_type shouldn't be provided together with + category. :rtype: :class:`dropbox.team_log.GetTeamEventsResult` :raises: :class:`.exceptions.ApiError` @@ -1962,7 +2295,8 @@ def team_log_get_events(self, arg = team_log.GetTeamEventsArg(limit, account_id, time, - category) + category, + event_type) r = self.request( team_log.get_events, 'team_log', diff --git a/script.module.dropbox/lib/dropbox/check.py b/script.module.dropbox/lib/dropbox/check.py new file mode 100644 index 000000000..95465021b --- /dev/null +++ b/script.module.dropbox/lib/dropbox/check.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +# Auto-generated by Stone, do not modify. +# @generated +# flake8: noqa +# pylint: skip-file +try: + from . import stone_validators as bv + from . import stone_base as bb +except (ImportError, SystemError, ValueError): + # Catch errors raised when importing a relative module when not in a package. + # This makes testing this file directly (outside of a package) easier. + import stone_validators as bv + import stone_base as bb + +class EchoArg(bb.Struct): + """ + EchoArg contains the arguments to be sent to the Dropbox servers. + + :ivar check.EchoArg.query: The string that you'd like to be echoed back to + you. + """ + + __slots__ = [ + '_query_value', + '_query_present', + ] + + _has_required_fields = False + + def __init__(self, + query=None): + self._query_value = None + self._query_present = False + if query is not None: + self.query = query + + @property + def query(self): + """ + The string that you'd like to be echoed back to you. + + :rtype: str + """ + if self._query_present: + return self._query_value + else: + return u'' + + @query.setter + def query(self, val): + val = self._query_validator.validate(val) + self._query_value = val + self._query_present = True + + @query.deleter + def query(self): + self._query_value = None + self._query_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EchoArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EchoArg(query={!r})'.format( + self._query_value, + ) + +EchoArg_validator = bv.Struct(EchoArg) + +class EchoResult(bb.Struct): + """ + EchoResult contains the result returned from the Dropbox servers. + + :ivar check.EchoResult.result: If everything worked correctly, this would be + the same as query. + """ + + __slots__ = [ + '_result_value', + '_result_present', + ] + + _has_required_fields = False + + def __init__(self, + result=None): + self._result_value = None + self._result_present = False + if result is not None: + self.result = result + + @property + def result(self): + """ + If everything worked correctly, this would be the same as query. + + :rtype: str + """ + if self._result_present: + return self._result_value + else: + return u'' + + @result.setter + def result(self, val): + val = self._result_validator.validate(val) + self._result_value = val + self._result_present = True + + @result.deleter + def result(self): + self._result_value = None + self._result_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EchoResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EchoResult(result={!r})'.format( + self._result_value, + ) + +EchoResult_validator = bv.Struct(EchoResult) + +EchoArg._query_validator = bv.String() +EchoArg._all_field_names_ = set(['query']) +EchoArg._all_fields_ = [('query', EchoArg._query_validator)] + +EchoResult._result_validator = bv.String() +EchoResult._all_field_names_ = set(['result']) +EchoResult._all_fields_ = [('result', EchoResult._result_validator)] + +app = bb.Route( + 'app', + 1, + False, + EchoArg_validator, + EchoResult_validator, + bv.Void(), + {'host': u'api', + 'style': u'rpc'}, +) +user = bb.Route( + 'user', + 1, + False, + EchoArg_validator, + EchoResult_validator, + bv.Void(), + {'host': u'api', + 'style': u'rpc'}, +) + +ROUTES = { + 'app': app, + 'user': user, +} + diff --git a/script.module.dropbox/lib/dropbox/cloud_docs.py b/script.module.dropbox/lib/dropbox/cloud_docs.py new file mode 100644 index 000000000..4b138a1b3 --- /dev/null +++ b/script.module.dropbox/lib/dropbox/cloud_docs.py @@ -0,0 +1,2316 @@ +# -*- coding: utf-8 -*- +# Auto-generated by Stone, do not modify. +# @generated +# flake8: noqa +# pylint: skip-file +""" +Endpoints and datatypes for Cloud Docs. +""" + +try: + from . import stone_validators as bv + from . import stone_base as bb +except (ImportError, SystemError, ValueError): + # Catch errors raised when importing a relative module when not in a package. + # This makes testing this file directly (outside of a package) easier. + import stone_validators as bv + import stone_base as bb + +try: + from . import ( + files, + ) +except (ImportError, SystemError, ValueError): + import files + +class CloudDocsAccessError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar cloud_docs.CloudDocsAccessError.invalid_doc_id: The Cloud Doc ID is + invalid. + :ivar cloud_docs.CloudDocsAccessError.not_found: A Cloud Doc could not be + found for the given ID. + :ivar cloud_docs.CloudDocsAccessError.permission_denied: Permission denied + for the Cloud Doc with the given ID. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_doc_id = None + # Attribute is overwritten below the class definition + not_found = None + # Attribute is overwritten below the class definition + permission_denied = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_doc_id(self): + """ + Check if the union tag is ``invalid_doc_id``. + + :rtype: bool + """ + return self._tag == 'invalid_doc_id' + + def is_not_found(self): + """ + Check if the union tag is ``not_found``. + + :rtype: bool + """ + return self._tag == 'not_found' + + def is_permission_denied(self): + """ + Check if the union tag is ``permission_denied``. + + :rtype: bool + """ + return self._tag == 'permission_denied' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(CloudDocsAccessError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'CloudDocsAccessError(%r, %r)' % (self._tag, self._value) + +CloudDocsAccessError_validator = bv.Union(CloudDocsAccessError) + +class Content(bb.Struct): + """ + :ivar cloud_docs.Content.content_key: The key returned from an + upload_additional_content response. + """ + + __slots__ = [ + '_purpose_value', + '_purpose_present', + '_content_key_value', + '_content_key_present', + ] + + _has_required_fields = True + + def __init__(self, + purpose=None, + content_key=None): + self._purpose_value = None + self._purpose_present = False + self._content_key_value = None + self._content_key_present = False + if purpose is not None: + self.purpose = purpose + if content_key is not None: + self.content_key = content_key + + @property + def purpose(self): + """ + :rtype: ContentPurpose + """ + if self._purpose_present: + return self._purpose_value + else: + raise AttributeError("missing required field 'purpose'") + + @purpose.setter + def purpose(self, val): + self._purpose_validator.validate_type_only(val) + self._purpose_value = val + self._purpose_present = True + + @purpose.deleter + def purpose(self): + self._purpose_value = None + self._purpose_present = False + + @property + def content_key(self): + """ + The key returned from an upload_additional_content response. + + :rtype: str + """ + if self._content_key_present: + return self._content_key_value + else: + raise AttributeError("missing required field 'content_key'") + + @content_key.setter + def content_key(self, val): + val = self._content_key_validator.validate(val) + self._content_key_value = val + self._content_key_present = True + + @content_key.deleter + def content_key(self): + self._content_key_value = None + self._content_key_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(Content, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'Content(purpose={!r}, content_key={!r})'.format( + self._purpose_value, + self._content_key_value, + ) + +Content_validator = bv.Struct(Content) + +class ContentPurpose(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + search = None + # Attribute is overwritten below the class definition + preview = None + # Attribute is overwritten below the class definition + other = None + + def is_search(self): + """ + Check if the union tag is ``search``. + + :rtype: bool + """ + return self._tag == 'search' + + def is_preview(self): + """ + Check if the union tag is ``preview``. + + :rtype: bool + """ + return self._tag == 'preview' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ContentPurpose, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ContentPurpose(%r, %r)' % (self._tag, self._value) + +ContentPurpose_validator = bv.Union(ContentPurpose) + +class GenericErrorTag(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar cloud_docs.GenericErrorTag.invalid_argument: Invalid argument + supplied. + :ivar cloud_docs.GenericErrorTag.unauthenticated: User is unauthenticated. + :ivar cloud_docs.GenericErrorTag.permission_denied: User does not have + access to the specified doc. + :ivar cloud_docs.GenericErrorTag.doc_not_found: Doc could not be found based + on the supplied doc ID. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_argument = None + # Attribute is overwritten below the class definition + unauthenticated = None + # Attribute is overwritten below the class definition + permission_denied = None + # Attribute is overwritten below the class definition + doc_not_found = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_argument(self): + """ + Check if the union tag is ``invalid_argument``. + + :rtype: bool + """ + return self._tag == 'invalid_argument' + + def is_unauthenticated(self): + """ + Check if the union tag is ``unauthenticated``. + + :rtype: bool + """ + return self._tag == 'unauthenticated' + + def is_permission_denied(self): + """ + Check if the union tag is ``permission_denied``. + + :rtype: bool + """ + return self._tag == 'permission_denied' + + def is_doc_not_found(self): + """ + Check if the union tag is ``doc_not_found``. + + :rtype: bool + """ + return self._tag == 'doc_not_found' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GenericErrorTag, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GenericErrorTag(%r, %r)' % (self._tag, self._value) + +GenericErrorTag_validator = bv.Union(GenericErrorTag) + +class GetContentArg(bb.Struct): + + __slots__ = [ + '_file_id_value', + '_file_id_present', + ] + + _has_required_fields = True + + def __init__(self, + file_id=None): + self._file_id_value = None + self._file_id_present = False + if file_id is not None: + self.file_id = file_id + + @property + def file_id(self): + """ + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + raise AttributeError("missing required field 'file_id'") + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetContentArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetContentArg(file_id={!r})'.format( + self._file_id_value, + ) + +GetContentArg_validator = bv.Struct(GetContentArg) + +class GetMetadataArg(bb.Struct): + """ + :ivar cloud_docs.GetMetadataArg.file_id: API ID ("id:...") associated with + the Cloud Doc. + """ + + __slots__ = [ + '_file_id_value', + '_file_id_present', + ] + + _has_required_fields = False + + def __init__(self, + file_id=None): + self._file_id_value = None + self._file_id_present = False + if file_id is not None: + self.file_id = file_id + + @property + def file_id(self): + """ + API ID ("id:...") associated with the Cloud Doc. + + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + return u'' + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetMetadataArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetMetadataArg(file_id={!r})'.format( + self._file_id_value, + ) + +GetMetadataArg_validator = bv.Struct(GetMetadataArg) + +class GetMetadataError(bb.Struct): + + __slots__ = [ + '_get_metadata_error_tag_value', + '_get_metadata_error_tag_present', + ] + + _has_required_fields = False + + def __init__(self, + get_metadata_error_tag=None): + self._get_metadata_error_tag_value = None + self._get_metadata_error_tag_present = False + if get_metadata_error_tag is not None: + self.get_metadata_error_tag = get_metadata_error_tag + + @property + def get_metadata_error_tag(self): + """ + :rtype: GetMetadataErrorTagUnion + """ + if self._get_metadata_error_tag_present: + return self._get_metadata_error_tag_value + else: + return None + + @get_metadata_error_tag.setter + def get_metadata_error_tag(self, val): + if val is None: + del self.get_metadata_error_tag + return + self._get_metadata_error_tag_validator.validate_type_only(val) + self._get_metadata_error_tag_value = val + self._get_metadata_error_tag_present = True + + @get_metadata_error_tag.deleter + def get_metadata_error_tag(self): + self._get_metadata_error_tag_value = None + self._get_metadata_error_tag_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetMetadataError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetMetadataError(get_metadata_error_tag={!r})'.format( + self._get_metadata_error_tag_value, + ) + +GetMetadataError_validator = bv.Struct(GetMetadataError) + +class GetMetadataResult(bb.Struct): + """ + :ivar cloud_docs.GetMetadataResult.title: Title of the Cloud Doc without + extension. + :ivar cloud_docs.GetMetadataResult.mime_type: MIME type of the Cloud Doc. + :ivar cloud_docs.GetMetadataResult.version: Opaque string representing the + version of the document stored in Dropbox (only set for Dropbox-stored + Documents). + :ivar cloud_docs.GetMetadataResult.provider_version: Application specific + string representing the revision of a document (only set for App-stored + Documents). + :ivar cloud_docs.GetMetadataResult.user: User identified by the auth token. + :ivar cloud_docs.GetMetadataResult.is_deleted: true if the document is + deleted or purged. + :ivar cloud_docs.GetMetadataResult.user_permissions: Actions that the user + identified by the auth token can performn. This message will not be + populated for deleted documents. + """ + + __slots__ = [ + '_file_id_value', + '_file_id_present', + '_title_value', + '_title_present', + '_mime_type_value', + '_mime_type_present', + '_version_value', + '_version_present', + '_provider_version_value', + '_provider_version_present', + '_user_value', + '_user_present', + '_is_deleted_value', + '_is_deleted_present', + '_user_permissions_value', + '_user_permissions_present', + ] + + _has_required_fields = False + + def __init__(self, + file_id=None, + title=None, + mime_type=None, + version=None, + provider_version=None, + user=None, + is_deleted=None, + user_permissions=None): + self._file_id_value = None + self._file_id_present = False + self._title_value = None + self._title_present = False + self._mime_type_value = None + self._mime_type_present = False + self._version_value = None + self._version_present = False + self._provider_version_value = None + self._provider_version_present = False + self._user_value = None + self._user_present = False + self._is_deleted_value = None + self._is_deleted_present = False + self._user_permissions_value = None + self._user_permissions_present = False + if file_id is not None: + self.file_id = file_id + if title is not None: + self.title = title + if mime_type is not None: + self.mime_type = mime_type + if version is not None: + self.version = version + if provider_version is not None: + self.provider_version = provider_version + if user is not None: + self.user = user + if is_deleted is not None: + self.is_deleted = is_deleted + if user_permissions is not None: + self.user_permissions = user_permissions + + @property + def file_id(self): + """ + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + return u'' + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + @property + def title(self): + """ + Title of the Cloud Doc without extension. + + :rtype: str + """ + if self._title_present: + return self._title_value + else: + return u'' + + @title.setter + def title(self, val): + val = self._title_validator.validate(val) + self._title_value = val + self._title_present = True + + @title.deleter + def title(self): + self._title_value = None + self._title_present = False + + @property + def mime_type(self): + """ + MIME type of the Cloud Doc. + + :rtype: str + """ + if self._mime_type_present: + return self._mime_type_value + else: + return u'' + + @mime_type.setter + def mime_type(self, val): + val = self._mime_type_validator.validate(val) + self._mime_type_value = val + self._mime_type_present = True + + @mime_type.deleter + def mime_type(self): + self._mime_type_value = None + self._mime_type_present = False + + @property + def version(self): + """ + Opaque string representing the version of the document stored in Dropbox + (only set for Dropbox-stored Documents). + + :rtype: str + """ + if self._version_present: + return self._version_value + else: + return u'' + + @version.setter + def version(self, val): + val = self._version_validator.validate(val) + self._version_value = val + self._version_present = True + + @version.deleter + def version(self): + self._version_value = None + self._version_present = False + + @property + def provider_version(self): + """ + Application specific string representing the revision of a document + (only set for App-stored Documents). + + :rtype: str + """ + if self._provider_version_present: + return self._provider_version_value + else: + return u'' + + @provider_version.setter + def provider_version(self, val): + val = self._provider_version_validator.validate(val) + self._provider_version_value = val + self._provider_version_present = True + + @provider_version.deleter + def provider_version(self): + self._provider_version_value = None + self._provider_version_present = False + + @property + def user(self): + """ + User identified by the auth token. + + :rtype: UserInfo + """ + if self._user_present: + return self._user_value + else: + return None + + @user.setter + def user(self, val): + if val is None: + del self.user + return + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False + + @property + def is_deleted(self): + """ + true if the document is deleted or purged. + + :rtype: bool + """ + if self._is_deleted_present: + return self._is_deleted_value + else: + return False + + @is_deleted.setter + def is_deleted(self, val): + val = self._is_deleted_validator.validate(val) + self._is_deleted_value = val + self._is_deleted_present = True + + @is_deleted.deleter + def is_deleted(self): + self._is_deleted_value = None + self._is_deleted_present = False + + @property + def user_permissions(self): + """ + Actions that the user identified by the auth token can performn. This + message will not be populated for deleted documents. + + :rtype: UserPermissions + """ + if self._user_permissions_present: + return self._user_permissions_value + else: + return None + + @user_permissions.setter + def user_permissions(self, val): + if val is None: + del self.user_permissions + return + self._user_permissions_validator.validate_type_only(val) + self._user_permissions_value = val + self._user_permissions_present = True + + @user_permissions.deleter + def user_permissions(self): + self._user_permissions_value = None + self._user_permissions_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetMetadataResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetMetadataResult(file_id={!r}, title={!r}, mime_type={!r}, version={!r}, provider_version={!r}, user={!r}, is_deleted={!r}, user_permissions={!r})'.format( + self._file_id_value, + self._title_value, + self._mime_type_value, + self._version_value, + self._provider_version_value, + self._user_value, + self._is_deleted_value, + self._user_permissions_value, + ) + +GetMetadataResult_validator = bv.Struct(GetMetadataResult) + +class LockArg(bb.Struct): + """ + :ivar cloud_docs.LockArg.file_id: The API ID ("id:...") associated with the + Cloud Doc + """ + + __slots__ = [ + '_file_id_value', + '_file_id_present', + ] + + _has_required_fields = False + + def __init__(self, + file_id=None): + self._file_id_value = None + self._file_id_present = False + if file_id is not None: + self.file_id = file_id + + @property + def file_id(self): + """ + The API ID ("id:...") associated with the Cloud Doc + + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + return u'' + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockArg(file_id={!r})'.format( + self._file_id_value, + ) + +LockArg_validator = bv.Struct(LockArg) + +class LockResult(bb.Struct): + """ + :ivar cloud_docs.LockResult.expires_at: The timestamp after which the lock + will expire, measured in seconds since 1970-01-01 00:00:00 UTC + """ + + __slots__ = [ + '_file_id_value', + '_file_id_present', + '_expires_at_value', + '_expires_at_present', + ] + + _has_required_fields = False + + def __init__(self, + file_id=None, + expires_at=None): + self._file_id_value = None + self._file_id_present = False + self._expires_at_value = None + self._expires_at_present = False + if file_id is not None: + self.file_id = file_id + if expires_at is not None: + self.expires_at = expires_at + + @property + def file_id(self): + """ + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + return u'' + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + @property + def expires_at(self): + """ + The timestamp after which the lock will expire, measured in seconds + since 1970-01-01 00:00:00 UTC + + :rtype: int + """ + if self._expires_at_present: + return self._expires_at_value + else: + return 0 + + @expires_at.setter + def expires_at(self, val): + val = self._expires_at_validator.validate(val) + self._expires_at_value = val + self._expires_at_present = True + + @expires_at.deleter + def expires_at(self): + self._expires_at_value = None + self._expires_at_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockResult(file_id={!r}, expires_at={!r})'.format( + self._file_id_value, + self._expires_at_value, + ) + +LockResult_validator = bv.Struct(LockResult) + +class LockingError(bb.Struct): + + __slots__ = [ + '_locking_error_tag_value', + '_locking_error_tag_present', + ] + + _has_required_fields = False + + def __init__(self, + locking_error_tag=None): + self._locking_error_tag_value = None + self._locking_error_tag_present = False + if locking_error_tag is not None: + self.locking_error_tag = locking_error_tag + + @property + def locking_error_tag(self): + """ + :rtype: LockingErrorTagUnion + """ + if self._locking_error_tag_present: + return self._locking_error_tag_value + else: + return None + + @locking_error_tag.setter + def locking_error_tag(self, val): + if val is None: + del self.locking_error_tag + return + self._locking_error_tag_validator.validate_type_only(val) + self._locking_error_tag_value = val + self._locking_error_tag_present = True + + @locking_error_tag.deleter + def locking_error_tag(self): + self._locking_error_tag_value = None + self._locking_error_tag_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockingError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockingError(locking_error_tag={!r})'.format( + self._locking_error_tag_value, + ) + +LockingError_validator = bv.Struct(LockingError) + +class LockingErrorTag(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar cloud_docs.LockingErrorTag.conflict: A lock on the doc is held by + another editor + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + conflict = None + # Attribute is overwritten below the class definition + other = None + + def is_conflict(self): + """ + Check if the union tag is ``conflict``. + + :rtype: bool + """ + return self._tag == 'conflict' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockingErrorTag, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockingErrorTag(%r, %r)' % (self._tag, self._value) + +LockingErrorTag_validator = bv.Union(LockingErrorTag) + +class RenameArg(bb.Struct): + """ + :ivar cloud_docs.RenameArg.file_id: The API ID ("id:...") associated with + the Cloud Doc + :ivar cloud_docs.RenameArg.title: The new title of the doc, excluding + extension + """ + + __slots__ = [ + '_file_id_value', + '_file_id_present', + '_title_value', + '_title_present', + ] + + _has_required_fields = False + + def __init__(self, + file_id=None, + title=None): + self._file_id_value = None + self._file_id_present = False + self._title_value = None + self._title_present = False + if file_id is not None: + self.file_id = file_id + if title is not None: + self.title = title + + @property + def file_id(self): + """ + The API ID ("id:...") associated with the Cloud Doc + + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + return u'' + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + @property + def title(self): + """ + The new title of the doc, excluding extension + + :rtype: str + """ + if self._title_present: + return self._title_value + else: + return u'' + + @title.setter + def title(self, val): + val = self._title_validator.validate(val) + self._title_value = val + self._title_present = True + + @title.deleter + def title(self): + self._title_value = None + self._title_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RenameArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RenameArg(file_id={!r}, title={!r})'.format( + self._file_id_value, + self._title_value, + ) + +RenameArg_validator = bv.Struct(RenameArg) + +class RenameError(bb.Struct): + + __slots__ = [ + '_rename_error_tag_value', + '_rename_error_tag_present', + ] + + _has_required_fields = False + + def __init__(self, + rename_error_tag=None): + self._rename_error_tag_value = None + self._rename_error_tag_present = False + if rename_error_tag is not None: + self.rename_error_tag = rename_error_tag + + @property + def rename_error_tag(self): + """ + :rtype: RenameErrorTagUnion + """ + if self._rename_error_tag_present: + return self._rename_error_tag_value + else: + return None + + @rename_error_tag.setter + def rename_error_tag(self, val): + if val is None: + del self.rename_error_tag + return + self._rename_error_tag_validator.validate_type_only(val) + self._rename_error_tag_value = val + self._rename_error_tag_present = True + + @rename_error_tag.deleter + def rename_error_tag(self): + self._rename_error_tag_value = None + self._rename_error_tag_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RenameError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RenameError(rename_error_tag={!r})'.format( + self._rename_error_tag_value, + ) + +RenameError_validator = bv.Struct(RenameError) + +class RenameErrorTag(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar cloud_docs.RenameErrorTag.invalid_title: The supplied title is + invalid, e.g. the length of the title is longer than max length (255 + characters); the title contains illegal characters. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_title = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_title(self): + """ + Check if the union tag is ``invalid_title``. + + :rtype: bool + """ + return self._tag == 'invalid_title' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RenameErrorTag, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RenameErrorTag(%r, %r)' % (self._tag, self._value) + +RenameErrorTag_validator = bv.Union(RenameErrorTag) + +class RenameResult(bb.Struct): + """ + :ivar cloud_docs.RenameResult.title: The updated title of the doc without + extension, which could be different from the supplied title in the + request because Dropbox may remove/replace charaters that are not + supported in Dropbox Filesystem. + """ + + __slots__ = [ + '_title_value', + '_title_present', + ] + + _has_required_fields = False + + def __init__(self, + title=None): + self._title_value = None + self._title_present = False + if title is not None: + self.title = title + + @property + def title(self): + """ + The updated title of the doc without extension, which could be different + from the supplied title in the request because Dropbox may + remove/replace charaters that are not supported in Dropbox Filesystem. + + :rtype: str + """ + if self._title_present: + return self._title_value + else: + return u'' + + @title.setter + def title(self, val): + val = self._title_validator.validate(val) + self._title_value = val + self._title_present = True + + @title.deleter + def title(self): + self._title_value = None + self._title_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RenameResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RenameResult(title={!r})'.format( + self._title_value, + ) + +RenameResult_validator = bv.Struct(RenameResult) + +class UnlockArg(bb.Struct): + """ + :ivar cloud_docs.UnlockArg.file_id: The API ID ("id:...") associated with + the Cloud Doc + """ + + __slots__ = [ + '_file_id_value', + '_file_id_present', + ] + + _has_required_fields = False + + def __init__(self, + file_id=None): + self._file_id_value = None + self._file_id_present = False + if file_id is not None: + self.file_id = file_id + + @property + def file_id(self): + """ + The API ID ("id:...") associated with the Cloud Doc + + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + return u'' + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UnlockArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UnlockArg(file_id={!r})'.format( + self._file_id_value, + ) + +UnlockArg_validator = bv.Struct(UnlockArg) + +class UnlockResult(bb.Struct): + """ + Empty message for unlock + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UnlockResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UnlockResult()' + +UnlockResult_validator = bv.Struct(UnlockResult) + +class UpdateContentArg(bb.Struct): + """ + :ivar cloud_docs.UpdateContentArg.actor_tokens: A list of auth_tokens, one + for each editor who made changes to the document since the last call to + update_content. + :ivar cloud_docs.UpdateContentArg.additional_contents: Currently, this will + always be empty until we implement upload_additional_content. + """ + + __slots__ = [ + '_file_id_value', + '_file_id_present', + '_actor_tokens_value', + '_actor_tokens_present', + '_additional_contents_value', + '_additional_contents_present', + ] + + _has_required_fields = True + + def __init__(self, + file_id=None, + actor_tokens=None, + additional_contents=None): + self._file_id_value = None + self._file_id_present = False + self._actor_tokens_value = None + self._actor_tokens_present = False + self._additional_contents_value = None + self._additional_contents_present = False + if file_id is not None: + self.file_id = file_id + if actor_tokens is not None: + self.actor_tokens = actor_tokens + if additional_contents is not None: + self.additional_contents = additional_contents + + @property + def file_id(self): + """ + :rtype: str + """ + if self._file_id_present: + return self._file_id_value + else: + raise AttributeError("missing required field 'file_id'") + + @file_id.setter + def file_id(self, val): + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True + + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False + + @property + def actor_tokens(self): + """ + A list of auth_tokens, one for each editor who made changes to the + document since the last call to update_content. + + :rtype: list of [str] + """ + if self._actor_tokens_present: + return self._actor_tokens_value + else: + raise AttributeError("missing required field 'actor_tokens'") + + @actor_tokens.setter + def actor_tokens(self, val): + val = self._actor_tokens_validator.validate(val) + self._actor_tokens_value = val + self._actor_tokens_present = True + + @actor_tokens.deleter + def actor_tokens(self): + self._actor_tokens_value = None + self._actor_tokens_present = False + + @property + def additional_contents(self): + """ + Currently, this will always be empty until we implement + upload_additional_content. + + :rtype: list of [Content] + """ + if self._additional_contents_present: + return self._additional_contents_value + else: + return None + + @additional_contents.setter + def additional_contents(self, val): + if val is None: + del self.additional_contents + return + val = self._additional_contents_validator.validate(val) + self._additional_contents_value = val + self._additional_contents_present = True + + @additional_contents.deleter + def additional_contents(self): + self._additional_contents_value = None + self._additional_contents_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UpdateContentArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UpdateContentArg(file_id={!r}, actor_tokens={!r}, additional_contents={!r})'.format( + self._file_id_value, + self._actor_tokens_value, + self._additional_contents_value, + ) + +UpdateContentArg_validator = bv.Struct(UpdateContentArg) + +class UpdateContentError(CloudDocsAccessError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar cloud_docs.UpdateContentError.upload_size_too_large: Upload payload + exceeds maximum allowed size of 150MB. + :ivar cloud_docs.UpdateContentError.conflict: A lock on the document + identified by path_or_id is held by another editor. + :ivar cloud_docs.UpdateContentError.unlocked: A lock is not held on the + document identified by path_or_id. Acquire lock before uploading content + for the document. + """ + + # Attribute is overwritten below the class definition + upload_size_too_large = None + # Attribute is overwritten below the class definition + conflict = None + # Attribute is overwritten below the class definition + unlocked = None + + def is_upload_size_too_large(self): + """ + Check if the union tag is ``upload_size_too_large``. + + :rtype: bool + """ + return self._tag == 'upload_size_too_large' + + def is_conflict(self): + """ + Check if the union tag is ``conflict``. + + :rtype: bool + """ + return self._tag == 'conflict' + + def is_unlocked(self): + """ + Check if the union tag is ``unlocked``. + + :rtype: bool + """ + return self._tag == 'unlocked' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UpdateContentError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UpdateContentError(%r, %r)' % (self._tag, self._value) + +UpdateContentError_validator = bv.Union(UpdateContentError) + +class UpdateContentResult(bb.Struct): + """ + :ivar cloud_docs.UpdateContentResult.version: Version of the document stored + in Dropbox. + """ + + __slots__ = [ + '_version_value', + '_version_present', + ] + + _has_required_fields = True + + def __init__(self, + version=None): + self._version_value = None + self._version_present = False + if version is not None: + self.version = version + + @property + def version(self): + """ + Version of the document stored in Dropbox. + + :rtype: str + """ + if self._version_present: + return self._version_value + else: + raise AttributeError("missing required field 'version'") + + @version.setter + def version(self, val): + val = self._version_validator.validate(val) + self._version_value = val + self._version_present = True + + @version.deleter + def version(self): + self._version_value = None + self._version_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UpdateContentResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UpdateContentResult(version={!r})'.format( + self._version_value, + ) + +UpdateContentResult_validator = bv.Struct(UpdateContentResult) + +class UserInfo(bb.Struct): + """ + :ivar cloud_docs.UserInfo.id: ID associated with the user. + :ivar cloud_docs.UserInfo.email: Email associated with the user. + """ + + __slots__ = [ + '_id_value', + '_id_present', + '_email_value', + '_email_present', + ] + + _has_required_fields = False + + def __init__(self, + id=None, + email=None): + self._id_value = None + self._id_present = False + self._email_value = None + self._email_present = False + if id is not None: + self.id = id + if email is not None: + self.email = email + + @property + def id(self): + """ + ID associated with the user. + + :rtype: str + """ + if self._id_present: + return self._id_value + else: + return u'' + + @id.setter + def id(self, val): + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True + + @id.deleter + def id(self): + self._id_value = None + self._id_present = False + + @property + def email(self): + """ + Email associated with the user. + + :rtype: str + """ + if self._email_present: + return self._email_value + else: + return u'' + + @email.setter + def email(self, val): + val = self._email_validator.validate(val) + self._email_value = val + self._email_present = True + + @email.deleter + def email(self): + self._email_value = None + self._email_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserInfo(id={!r}, email={!r})'.format( + self._id_value, + self._email_value, + ) + +UserInfo_validator = bv.Struct(UserInfo) + +class UserPermissions(bb.Struct): + """ + :ivar cloud_docs.UserPermissions.can_edit: true if the user can edit the + content of this document + :ivar cloud_docs.UserPermissions.can_rename: true if the user can edit the + title of this document + :ivar cloud_docs.UserPermissions.can_comment: true if the user can comment + on this document + :ivar cloud_docs.UserPermissions.can_download: true if the user can download + the contents of this document. currently always true if the user has + view access to the document. + """ + + __slots__ = [ + '_can_edit_value', + '_can_edit_present', + '_can_rename_value', + '_can_rename_present', + '_can_comment_value', + '_can_comment_present', + '_can_download_value', + '_can_download_present', + ] + + _has_required_fields = False + + def __init__(self, + can_edit=None, + can_rename=None, + can_comment=None, + can_download=None): + self._can_edit_value = None + self._can_edit_present = False + self._can_rename_value = None + self._can_rename_present = False + self._can_comment_value = None + self._can_comment_present = False + self._can_download_value = None + self._can_download_present = False + if can_edit is not None: + self.can_edit = can_edit + if can_rename is not None: + self.can_rename = can_rename + if can_comment is not None: + self.can_comment = can_comment + if can_download is not None: + self.can_download = can_download + + @property + def can_edit(self): + """ + true if the user can edit the content of this document + + :rtype: bool + """ + if self._can_edit_present: + return self._can_edit_value + else: + return False + + @can_edit.setter + def can_edit(self, val): + val = self._can_edit_validator.validate(val) + self._can_edit_value = val + self._can_edit_present = True + + @can_edit.deleter + def can_edit(self): + self._can_edit_value = None + self._can_edit_present = False + + @property + def can_rename(self): + """ + true if the user can edit the title of this document + + :rtype: bool + """ + if self._can_rename_present: + return self._can_rename_value + else: + return False + + @can_rename.setter + def can_rename(self, val): + val = self._can_rename_validator.validate(val) + self._can_rename_value = val + self._can_rename_present = True + + @can_rename.deleter + def can_rename(self): + self._can_rename_value = None + self._can_rename_present = False + + @property + def can_comment(self): + """ + true if the user can comment on this document + + :rtype: bool + """ + if self._can_comment_present: + return self._can_comment_value + else: + return False + + @can_comment.setter + def can_comment(self, val): + val = self._can_comment_validator.validate(val) + self._can_comment_value = val + self._can_comment_present = True + + @can_comment.deleter + def can_comment(self): + self._can_comment_value = None + self._can_comment_present = False + + @property + def can_download(self): + """ + true if the user can download the contents of this document. currently + always true if the user has view access to the document. + + :rtype: bool + """ + if self._can_download_present: + return self._can_download_value + else: + return False + + @can_download.setter + def can_download(self, val): + val = self._can_download_validator.validate(val) + self._can_download_value = val + self._can_download_present = True + + @can_download.deleter + def can_download(self): + self._can_download_value = None + self._can_download_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserPermissions, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserPermissions(can_edit={!r}, can_rename={!r}, can_comment={!r}, can_download={!r})'.format( + self._can_edit_value, + self._can_rename_value, + self._can_comment_value, + self._can_download_value, + ) + +UserPermissions_validator = bv.Struct(UserPermissions) + +class GetMetadataErrorTagUnion(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def generic_error(cls, val): + """ + Create an instance of this class set to the ``generic_error`` tag with + value ``val``. + + :param GenericErrorTag val: + :rtype: GetMetadataErrorTagUnion + """ + return cls('generic_error', val) + + def is_generic_error(self): + """ + Check if the union tag is ``generic_error``. + + :rtype: bool + """ + return self._tag == 'generic_error' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_generic_error(self): + """ + Only call this if :meth:`is_generic_error` is true. + + :rtype: GenericErrorTag + """ + if not self.is_generic_error(): + raise AttributeError("tag 'generic_error' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetMetadataErrorTagUnion, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetMetadataErrorTagUnion(%r, %r)' % (self._tag, self._value) + +GetMetadataErrorTagUnion_validator = bv.Union(GetMetadataErrorTagUnion) + +class LockingErrorTagUnion(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def locking_error(cls, val): + """ + Create an instance of this class set to the ``locking_error`` tag with + value ``val``. + + :param LockingErrorTag val: + :rtype: LockingErrorTagUnion + """ + return cls('locking_error', val) + + @classmethod + def generic_error(cls, val): + """ + Create an instance of this class set to the ``generic_error`` tag with + value ``val``. + + :param GenericErrorTag val: + :rtype: LockingErrorTagUnion + """ + return cls('generic_error', val) + + def is_locking_error(self): + """ + Check if the union tag is ``locking_error``. + + :rtype: bool + """ + return self._tag == 'locking_error' + + def is_generic_error(self): + """ + Check if the union tag is ``generic_error``. + + :rtype: bool + """ + return self._tag == 'generic_error' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_locking_error(self): + """ + Only call this if :meth:`is_locking_error` is true. + + :rtype: LockingErrorTag + """ + if not self.is_locking_error(): + raise AttributeError("tag 'locking_error' not set") + return self._value + + def get_generic_error(self): + """ + Only call this if :meth:`is_generic_error` is true. + + :rtype: GenericErrorTag + """ + if not self.is_generic_error(): + raise AttributeError("tag 'generic_error' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockingErrorTagUnion, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockingErrorTagUnion(%r, %r)' % (self._tag, self._value) + +LockingErrorTagUnion_validator = bv.Union(LockingErrorTagUnion) + +class RenameErrorTagUnion(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def rename_error(cls, val): + """ + Create an instance of this class set to the ``rename_error`` tag with + value ``val``. + + :param RenameErrorTag val: + :rtype: RenameErrorTagUnion + """ + return cls('rename_error', val) + + @classmethod + def generic_error(cls, val): + """ + Create an instance of this class set to the ``generic_error`` tag with + value ``val``. + + :param GenericErrorTag val: + :rtype: RenameErrorTagUnion + """ + return cls('generic_error', val) + + @classmethod + def locking_error(cls, val): + """ + Create an instance of this class set to the ``locking_error`` tag with + value ``val``. + + :param LockingErrorTag val: + :rtype: RenameErrorTagUnion + """ + return cls('locking_error', val) + + def is_rename_error(self): + """ + Check if the union tag is ``rename_error``. + + :rtype: bool + """ + return self._tag == 'rename_error' + + def is_generic_error(self): + """ + Check if the union tag is ``generic_error``. + + :rtype: bool + """ + return self._tag == 'generic_error' + + def is_locking_error(self): + """ + Check if the union tag is ``locking_error``. + + :rtype: bool + """ + return self._tag == 'locking_error' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_rename_error(self): + """ + Only call this if :meth:`is_rename_error` is true. + + :rtype: RenameErrorTag + """ + if not self.is_rename_error(): + raise AttributeError("tag 'rename_error' not set") + return self._value + + def get_generic_error(self): + """ + Only call this if :meth:`is_generic_error` is true. + + :rtype: GenericErrorTag + """ + if not self.is_generic_error(): + raise AttributeError("tag 'generic_error' not set") + return self._value + + def get_locking_error(self): + """ + Only call this if :meth:`is_locking_error` is true. + + :rtype: LockingErrorTag + """ + if not self.is_locking_error(): + raise AttributeError("tag 'locking_error' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RenameErrorTagUnion, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RenameErrorTagUnion(%r, %r)' % (self._tag, self._value) + +RenameErrorTagUnion_validator = bv.Union(RenameErrorTagUnion) + +CloudDocsAccessError._invalid_doc_id_validator = bv.Void() +CloudDocsAccessError._not_found_validator = bv.Void() +CloudDocsAccessError._permission_denied_validator = bv.Void() +CloudDocsAccessError._other_validator = bv.Void() +CloudDocsAccessError._tagmap = { + 'invalid_doc_id': CloudDocsAccessError._invalid_doc_id_validator, + 'not_found': CloudDocsAccessError._not_found_validator, + 'permission_denied': CloudDocsAccessError._permission_denied_validator, + 'other': CloudDocsAccessError._other_validator, +} + +CloudDocsAccessError.invalid_doc_id = CloudDocsAccessError('invalid_doc_id') +CloudDocsAccessError.not_found = CloudDocsAccessError('not_found') +CloudDocsAccessError.permission_denied = CloudDocsAccessError('permission_denied') +CloudDocsAccessError.other = CloudDocsAccessError('other') + +Content._purpose_validator = ContentPurpose_validator +Content._content_key_validator = bv.String() +Content._all_field_names_ = set([ + 'purpose', + 'content_key', +]) +Content._all_fields_ = [ + ('purpose', Content._purpose_validator), + ('content_key', Content._content_key_validator), +] + +ContentPurpose._search_validator = bv.Void() +ContentPurpose._preview_validator = bv.Void() +ContentPurpose._other_validator = bv.Void() +ContentPurpose._tagmap = { + 'search': ContentPurpose._search_validator, + 'preview': ContentPurpose._preview_validator, + 'other': ContentPurpose._other_validator, +} + +ContentPurpose.search = ContentPurpose('search') +ContentPurpose.preview = ContentPurpose('preview') +ContentPurpose.other = ContentPurpose('other') + +GenericErrorTag._invalid_argument_validator = bv.Void() +GenericErrorTag._unauthenticated_validator = bv.Void() +GenericErrorTag._permission_denied_validator = bv.Void() +GenericErrorTag._doc_not_found_validator = bv.Void() +GenericErrorTag._other_validator = bv.Void() +GenericErrorTag._tagmap = { + 'invalid_argument': GenericErrorTag._invalid_argument_validator, + 'unauthenticated': GenericErrorTag._unauthenticated_validator, + 'permission_denied': GenericErrorTag._permission_denied_validator, + 'doc_not_found': GenericErrorTag._doc_not_found_validator, + 'other': GenericErrorTag._other_validator, +} + +GenericErrorTag.invalid_argument = GenericErrorTag('invalid_argument') +GenericErrorTag.unauthenticated = GenericErrorTag('unauthenticated') +GenericErrorTag.permission_denied = GenericErrorTag('permission_denied') +GenericErrorTag.doc_not_found = GenericErrorTag('doc_not_found') +GenericErrorTag.other = GenericErrorTag('other') + +GetContentArg._file_id_validator = files.FileId_validator +GetContentArg._all_field_names_ = set(['file_id']) +GetContentArg._all_fields_ = [('file_id', GetContentArg._file_id_validator)] + +GetMetadataArg._file_id_validator = bv.String() +GetMetadataArg._all_field_names_ = set(['file_id']) +GetMetadataArg._all_fields_ = [('file_id', GetMetadataArg._file_id_validator)] + +GetMetadataError._get_metadata_error_tag_validator = bv.Nullable(GetMetadataErrorTagUnion_validator) +GetMetadataError._all_field_names_ = set(['get_metadata_error_tag']) +GetMetadataError._all_fields_ = [('get_metadata_error_tag', GetMetadataError._get_metadata_error_tag_validator)] + +GetMetadataResult._file_id_validator = bv.String() +GetMetadataResult._title_validator = bv.String() +GetMetadataResult._mime_type_validator = bv.String() +GetMetadataResult._version_validator = bv.String() +GetMetadataResult._provider_version_validator = bv.String() +GetMetadataResult._user_validator = bv.Nullable(UserInfo_validator) +GetMetadataResult._is_deleted_validator = bv.Boolean() +GetMetadataResult._user_permissions_validator = bv.Nullable(UserPermissions_validator) +GetMetadataResult._all_field_names_ = set([ + 'file_id', + 'title', + 'mime_type', + 'version', + 'provider_version', + 'user', + 'is_deleted', + 'user_permissions', +]) +GetMetadataResult._all_fields_ = [ + ('file_id', GetMetadataResult._file_id_validator), + ('title', GetMetadataResult._title_validator), + ('mime_type', GetMetadataResult._mime_type_validator), + ('version', GetMetadataResult._version_validator), + ('provider_version', GetMetadataResult._provider_version_validator), + ('user', GetMetadataResult._user_validator), + ('is_deleted', GetMetadataResult._is_deleted_validator), + ('user_permissions', GetMetadataResult._user_permissions_validator), +] + +LockArg._file_id_validator = bv.String() +LockArg._all_field_names_ = set(['file_id']) +LockArg._all_fields_ = [('file_id', LockArg._file_id_validator)] + +LockResult._file_id_validator = bv.String() +LockResult._expires_at_validator = bv.Int64() +LockResult._all_field_names_ = set([ + 'file_id', + 'expires_at', +]) +LockResult._all_fields_ = [ + ('file_id', LockResult._file_id_validator), + ('expires_at', LockResult._expires_at_validator), +] + +LockingError._locking_error_tag_validator = bv.Nullable(LockingErrorTagUnion_validator) +LockingError._all_field_names_ = set(['locking_error_tag']) +LockingError._all_fields_ = [('locking_error_tag', LockingError._locking_error_tag_validator)] + +LockingErrorTag._conflict_validator = bv.Void() +LockingErrorTag._other_validator = bv.Void() +LockingErrorTag._tagmap = { + 'conflict': LockingErrorTag._conflict_validator, + 'other': LockingErrorTag._other_validator, +} + +LockingErrorTag.conflict = LockingErrorTag('conflict') +LockingErrorTag.other = LockingErrorTag('other') + +RenameArg._file_id_validator = bv.String() +RenameArg._title_validator = bv.String() +RenameArg._all_field_names_ = set([ + 'file_id', + 'title', +]) +RenameArg._all_fields_ = [ + ('file_id', RenameArg._file_id_validator), + ('title', RenameArg._title_validator), +] + +RenameError._rename_error_tag_validator = bv.Nullable(RenameErrorTagUnion_validator) +RenameError._all_field_names_ = set(['rename_error_tag']) +RenameError._all_fields_ = [('rename_error_tag', RenameError._rename_error_tag_validator)] + +RenameErrorTag._invalid_title_validator = bv.Void() +RenameErrorTag._other_validator = bv.Void() +RenameErrorTag._tagmap = { + 'invalid_title': RenameErrorTag._invalid_title_validator, + 'other': RenameErrorTag._other_validator, +} + +RenameErrorTag.invalid_title = RenameErrorTag('invalid_title') +RenameErrorTag.other = RenameErrorTag('other') + +RenameResult._title_validator = bv.String() +RenameResult._all_field_names_ = set(['title']) +RenameResult._all_fields_ = [('title', RenameResult._title_validator)] + +UnlockArg._file_id_validator = bv.String() +UnlockArg._all_field_names_ = set(['file_id']) +UnlockArg._all_fields_ = [('file_id', UnlockArg._file_id_validator)] + +UnlockResult._all_field_names_ = set([]) +UnlockResult._all_fields_ = [] + +UpdateContentArg._file_id_validator = files.FileId_validator +UpdateContentArg._actor_tokens_validator = bv.List(bv.String()) +UpdateContentArg._additional_contents_validator = bv.Nullable(bv.List(Content_validator)) +UpdateContentArg._all_field_names_ = set([ + 'file_id', + 'actor_tokens', + 'additional_contents', +]) +UpdateContentArg._all_fields_ = [ + ('file_id', UpdateContentArg._file_id_validator), + ('actor_tokens', UpdateContentArg._actor_tokens_validator), + ('additional_contents', UpdateContentArg._additional_contents_validator), +] + +UpdateContentError._upload_size_too_large_validator = bv.Void() +UpdateContentError._conflict_validator = bv.Void() +UpdateContentError._unlocked_validator = bv.Void() +UpdateContentError._tagmap = { + 'upload_size_too_large': UpdateContentError._upload_size_too_large_validator, + 'conflict': UpdateContentError._conflict_validator, + 'unlocked': UpdateContentError._unlocked_validator, +} +UpdateContentError._tagmap.update(CloudDocsAccessError._tagmap) + +UpdateContentError.upload_size_too_large = UpdateContentError('upload_size_too_large') +UpdateContentError.conflict = UpdateContentError('conflict') +UpdateContentError.unlocked = UpdateContentError('unlocked') + +UpdateContentResult._version_validator = bv.String() +UpdateContentResult._all_field_names_ = set(['version']) +UpdateContentResult._all_fields_ = [('version', UpdateContentResult._version_validator)] + +UserInfo._id_validator = bv.String() +UserInfo._email_validator = bv.String() +UserInfo._all_field_names_ = set([ + 'id', + 'email', +]) +UserInfo._all_fields_ = [ + ('id', UserInfo._id_validator), + ('email', UserInfo._email_validator), +] + +UserPermissions._can_edit_validator = bv.Boolean() +UserPermissions._can_rename_validator = bv.Boolean() +UserPermissions._can_comment_validator = bv.Boolean() +UserPermissions._can_download_validator = bv.Boolean() +UserPermissions._all_field_names_ = set([ + 'can_edit', + 'can_rename', + 'can_comment', + 'can_download', +]) +UserPermissions._all_fields_ = [ + ('can_edit', UserPermissions._can_edit_validator), + ('can_rename', UserPermissions._can_rename_validator), + ('can_comment', UserPermissions._can_comment_validator), + ('can_download', UserPermissions._can_download_validator), +] + +GetMetadataErrorTagUnion._generic_error_validator = GenericErrorTag_validator +GetMetadataErrorTagUnion._other_validator = bv.Void() +GetMetadataErrorTagUnion._tagmap = { + 'generic_error': GetMetadataErrorTagUnion._generic_error_validator, + 'other': GetMetadataErrorTagUnion._other_validator, +} + +GetMetadataErrorTagUnion.other = GetMetadataErrorTagUnion('other') + +LockingErrorTagUnion._locking_error_validator = LockingErrorTag_validator +LockingErrorTagUnion._generic_error_validator = GenericErrorTag_validator +LockingErrorTagUnion._other_validator = bv.Void() +LockingErrorTagUnion._tagmap = { + 'locking_error': LockingErrorTagUnion._locking_error_validator, + 'generic_error': LockingErrorTagUnion._generic_error_validator, + 'other': LockingErrorTagUnion._other_validator, +} + +LockingErrorTagUnion.other = LockingErrorTagUnion('other') + +RenameErrorTagUnion._rename_error_validator = RenameErrorTag_validator +RenameErrorTagUnion._generic_error_validator = GenericErrorTag_validator +RenameErrorTagUnion._locking_error_validator = LockingErrorTag_validator +RenameErrorTagUnion._other_validator = bv.Void() +RenameErrorTagUnion._tagmap = { + 'rename_error': RenameErrorTagUnion._rename_error_validator, + 'generic_error': RenameErrorTagUnion._generic_error_validator, + 'locking_error': RenameErrorTagUnion._locking_error_validator, + 'other': RenameErrorTagUnion._other_validator, +} + +RenameErrorTagUnion.other = RenameErrorTagUnion('other') + +get_content = bb.Route( + 'get_content', + 1, + False, + GetContentArg_validator, + bv.Void(), + CloudDocsAccessError_validator, + {'host': u'content', + 'style': u'download'}, +) +get_metadata = bb.Route( + 'get_metadata', + 1, + False, + GetMetadataArg_validator, + GetMetadataResult_validator, + GetMetadataError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +lock = bb.Route( + 'lock', + 1, + False, + LockArg_validator, + LockResult_validator, + LockingError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +rename = bb.Route( + 'rename', + 1, + False, + RenameArg_validator, + RenameResult_validator, + RenameError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +unlock = bb.Route( + 'unlock', + 1, + False, + UnlockArg_validator, + UnlockResult_validator, + LockingError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +update_content = bb.Route( + 'update_content', + 1, + False, + UpdateContentArg_validator, + UpdateContentResult_validator, + UpdateContentError_validator, + {'host': u'content', + 'style': u'upload'}, +) + +ROUTES = { + 'get_content': get_content, + 'get_metadata': get_metadata, + 'lock': lock, + 'rename': rename, + 'unlock': unlock, + 'update_content': update_content, +} + diff --git a/script.module.dropbox/lib/dropbox/dropbox.py b/script.module.dropbox/lib/dropbox/dropbox.py index 828f8581c..bf2708d8e 100644 --- a/script.module.dropbox/lib/dropbox/dropbox.py +++ b/script.module.dropbox/lib/dropbox/dropbox.py @@ -6,7 +6,7 @@ # This should always be 0.0.0 in master. Only update this after tagging # before release. -__version__ = '9.4.0' +__version__ = '10.3.1' import contextlib import json @@ -17,6 +17,7 @@ import requests import six +from datetime import datetime, timedelta from . import files, stone_serializers from .auth import ( AuthError_validator, @@ -46,10 +47,16 @@ HOST_CONTENT, HOST_NOTIFY, pinned_session, + DEFAULT_TIMEOUT ) PATH_ROOT_HEADER = 'Dropbox-API-Path-Root' HTTP_STATUS_INVALID_PATH_ROOT = 422 +TOKEN_EXPIRATION_BUFFER = 300 + +SELECT_ADMIN_HEADER = 'Dropbox-API-Select-Admin' + +SELECT_USER_HEADER = 'Dropbox-API-Select-User' class RouteResult(object): """The successful result of a call to a route.""" @@ -125,21 +132,22 @@ class _DropboxTransport(object): # the HTTP body. _ROUTE_STYLE_RPC = 'rpc' - # This is the default longest time we'll block on receiving data from the server - _DEFAULT_TIMEOUT = 30 - def __init__(self, - oauth2_access_token, + oauth2_access_token=None, max_retries_on_error=4, max_retries_on_rate_limit=None, user_agent=None, session=None, headers=None, - timeout=_DEFAULT_TIMEOUT): + timeout=DEFAULT_TIMEOUT, + oauth2_refresh_token=None, + oauth2_access_token_expiration=None, + app_key=None, + app_secret=None, + scope=None,): """ :param str oauth2_access_token: OAuth2 access token for making client requests. - :param int max_retries_on_error: On 5xx errors, the number of times to retry. :param Optional[int] max_retries_on_rate_limit: On 429 errors, the @@ -157,19 +165,42 @@ def __init__(self, client will wait for any single packet from the server. After the timeout the client will give up on connection. If `None`, client will wait forever. Defaults - to 30 seconds. + to 100 seconds. + :param str oauth2_refresh_token: OAuth2 refresh token for refreshing access token + :param datetime oauth2_access_token_expiration: Expiration for oauth2_access_token + :param str app_key: application key of requesting application; used for token refresh + :param str app_secret: application secret of requesting application; used for token refresh + Not required if PKCE was used to authorize the token + :param list scope: list of scopes to request on refresh. If left blank, + refresh will request all available scopes for application """ - assert len(oauth2_access_token) > 0, \ - 'OAuth2 access token cannot be empty.' - assert headers is None or isinstance(headers, dict), \ - 'Expected dict, got %r' % headers + + if not (oauth2_access_token or oauth2_refresh_token): + raise BadInputException('OAuth2 access token or refresh token must be set') + + if headers is not None and not isinstance(headers, dict): + raise BadInputException('Expected dict, got {}'.format(headers)) + + if oauth2_refresh_token and not app_key: + raise BadInputException("app_key is required to refresh tokens") + + if scope is not None and (len(scope) == 0 or not isinstance(scope, list)): + raise BadInputException("Scope list must be of type list") + self._oauth2_access_token = oauth2_access_token + self._oauth2_refresh_token = oauth2_refresh_token + self._oauth2_access_token_expiration = oauth2_access_token_expiration + + self._app_key = app_key + self._app_secret = app_secret + self._scope = scope self._max_retries_on_error = max_retries_on_error self._max_retries_on_rate_limit = max_retries_on_rate_limit if session: - assert isinstance(session, requests.sessions.Session), \ - 'Expected requests.sessions.Session, got %r' % session + if not isinstance(session, requests.sessions.Session): + raise BadInputException('Expected requests.sessions.Session, got {}' + .format(session)) self._session = session else: self._session = create_session() @@ -199,14 +230,19 @@ def clone( user_agent=None, session=None, headers=None, - timeout=None): + timeout=None, + oauth2_refresh_token=None, + oauth2_access_token_expiration=None, + app_key=None, + app_secret=None, + scope=None): """ Creates a new copy of the Dropbox client with the same defaults unless modified by arguments to clone() See constructor for original parameter descriptions. - :return: New instance of Dropbox clent + :return: New instance of Dropbox client :rtype: Dropbox """ @@ -217,7 +253,12 @@ def clone( user_agent or self._user_agent, session or self._session, headers or self._headers, - timeout or self._timeout + timeout or self._timeout, + oauth2_refresh_token or self._oauth2_refresh_token, + oauth2_access_token_expiration or self._oauth2_access_token_expiration, + app_key or self._app_key, + app_secret or self._app_secret, + scope or self._scope ) def request(self, @@ -247,6 +288,9 @@ def request(self, Dropbox object. Defaults to `None`. :return: The route's result. """ + + self.check_and_refresh_access_token() + host = route.attrs['host'] or 'api' route_name = namespace + '/' + route.name if route.version > 1: @@ -299,6 +343,64 @@ def request(self, else: return deserialized_result + def check_and_refresh_access_token(self): + """ + Checks if access token needs to be refreshed and refreshes if possible + :return: + """ + can_refresh = self._oauth2_refresh_token and self._app_key + needs_refresh = self._oauth2_access_token_expiration and \ + (datetime.utcnow() + timedelta(seconds=TOKEN_EXPIRATION_BUFFER)) >= \ + self._oauth2_access_token_expiration + needs_token = not self._oauth2_access_token + if (needs_refresh or needs_token) and can_refresh: + self.refresh_access_token(scope=self._scope) + + def refresh_access_token(self, host=API_HOST, scope=None): + """ + Refreshes an access token via refresh token if available + + :param host: host to hit token endpoint with + :param scope: list of permission scopes for access token + :return: + """ + + if scope is not None and (len(scope) == 0 or not isinstance(scope, list)): + raise BadInputException("Scope list must be of type list") + + if not (self._oauth2_refresh_token and self._app_key): + self._logger.warning('Unable to refresh access token without \ + refresh token and app key') + return + + self._logger.info('Refreshing access token.') + url = "https://{}/oauth2/token".format(host) + body = {'grant_type': 'refresh_token', + 'refresh_token': self._oauth2_refresh_token, + 'client_id': self._app_key, + } + if self._app_secret: + body['client_secret'] = self._app_secret + if scope: + scope = " ".join(scope) + body['scope'] = scope + + timeout = DEFAULT_TIMEOUT + if self._timeout: + timeout = self._timeout + res = self._session.post(url, data=body, timeout=timeout) + if res.status_code == 400 and res.json()['error'] == 'invalid_grant': + request_id = res.headers.get('x-dropbox-request-id') + err = stone_serializers.json_compat_obj_decode( + AuthError_validator, 'invalid_access_token') + raise AuthError(request_id, err) + res.raise_for_status() + + token_content = res.json() + self._oauth2_access_token = token_content["access_token"] + self._oauth2_access_token_expiration = datetime.utcnow() + \ + timedelta(seconds=int(token_content["expires_in"])) + def request_json_object(self, host, route_name, @@ -354,6 +456,7 @@ def request_json_string_with_retry(self, """ attempt = 0 rate_limit_errors = 0 + has_refreshed = False while True: self._logger.info('Request to %s', route_name) try: @@ -363,6 +466,18 @@ def request_json_string_with_retry(self, request_json_arg, request_binary, timeout=timeout) + except AuthError as e: + if e.error and e.error.is_expired_access_token(): + if has_refreshed: + raise + else: + self._logger.info( + 'ExpiredCredentials status_code=%s: Refreshing and Retrying', + e.status_code) + self.refresh_access_token() + has_refreshed = True + else: + raise except InternalServerError as e: attempt += 1 if attempt <= self._max_retries_on_error: @@ -539,12 +654,26 @@ def with_path_root(self, path_root): if not isinstance(path_root, PathRoot): raise ValueError("path_root must be an instance of PathRoot") + new_headers = self._headers.copy() if self._headers else {} + new_headers[PATH_ROOT_HEADER] = stone_serializers.json_encode(PathRoot_validator, path_root) + return self.clone( - headers={ - PATH_ROOT_HEADER: stone_serializers.json_encode(PathRoot_validator, path_root) - } + headers=new_headers ) + def close(self): + """ + Cleans up all resources like the request session/network connection. + """ + self._session.close() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + class Dropbox(_DropboxTransport, DropboxBase): """ Use this class to make requests to the Dropbox API using a user's access @@ -569,7 +698,7 @@ def as_admin(self, team_member_id): of this admin of the team. :rtype: Dropbox """ - return self._get_dropbox_client_with_select_header('Dropbox-API-Select-Admin', + return self._get_dropbox_client_with_select_header(SELECT_ADMIN_HEADER, team_member_id) def as_user(self, team_member_id): @@ -582,7 +711,7 @@ def as_user(self, team_member_id): of this member of the team. :rtype: Dropbox """ - return self._get_dropbox_client_with_select_header('Dropbox-API-Select-User', + return self._get_dropbox_client_with_select_header(SELECT_USER_HEADER, team_member_id) def _get_dropbox_client_with_select_header(self, select_header_name, team_member_id): @@ -600,6 +729,8 @@ def _get_dropbox_client_with_select_header(self, select_header_name, team_member new_headers[select_header_name] = team_member_id return Dropbox( self._oauth2_access_token, + oauth2_refresh_token=self._oauth2_refresh_token, + oauth2_access_token_expiration=self._oauth2_access_token_expiration, max_retries_on_error=self._max_retries_on_error, max_retries_on_rate_limit=self._max_retries_on_rate_limit, timeout=self._timeout, @@ -607,3 +738,12 @@ def _get_dropbox_client_with_select_header(self, select_header_name, team_member session=self._session, headers=new_headers, ) + +class BadInputException(Exception): + """ + Thrown if incorrect types/values are used + + This should only ever be thrown during testing, app should have validation of input prior to + reaching this point + """ + pass diff --git a/script.module.dropbox/lib/dropbox/file_properties.py b/script.module.dropbox/lib/dropbox/file_properties.py index 252de5aaf..c03154e56 100644 --- a/script.module.dropbox/lib/dropbox/file_properties.py +++ b/script.module.dropbox/lib/dropbox/file_properties.py @@ -37,7 +37,8 @@ class AddPropertiesArg(bb.Struct): :ivar file_properties.AddPropertiesArg.path: A unique identifier for the file or folder. :ivar file_properties.AddPropertiesArg.property_groups: The property groups - which are to be added to a Dropbox file. + which are to be added to a Dropbox file. No two groups in the input + should refer to the same template. """ __slots__ = [ @@ -87,7 +88,8 @@ def path(self): @property def property_groups(self): """ - The property groups which are to be added to a Dropbox file. + The property groups which are to be added to a Dropbox file. No two + groups in the input should refer to the same template. :rtype: list of [PropertyGroup] """ @@ -260,12 +262,17 @@ class InvalidPropertyGroupError(PropertiesError): :ivar file_properties.InvalidPropertyGroupError.does_not_fit_template: One or more of the supplied property fields does not conform to the template specifications. + :ivar file_properties.InvalidPropertyGroupError.duplicate_property_groups: + There are 2 or more property groups referring to the same templates in + the input. """ # Attribute is overwritten below the class definition property_field_too_large = None # Attribute is overwritten below the class definition does_not_fit_template = None + # Attribute is overwritten below the class definition + duplicate_property_groups = None def is_property_field_too_large(self): """ @@ -283,6 +290,14 @@ def is_does_not_fit_template(self): """ return self._tag == 'does_not_fit_template' + def is_duplicate_property_groups(self): + """ + Check if the union tag is ``duplicate_property_groups``. + + :rtype: bool + """ + return self._tag == 'duplicate_property_groups' + def _process_custom_annotations(self, annotation_type, field_path, processor): super(InvalidPropertyGroupError, self)._process_custom_annotations(annotation_type, field_path, processor) @@ -935,7 +950,8 @@ class OverwritePropertyGroupArg(bb.Struct): :ivar file_properties.OverwritePropertyGroupArg.path: A unique identifier for the file or folder. :ivar file_properties.OverwritePropertyGroupArg.property_groups: The - property groups "snapshot" updates to force apply. + property groups "snapshot" updates to force apply. No two groups in the + input should refer to the same template. """ __slots__ = [ @@ -985,7 +1001,8 @@ def path(self): @property def property_groups(self): """ - The property groups "snapshot" updates to force apply. + The property groups "snapshot" updates to force apply. No two groups in + the input should refer to the same template. :rtype: list of [PropertyGroup] """ @@ -2899,14 +2916,17 @@ def __repr__(self): InvalidPropertyGroupError._property_field_too_large_validator = bv.Void() InvalidPropertyGroupError._does_not_fit_template_validator = bv.Void() +InvalidPropertyGroupError._duplicate_property_groups_validator = bv.Void() InvalidPropertyGroupError._tagmap = { 'property_field_too_large': InvalidPropertyGroupError._property_field_too_large_validator, 'does_not_fit_template': InvalidPropertyGroupError._does_not_fit_template_validator, + 'duplicate_property_groups': InvalidPropertyGroupError._duplicate_property_groups_validator, } InvalidPropertyGroupError._tagmap.update(PropertiesError._tagmap) InvalidPropertyGroupError.property_field_too_large = InvalidPropertyGroupError('property_field_too_large') InvalidPropertyGroupError.does_not_fit_template = InvalidPropertyGroupError('does_not_fit_template') +InvalidPropertyGroupError.duplicate_property_groups = InvalidPropertyGroupError('duplicate_property_groups') AddPropertiesError._property_group_already_exists_validator = bv.Void() AddPropertiesError._tagmap = { diff --git a/script.module.dropbox/lib/dropbox/file_requests.py b/script.module.dropbox/lib/dropbox/file_requests.py index d2ea6f400..d3b5a582f 100644 --- a/script.module.dropbox/lib/dropbox/file_requests.py +++ b/script.module.dropbox/lib/dropbox/file_requests.py @@ -410,8 +410,8 @@ class CreateFileRequestError(FileRequestError): :ivar file_requests.CreateFileRequestError.invalid_location: File requests are not available on the specified folder. :ivar file_requests.CreateFileRequestError.rate_limit: The user has reached - the rate limit for creating file requests. The limit is currently 100 - file requests per day. + the rate limit for creating file requests. The limit is currently 4000 + file requests total. """ # Attribute is overwritten below the class definition diff --git a/script.module.dropbox/lib/dropbox/files.py b/script.module.dropbox/lib/dropbox/files.py index 91b43626e..00e5531c9 100644 --- a/script.module.dropbox/lib/dropbox/files.py +++ b/script.module.dropbox/lib/dropbox/files.py @@ -3002,12 +3002,16 @@ class ExportError(bb.Union): :ivar files.ExportError.non_exportable: This file type cannot be exported. Use :meth:`dropbox.dropbox.Dropbox.files_download` instead. + :ivar files.ExportError.retry_error: The exportable content is not yet + available. Please retry later. """ _catch_all = 'other' # Attribute is overwritten below the class definition non_exportable = None # Attribute is overwritten below the class definition + retry_error = None + # Attribute is overwritten below the class definition other = None @classmethod @@ -3037,6 +3041,14 @@ def is_non_exportable(self): """ return self._tag == 'non_exportable' + def is_retry_error(self): + """ + Check if the union tag is ``retry_error``. + + :rtype: bool + """ + return self._tag == 'retry_error' + def is_other(self): """ Check if the union tag is ``other``. @@ -3333,6 +3345,432 @@ def __repr__(self): ExportResult_validator = bv.Struct(ExportResult) +class FileCategory(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar files.FileCategory.image: jpg, png, gif, and more. + :ivar files.FileCategory.document: doc, docx, txt, and more. + :ivar files.FileCategory.pdf: pdf. + :ivar files.FileCategory.spreadsheet: xlsx, xls, csv, and more. + :ivar files.FileCategory.presentation: ppt, pptx, key, and more. + :ivar files.FileCategory.audio: mp3, wav, mid, and more. + :ivar files.FileCategory.video: mov, wmv, mp4, and more. + :ivar files.FileCategory.folder: dropbox folder. + :ivar files.FileCategory.paper: dropbox paper doc. + :ivar files.FileCategory.others: any file not in one of the categories + above. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + image = None + # Attribute is overwritten below the class definition + document = None + # Attribute is overwritten below the class definition + pdf = None + # Attribute is overwritten below the class definition + spreadsheet = None + # Attribute is overwritten below the class definition + presentation = None + # Attribute is overwritten below the class definition + audio = None + # Attribute is overwritten below the class definition + video = None + # Attribute is overwritten below the class definition + folder = None + # Attribute is overwritten below the class definition + paper = None + # Attribute is overwritten below the class definition + others = None + # Attribute is overwritten below the class definition + other = None + + def is_image(self): + """ + Check if the union tag is ``image``. + + :rtype: bool + """ + return self._tag == 'image' + + def is_document(self): + """ + Check if the union tag is ``document``. + + :rtype: bool + """ + return self._tag == 'document' + + def is_pdf(self): + """ + Check if the union tag is ``pdf``. + + :rtype: bool + """ + return self._tag == 'pdf' + + def is_spreadsheet(self): + """ + Check if the union tag is ``spreadsheet``. + + :rtype: bool + """ + return self._tag == 'spreadsheet' + + def is_presentation(self): + """ + Check if the union tag is ``presentation``. + + :rtype: bool + """ + return self._tag == 'presentation' + + def is_audio(self): + """ + Check if the union tag is ``audio``. + + :rtype: bool + """ + return self._tag == 'audio' + + def is_video(self): + """ + Check if the union tag is ``video``. + + :rtype: bool + """ + return self._tag == 'video' + + def is_folder(self): + """ + Check if the union tag is ``folder``. + + :rtype: bool + """ + return self._tag == 'folder' + + def is_paper(self): + """ + Check if the union tag is ``paper``. + + :rtype: bool + """ + return self._tag == 'paper' + + def is_others(self): + """ + Check if the union tag is ``others``. + + :rtype: bool + """ + return self._tag == 'others' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileCategory, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileCategory(%r, %r)' % (self._tag, self._value) + +FileCategory_validator = bv.Union(FileCategory) + +class FileLock(bb.Struct): + """ + :ivar files.FileLock.content: The lock description. + """ + + __slots__ = [ + '_content_value', + '_content_present', + ] + + _has_required_fields = True + + def __init__(self, + content=None): + self._content_value = None + self._content_present = False + if content is not None: + self.content = content + + @property + def content(self): + """ + The lock description. + + :rtype: FileLockContent + """ + if self._content_present: + return self._content_value + else: + raise AttributeError("missing required field 'content'") + + @content.setter + def content(self, val): + self._content_validator.validate_type_only(val) + self._content_value = val + self._content_present = True + + @content.deleter + def content(self): + self._content_value = None + self._content_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLock, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileLock(content={!r})'.format( + self._content_value, + ) + +FileLock_validator = bv.Struct(FileLock) + +class FileLockContent(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar files.FileLockContent.unlocked: Empty type to indicate no lock. + :ivar SingleUserLock FileLockContent.single_user: A lock held by a single + user. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + unlocked = None + # Attribute is overwritten below the class definition + other = None + + @classmethod + def single_user(cls, val): + """ + Create an instance of this class set to the ``single_user`` tag with + value ``val``. + + :param SingleUserLock val: + :rtype: FileLockContent + """ + return cls('single_user', val) + + def is_unlocked(self): + """ + Check if the union tag is ``unlocked``. + + :rtype: bool + """ + return self._tag == 'unlocked' + + def is_single_user(self): + """ + Check if the union tag is ``single_user``. + + :rtype: bool + """ + return self._tag == 'single_user' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_single_user(self): + """ + A lock held by a single user. + + Only call this if :meth:`is_single_user` is true. + + :rtype: SingleUserLock + """ + if not self.is_single_user(): + raise AttributeError("tag 'single_user' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockContent, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileLockContent(%r, %r)' % (self._tag, self._value) + +FileLockContent_validator = bv.Union(FileLockContent) + +class FileLockMetadata(bb.Struct): + """ + :ivar files.FileLockMetadata.is_lockholder: True if caller holds the file + lock. + :ivar files.FileLockMetadata.lockholder_name: The display name of the lock + holder. + :ivar files.FileLockMetadata.lockholder_account_id: The account ID of the + lock holder if known. + :ivar files.FileLockMetadata.created: The timestamp of the lock was created. + """ + + __slots__ = [ + '_is_lockholder_value', + '_is_lockholder_present', + '_lockholder_name_value', + '_lockholder_name_present', + '_lockholder_account_id_value', + '_lockholder_account_id_present', + '_created_value', + '_created_present', + ] + + _has_required_fields = False + + def __init__(self, + is_lockholder=None, + lockholder_name=None, + lockholder_account_id=None, + created=None): + self._is_lockholder_value = None + self._is_lockholder_present = False + self._lockholder_name_value = None + self._lockholder_name_present = False + self._lockholder_account_id_value = None + self._lockholder_account_id_present = False + self._created_value = None + self._created_present = False + if is_lockholder is not None: + self.is_lockholder = is_lockholder + if lockholder_name is not None: + self.lockholder_name = lockholder_name + if lockholder_account_id is not None: + self.lockholder_account_id = lockholder_account_id + if created is not None: + self.created = created + + @property + def is_lockholder(self): + """ + True if caller holds the file lock. + + :rtype: bool + """ + if self._is_lockholder_present: + return self._is_lockholder_value + else: + return None + + @is_lockholder.setter + def is_lockholder(self, val): + if val is None: + del self.is_lockholder + return + val = self._is_lockholder_validator.validate(val) + self._is_lockholder_value = val + self._is_lockholder_present = True + + @is_lockholder.deleter + def is_lockholder(self): + self._is_lockholder_value = None + self._is_lockholder_present = False + + @property + def lockholder_name(self): + """ + The display name of the lock holder. + + :rtype: str + """ + if self._lockholder_name_present: + return self._lockholder_name_value + else: + return None + + @lockholder_name.setter + def lockholder_name(self, val): + if val is None: + del self.lockholder_name + return + val = self._lockholder_name_validator.validate(val) + self._lockholder_name_value = val + self._lockholder_name_present = True + + @lockholder_name.deleter + def lockholder_name(self): + self._lockholder_name_value = None + self._lockholder_name_present = False + + @property + def lockholder_account_id(self): + """ + The account ID of the lock holder if known. + + :rtype: str + """ + if self._lockholder_account_id_present: + return self._lockholder_account_id_value + else: + return None + + @lockholder_account_id.setter + def lockholder_account_id(self, val): + if val is None: + del self.lockholder_account_id + return + val = self._lockholder_account_id_validator.validate(val) + self._lockholder_account_id_value = val + self._lockholder_account_id_present = True + + @lockholder_account_id.deleter + def lockholder_account_id(self): + self._lockholder_account_id_value = None + self._lockholder_account_id_present = False + + @property + def created(self): + """ + The timestamp of the lock was created. + + :rtype: datetime.datetime + """ + if self._created_present: + return self._created_value + else: + return None + + @created.setter + def created(self, val): + if val is None: + del self.created + return + val = self._created_validator.validate(val) + self._created_value = val + self._created_present = True + + @created.deleter + def created(self): + self._created_value = None + self._created_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileLockMetadata(is_lockholder={!r}, lockholder_name={!r}, lockholder_account_id={!r}, created={!r})'.format( + self._is_lockholder_value, + self._lockholder_name_value, + self._lockholder_account_id_value, + self._created_value, + ) + +FileLockMetadata_validator = bv.Struct(FileLockMetadata) + class FileMetadata(Metadata): """ :ivar files.FileMetadata.id: A unique identifier for the file. @@ -3376,6 +3814,8 @@ class FileMetadata(Metadata): field can be used to verify data integrity. For more information see our `Content hash `_ page. + :ivar files.FileMetadata.file_lock_info: If present, the metadata associated + with the file's current lock. """ __slots__ = [ @@ -3405,6 +3845,8 @@ class FileMetadata(Metadata): '_has_explicit_shared_members_present', '_content_hash_value', '_content_hash_present', + '_file_lock_info_value', + '_file_lock_info_present', ] _has_required_fields = True @@ -3426,7 +3868,8 @@ def __init__(self, export_info=None, property_groups=None, has_explicit_shared_members=None, - content_hash=None): + content_hash=None, + file_lock_info=None): super(FileMetadata, self).__init__(name, path_lower, path_display, @@ -3457,6 +3900,8 @@ def __init__(self, self._has_explicit_shared_members_present = False self._content_hash_value = None self._content_hash_present = False + self._file_lock_info_value = None + self._file_lock_info_present = False if id is not None: self.id = id if client_modified is not None: @@ -3483,6 +3928,8 @@ def __init__(self, self.has_explicit_shared_members = has_explicit_shared_members if content_hash is not None: self.content_hash = content_hash + if file_lock_info is not None: + self.file_lock_info = file_lock_info @property def id(self): @@ -3826,11 +4273,37 @@ def content_hash(self): self._content_hash_value = None self._content_hash_present = False + @property + def file_lock_info(self): + """ + If present, the metadata associated with the file's current lock. + + :rtype: FileLockMetadata + """ + if self._file_lock_info_present: + return self._file_lock_info_value + else: + return None + + @file_lock_info.setter + def file_lock_info(self, val): + if val is None: + del self.file_lock_info + return + self._file_lock_info_validator.validate_type_only(val) + self._file_lock_info_value = val + self._file_lock_info_present = True + + @file_lock_info.deleter + def file_lock_info(self): + self._file_lock_info_value = None + self._file_lock_info_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): super(FileMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileMetadata(name={!r}, id={!r}, client_modified={!r}, server_modified={!r}, rev={!r}, size={!r}, path_lower={!r}, path_display={!r}, parent_shared_folder_id={!r}, media_info={!r}, symlink_info={!r}, sharing_info={!r}, is_downloadable={!r}, export_info={!r}, property_groups={!r}, has_explicit_shared_members={!r}, content_hash={!r})'.format( + return 'FileMetadata(name={!r}, id={!r}, client_modified={!r}, server_modified={!r}, rev={!r}, size={!r}, path_lower={!r}, path_display={!r}, parent_shared_folder_id={!r}, media_info={!r}, symlink_info={!r}, sharing_info={!r}, is_downloadable={!r}, export_info={!r}, property_groups={!r}, has_explicit_shared_members={!r}, content_hash={!r}, file_lock_info={!r})'.format( self._name_value, self._id_value, self._client_modified_value, @@ -3848,6 +4321,7 @@ def __repr__(self): self._property_groups_value, self._has_explicit_shared_members_value, self._content_hash_value, + self._file_lock_info_value, ) FileMetadata_validator = bv.Struct(FileMetadata) @@ -4002,22 +4476,69 @@ def __repr__(self): FileSharingInfo_validator = bv.Struct(FileSharingInfo) -class FolderMetadata(Metadata): +class FileStatus(bb.Union): """ - :ivar files.FolderMetadata.id: A unique identifier for the folder. - :ivar files.FolderMetadata.shared_folder_id: Please use ``sharing_info`` - instead. - :ivar files.FolderMetadata.sharing_info: Set if the folder is contained in a - shared folder or is a shared folder mount point. - :ivar files.FolderMetadata.property_groups: Additional information if the - file has custom properties with the property template specified. Note - that only properties associated with user-owned templates, not - team-owned templates, can be attached to folders. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_id_value', - '_id_present', + _catch_all = 'other' + # Attribute is overwritten below the class definition + active = None + # Attribute is overwritten below the class definition + deleted = None + # Attribute is overwritten below the class definition + other = None + + def is_active(self): + """ + Check if the union tag is ``active``. + + :rtype: bool + """ + return self._tag == 'active' + + def is_deleted(self): + """ + Check if the union tag is ``deleted``. + + :rtype: bool + """ + return self._tag == 'deleted' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileStatus(%r, %r)' % (self._tag, self._value) + +FileStatus_validator = bv.Union(FileStatus) + +class FolderMetadata(Metadata): + """ + :ivar files.FolderMetadata.id: A unique identifier for the folder. + :ivar files.FolderMetadata.shared_folder_id: Please use ``sharing_info`` + instead. + :ivar files.FolderMetadata.sharing_info: Set if the folder is contained in a + shared folder or is a shared folder mount point. + :ivar files.FolderMetadata.property_groups: Additional information if the + file has custom properties with the property template specified. Note + that only properties associated with user-owned templates, not + team-owned templates, can be attached to folders. + """ + + __slots__ = [ + '_id_value', + '_id_present', '_shared_folder_id_value', '_shared_folder_id_present', '_sharing_info_value', @@ -5353,6 +5874,92 @@ def __repr__(self): GpsCoordinates_validator = bv.Struct(GpsCoordinates) +class HighlightSpan(bb.Struct): + """ + :ivar files.HighlightSpan.highlight_str: String to be determined whether it + should be highlighted or not. + :ivar files.HighlightSpan.is_highlighted: The string should be highlighted + or not. + """ + + __slots__ = [ + '_highlight_str_value', + '_highlight_str_present', + '_is_highlighted_value', + '_is_highlighted_present', + ] + + _has_required_fields = True + + def __init__(self, + highlight_str=None, + is_highlighted=None): + self._highlight_str_value = None + self._highlight_str_present = False + self._is_highlighted_value = None + self._is_highlighted_present = False + if highlight_str is not None: + self.highlight_str = highlight_str + if is_highlighted is not None: + self.is_highlighted = is_highlighted + + @property + def highlight_str(self): + """ + String to be determined whether it should be highlighted or not. + + :rtype: str + """ + if self._highlight_str_present: + return self._highlight_str_value + else: + raise AttributeError("missing required field 'highlight_str'") + + @highlight_str.setter + def highlight_str(self, val): + val = self._highlight_str_validator.validate(val) + self._highlight_str_value = val + self._highlight_str_present = True + + @highlight_str.deleter + def highlight_str(self): + self._highlight_str_value = None + self._highlight_str_present = False + + @property + def is_highlighted(self): + """ + The string should be highlighted or not. + + :rtype: bool + """ + if self._is_highlighted_present: + return self._is_highlighted_value + else: + raise AttributeError("missing required field 'is_highlighted'") + + @is_highlighted.setter + def is_highlighted(self, val): + val = self._is_highlighted_validator.validate(val) + self._is_highlighted_value = val + self._is_highlighted_present = True + + @is_highlighted.deleter + def is_highlighted(self): + self._is_highlighted_value = None + self._is_highlighted_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(HighlightSpan, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'HighlightSpan(highlight_str={!r}, is_highlighted={!r})'.format( + self._highlight_str_value, + self._is_highlighted_value, + ) + +HighlightSpan_validator = bv.Struct(HighlightSpan) + class ListFolderArg(bb.Struct): """ :ivar files.ListFolderArg.path: A unique identifier for the file. @@ -5880,6 +6487,17 @@ def path(cls, val): """ return cls('path', val) + @classmethod + def template_error(cls, val): + """ + Create an instance of this class set to the ``template_error`` tag with + value ``val``. + + :param file_properties.TemplateError val: + :rtype: ListFolderError + """ + return cls('template_error', val) + def is_path(self): """ Check if the union tag is ``path``. @@ -5888,6 +6506,14 @@ def is_path(self): """ return self._tag == 'path' + def is_template_error(self): + """ + Check if the union tag is ``template_error``. + + :rtype: bool + """ + return self._tag == 'template_error' + def is_other(self): """ Check if the union tag is ``other``. @@ -5906,6 +6532,16 @@ def get_path(self): raise AttributeError("tag 'path' not set") return self._value + def get_template_error(self): + """ + Only call this if :meth:`is_template_error` is true. + + :rtype: file_properties.TemplateError + """ + if not self.is_template_error(): + raise AttributeError("tag 'template_error' not set") + return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): super(ListFolderError, self)._process_custom_annotations(annotation_type, field_path, processor) @@ -6684,155 +7320,698 @@ def __repr__(self): ListRevisionsResult_validator = bv.Struct(ListRevisionsResult) -class LookupError(bb.Union): +class LockConflictError(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar Optional[str] files.LookupError.malformed_path: The given path does - not satisfy the required path format. Please refer to the :link:`Path - formats documentation - https://www.dropbox.com/developers/documentation/http/documentation#path-formats` - for more information. - :ivar files.LookupError.not_found: There is nothing at the given path. - :ivar files.LookupError.not_file: We were expecting a file, but the given - path refers to something that isn't a file. - :ivar files.LookupError.not_folder: We were expecting a folder, but the - given path refers to something that isn't a folder. - :ivar files.LookupError.restricted_content: The file cannot be transferred - because the content is restricted. For example, sometimes there are - legal restrictions due to copyright claims. - :ivar files.LookupError.unsupported_content_type: This operation is not - supported for this content type. + :ivar files.LockConflictError.lock: The lock that caused the conflict. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - not_found = None - # Attribute is overwritten below the class definition - not_file = None - # Attribute is overwritten below the class definition - not_folder = None - # Attribute is overwritten below the class definition - restricted_content = None - # Attribute is overwritten below the class definition - unsupported_content_type = None - # Attribute is overwritten below the class definition - other = None - - @classmethod - def malformed_path(cls, val): - """ - Create an instance of this class set to the ``malformed_path`` tag with - value ``val``. - - :param Optional[str] val: - :rtype: LookupError - """ - return cls('malformed_path', val) + __slots__ = [ + '_lock_value', + '_lock_present', + ] - def is_malformed_path(self): - """ - Check if the union tag is ``malformed_path``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'malformed_path' + def __init__(self, + lock=None): + self._lock_value = None + self._lock_present = False + if lock is not None: + self.lock = lock - def is_not_found(self): + @property + def lock(self): """ - Check if the union tag is ``not_found``. + The lock that caused the conflict. - :rtype: bool + :rtype: FileLock """ - return self._tag == 'not_found' + if self._lock_present: + return self._lock_value + else: + raise AttributeError("missing required field 'lock'") - def is_not_file(self): - """ - Check if the union tag is ``not_file``. + @lock.setter + def lock(self, val): + self._lock_validator.validate_type_only(val) + self._lock_value = val + self._lock_present = True - :rtype: bool - """ - return self._tag == 'not_file' + @lock.deleter + def lock(self): + self._lock_value = None + self._lock_present = False - def is_not_folder(self): - """ - Check if the union tag is ``not_folder``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockConflictError, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'not_folder' + def __repr__(self): + return 'LockConflictError(lock={!r})'.format( + self._lock_value, + ) - def is_restricted_content(self): - """ - Check if the union tag is ``restricted_content``. +LockConflictError_validator = bv.Struct(LockConflictError) - :rtype: bool - """ - return self._tag == 'restricted_content' +class LockFileArg(bb.Struct): + """ + :ivar files.LockFileArg.path: Path in the user's Dropbox to a file. + """ - def is_unsupported_content_type(self): - """ - Check if the union tag is ``unsupported_content_type``. + __slots__ = [ + '_path_value', + '_path_present', + ] - :rtype: bool - """ - return self._tag == 'unsupported_content_type' + _has_required_fields = True - def is_other(self): - """ - Check if the union tag is ``other``. + def __init__(self, + path=None): + self._path_value = None + self._path_present = False + if path is not None: + self.path = path - :rtype: bool + @property + def path(self): """ - return self._tag == 'other' + Path in the user's Dropbox to a file. - def get_malformed_path(self): + :rtype: str """ - The given path does not satisfy the required path format. Please refer - to the `Path formats documentation - `_ - for more information. + if self._path_present: + return self._path_value + else: + raise AttributeError("missing required field 'path'") - Only call this if :meth:`is_malformed_path` is true. + @path.setter + def path(self, val): + val = self._path_validator.validate(val) + self._path_value = val + self._path_present = True - :rtype: Optional[str] - """ - if not self.is_malformed_path(): - raise AttributeError("tag 'malformed_path' not set") - return self._value + @path.deleter + def path(self): + self._path_value = None + self._path_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LookupError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LockFileArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LookupError(%r, %r)' % (self._tag, self._value) + return 'LockFileArg(path={!r})'.format( + self._path_value, + ) -LookupError_validator = bv.Union(LookupError) +LockFileArg_validator = bv.Struct(LockFileArg) -class MediaInfo(bb.Union): +class LockFileBatchArg(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar files.MediaInfo.pending: Indicate the photo/video is still under - processing and metadata is not available yet. - :ivar MediaMetadata MediaInfo.metadata: The metadata for the photo/video. + :ivar files.LockFileBatchArg.entries: List of 'entries'. Each 'entry' + contains a path of the file which will be locked or queried. Duplicate + path arguments in the batch are considered only once. """ - _catch_all = None - # Attribute is overwritten below the class definition - pending = None + __slots__ = [ + '_entries_value', + '_entries_present', + ] - @classmethod - def metadata(cls, val): - """ - Create an instance of this class set to the ``metadata`` tag with value - ``val``. + _has_required_fields = True - :param MediaMetadata val: + def __init__(self, + entries=None): + self._entries_value = None + self._entries_present = False + if entries is not None: + self.entries = entries + + @property + def entries(self): + """ + List of 'entries'. Each 'entry' contains a path of the file which will + be locked or queried. Duplicate path arguments in the batch are + considered only once. + + :rtype: list of [LockFileArg] + """ + if self._entries_present: + return self._entries_value + else: + raise AttributeError("missing required field 'entries'") + + @entries.setter + def entries(self, val): + val = self._entries_validator.validate(val) + self._entries_value = val + self._entries_present = True + + @entries.deleter + def entries(self): + self._entries_value = None + self._entries_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockFileBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockFileBatchArg(entries={!r})'.format( + self._entries_value, + ) + +LockFileBatchArg_validator = bv.Struct(LockFileBatchArg) + +class LockFileBatchResult(FileOpsResult): + """ + :ivar files.LockFileBatchResult.entries: Each Entry in the 'entries' will + have '.tag' with the operation status (e.g. success), the metadata for + the file and the lock state after the operation. + """ + + __slots__ = [ + '_entries_value', + '_entries_present', + ] + + _has_required_fields = True + + def __init__(self, + entries=None): + super(LockFileBatchResult, self).__init__() + self._entries_value = None + self._entries_present = False + if entries is not None: + self.entries = entries + + @property + def entries(self): + """ + Each Entry in the 'entries' will have '.tag' with the operation status + (e.g. success), the metadata for the file and the lock state after the + operation. + + :rtype: list of [LockFileResultEntry] + """ + if self._entries_present: + return self._entries_value + else: + raise AttributeError("missing required field 'entries'") + + @entries.setter + def entries(self, val): + val = self._entries_validator.validate(val) + self._entries_value = val + self._entries_present = True + + @entries.deleter + def entries(self): + self._entries_value = None + self._entries_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockFileBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockFileBatchResult(entries={!r})'.format( + self._entries_value, + ) + +LockFileBatchResult_validator = bv.Struct(LockFileBatchResult) + +class LockFileError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar LookupError LockFileError.path_lookup: Could not find the specified + resource. + :ivar files.LockFileError.too_many_write_operations: There are too many + write operations in user's Dropbox. Please retry this request. + :ivar files.LockFileError.too_many_files: There are too many files in one + request. Please retry with fewer files. + :ivar files.LockFileError.no_write_permission: The user does not have + permissions to change the lock state or access the file. + :ivar files.LockFileError.cannot_be_locked: Item is a type that cannot be + locked. + :ivar files.LockFileError.file_not_shared: Requested file is not currently + shared. + :ivar LockConflictError LockFileError.lock_conflict: The user action + conflicts with an existing lock on the file. + :ivar files.LockFileError.internal_error: Something went wrong with the job + on Dropbox's end. You'll need to verify that the action you were taking + succeeded, and if not, try again. This should happen very rarely. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + too_many_write_operations = None + # Attribute is overwritten below the class definition + too_many_files = None + # Attribute is overwritten below the class definition + no_write_permission = None + # Attribute is overwritten below the class definition + cannot_be_locked = None + # Attribute is overwritten below the class definition + file_not_shared = None + # Attribute is overwritten below the class definition + internal_error = None + # Attribute is overwritten below the class definition + other = None + + @classmethod + def path_lookup(cls, val): + """ + Create an instance of this class set to the ``path_lookup`` tag with + value ``val``. + + :param LookupError val: + :rtype: LockFileError + """ + return cls('path_lookup', val) + + @classmethod + def lock_conflict(cls, val): + """ + Create an instance of this class set to the ``lock_conflict`` tag with + value ``val``. + + :param LockConflictError val: + :rtype: LockFileError + """ + return cls('lock_conflict', val) + + def is_path_lookup(self): + """ + Check if the union tag is ``path_lookup``. + + :rtype: bool + """ + return self._tag == 'path_lookup' + + def is_too_many_write_operations(self): + """ + Check if the union tag is ``too_many_write_operations``. + + :rtype: bool + """ + return self._tag == 'too_many_write_operations' + + def is_too_many_files(self): + """ + Check if the union tag is ``too_many_files``. + + :rtype: bool + """ + return self._tag == 'too_many_files' + + def is_no_write_permission(self): + """ + Check if the union tag is ``no_write_permission``. + + :rtype: bool + """ + return self._tag == 'no_write_permission' + + def is_cannot_be_locked(self): + """ + Check if the union tag is ``cannot_be_locked``. + + :rtype: bool + """ + return self._tag == 'cannot_be_locked' + + def is_file_not_shared(self): + """ + Check if the union tag is ``file_not_shared``. + + :rtype: bool + """ + return self._tag == 'file_not_shared' + + def is_lock_conflict(self): + """ + Check if the union tag is ``lock_conflict``. + + :rtype: bool + """ + return self._tag == 'lock_conflict' + + def is_internal_error(self): + """ + Check if the union tag is ``internal_error``. + + :rtype: bool + """ + return self._tag == 'internal_error' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_path_lookup(self): + """ + Could not find the specified resource. + + Only call this if :meth:`is_path_lookup` is true. + + :rtype: LookupError + """ + if not self.is_path_lookup(): + raise AttributeError("tag 'path_lookup' not set") + return self._value + + def get_lock_conflict(self): + """ + The user action conflicts with an existing lock on the file. + + Only call this if :meth:`is_lock_conflict` is true. + + :rtype: LockConflictError + """ + if not self.is_lock_conflict(): + raise AttributeError("tag 'lock_conflict' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockFileError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockFileError(%r, %r)' % (self._tag, self._value) + +LockFileError_validator = bv.Union(LockFileError) + +class LockFileResult(bb.Struct): + """ + :ivar files.LockFileResult.metadata: Metadata of the file. + :ivar files.LockFileResult.lock: The file lock state after the operation. + """ + + __slots__ = [ + '_metadata_value', + '_metadata_present', + '_lock_value', + '_lock_present', + ] + + _has_required_fields = True + + def __init__(self, + metadata=None, + lock=None): + self._metadata_value = None + self._metadata_present = False + self._lock_value = None + self._lock_present = False + if metadata is not None: + self.metadata = metadata + if lock is not None: + self.lock = lock + + @property + def metadata(self): + """ + Metadata of the file. + + :rtype: Metadata + """ + if self._metadata_present: + return self._metadata_value + else: + raise AttributeError("missing required field 'metadata'") + + @metadata.setter + def metadata(self, val): + self._metadata_validator.validate_type_only(val) + self._metadata_value = val + self._metadata_present = True + + @metadata.deleter + def metadata(self): + self._metadata_value = None + self._metadata_present = False + + @property + def lock(self): + """ + The file lock state after the operation. + + :rtype: FileLock + """ + if self._lock_present: + return self._lock_value + else: + raise AttributeError("missing required field 'lock'") + + @lock.setter + def lock(self, val): + self._lock_validator.validate_type_only(val) + self._lock_value = val + self._lock_present = True + + @lock.deleter + def lock(self): + self._lock_value = None + self._lock_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockFileResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockFileResult(metadata={!r}, lock={!r})'.format( + self._metadata_value, + self._lock_value, + ) + +LockFileResult_validator = bv.Struct(LockFileResult) + +class LockFileResultEntry(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = None + + @classmethod + def success(cls, val): + """ + Create an instance of this class set to the ``success`` tag with value + ``val``. + + :param LockFileResult val: + :rtype: LockFileResultEntry + """ + return cls('success', val) + + @classmethod + def failure(cls, val): + """ + Create an instance of this class set to the ``failure`` tag with value + ``val``. + + :param LockFileError val: + :rtype: LockFileResultEntry + """ + return cls('failure', val) + + def is_success(self): + """ + Check if the union tag is ``success``. + + :rtype: bool + """ + return self._tag == 'success' + + def is_failure(self): + """ + Check if the union tag is ``failure``. + + :rtype: bool + """ + return self._tag == 'failure' + + def get_success(self): + """ + Only call this if :meth:`is_success` is true. + + :rtype: LockFileResult + """ + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value + + def get_failure(self): + """ + Only call this if :meth:`is_failure` is true. + + :rtype: LockFileError + """ + if not self.is_failure(): + raise AttributeError("tag 'failure' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockFileResultEntry, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockFileResultEntry(%r, %r)' % (self._tag, self._value) + +LockFileResultEntry_validator = bv.Union(LockFileResultEntry) + +class LookupError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar Optional[str] files.LookupError.malformed_path: The given path does + not satisfy the required path format. Please refer to the :link:`Path + formats documentation + https://www.dropbox.com/developers/documentation/http/documentation#path-formats` + for more information. + :ivar files.LookupError.not_found: There is nothing at the given path. + :ivar files.LookupError.not_file: We were expecting a file, but the given + path refers to something that isn't a file. + :ivar files.LookupError.not_folder: We were expecting a folder, but the + given path refers to something that isn't a folder. + :ivar files.LookupError.restricted_content: The file cannot be transferred + because the content is restricted. For example, sometimes there are + legal restrictions due to copyright claims. + :ivar files.LookupError.unsupported_content_type: This operation is not + supported for this content type. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + not_found = None + # Attribute is overwritten below the class definition + not_file = None + # Attribute is overwritten below the class definition + not_folder = None + # Attribute is overwritten below the class definition + restricted_content = None + # Attribute is overwritten below the class definition + unsupported_content_type = None + # Attribute is overwritten below the class definition + other = None + + @classmethod + def malformed_path(cls, val): + """ + Create an instance of this class set to the ``malformed_path`` tag with + value ``val``. + + :param Optional[str] val: + :rtype: LookupError + """ + return cls('malformed_path', val) + + def is_malformed_path(self): + """ + Check if the union tag is ``malformed_path``. + + :rtype: bool + """ + return self._tag == 'malformed_path' + + def is_not_found(self): + """ + Check if the union tag is ``not_found``. + + :rtype: bool + """ + return self._tag == 'not_found' + + def is_not_file(self): + """ + Check if the union tag is ``not_file``. + + :rtype: bool + """ + return self._tag == 'not_file' + + def is_not_folder(self): + """ + Check if the union tag is ``not_folder``. + + :rtype: bool + """ + return self._tag == 'not_folder' + + def is_restricted_content(self): + """ + Check if the union tag is ``restricted_content``. + + :rtype: bool + """ + return self._tag == 'restricted_content' + + def is_unsupported_content_type(self): + """ + Check if the union tag is ``unsupported_content_type``. + + :rtype: bool + """ + return self._tag == 'unsupported_content_type' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_malformed_path(self): + """ + The given path does not satisfy the required path format. Please refer + to the `Path formats documentation + `_ + for more information. + + Only call this if :meth:`is_malformed_path` is true. + + :rtype: Optional[str] + """ + if not self.is_malformed_path(): + raise AttributeError("tag 'malformed_path' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LookupError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LookupError(%r, %r)' % (self._tag, self._value) + +LookupError_validator = bv.Union(LookupError) + +class MediaInfo(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar files.MediaInfo.pending: Indicate the photo/video is still under + processing and metadata is not available yet. + :ivar MediaMetadata MediaInfo.metadata: The metadata for the photo/video. + """ + + _catch_all = None + # Attribute is overwritten below the class definition + pending = None + + @classmethod + def metadata(cls, val): + """ + Create an instance of this class set to the ``metadata`` tag with value + ``val``. + + :param MediaMetadata val: :rtype: MediaInfo """ return cls('metadata', val) @@ -6894,112 +8073,333 @@ class MediaMetadata(bb.Struct): _has_required_fields = False - def __init__(self, - dimensions=None, - location=None, - time_taken=None): - self._dimensions_value = None - self._dimensions_present = False - self._location_value = None - self._location_present = False - self._time_taken_value = None - self._time_taken_present = False - if dimensions is not None: - self.dimensions = dimensions - if location is not None: - self.location = location - if time_taken is not None: - self.time_taken = time_taken + def __init__(self, + dimensions=None, + location=None, + time_taken=None): + self._dimensions_value = None + self._dimensions_present = False + self._location_value = None + self._location_present = False + self._time_taken_value = None + self._time_taken_present = False + if dimensions is not None: + self.dimensions = dimensions + if location is not None: + self.location = location + if time_taken is not None: + self.time_taken = time_taken + + @property + def dimensions(self): + """ + Dimension of the photo/video. + + :rtype: Dimensions + """ + if self._dimensions_present: + return self._dimensions_value + else: + return None + + @dimensions.setter + def dimensions(self, val): + if val is None: + del self.dimensions + return + self._dimensions_validator.validate_type_only(val) + self._dimensions_value = val + self._dimensions_present = True + + @dimensions.deleter + def dimensions(self): + self._dimensions_value = None + self._dimensions_present = False + + @property + def location(self): + """ + The GPS coordinate of the photo/video. + + :rtype: GpsCoordinates + """ + if self._location_present: + return self._location_value + else: + return None + + @location.setter + def location(self, val): + if val is None: + del self.location + return + self._location_validator.validate_type_only(val) + self._location_value = val + self._location_present = True + + @location.deleter + def location(self): + self._location_value = None + self._location_present = False + + @property + def time_taken(self): + """ + The timestamp when the photo/video is taken. + + :rtype: datetime.datetime + """ + if self._time_taken_present: + return self._time_taken_value + else: + return None + + @time_taken.setter + def time_taken(self, val): + if val is None: + del self.time_taken + return + val = self._time_taken_validator.validate(val) + self._time_taken_value = val + self._time_taken_present = True + + @time_taken.deleter + def time_taken(self): + self._time_taken_value = None + self._time_taken_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MediaMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MediaMetadata(dimensions={!r}, location={!r}, time_taken={!r})'.format( + self._dimensions_value, + self._location_value, + self._time_taken_value, + ) + +MediaMetadata_validator = bv.StructTree(MediaMetadata) + +class MetadataV2(bb.Union): + """ + Metadata for a file, folder or other resource types. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def metadata(cls, val): + """ + Create an instance of this class set to the ``metadata`` tag with value + ``val``. + + :param Metadata val: + :rtype: MetadataV2 + """ + return cls('metadata', val) + + def is_metadata(self): + """ + Check if the union tag is ``metadata``. + + :rtype: bool + """ + return self._tag == 'metadata' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_metadata(self): + """ + Only call this if :meth:`is_metadata` is true. + + :rtype: Metadata + """ + if not self.is_metadata(): + raise AttributeError("tag 'metadata' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MetadataV2, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MetadataV2(%r, %r)' % (self._tag, self._value) + +MetadataV2_validator = bv.Union(MetadataV2) + +class MinimalFileLinkMetadata(bb.Struct): + """ + :ivar files.MinimalFileLinkMetadata.url: URL of the shared link. + :ivar files.MinimalFileLinkMetadata.id: Unique identifier for the linked + file. + :ivar files.MinimalFileLinkMetadata.path: Full path in the user's Dropbox. + This always starts with a slash. This field will only be present only if + the linked file is in the authenticated user's Dropbox. + :ivar files.MinimalFileLinkMetadata.rev: A unique identifier for the current + revision of a file. This field is the same rev as elsewhere in the API + and can be used to detect changes and avoid conflicts. + """ + + __slots__ = [ + '_url_value', + '_url_present', + '_id_value', + '_id_present', + '_path_value', + '_path_present', + '_rev_value', + '_rev_present', + ] + + _has_required_fields = True + + def __init__(self, + url=None, + rev=None, + id=None, + path=None): + self._url_value = None + self._url_present = False + self._id_value = None + self._id_present = False + self._path_value = None + self._path_present = False + self._rev_value = None + self._rev_present = False + if url is not None: + self.url = url + if id is not None: + self.id = id + if path is not None: + self.path = path + if rev is not None: + self.rev = rev + + @property + def url(self): + """ + URL of the shared link. + + :rtype: str + """ + if self._url_present: + return self._url_value + else: + raise AttributeError("missing required field 'url'") + + @url.setter + def url(self, val): + val = self._url_validator.validate(val) + self._url_value = val + self._url_present = True + + @url.deleter + def url(self): + self._url_value = None + self._url_present = False @property - def dimensions(self): + def id(self): """ - Dimension of the photo/video. + Unique identifier for the linked file. - :rtype: Dimensions + :rtype: str """ - if self._dimensions_present: - return self._dimensions_value + if self._id_present: + return self._id_value else: return None - @dimensions.setter - def dimensions(self, val): + @id.setter + def id(self, val): if val is None: - del self.dimensions + del self.id return - self._dimensions_validator.validate_type_only(val) - self._dimensions_value = val - self._dimensions_present = True + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True - @dimensions.deleter - def dimensions(self): - self._dimensions_value = None - self._dimensions_present = False + @id.deleter + def id(self): + self._id_value = None + self._id_present = False @property - def location(self): + def path(self): """ - The GPS coordinate of the photo/video. + Full path in the user's Dropbox. This always starts with a slash. This + field will only be present only if the linked file is in the + authenticated user's Dropbox. - :rtype: GpsCoordinates + :rtype: str """ - if self._location_present: - return self._location_value + if self._path_present: + return self._path_value else: return None - @location.setter - def location(self, val): + @path.setter + def path(self, val): if val is None: - del self.location + del self.path return - self._location_validator.validate_type_only(val) - self._location_value = val - self._location_present = True + val = self._path_validator.validate(val) + self._path_value = val + self._path_present = True - @location.deleter - def location(self): - self._location_value = None - self._location_present = False + @path.deleter + def path(self): + self._path_value = None + self._path_present = False @property - def time_taken(self): + def rev(self): """ - The timestamp when the photo/video is taken. + A unique identifier for the current revision of a file. This field is + the same rev as elsewhere in the API and can be used to detect changes + and avoid conflicts. - :rtype: datetime.datetime + :rtype: str """ - if self._time_taken_present: - return self._time_taken_value + if self._rev_present: + return self._rev_value else: - return None + raise AttributeError("missing required field 'rev'") - @time_taken.setter - def time_taken(self, val): - if val is None: - del self.time_taken - return - val = self._time_taken_validator.validate(val) - self._time_taken_value = val - self._time_taken_present = True + @rev.setter + def rev(self, val): + val = self._rev_validator.validate(val) + self._rev_value = val + self._rev_present = True - @time_taken.deleter - def time_taken(self): - self._time_taken_value = None - self._time_taken_present = False + @rev.deleter + def rev(self): + self._rev_value = None + self._rev_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MediaMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MinimalFileLinkMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MediaMetadata(dimensions={!r}, location={!r}, time_taken={!r})'.format( - self._dimensions_value, - self._location_value, - self._time_taken_value, + return 'MinimalFileLinkMetadata(url={!r}, rev={!r}, id={!r}, path={!r})'.format( + self._url_value, + self._rev_value, + self._id_value, + self._path_value, ) -MediaMetadata_validator = bv.StructTree(MediaMetadata) +MinimalFileLinkMetadata_validator = bv.Struct(MinimalFileLinkMetadata) class RelocationBatchArgBase(bb.Struct): """ @@ -7151,6 +8551,91 @@ def __repr__(self): MoveBatchArg_validator = bv.Struct(MoveBatchArg) +class PathOrLink(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def path(cls, val): + """ + Create an instance of this class set to the ``path`` tag with value + ``val``. + + :param str val: + :rtype: PathOrLink + """ + return cls('path', val) + + @classmethod + def link(cls, val): + """ + Create an instance of this class set to the ``link`` tag with value + ``val``. + + :param SharedLinkFileInfo val: + :rtype: PathOrLink + """ + return cls('link', val) + + def is_path(self): + """ + Check if the union tag is ``path``. + + :rtype: bool + """ + return self._tag == 'path' + + def is_link(self): + """ + Check if the union tag is ``link``. + + :rtype: bool + """ + return self._tag == 'link' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_path(self): + """ + Only call this if :meth:`is_path` is true. + + :rtype: str + """ + if not self.is_path(): + raise AttributeError("tag 'path' not set") + return self._value + + def get_link(self): + """ + Only call this if :meth:`is_link` is true. + + :rtype: SharedLinkFileInfo + """ + if not self.is_link(): + raise AttributeError("tag 'link' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PathOrLink, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PathOrLink(%r, %r)' % (self._tag, self._value) + +PathOrLink_validator = bv.Union(PathOrLink) + class PhotoMetadata(MediaMetadata): """ Metadata for a photo. @@ -7331,29 +8816,126 @@ def is_unsupported_content(self): """ Check if the union tag is ``unsupported_content``. - :rtype: bool + :rtype: bool + """ + return self._tag == 'unsupported_content' + + def get_path(self): + """ + An error occurs when downloading metadata for the file. + + Only call this if :meth:`is_path` is true. + + :rtype: LookupError + """ + if not self.is_path(): + raise AttributeError("tag 'path' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PreviewError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PreviewError(%r, %r)' % (self._tag, self._value) + +PreviewError_validator = bv.Union(PreviewError) + +class PreviewResult(bb.Struct): + """ + :ivar files.PreviewResult.file_metadata: Metadata corresponding to the file + received as an argument. Will be populated if the endpoint is called + with a path (ReadPath). + :ivar files.PreviewResult.link_metadata: Minimal metadata corresponding to + the file received as an argument. Will be populated if the endpoint is + called using a shared link (SharedLinkFileInfo). + """ + + __slots__ = [ + '_file_metadata_value', + '_file_metadata_present', + '_link_metadata_value', + '_link_metadata_present', + ] + + _has_required_fields = False + + def __init__(self, + file_metadata=None, + link_metadata=None): + self._file_metadata_value = None + self._file_metadata_present = False + self._link_metadata_value = None + self._link_metadata_present = False + if file_metadata is not None: + self.file_metadata = file_metadata + if link_metadata is not None: + self.link_metadata = link_metadata + + @property + def file_metadata(self): + """ + Metadata corresponding to the file received as an argument. Will be + populated if the endpoint is called with a path (ReadPath). + + :rtype: FileMetadata + """ + if self._file_metadata_present: + return self._file_metadata_value + else: + return None + + @file_metadata.setter + def file_metadata(self, val): + if val is None: + del self.file_metadata + return + self._file_metadata_validator.validate_type_only(val) + self._file_metadata_value = val + self._file_metadata_present = True + + @file_metadata.deleter + def file_metadata(self): + self._file_metadata_value = None + self._file_metadata_present = False + + @property + def link_metadata(self): """ - return self._tag == 'unsupported_content' + Minimal metadata corresponding to the file received as an argument. Will + be populated if the endpoint is called using a shared link + (SharedLinkFileInfo). - def get_path(self): + :rtype: MinimalFileLinkMetadata """ - An error occurs when downloading metadata for the file. + if self._link_metadata_present: + return self._link_metadata_value + else: + return None - Only call this if :meth:`is_path` is true. + @link_metadata.setter + def link_metadata(self, val): + if val is None: + del self.link_metadata + return + self._link_metadata_validator.validate_type_only(val) + self._link_metadata_value = val + self._link_metadata_present = True - :rtype: LookupError - """ - if not self.is_path(): - raise AttributeError("tag 'path' not set") - return self._value + @link_metadata.deleter + def link_metadata(self): + self._link_metadata_value = None + self._link_metadata_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PreviewError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PreviewResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PreviewError(%r, %r)' % (self._tag, self._value) + return 'PreviewResult(file_metadata={!r}, link_metadata={!r})'.format( + self._file_metadata_value, + self._link_metadata_value, + ) -PreviewError_validator = bv.Union(PreviewError) +PreviewResult_validator = bv.Struct(PreviewResult) class RelocationPath(bb.Struct): """ @@ -8719,91 +10301,313 @@ def get_path_lookup(self): """ An error occurs when downloading metadata for the file. - Only call this if :meth:`is_path_lookup` is true. + Only call this if :meth:`is_path_lookup` is true. + + :rtype: LookupError + """ + if not self.is_path_lookup(): + raise AttributeError("tag 'path_lookup' not set") + return self._value + + def get_path_write(self): + """ + An error occurs when trying to restore the file to that path. + + Only call this if :meth:`is_path_write` is true. + + :rtype: WriteError + """ + if not self.is_path_write(): + raise AttributeError("tag 'path_write' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RestoreError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RestoreError(%r, %r)' % (self._tag, self._value) + +RestoreError_validator = bv.Union(RestoreError) + +class SaveCopyReferenceArg(bb.Struct): + """ + :ivar files.SaveCopyReferenceArg.copy_reference: A copy reference returned + by :meth:`dropbox.dropbox.Dropbox.files_copy_reference_get`. + :ivar files.SaveCopyReferenceArg.path: Path in the user's Dropbox that is + the destination. + """ + + __slots__ = [ + '_copy_reference_value', + '_copy_reference_present', + '_path_value', + '_path_present', + ] + + _has_required_fields = True + + def __init__(self, + copy_reference=None, + path=None): + self._copy_reference_value = None + self._copy_reference_present = False + self._path_value = None + self._path_present = False + if copy_reference is not None: + self.copy_reference = copy_reference + if path is not None: + self.path = path + + @property + def copy_reference(self): + """ + A copy reference returned by + :meth:`dropbox.dropbox.Dropbox.files_copy_reference_get`. + + :rtype: str + """ + if self._copy_reference_present: + return self._copy_reference_value + else: + raise AttributeError("missing required field 'copy_reference'") + + @copy_reference.setter + def copy_reference(self, val): + val = self._copy_reference_validator.validate(val) + self._copy_reference_value = val + self._copy_reference_present = True + + @copy_reference.deleter + def copy_reference(self): + self._copy_reference_value = None + self._copy_reference_present = False + + @property + def path(self): + """ + Path in the user's Dropbox that is the destination. + + :rtype: str + """ + if self._path_present: + return self._path_value + else: + raise AttributeError("missing required field 'path'") + + @path.setter + def path(self, val): + val = self._path_validator.validate(val) + self._path_value = val + self._path_present = True + + @path.deleter + def path(self): + self._path_value = None + self._path_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SaveCopyReferenceArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SaveCopyReferenceArg(copy_reference={!r}, path={!r})'.format( + self._copy_reference_value, + self._path_value, + ) + +SaveCopyReferenceArg_validator = bv.Struct(SaveCopyReferenceArg) + +class SaveCopyReferenceError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar files.SaveCopyReferenceError.invalid_copy_reference: The copy + reference is invalid. + :ivar files.SaveCopyReferenceError.no_permission: You don't have permission + to save the given copy reference. Please make sure this app is same app + which created the copy reference and the source user is still linked to + the app. + :ivar files.SaveCopyReferenceError.not_found: The file referenced by the + copy reference cannot be found. + :ivar files.SaveCopyReferenceError.too_many_files: The operation would + involve more than 10,000 files and folders. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_copy_reference = None + # Attribute is overwritten below the class definition + no_permission = None + # Attribute is overwritten below the class definition + not_found = None + # Attribute is overwritten below the class definition + too_many_files = None + # Attribute is overwritten below the class definition + other = None + + @classmethod + def path(cls, val): + """ + Create an instance of this class set to the ``path`` tag with value + ``val``. + + :param WriteError val: + :rtype: SaveCopyReferenceError + """ + return cls('path', val) + + def is_path(self): + """ + Check if the union tag is ``path``. + + :rtype: bool + """ + return self._tag == 'path' + + def is_invalid_copy_reference(self): + """ + Check if the union tag is ``invalid_copy_reference``. + + :rtype: bool + """ + return self._tag == 'invalid_copy_reference' + + def is_no_permission(self): + """ + Check if the union tag is ``no_permission``. + + :rtype: bool + """ + return self._tag == 'no_permission' + + def is_not_found(self): + """ + Check if the union tag is ``not_found``. + + :rtype: bool + """ + return self._tag == 'not_found' + + def is_too_many_files(self): + """ + Check if the union tag is ``too_many_files``. + + :rtype: bool + """ + return self._tag == 'too_many_files' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_path(self): + """ + Only call this if :meth:`is_path` is true. + + :rtype: WriteError + """ + if not self.is_path(): + raise AttributeError("tag 'path' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SaveCopyReferenceError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SaveCopyReferenceError(%r, %r)' % (self._tag, self._value) + +SaveCopyReferenceError_validator = bv.Union(SaveCopyReferenceError) + +class SaveCopyReferenceResult(bb.Struct): + """ + :ivar files.SaveCopyReferenceResult.metadata: The metadata of the saved file + or folder in the user's Dropbox. + """ + + __slots__ = [ + '_metadata_value', + '_metadata_present', + ] + + _has_required_fields = True + + def __init__(self, + metadata=None): + self._metadata_value = None + self._metadata_present = False + if metadata is not None: + self.metadata = metadata - :rtype: LookupError + @property + def metadata(self): """ - if not self.is_path_lookup(): - raise AttributeError("tag 'path_lookup' not set") - return self._value + The metadata of the saved file or folder in the user's Dropbox. - def get_path_write(self): + :rtype: Metadata """ - An error occurs when trying to restore the file to that path. + if self._metadata_present: + return self._metadata_value + else: + raise AttributeError("missing required field 'metadata'") - Only call this if :meth:`is_path_write` is true. + @metadata.setter + def metadata(self, val): + self._metadata_validator.validate_type_only(val) + self._metadata_value = val + self._metadata_present = True - :rtype: WriteError - """ - if not self.is_path_write(): - raise AttributeError("tag 'path_write' not set") - return self._value + @metadata.deleter + def metadata(self): + self._metadata_value = None + self._metadata_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RestoreError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SaveCopyReferenceResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RestoreError(%r, %r)' % (self._tag, self._value) + return 'SaveCopyReferenceResult(metadata={!r})'.format( + self._metadata_value, + ) -RestoreError_validator = bv.Union(RestoreError) +SaveCopyReferenceResult_validator = bv.Struct(SaveCopyReferenceResult) -class SaveCopyReferenceArg(bb.Struct): +class SaveUrlArg(bb.Struct): """ - :ivar files.SaveCopyReferenceArg.copy_reference: A copy reference returned - by :meth:`dropbox.dropbox.Dropbox.files_copy_reference_get`. - :ivar files.SaveCopyReferenceArg.path: Path in the user's Dropbox that is - the destination. + :ivar files.SaveUrlArg.path: The path in Dropbox where the URL will be saved + to. + :ivar files.SaveUrlArg.url: The URL to be saved. """ __slots__ = [ - '_copy_reference_value', - '_copy_reference_present', '_path_value', '_path_present', + '_url_value', + '_url_present', ] _has_required_fields = True def __init__(self, - copy_reference=None, - path=None): - self._copy_reference_value = None - self._copy_reference_present = False + path=None, + url=None): self._path_value = None self._path_present = False - if copy_reference is not None: - self.copy_reference = copy_reference + self._url_value = None + self._url_present = False if path is not None: self.path = path - - @property - def copy_reference(self): - """ - A copy reference returned by - :meth:`dropbox.dropbox.Dropbox.files_copy_reference_get`. - - :rtype: str - """ - if self._copy_reference_present: - return self._copy_reference_value - else: - raise AttributeError("missing required field 'copy_reference'") - - @copy_reference.setter - def copy_reference(self, val): - val = self._copy_reference_validator.validate(val) - self._copy_reference_value = val - self._copy_reference_present = True - - @copy_reference.deleter - def copy_reference(self): - self._copy_reference_value = None - self._copy_reference_present = False + if url is not None: + self.url = url @property def path(self): """ - Path in the user's Dropbox that is the destination. + The path in Dropbox where the URL will be saved to. :rtype: str """ @@ -8823,45 +10627,62 @@ def path(self): self._path_value = None self._path_present = False + @property + def url(self): + """ + The URL to be saved. + + :rtype: str + """ + if self._url_present: + return self._url_value + else: + raise AttributeError("missing required field 'url'") + + @url.setter + def url(self, val): + val = self._url_validator.validate(val) + self._url_value = val + self._url_present = True + + @url.deleter + def url(self): + self._url_value = None + self._url_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SaveCopyReferenceArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SaveUrlArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SaveCopyReferenceArg(copy_reference={!r}, path={!r})'.format( - self._copy_reference_value, + return 'SaveUrlArg(path={!r}, url={!r})'.format( self._path_value, + self._url_value, ) -SaveCopyReferenceArg_validator = bv.Struct(SaveCopyReferenceArg) +SaveUrlArg_validator = bv.Struct(SaveUrlArg) -class SaveCopyReferenceError(bb.Union): +class SaveUrlError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar files.SaveCopyReferenceError.invalid_copy_reference: The copy - reference is invalid. - :ivar files.SaveCopyReferenceError.no_permission: You don't have permission - to save the given copy reference. Please make sure this app is same app - which created the copy reference and the source user is still linked to - the app. - :ivar files.SaveCopyReferenceError.not_found: The file referenced by the - copy reference cannot be found. - :ivar files.SaveCopyReferenceError.too_many_files: The operation would - involve more than 10,000 files and folders. + :ivar files.SaveUrlError.download_failed: Failed downloading the given URL. + The URL may be password-protected and the password provided was + incorrect, or the link may be disabled. + :ivar files.SaveUrlError.invalid_url: The given URL is invalid. + :ivar files.SaveUrlError.not_found: The file where the URL is saved to no + longer exists. """ _catch_all = 'other' # Attribute is overwritten below the class definition - invalid_copy_reference = None + download_failed = None # Attribute is overwritten below the class definition - no_permission = None + invalid_url = None # Attribute is overwritten below the class definition not_found = None # Attribute is overwritten below the class definition - too_many_files = None - # Attribute is overwritten below the class definition other = None @classmethod @@ -8871,7 +10692,7 @@ def path(cls, val): ``val``. :param WriteError val: - :rtype: SaveCopyReferenceError + :rtype: SaveUrlError """ return cls('path', val) @@ -8883,21 +10704,21 @@ def is_path(self): """ return self._tag == 'path' - def is_invalid_copy_reference(self): + def is_download_failed(self): """ - Check if the union tag is ``invalid_copy_reference``. + Check if the union tag is ``download_failed``. :rtype: bool """ - return self._tag == 'invalid_copy_reference' + return self._tag == 'download_failed' - def is_no_permission(self): + def is_invalid_url(self): """ - Check if the union tag is ``no_permission``. + Check if the union tag is ``invalid_url``. :rtype: bool """ - return self._tag == 'no_permission' + return self._tag == 'invalid_url' def is_not_found(self): """ @@ -8907,14 +10728,6 @@ def is_not_found(self): """ return self._tag == 'not_found' - def is_too_many_files(self): - """ - Check if the union tag is ``too_many_files``. - - :rtype: bool - """ - return self._tag == 'too_many_files' - def is_other(self): """ Check if the union tag is ``other``. @@ -8934,98 +10747,204 @@ def get_path(self): return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SaveCopyReferenceError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SaveUrlError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SaveCopyReferenceError(%r, %r)' % (self._tag, self._value) + return 'SaveUrlError(%r, %r)' % (self._tag, self._value) -SaveCopyReferenceError_validator = bv.Union(SaveCopyReferenceError) +SaveUrlError_validator = bv.Union(SaveUrlError) -class SaveCopyReferenceResult(bb.Struct): +class SaveUrlJobStatus(async_.PollResultBase): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar FileMetadata SaveUrlJobStatus.complete: Metadata of the file where the + URL is saved to. + """ + + @classmethod + def complete(cls, val): + """ + Create an instance of this class set to the ``complete`` tag with value + ``val``. + + :param FileMetadata val: + :rtype: SaveUrlJobStatus + """ + return cls('complete', val) + + @classmethod + def failed(cls, val): + """ + Create an instance of this class set to the ``failed`` tag with value + ``val``. + + :param SaveUrlError val: + :rtype: SaveUrlJobStatus + """ + return cls('failed', val) + + def is_complete(self): + """ + Check if the union tag is ``complete``. + + :rtype: bool + """ + return self._tag == 'complete' + + def is_failed(self): + """ + Check if the union tag is ``failed``. + + :rtype: bool + """ + return self._tag == 'failed' + + def get_complete(self): + """ + Metadata of the file where the URL is saved to. + + Only call this if :meth:`is_complete` is true. + + :rtype: FileMetadata + """ + if not self.is_complete(): + raise AttributeError("tag 'complete' not set") + return self._value + + def get_failed(self): + """ + Only call this if :meth:`is_failed` is true. + + :rtype: SaveUrlError + """ + if not self.is_failed(): + raise AttributeError("tag 'failed' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SaveUrlJobStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SaveUrlJobStatus(%r, %r)' % (self._tag, self._value) + +SaveUrlJobStatus_validator = bv.Union(SaveUrlJobStatus) + +class SaveUrlResult(async_.LaunchResultBase): """ - :ivar files.SaveCopyReferenceResult.metadata: The metadata of the saved file - or folder in the user's Dropbox. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar FileMetadata SaveUrlResult.complete: Metadata of the file where the + URL is saved to. """ - __slots__ = [ - '_metadata_value', - '_metadata_present', - ] + @classmethod + def complete(cls, val): + """ + Create an instance of this class set to the ``complete`` tag with value + ``val``. - _has_required_fields = True + :param FileMetadata val: + :rtype: SaveUrlResult + """ + return cls('complete', val) - def __init__(self, - metadata=None): - self._metadata_value = None - self._metadata_present = False - if metadata is not None: - self.metadata = metadata + def is_complete(self): + """ + Check if the union tag is ``complete``. - @property - def metadata(self): + :rtype: bool """ - The metadata of the saved file or folder in the user's Dropbox. + return self._tag == 'complete' - :rtype: Metadata + def get_complete(self): """ - if self._metadata_present: - return self._metadata_value - else: - raise AttributeError("missing required field 'metadata'") + Metadata of the file where the URL is saved to. - @metadata.setter - def metadata(self, val): - self._metadata_validator.validate_type_only(val) - self._metadata_value = val - self._metadata_present = True + Only call this if :meth:`is_complete` is true. - @metadata.deleter - def metadata(self): - self._metadata_value = None - self._metadata_present = False + :rtype: FileMetadata + """ + if not self.is_complete(): + raise AttributeError("tag 'complete' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SaveCopyReferenceResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SaveUrlResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SaveCopyReferenceResult(metadata={!r})'.format( - self._metadata_value, - ) + return 'SaveUrlResult(%r, %r)' % (self._tag, self._value) -SaveCopyReferenceResult_validator = bv.Struct(SaveCopyReferenceResult) +SaveUrlResult_validator = bv.Union(SaveUrlResult) -class SaveUrlArg(bb.Struct): +class SearchArg(bb.Struct): """ - :ivar files.SaveUrlArg.path: The path in Dropbox where the URL will be saved - to. - :ivar files.SaveUrlArg.url: The URL to be saved. + :ivar files.SearchArg.path: The path in the user's Dropbox to search. Should + probably be a folder. + :ivar files.SearchArg.query: The string to search for. Query string may be + rewritten to improve relevance of results. The string is split on spaces + into multiple tokens. For file name searching, the last token is used + for prefix matching (i.e. "bat c" matches "bat cave" but not "batman + car"). + :ivar files.SearchArg.start: The starting index within the search results + (used for paging). + :ivar files.SearchArg.max_results: The maximum number of search results to + return. + :ivar files.SearchArg.mode: The search mode (filename, filename_and_content, + or deleted_filename). Note that searching file content is only available + for Dropbox Business accounts. """ __slots__ = [ '_path_value', '_path_present', - '_url_value', - '_url_present', + '_query_value', + '_query_present', + '_start_value', + '_start_present', + '_max_results_value', + '_max_results_present', + '_mode_value', + '_mode_present', ] _has_required_fields = True def __init__(self, path=None, - url=None): + query=None, + start=None, + max_results=None, + mode=None): self._path_value = None self._path_present = False - self._url_value = None - self._url_present = False + self._query_value = None + self._query_present = False + self._start_value = None + self._start_present = False + self._max_results_value = None + self._max_results_present = False + self._mode_value = None + self._mode_present = False if path is not None: self.path = path - if url is not None: - self.url = url + if query is not None: + self.query = query + if start is not None: + self.start = start + if max_results is not None: + self.max_results = max_results + if mode is not None: + self.mode = mode @property def path(self): """ - The path in Dropbox where the URL will be saved to. + The path in the user's Dropbox to search. Should probably be a folder. :rtype: str """ @@ -9046,60 +10965,125 @@ def path(self): self._path_present = False @property - def url(self): + def query(self): """ - The URL to be saved. + The string to search for. Query string may be rewritten to improve + relevance of results. The string is split on spaces into multiple + tokens. For file name searching, the last token is used for prefix + matching (i.e. "bat c" matches "bat cave" but not "batman car"). :rtype: str """ - if self._url_present: - return self._url_value + if self._query_present: + return self._query_value else: - raise AttributeError("missing required field 'url'") + raise AttributeError("missing required field 'query'") - @url.setter - def url(self, val): - val = self._url_validator.validate(val) - self._url_value = val - self._url_present = True + @query.setter + def query(self, val): + val = self._query_validator.validate(val) + self._query_value = val + self._query_present = True - @url.deleter - def url(self): - self._url_value = None - self._url_present = False + @query.deleter + def query(self): + self._query_value = None + self._query_present = False + + @property + def start(self): + """ + The starting index within the search results (used for paging). + + :rtype: int + """ + if self._start_present: + return self._start_value + else: + return 0 + + @start.setter + def start(self, val): + val = self._start_validator.validate(val) + self._start_value = val + self._start_present = True + + @start.deleter + def start(self): + self._start_value = None + self._start_present = False + + @property + def max_results(self): + """ + The maximum number of search results to return. + + :rtype: int + """ + if self._max_results_present: + return self._max_results_value + else: + return 100 + + @max_results.setter + def max_results(self, val): + val = self._max_results_validator.validate(val) + self._max_results_value = val + self._max_results_present = True + + @max_results.deleter + def max_results(self): + self._max_results_value = None + self._max_results_present = False + + @property + def mode(self): + """ + The search mode (filename, filename_and_content, or deleted_filename). + Note that searching file content is only available for Dropbox Business + accounts. + + :rtype: SearchMode + """ + if self._mode_present: + return self._mode_value + else: + return SearchMode.filename + + @mode.setter + def mode(self, val): + self._mode_validator.validate_type_only(val) + self._mode_value = val + self._mode_present = True + + @mode.deleter + def mode(self): + self._mode_value = None + self._mode_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SaveUrlArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SaveUrlArg(path={!r}, url={!r})'.format( + return 'SearchArg(path={!r}, query={!r}, start={!r}, max_results={!r}, mode={!r})'.format( self._path_value, - self._url_value, + self._query_value, + self._start_value, + self._max_results_value, + self._mode_value, ) -SaveUrlArg_validator = bv.Struct(SaveUrlArg) +SearchArg_validator = bv.Struct(SearchArg) -class SaveUrlError(bb.Union): +class SearchError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - - :ivar files.SaveUrlError.download_failed: Failed downloading the given URL. - The url may be password-protected / the password provided was incorrect. - :ivar files.SaveUrlError.invalid_url: The given URL is invalid. - :ivar files.SaveUrlError.not_found: The file where the URL is saved to no - longer exists. """ _catch_all = 'other' # Attribute is overwritten below the class definition - download_failed = None - # Attribute is overwritten below the class definition - invalid_url = None - # Attribute is overwritten below the class definition - not_found = None - # Attribute is overwritten below the class definition other = None @classmethod @@ -9108,42 +11092,37 @@ def path(cls, val): Create an instance of this class set to the ``path`` tag with value ``val``. - :param WriteError val: - :rtype: SaveUrlError + :param LookupError val: + :rtype: SearchError """ return cls('path', val) - def is_path(self): - """ - Check if the union tag is ``path``. - - :rtype: bool - """ - return self._tag == 'path' - - def is_download_failed(self): + @classmethod + def invalid_argument(cls, val): """ - Check if the union tag is ``download_failed``. + Create an instance of this class set to the ``invalid_argument`` tag + with value ``val``. - :rtype: bool + :param str val: + :rtype: SearchError """ - return self._tag == 'download_failed' + return cls('invalid_argument', val) - def is_invalid_url(self): + def is_path(self): """ - Check if the union tag is ``invalid_url``. + Check if the union tag is ``path``. :rtype: bool """ - return self._tag == 'invalid_url' + return self._tag == 'path' - def is_not_found(self): + def is_invalid_argument(self): """ - Check if the union tag is ``not_found``. + Check if the union tag is ``invalid_argument``. :rtype: bool """ - return self._tag == 'not_found' + return self._tag == 'invalid_argument' def is_other(self): """ @@ -9157,220 +11136,397 @@ def get_path(self): """ Only call this if :meth:`is_path` is true. - :rtype: WriteError + :rtype: LookupError """ if not self.is_path(): raise AttributeError("tag 'path' not set") return self._value + def get_invalid_argument(self): + """ + Only call this if :meth:`is_invalid_argument` is true. + + :rtype: str + """ + if not self.is_invalid_argument(): + raise AttributeError("tag 'invalid_argument' not set") + return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SaveUrlError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SaveUrlError(%r, %r)' % (self._tag, self._value) + return 'SearchError(%r, %r)' % (self._tag, self._value) -SaveUrlError_validator = bv.Union(SaveUrlError) +SearchError_validator = bv.Union(SearchError) -class SaveUrlJobStatus(async_.PollResultBase): +class SearchMatch(bb.Struct): + """ + :ivar files.SearchMatch.match_type: The type of the match. + :ivar files.SearchMatch.metadata: The metadata for the matched file or + folder. + """ + + __slots__ = [ + '_match_type_value', + '_match_type_present', + '_metadata_value', + '_metadata_present', + ] + + _has_required_fields = True + + def __init__(self, + match_type=None, + metadata=None): + self._match_type_value = None + self._match_type_present = False + self._metadata_value = None + self._metadata_present = False + if match_type is not None: + self.match_type = match_type + if metadata is not None: + self.metadata = metadata + + @property + def match_type(self): + """ + The type of the match. + + :rtype: SearchMatchType + """ + if self._match_type_present: + return self._match_type_value + else: + raise AttributeError("missing required field 'match_type'") + + @match_type.setter + def match_type(self, val): + self._match_type_validator.validate_type_only(val) + self._match_type_value = val + self._match_type_present = True + + @match_type.deleter + def match_type(self): + self._match_type_value = None + self._match_type_present = False + + @property + def metadata(self): + """ + The metadata for the matched file or folder. + + :rtype: Metadata + """ + if self._metadata_present: + return self._metadata_value + else: + raise AttributeError("missing required field 'metadata'") + + @metadata.setter + def metadata(self, val): + self._metadata_validator.validate_type_only(val) + self._metadata_value = val + self._metadata_present = True + + @metadata.deleter + def metadata(self): + self._metadata_value = None + self._metadata_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SearchMatch, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SearchMatch(match_type={!r}, metadata={!r})'.format( + self._match_type_value, + self._metadata_value, + ) + +SearchMatch_validator = bv.Struct(SearchMatch) + +class SearchMatchType(bb.Union): """ + Indicates what type of match was found for a given item. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar FileMetadata SaveUrlJobStatus.complete: Metadata of the file where the - URL is saved to. + :ivar files.SearchMatchType.filename: This item was matched on its file or + folder name. + :ivar files.SearchMatchType.content: This item was matched based on its file + contents. + :ivar files.SearchMatchType.both: This item was matched based on both its + contents and its file name. """ - @classmethod - def complete(cls, val): + _catch_all = None + # Attribute is overwritten below the class definition + filename = None + # Attribute is overwritten below the class definition + content = None + # Attribute is overwritten below the class definition + both = None + + def is_filename(self): """ - Create an instance of this class set to the ``complete`` tag with value - ``val``. + Check if the union tag is ``filename``. - :param FileMetadata val: - :rtype: SaveUrlJobStatus + :rtype: bool """ - return cls('complete', val) + return self._tag == 'filename' - @classmethod - def failed(cls, val): + def is_content(self): """ - Create an instance of this class set to the ``failed`` tag with value - ``val``. + Check if the union tag is ``content``. - :param SaveUrlError val: - :rtype: SaveUrlJobStatus + :rtype: bool """ - return cls('failed', val) + return self._tag == 'content' - def is_complete(self): + def is_both(self): """ - Check if the union tag is ``complete``. + Check if the union tag is ``both``. :rtype: bool """ - return self._tag == 'complete' + return self._tag == 'both' - def is_failed(self): - """ - Check if the union tag is ``failed``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SearchMatchType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool + def __repr__(self): + return 'SearchMatchType(%r, %r)' % (self._tag, self._value) + +SearchMatchType_validator = bv.Union(SearchMatchType) + +class SearchMatchV2(bb.Struct): + """ + :ivar files.SearchMatchV2.metadata: The metadata for the matched file or + folder. + :ivar files.SearchMatchV2.highlight_spans: The list of HighlightSpan + determines which parts of the result should be highlighted. + """ + + __slots__ = [ + '_metadata_value', + '_metadata_present', + '_highlight_spans_value', + '_highlight_spans_present', + ] + + _has_required_fields = True + + def __init__(self, + metadata=None, + highlight_spans=None): + self._metadata_value = None + self._metadata_present = False + self._highlight_spans_value = None + self._highlight_spans_present = False + if metadata is not None: + self.metadata = metadata + if highlight_spans is not None: + self.highlight_spans = highlight_spans + + @property + def metadata(self): """ - return self._tag == 'failed' + The metadata for the matched file or folder. - def get_complete(self): + :rtype: MetadataV2 """ - Metadata of the file where the URL is saved to. + if self._metadata_present: + return self._metadata_value + else: + raise AttributeError("missing required field 'metadata'") - Only call this if :meth:`is_complete` is true. + @metadata.setter + def metadata(self, val): + self._metadata_validator.validate_type_only(val) + self._metadata_value = val + self._metadata_present = True - :rtype: FileMetadata - """ - if not self.is_complete(): - raise AttributeError("tag 'complete' not set") - return self._value + @metadata.deleter + def metadata(self): + self._metadata_value = None + self._metadata_present = False - def get_failed(self): + @property + def highlight_spans(self): """ - Only call this if :meth:`is_failed` is true. + The list of HighlightSpan determines which parts of the result should be + highlighted. - :rtype: SaveUrlError + :rtype: list of [HighlightSpan] """ - if not self.is_failed(): - raise AttributeError("tag 'failed' not set") - return self._value + if self._highlight_spans_present: + return self._highlight_spans_value + else: + return None + + @highlight_spans.setter + def highlight_spans(self, val): + if val is None: + del self.highlight_spans + return + val = self._highlight_spans_validator.validate(val) + self._highlight_spans_value = val + self._highlight_spans_present = True + + @highlight_spans.deleter + def highlight_spans(self): + self._highlight_spans_value = None + self._highlight_spans_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SaveUrlJobStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchMatchV2, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SaveUrlJobStatus(%r, %r)' % (self._tag, self._value) + return 'SearchMatchV2(metadata={!r}, highlight_spans={!r})'.format( + self._metadata_value, + self._highlight_spans_value, + ) -SaveUrlJobStatus_validator = bv.Union(SaveUrlJobStatus) +SearchMatchV2_validator = bv.Struct(SearchMatchV2) -class SaveUrlResult(async_.LaunchResultBase): +class SearchMode(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar FileMetadata SaveUrlResult.complete: Metadata of the file where the - URL is saved to. + :ivar files.SearchMode.filename: Search file and folder names. + :ivar files.SearchMode.filename_and_content: Search file and folder names as + well as file contents. + :ivar files.SearchMode.deleted_filename: Search for deleted file and folder + names. """ - @classmethod - def complete(cls, val): + _catch_all = None + # Attribute is overwritten below the class definition + filename = None + # Attribute is overwritten below the class definition + filename_and_content = None + # Attribute is overwritten below the class definition + deleted_filename = None + + def is_filename(self): """ - Create an instance of this class set to the ``complete`` tag with value - ``val``. + Check if the union tag is ``filename``. - :param FileMetadata val: - :rtype: SaveUrlResult + :rtype: bool """ - return cls('complete', val) + return self._tag == 'filename' - def is_complete(self): + def is_filename_and_content(self): """ - Check if the union tag is ``complete``. + Check if the union tag is ``filename_and_content``. :rtype: bool """ - return self._tag == 'complete' + return self._tag == 'filename_and_content' - def get_complete(self): + def is_deleted_filename(self): """ - Metadata of the file where the URL is saved to. - - Only call this if :meth:`is_complete` is true. + Check if the union tag is ``deleted_filename``. - :rtype: FileMetadata + :rtype: bool """ - if not self.is_complete(): - raise AttributeError("tag 'complete' not set") - return self._value + return self._tag == 'deleted_filename' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SaveUrlResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchMode, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SaveUrlResult(%r, %r)' % (self._tag, self._value) + return 'SearchMode(%r, %r)' % (self._tag, self._value) -SaveUrlResult_validator = bv.Union(SaveUrlResult) +SearchMode_validator = bv.Union(SearchMode) -class SearchArg(bb.Struct): +class SearchOptions(bb.Struct): """ - :ivar files.SearchArg.path: The path in the user's Dropbox to search. Should - probably be a folder. - :ivar files.SearchArg.query: The string to search for. The search string is - split on spaces into multiple tokens. For file name searching, the last - token is used for prefix matching (i.e. "bat c" matches "bat cave" but - not "batman car"). - :ivar files.SearchArg.start: The starting index within the search results - (used for paging). - :ivar files.SearchArg.max_results: The maximum number of search results to - return. - :ivar files.SearchArg.mode: The search mode (filename, filename_and_content, - or deleted_filename). Note that searching file content is only available - for Dropbox Business accounts. + :ivar files.SearchOptions.path: Scopes the search to a path in the user's + Dropbox. Searches the entire Dropbox if not specified. + :ivar files.SearchOptions.max_results: The maximum number of search results + to return. + :ivar files.SearchOptions.file_status: Restricts search to the given file + status. + :ivar files.SearchOptions.filename_only: Restricts search to only match on + filenames. + :ivar files.SearchOptions.file_extensions: Restricts search to only the + extensions specified. Only supported for active file search. + :ivar files.SearchOptions.file_categories: Restricts search to only the file + categories specified. Only supported for active file search. """ __slots__ = [ '_path_value', '_path_present', - '_query_value', - '_query_present', - '_start_value', - '_start_present', '_max_results_value', '_max_results_present', - '_mode_value', - '_mode_present', + '_file_status_value', + '_file_status_present', + '_filename_only_value', + '_filename_only_present', + '_file_extensions_value', + '_file_extensions_present', + '_file_categories_value', + '_file_categories_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, path=None, - query=None, - start=None, max_results=None, - mode=None): + file_status=None, + filename_only=None, + file_extensions=None, + file_categories=None): self._path_value = None self._path_present = False - self._query_value = None - self._query_present = False - self._start_value = None - self._start_present = False self._max_results_value = None self._max_results_present = False - self._mode_value = None - self._mode_present = False + self._file_status_value = None + self._file_status_present = False + self._filename_only_value = None + self._filename_only_present = False + self._file_extensions_value = None + self._file_extensions_present = False + self._file_categories_value = None + self._file_categories_present = False if path is not None: self.path = path - if query is not None: - self.query = query - if start is not None: - self.start = start if max_results is not None: self.max_results = max_results - if mode is not None: - self.mode = mode + if file_status is not None: + self.file_status = file_status + if filename_only is not None: + self.filename_only = filename_only + if file_extensions is not None: + self.file_extensions = file_extensions + if file_categories is not None: + self.file_categories = file_categories @property def path(self): """ - The path in the user's Dropbox to search. Should probably be a folder. + Scopes the search to a path in the user's Dropbox. Searches the entire + Dropbox if not specified. :rtype: str """ if self._path_present: return self._path_value else: - raise AttributeError("missing required field 'path'") + return None @path.setter def path(self, val): + if val is None: + del self.path + return val = self._path_validator.validate(val) self._path_value = val self._path_present = True @@ -9380,54 +11536,6 @@ def path(self): self._path_value = None self._path_present = False - @property - def query(self): - """ - The string to search for. The search string is split on spaces into - multiple tokens. For file name searching, the last token is used for - prefix matching (i.e. "bat c" matches "bat cave" but not "batman car"). - - :rtype: str - """ - if self._query_present: - return self._query_value - else: - raise AttributeError("missing required field 'query'") - - @query.setter - def query(self, val): - val = self._query_validator.validate(val) - self._query_value = val - self._query_present = True - - @query.deleter - def query(self): - self._query_value = None - self._query_present = False - - @property - def start(self): - """ - The starting index within the search results (used for paging). - - :rtype: int - """ - if self._start_present: - return self._start_value - else: - return 0 - - @start.setter - def start(self, val): - val = self._start_validator.validate(val) - self._start_value = val - self._start_present = True - - @start.deleter - def start(self): - self._start_value = None - self._start_present = False - @property def max_results(self): """ @@ -9452,340 +11560,468 @@ def max_results(self): self._max_results_present = False @property - def mode(self): + def file_status(self): """ - The search mode (filename, filename_and_content, or deleted_filename). - Note that searching file content is only available for Dropbox Business - accounts. + Restricts search to the given file status. - :rtype: SearchMode + :rtype: FileStatus """ - if self._mode_present: - return self._mode_value + if self._file_status_present: + return self._file_status_value else: - return SearchMode.filename - - @mode.setter - def mode(self, val): - self._mode_validator.validate_type_only(val) - self._mode_value = val - self._mode_present = True + return FileStatus.active - @mode.deleter - def mode(self): - self._mode_value = None - self._mode_present = False + @file_status.setter + def file_status(self, val): + self._file_status_validator.validate_type_only(val) + self._file_status_value = val + self._file_status_present = True - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SearchArg, self)._process_custom_annotations(annotation_type, field_path, processor) + @file_status.deleter + def file_status(self): + self._file_status_value = None + self._file_status_present = False - def __repr__(self): - return 'SearchArg(path={!r}, query={!r}, start={!r}, max_results={!r}, mode={!r})'.format( - self._path_value, - self._query_value, - self._start_value, - self._max_results_value, - self._mode_value, - ) + @property + def filename_only(self): + """ + Restricts search to only match on filenames. -SearchArg_validator = bv.Struct(SearchArg) + :rtype: bool + """ + if self._filename_only_present: + return self._filename_only_value + else: + return False -class SearchError(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + @filename_only.setter + def filename_only(self, val): + val = self._filename_only_validator.validate(val) + self._filename_only_value = val + self._filename_only_present = True - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + @filename_only.deleter + def filename_only(self): + self._filename_only_value = None + self._filename_only_present = False - @classmethod - def path(cls, val): + @property + def file_extensions(self): """ - Create an instance of this class set to the ``path`` tag with value - ``val``. + Restricts search to only the extensions specified. Only supported for + active file search. - :param LookupError val: - :rtype: SearchError + :rtype: list of [str] """ - return cls('path', val) + if self._file_extensions_present: + return self._file_extensions_value + else: + return None - def is_path(self): - """ - Check if the union tag is ``path``. + @file_extensions.setter + def file_extensions(self, val): + if val is None: + del self.file_extensions + return + val = self._file_extensions_validator.validate(val) + self._file_extensions_value = val + self._file_extensions_present = True - :rtype: bool - """ - return self._tag == 'path' + @file_extensions.deleter + def file_extensions(self): + self._file_extensions_value = None + self._file_extensions_present = False - def is_other(self): + @property + def file_categories(self): """ - Check if the union tag is ``other``. + Restricts search to only the file categories specified. Only supported + for active file search. - :rtype: bool + :rtype: list of [FileCategory] """ - return self._tag == 'other' + if self._file_categories_present: + return self._file_categories_value + else: + return None - def get_path(self): - """ - Only call this if :meth:`is_path` is true. + @file_categories.setter + def file_categories(self, val): + if val is None: + del self.file_categories + return + val = self._file_categories_validator.validate(val) + self._file_categories_value = val + self._file_categories_present = True - :rtype: LookupError - """ - if not self.is_path(): - raise AttributeError("tag 'path' not set") - return self._value + @file_categories.deleter + def file_categories(self): + self._file_categories_value = None + self._file_categories_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SearchError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchOptions, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SearchError(%r, %r)' % (self._tag, self._value) + return 'SearchOptions(path={!r}, max_results={!r}, file_status={!r}, filename_only={!r}, file_extensions={!r}, file_categories={!r})'.format( + self._path_value, + self._max_results_value, + self._file_status_value, + self._filename_only_value, + self._file_extensions_value, + self._file_categories_value, + ) -SearchError_validator = bv.Union(SearchError) +SearchOptions_validator = bv.Struct(SearchOptions) -class SearchMatch(bb.Struct): +class SearchResult(bb.Struct): """ - :ivar files.SearchMatch.match_type: The type of the match. - :ivar files.SearchMatch.metadata: The metadata for the matched file or - folder. + :ivar files.SearchResult.matches: A list (possibly empty) of matches for the + query. + :ivar files.SearchResult.more: Used for paging. If true, indicates there is + another page of results available that can be fetched by calling + :meth:`dropbox.dropbox.Dropbox.files_search` again. + :ivar files.SearchResult.start: Used for paging. Value to set the start + argument to when calling :meth:`dropbox.dropbox.Dropbox.files_search` to + fetch the next page of results. """ __slots__ = [ - '_match_type_value', - '_match_type_present', - '_metadata_value', - '_metadata_present', + '_matches_value', + '_matches_present', + '_more_value', + '_more_present', + '_start_value', + '_start_present', ] _has_required_fields = True def __init__(self, - match_type=None, - metadata=None): - self._match_type_value = None - self._match_type_present = False - self._metadata_value = None - self._metadata_present = False - if match_type is not None: - self.match_type = match_type - if metadata is not None: - self.metadata = metadata + matches=None, + more=None, + start=None): + self._matches_value = None + self._matches_present = False + self._more_value = None + self._more_present = False + self._start_value = None + self._start_present = False + if matches is not None: + self.matches = matches + if more is not None: + self.more = more + if start is not None: + self.start = start + + @property + def matches(self): + """ + A list (possibly empty) of matches for the query. + + :rtype: list of [SearchMatch] + """ + if self._matches_present: + return self._matches_value + else: + raise AttributeError("missing required field 'matches'") + + @matches.setter + def matches(self, val): + val = self._matches_validator.validate(val) + self._matches_value = val + self._matches_present = True + + @matches.deleter + def matches(self): + self._matches_value = None + self._matches_present = False @property - def match_type(self): + def more(self): """ - The type of the match. + Used for paging. If true, indicates there is another page of results + available that can be fetched by calling + :meth:`dropbox.dropbox.Dropbox.files_search` again. - :rtype: SearchMatchType + :rtype: bool """ - if self._match_type_present: - return self._match_type_value + if self._more_present: + return self._more_value else: - raise AttributeError("missing required field 'match_type'") + raise AttributeError("missing required field 'more'") - @match_type.setter - def match_type(self, val): - self._match_type_validator.validate_type_only(val) - self._match_type_value = val - self._match_type_present = True + @more.setter + def more(self, val): + val = self._more_validator.validate(val) + self._more_value = val + self._more_present = True - @match_type.deleter - def match_type(self): - self._match_type_value = None - self._match_type_present = False + @more.deleter + def more(self): + self._more_value = None + self._more_present = False @property - def metadata(self): + def start(self): """ - The metadata for the matched file or folder. + Used for paging. Value to set the start argument to when calling + :meth:`dropbox.dropbox.Dropbox.files_search` to fetch the next page of + results. - :rtype: Metadata + :rtype: int """ - if self._metadata_present: - return self._metadata_value + if self._start_present: + return self._start_value else: - raise AttributeError("missing required field 'metadata'") + raise AttributeError("missing required field 'start'") - @metadata.setter - def metadata(self, val): - self._metadata_validator.validate_type_only(val) - self._metadata_value = val - self._metadata_present = True + @start.setter + def start(self, val): + val = self._start_validator.validate(val) + self._start_value = val + self._start_present = True - @metadata.deleter - def metadata(self): - self._metadata_value = None - self._metadata_present = False + @start.deleter + def start(self): + self._start_value = None + self._start_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SearchMatch, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SearchMatch(match_type={!r}, metadata={!r})'.format( - self._match_type_value, - self._metadata_value, + return 'SearchResult(matches={!r}, more={!r}, start={!r})'.format( + self._matches_value, + self._more_value, + self._start_value, ) -SearchMatch_validator = bv.Struct(SearchMatch) +SearchResult_validator = bv.Struct(SearchResult) -class SearchMatchType(bb.Union): +class SearchV2Arg(bb.Struct): + """ + :ivar files.SearchV2Arg.query: The string to search for. May match across + multiple fields based on the request arguments. Query string may be + rewritten to improve relevance of results. + :ivar files.SearchV2Arg.options: Options for more targeted search results. """ - Indicates what type of match was found for a given item. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + __slots__ = [ + '_query_value', + '_query_present', + '_options_value', + '_options_present', + '_include_highlights_value', + '_include_highlights_present', + ] - :ivar files.SearchMatchType.filename: This item was matched on its file or - folder name. - :ivar files.SearchMatchType.content: This item was matched based on its file - contents. - :ivar files.SearchMatchType.both: This item was matched based on both its - contents and its file name. - """ + _has_required_fields = True - _catch_all = None - # Attribute is overwritten below the class definition - filename = None - # Attribute is overwritten below the class definition - content = None - # Attribute is overwritten below the class definition - both = None + def __init__(self, + query=None, + options=None, + include_highlights=None): + self._query_value = None + self._query_present = False + self._options_value = None + self._options_present = False + self._include_highlights_value = None + self._include_highlights_present = False + if query is not None: + self.query = query + if options is not None: + self.options = options + if include_highlights is not None: + self.include_highlights = include_highlights - def is_filename(self): + @property + def query(self): """ - Check if the union tag is ``filename``. + The string to search for. May match across multiple fields based on the + request arguments. Query string may be rewritten to improve relevance of + results. - :rtype: bool + :rtype: str """ - return self._tag == 'filename' + if self._query_present: + return self._query_value + else: + raise AttributeError("missing required field 'query'") - def is_content(self): - """ - Check if the union tag is ``content``. + @query.setter + def query(self, val): + val = self._query_validator.validate(val) + self._query_value = val + self._query_present = True - :rtype: bool + @query.deleter + def query(self): + self._query_value = None + self._query_present = False + + @property + def options(self): """ - return self._tag == 'content' + Options for more targeted search results. - def is_both(self): + :rtype: SearchOptions """ - Check if the union tag is ``both``. + if self._options_present: + return self._options_value + else: + return None + + @options.setter + def options(self, val): + if val is None: + del self.options + return + self._options_validator.validate_type_only(val) + self._options_value = val + self._options_present = True + @options.deleter + def options(self): + self._options_value = None + self._options_present = False + + @property + def include_highlights(self): + """ :rtype: bool """ - return self._tag == 'both' + if self._include_highlights_present: + return self._include_highlights_value + else: + return False + + @include_highlights.setter + def include_highlights(self, val): + val = self._include_highlights_validator.validate(val) + self._include_highlights_value = val + self._include_highlights_present = True + + @include_highlights.deleter + def include_highlights(self): + self._include_highlights_value = None + self._include_highlights_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SearchMatchType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchV2Arg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SearchMatchType(%r, %r)' % (self._tag, self._value) + return 'SearchV2Arg(query={!r}, options={!r}, include_highlights={!r})'.format( + self._query_value, + self._options_value, + self._include_highlights_value, + ) -SearchMatchType_validator = bv.Union(SearchMatchType) +SearchV2Arg_validator = bv.Struct(SearchV2Arg) -class SearchMode(bb.Union): +class SearchV2ContinueArg(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar files.SearchMode.filename: Search file and folder names. - :ivar files.SearchMode.filename_and_content: Search file and folder names as - well as file contents. - :ivar files.SearchMode.deleted_filename: Search for deleted file and folder - names. + :ivar files.SearchV2ContinueArg.cursor: The cursor returned by your last + call to :meth:`dropbox.dropbox.Dropbox.files_search`. Used to fetch the + next page of results. """ - _catch_all = None - # Attribute is overwritten below the class definition - filename = None - # Attribute is overwritten below the class definition - filename_and_content = None - # Attribute is overwritten below the class definition - deleted_filename = None + __slots__ = [ + '_cursor_value', + '_cursor_present', + ] - def is_filename(self): - """ - Check if the union tag is ``filename``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'filename' + def __init__(self, + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor - def is_filename_and_content(self): + @property + def cursor(self): """ - Check if the union tag is ``filename_and_content``. + The cursor returned by your last call to + :meth:`dropbox.dropbox.Dropbox.files_search`. Used to fetch the next + page of results. - :rtype: bool + :rtype: str """ - return self._tag == 'filename_and_content' + if self._cursor_present: + return self._cursor_value + else: + raise AttributeError("missing required field 'cursor'") - def is_deleted_filename(self): - """ - Check if the union tag is ``deleted_filename``. + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - :rtype: bool - """ - return self._tag == 'deleted_filename' + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SearchMode, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchV2ContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SearchMode(%r, %r)' % (self._tag, self._value) + return 'SearchV2ContinueArg(cursor={!r})'.format( + self._cursor_value, + ) -SearchMode_validator = bv.Union(SearchMode) +SearchV2ContinueArg_validator = bv.Struct(SearchV2ContinueArg) -class SearchResult(bb.Struct): +class SearchV2Result(bb.Struct): """ - :ivar files.SearchResult.matches: A list (possibly empty) of matches for the - query. - :ivar files.SearchResult.more: Used for paging. If true, indicates there is - another page of results available that can be fetched by calling - :meth:`dropbox.dropbox.Dropbox.files_search` again. - :ivar files.SearchResult.start: Used for paging. Value to set the start - argument to when calling :meth:`dropbox.dropbox.Dropbox.files_search` to - fetch the next page of results. + :ivar files.SearchV2Result.matches: A list (possibly empty) of matches for + the query. + :ivar files.SearchV2Result.has_more: Used for paging. If true, indicates + there is another page of results available that can be fetched by + calling :meth:`dropbox.dropbox.Dropbox.files_search_continue` with the + cursor. + :ivar files.SearchV2Result.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.files_search_continue` to fetch the next + page of results. """ __slots__ = [ '_matches_value', '_matches_present', - '_more_value', - '_more_present', - '_start_value', - '_start_present', + '_has_more_value', + '_has_more_present', + '_cursor_value', + '_cursor_present', ] _has_required_fields = True def __init__(self, matches=None, - more=None, - start=None): - self._matches_value = None - self._matches_present = False - self._more_value = None - self._more_present = False - self._start_value = None - self._start_present = False + has_more=None, + cursor=None): + self._matches_value = None + self._matches_present = False + self._has_more_value = None + self._has_more_present = False + self._cursor_value = None + self._cursor_present = False if matches is not None: self.matches = matches - if more is not None: - self.more = more - if start is not None: - self.start = start + if has_more is not None: + self.has_more = has_more + if cursor is not None: + self.cursor = cursor @property def matches(self): """ A list (possibly empty) of matches for the query. - :rtype: list of [SearchMatch] + :rtype: list of [SearchMatchV2] """ if self._matches_present: return self._matches_value @@ -9804,66 +12040,69 @@ def matches(self): self._matches_present = False @property - def more(self): + def has_more(self): """ Used for paging. If true, indicates there is another page of results available that can be fetched by calling - :meth:`dropbox.dropbox.Dropbox.files_search` again. + :meth:`dropbox.dropbox.Dropbox.files_search_continue` with the cursor. :rtype: bool """ - if self._more_present: - return self._more_value + if self._has_more_present: + return self._has_more_value else: - raise AttributeError("missing required field 'more'") + raise AttributeError("missing required field 'has_more'") - @more.setter - def more(self, val): - val = self._more_validator.validate(val) - self._more_value = val - self._more_present = True + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - @more.deleter - def more(self): - self._more_value = None - self._more_present = False + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False @property - def start(self): + def cursor(self): """ - Used for paging. Value to set the start argument to when calling - :meth:`dropbox.dropbox.Dropbox.files_search` to fetch the next page of - results. + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.files_search_continue` to fetch the next + page of results. - :rtype: int + :rtype: str """ - if self._start_present: - return self._start_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'start'") + return None - @start.setter - def start(self, val): - val = self._start_validator.validate(val) - self._start_value = val - self._start_present = True + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @start.deleter - def start(self): - self._start_value = None - self._start_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SearchResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SearchV2Result, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SearchResult(matches={!r}, more={!r}, start={!r})'.format( + return 'SearchV2Result(matches={!r}, has_more={!r}, cursor={!r})'.format( self._matches_value, - self._more_value, - self._start_value, + self._has_more_value, + self._cursor_value, ) -SearchResult_validator = bv.Struct(SearchResult) +SearchV2Result_validator = bv.Struct(SearchV2Result) class SharedLink(bb.Struct): """ @@ -9927,30 +12166,283 @@ def password(self): else: return None - @password.setter - def password(self, val): + @password.setter + def password(self, val): + if val is None: + del self.password + return + val = self._password_validator.validate(val) + self._password_value = val + self._password_present = True + + @password.deleter + def password(self): + self._password_value = None + self._password_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedLink, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedLink(url={!r}, password={!r})'.format( + self._url_value, + self._password_value, + ) + +SharedLink_validator = bv.Struct(SharedLink) + +class SharedLinkFileInfo(bb.Struct): + """ + :ivar files.SharedLinkFileInfo.url: The shared link corresponding to either + a file or shared link to a folder. If it is for a folder shared link, we + use the path param to determine for which file in the folder the view is + for. + :ivar files.SharedLinkFileInfo.path: The path corresponding to a file in a + shared link to a folder. Required for shared links to folders. + :ivar files.SharedLinkFileInfo.password: Password for the shared link. + Required for password-protected shared links to files unless it can be + read from a cookie. + """ + + __slots__ = [ + '_url_value', + '_url_present', + '_path_value', + '_path_present', + '_password_value', + '_password_present', + ] + + _has_required_fields = True + + def __init__(self, + url=None, + path=None, + password=None): + self._url_value = None + self._url_present = False + self._path_value = None + self._path_present = False + self._password_value = None + self._password_present = False + if url is not None: + self.url = url + if path is not None: + self.path = path + if password is not None: + self.password = password + + @property + def url(self): + """ + The shared link corresponding to either a file or shared link to a + folder. If it is for a folder shared link, we use the path param to + determine for which file in the folder the view is for. + + :rtype: str + """ + if self._url_present: + return self._url_value + else: + raise AttributeError("missing required field 'url'") + + @url.setter + def url(self, val): + val = self._url_validator.validate(val) + self._url_value = val + self._url_present = True + + @url.deleter + def url(self): + self._url_value = None + self._url_present = False + + @property + def path(self): + """ + The path corresponding to a file in a shared link to a folder. Required + for shared links to folders. + + :rtype: str + """ + if self._path_present: + return self._path_value + else: + return None + + @path.setter + def path(self, val): + if val is None: + del self.path + return + val = self._path_validator.validate(val) + self._path_value = val + self._path_present = True + + @path.deleter + def path(self): + self._path_value = None + self._path_present = False + + @property + def password(self): + """ + Password for the shared link. Required for password-protected shared + links to files unless it can be read from a cookie. + + :rtype: str + """ + if self._password_present: + return self._password_value + else: + return None + + @password.setter + def password(self, val): + if val is None: + del self.password + return + val = self._password_validator.validate(val) + self._password_value = val + self._password_present = True + + @password.deleter + def password(self): + self._password_value = None + self._password_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedLinkFileInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedLinkFileInfo(url={!r}, path={!r}, password={!r})'.format( + self._url_value, + self._path_value, + self._password_value, + ) + +SharedLinkFileInfo_validator = bv.Struct(SharedLinkFileInfo) + +class SingleUserLock(bb.Struct): + """ + :ivar files.SingleUserLock.created: The time the lock was created. + :ivar files.SingleUserLock.lock_holder_account_id: The account ID of the + lock holder if known. + :ivar files.SingleUserLock.lock_holder_team_id: The id of the team of the + account holder if it exists. + """ + + __slots__ = [ + '_created_value', + '_created_present', + '_lock_holder_account_id_value', + '_lock_holder_account_id_present', + '_lock_holder_team_id_value', + '_lock_holder_team_id_present', + ] + + _has_required_fields = True + + def __init__(self, + created=None, + lock_holder_account_id=None, + lock_holder_team_id=None): + self._created_value = None + self._created_present = False + self._lock_holder_account_id_value = None + self._lock_holder_account_id_present = False + self._lock_holder_team_id_value = None + self._lock_holder_team_id_present = False + if created is not None: + self.created = created + if lock_holder_account_id is not None: + self.lock_holder_account_id = lock_holder_account_id + if lock_holder_team_id is not None: + self.lock_holder_team_id = lock_holder_team_id + + @property + def created(self): + """ + The time the lock was created. + + :rtype: datetime.datetime + """ + if self._created_present: + return self._created_value + else: + raise AttributeError("missing required field 'created'") + + @created.setter + def created(self, val): + val = self._created_validator.validate(val) + self._created_value = val + self._created_present = True + + @created.deleter + def created(self): + self._created_value = None + self._created_present = False + + @property + def lock_holder_account_id(self): + """ + The account ID of the lock holder if known. + + :rtype: str + """ + if self._lock_holder_account_id_present: + return self._lock_holder_account_id_value + else: + raise AttributeError("missing required field 'lock_holder_account_id'") + + @lock_holder_account_id.setter + def lock_holder_account_id(self, val): + val = self._lock_holder_account_id_validator.validate(val) + self._lock_holder_account_id_value = val + self._lock_holder_account_id_present = True + + @lock_holder_account_id.deleter + def lock_holder_account_id(self): + self._lock_holder_account_id_value = None + self._lock_holder_account_id_present = False + + @property + def lock_holder_team_id(self): + """ + The id of the team of the account holder if it exists. + + :rtype: str + """ + if self._lock_holder_team_id_present: + return self._lock_holder_team_id_value + else: + return None + + @lock_holder_team_id.setter + def lock_holder_team_id(self, val): if val is None: - del self.password + del self.lock_holder_team_id return - val = self._password_validator.validate(val) - self._password_value = val - self._password_present = True + val = self._lock_holder_team_id_validator.validate(val) + self._lock_holder_team_id_value = val + self._lock_holder_team_id_present = True - @password.deleter - def password(self): - self._password_value = None - self._password_present = False + @lock_holder_team_id.deleter + def lock_holder_team_id(self): + self._lock_holder_team_id_value = None + self._lock_holder_team_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLink, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SingleUserLock, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLink(url={!r}, password={!r})'.format( - self._url_value, - self._password_value, + return 'SingleUserLock(created={!r}, lock_holder_account_id={!r}, lock_holder_team_id={!r})'.format( + self._created_value, + self._lock_holder_account_id_value, + self._lock_holder_team_id_value, ) -SharedLink_validator = bv.Struct(SharedLink) +SingleUserLock_validator = bv.Struct(SingleUserLock) class SymlinkInfo(bb.Struct): """ @@ -10575,83 +13067,468 @@ class ThumbnailSize(bb.Union): def is_w32h32(self): """ - Check if the union tag is ``w32h32``. + Check if the union tag is ``w32h32``. + + :rtype: bool + """ + return self._tag == 'w32h32' + + def is_w64h64(self): + """ + Check if the union tag is ``w64h64``. + + :rtype: bool + """ + return self._tag == 'w64h64' + + def is_w128h128(self): + """ + Check if the union tag is ``w128h128``. + + :rtype: bool + """ + return self._tag == 'w128h128' + + def is_w256h256(self): + """ + Check if the union tag is ``w256h256``. + + :rtype: bool + """ + return self._tag == 'w256h256' + + def is_w480h320(self): + """ + Check if the union tag is ``w480h320``. + + :rtype: bool + """ + return self._tag == 'w480h320' + + def is_w640h480(self): + """ + Check if the union tag is ``w640h480``. + + :rtype: bool + """ + return self._tag == 'w640h480' + + def is_w960h640(self): + """ + Check if the union tag is ``w960h640``. + + :rtype: bool + """ + return self._tag == 'w960h640' + + def is_w1024h768(self): + """ + Check if the union tag is ``w1024h768``. + + :rtype: bool + """ + return self._tag == 'w1024h768' + + def is_w2048h1536(self): + """ + Check if the union tag is ``w2048h1536``. + + :rtype: bool + """ + return self._tag == 'w2048h1536' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ThumbnailSize, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ThumbnailSize(%r, %r)' % (self._tag, self._value) + +ThumbnailSize_validator = bv.Union(ThumbnailSize) + +class ThumbnailV2Arg(bb.Struct): + """ + :ivar files.ThumbnailV2Arg.resource: Information specifying which file to + preview. This could be a path to a file, a shared link pointing to a + file, or a shared link pointing to a folder, with a relative path. + :ivar files.ThumbnailV2Arg.format: The format for the thumbnail image, jpeg + (default) or png. For images that are photos, jpeg should be preferred, + while png is better for screenshots and digital arts. + :ivar files.ThumbnailV2Arg.size: The size for the thumbnail image. + :ivar files.ThumbnailV2Arg.mode: How to resize and crop the image to achieve + the desired size. + """ + + __slots__ = [ + '_resource_value', + '_resource_present', + '_format_value', + '_format_present', + '_size_value', + '_size_present', + '_mode_value', + '_mode_present', + ] + + _has_required_fields = True + + def __init__(self, + resource=None, + format=None, + size=None, + mode=None): + self._resource_value = None + self._resource_present = False + self._format_value = None + self._format_present = False + self._size_value = None + self._size_present = False + self._mode_value = None + self._mode_present = False + if resource is not None: + self.resource = resource + if format is not None: + self.format = format + if size is not None: + self.size = size + if mode is not None: + self.mode = mode + + @property + def resource(self): + """ + Information specifying which file to preview. This could be a path to a + file, a shared link pointing to a file, or a shared link pointing to a + folder, with a relative path. + + :rtype: PathOrLink + """ + if self._resource_present: + return self._resource_value + else: + raise AttributeError("missing required field 'resource'") + + @resource.setter + def resource(self, val): + self._resource_validator.validate_type_only(val) + self._resource_value = val + self._resource_present = True + + @resource.deleter + def resource(self): + self._resource_value = None + self._resource_present = False + + @property + def format(self): + """ + The format for the thumbnail image, jpeg (default) or png. For images + that are photos, jpeg should be preferred, while png is better for + screenshots and digital arts. + + :rtype: ThumbnailFormat + """ + if self._format_present: + return self._format_value + else: + return ThumbnailFormat.jpeg + + @format.setter + def format(self, val): + self._format_validator.validate_type_only(val) + self._format_value = val + self._format_present = True + + @format.deleter + def format(self): + self._format_value = None + self._format_present = False + + @property + def size(self): + """ + The size for the thumbnail image. + + :rtype: ThumbnailSize + """ + if self._size_present: + return self._size_value + else: + return ThumbnailSize.w64h64 + + @size.setter + def size(self, val): + self._size_validator.validate_type_only(val) + self._size_value = val + self._size_present = True + + @size.deleter + def size(self): + self._size_value = None + self._size_present = False + + @property + def mode(self): + """ + How to resize and crop the image to achieve the desired size. + + :rtype: ThumbnailMode + """ + if self._mode_present: + return self._mode_value + else: + return ThumbnailMode.strict + + @mode.setter + def mode(self, val): + self._mode_validator.validate_type_only(val) + self._mode_value = val + self._mode_present = True + + @mode.deleter + def mode(self): + self._mode_value = None + self._mode_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ThumbnailV2Arg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ThumbnailV2Arg(resource={!r}, format={!r}, size={!r}, mode={!r})'.format( + self._resource_value, + self._format_value, + self._size_value, + self._mode_value, + ) + +ThumbnailV2Arg_validator = bv.Struct(ThumbnailV2Arg) + +class ThumbnailV2Error(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar LookupError ThumbnailV2Error.path: An error occurred when downloading + metadata for the image. + :ivar files.ThumbnailV2Error.unsupported_extension: The file extension + doesn't allow conversion to a thumbnail. + :ivar files.ThumbnailV2Error.unsupported_image: The image cannot be + converted to a thumbnail. + :ivar files.ThumbnailV2Error.conversion_error: An error occurred during + thumbnail conversion. + :ivar files.ThumbnailV2Error.access_denied: Access to this shared link is + forbidden. + :ivar files.ThumbnailV2Error.not_found: The shared link does not exist. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + unsupported_extension = None + # Attribute is overwritten below the class definition + unsupported_image = None + # Attribute is overwritten below the class definition + conversion_error = None + # Attribute is overwritten below the class definition + access_denied = None + # Attribute is overwritten below the class definition + not_found = None + # Attribute is overwritten below the class definition + other = None + + @classmethod + def path(cls, val): + """ + Create an instance of this class set to the ``path`` tag with value + ``val``. + + :param LookupError val: + :rtype: ThumbnailV2Error + """ + return cls('path', val) + + def is_path(self): + """ + Check if the union tag is ``path``. + + :rtype: bool + """ + return self._tag == 'path' + + def is_unsupported_extension(self): + """ + Check if the union tag is ``unsupported_extension``. :rtype: bool """ - return self._tag == 'w32h32' + return self._tag == 'unsupported_extension' - def is_w64h64(self): + def is_unsupported_image(self): """ - Check if the union tag is ``w64h64``. + Check if the union tag is ``unsupported_image``. :rtype: bool """ - return self._tag == 'w64h64' + return self._tag == 'unsupported_image' - def is_w128h128(self): + def is_conversion_error(self): """ - Check if the union tag is ``w128h128``. + Check if the union tag is ``conversion_error``. :rtype: bool """ - return self._tag == 'w128h128' + return self._tag == 'conversion_error' - def is_w256h256(self): + def is_access_denied(self): """ - Check if the union tag is ``w256h256``. + Check if the union tag is ``access_denied``. :rtype: bool """ - return self._tag == 'w256h256' + return self._tag == 'access_denied' - def is_w480h320(self): + def is_not_found(self): """ - Check if the union tag is ``w480h320``. + Check if the union tag is ``not_found``. :rtype: bool """ - return self._tag == 'w480h320' + return self._tag == 'not_found' - def is_w640h480(self): + def is_other(self): """ - Check if the union tag is ``w640h480``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'w640h480' + return self._tag == 'other' - def is_w960h640(self): + def get_path(self): """ - Check if the union tag is ``w960h640``. + An error occurred when downloading metadata for the image. - :rtype: bool + Only call this if :meth:`is_path` is true. + + :rtype: LookupError """ - return self._tag == 'w960h640' + if not self.is_path(): + raise AttributeError("tag 'path' not set") + return self._value - def is_w1024h768(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ThumbnailV2Error, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ThumbnailV2Error(%r, %r)' % (self._tag, self._value) + +ThumbnailV2Error_validator = bv.Union(ThumbnailV2Error) + +class UnlockFileArg(bb.Struct): + """ + :ivar files.UnlockFileArg.path: Path in the user's Dropbox to a file. + """ + + __slots__ = [ + '_path_value', + '_path_present', + ] + + _has_required_fields = True + + def __init__(self, + path=None): + self._path_value = None + self._path_present = False + if path is not None: + self.path = path + + @property + def path(self): """ - Check if the union tag is ``w1024h768``. + Path in the user's Dropbox to a file. - :rtype: bool + :rtype: str """ - return self._tag == 'w1024h768' + if self._path_present: + return self._path_value + else: + raise AttributeError("missing required field 'path'") - def is_w2048h1536(self): + @path.setter + def path(self, val): + val = self._path_validator.validate(val) + self._path_value = val + self._path_present = True + + @path.deleter + def path(self): + self._path_value = None + self._path_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UnlockFileArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UnlockFileArg(path={!r})'.format( + self._path_value, + ) + +UnlockFileArg_validator = bv.Struct(UnlockFileArg) + +class UnlockFileBatchArg(bb.Struct): + """ + :ivar files.UnlockFileBatchArg.entries: List of 'entries'. Each 'entry' + contains a path of the file which will be unlocked. Duplicate path + arguments in the batch are considered only once. + """ + + __slots__ = [ + '_entries_value', + '_entries_present', + ] + + _has_required_fields = True + + def __init__(self, + entries=None): + self._entries_value = None + self._entries_present = False + if entries is not None: + self.entries = entries + + @property + def entries(self): """ - Check if the union tag is ``w2048h1536``. + List of 'entries'. Each 'entry' contains a path of the file which will + be unlocked. Duplicate path arguments in the batch are considered only + once. - :rtype: bool + :rtype: list of [UnlockFileArg] """ - return self._tag == 'w2048h1536' + if self._entries_present: + return self._entries_value + else: + raise AttributeError("missing required field 'entries'") + + @entries.setter + def entries(self, val): + val = self._entries_validator.validate(val) + self._entries_value = val + self._entries_present = True + + @entries.deleter + def entries(self): + self._entries_value = None + self._entries_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ThumbnailSize, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UnlockFileBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ThumbnailSize(%r, %r)' % (self._tag, self._value) + return 'UnlockFileBatchArg(entries={!r})'.format( + self._entries_value, + ) -ThumbnailSize_validator = bv.Union(ThumbnailSize) +UnlockFileBatchArg_validator = bv.Struct(UnlockFileBatchArg) class UploadError(bb.Union): """ @@ -12251,6 +15128,7 @@ def __repr__(self): PathROrId_validator = bv.String(pattern=u'(/(.|[\\r\\n])*)?|id:.*|(ns:[0-9]+(/.*)?)') ReadPath_validator = bv.String(pattern=u'(/(.|[\\r\\n])*|id:.*)|(rev:[0-9a-f]{9,})|(ns:[0-9]+(/.*)?)') Rev_validator = bv.String(min_length=9, pattern=u'[0-9a-f]+') +SearchV2Cursor_validator = bv.String(min_length=1) Sha256HexHash_validator = bv.String(min_length=64, max_length=64) SharedLinkUrl_validator = bv.String() WritePath_validator = bv.String(pattern=u'(/(.|[\\r\\n])*)|(ns:[0-9]+(/.*)?)') @@ -12616,14 +15494,17 @@ def __repr__(self): ExportError._path_validator = LookupError_validator ExportError._non_exportable_validator = bv.Void() +ExportError._retry_error_validator = bv.Void() ExportError._other_validator = bv.Void() ExportError._tagmap = { 'path': ExportError._path_validator, 'non_exportable': ExportError._non_exportable_validator, + 'retry_error': ExportError._retry_error_validator, 'other': ExportError._other_validator, } ExportError.non_exportable = ExportError('non_exportable') +ExportError.retry_error = ExportError('retry_error') ExportError.other = ExportError('other') ExportInfo._export_as_validator = bv.Nullable(bv.String()) @@ -12655,6 +15536,76 @@ def __repr__(self): ('file_metadata', ExportResult._file_metadata_validator), ] +FileCategory._image_validator = bv.Void() +FileCategory._document_validator = bv.Void() +FileCategory._pdf_validator = bv.Void() +FileCategory._spreadsheet_validator = bv.Void() +FileCategory._presentation_validator = bv.Void() +FileCategory._audio_validator = bv.Void() +FileCategory._video_validator = bv.Void() +FileCategory._folder_validator = bv.Void() +FileCategory._paper_validator = bv.Void() +FileCategory._others_validator = bv.Void() +FileCategory._other_validator = bv.Void() +FileCategory._tagmap = { + 'image': FileCategory._image_validator, + 'document': FileCategory._document_validator, + 'pdf': FileCategory._pdf_validator, + 'spreadsheet': FileCategory._spreadsheet_validator, + 'presentation': FileCategory._presentation_validator, + 'audio': FileCategory._audio_validator, + 'video': FileCategory._video_validator, + 'folder': FileCategory._folder_validator, + 'paper': FileCategory._paper_validator, + 'others': FileCategory._others_validator, + 'other': FileCategory._other_validator, +} + +FileCategory.image = FileCategory('image') +FileCategory.document = FileCategory('document') +FileCategory.pdf = FileCategory('pdf') +FileCategory.spreadsheet = FileCategory('spreadsheet') +FileCategory.presentation = FileCategory('presentation') +FileCategory.audio = FileCategory('audio') +FileCategory.video = FileCategory('video') +FileCategory.folder = FileCategory('folder') +FileCategory.paper = FileCategory('paper') +FileCategory.others = FileCategory('others') +FileCategory.other = FileCategory('other') + +FileLock._content_validator = FileLockContent_validator +FileLock._all_field_names_ = set(['content']) +FileLock._all_fields_ = [('content', FileLock._content_validator)] + +FileLockContent._unlocked_validator = bv.Void() +FileLockContent._single_user_validator = SingleUserLock_validator +FileLockContent._other_validator = bv.Void() +FileLockContent._tagmap = { + 'unlocked': FileLockContent._unlocked_validator, + 'single_user': FileLockContent._single_user_validator, + 'other': FileLockContent._other_validator, +} + +FileLockContent.unlocked = FileLockContent('unlocked') +FileLockContent.other = FileLockContent('other') + +FileLockMetadata._is_lockholder_validator = bv.Nullable(bv.Boolean()) +FileLockMetadata._lockholder_name_validator = bv.Nullable(bv.String()) +FileLockMetadata._lockholder_account_id_validator = bv.Nullable(users_common.AccountId_validator) +FileLockMetadata._created_validator = bv.Nullable(common.DropboxTimestamp_validator) +FileLockMetadata._all_field_names_ = set([ + 'is_lockholder', + 'lockholder_name', + 'lockholder_account_id', + 'created', +]) +FileLockMetadata._all_fields_ = [ + ('is_lockholder', FileLockMetadata._is_lockholder_validator), + ('lockholder_name', FileLockMetadata._lockholder_name_validator), + ('lockholder_account_id', FileLockMetadata._lockholder_account_id_validator), + ('created', FileLockMetadata._created_validator), +] + FileMetadata._id_validator = Id_validator FileMetadata._client_modified_validator = common.DropboxTimestamp_validator FileMetadata._server_modified_validator = common.DropboxTimestamp_validator @@ -12668,6 +15619,7 @@ def __repr__(self): FileMetadata._property_groups_validator = bv.Nullable(bv.List(file_properties.PropertyGroup_validator)) FileMetadata._has_explicit_shared_members_validator = bv.Nullable(bv.Boolean()) FileMetadata._content_hash_validator = bv.Nullable(Sha256HexHash_validator) +FileMetadata._file_lock_info_validator = bv.Nullable(FileLockMetadata_validator) FileMetadata._field_names_ = set([ 'id', 'client_modified', @@ -12682,6 +15634,7 @@ def __repr__(self): 'property_groups', 'has_explicit_shared_members', 'content_hash', + 'file_lock_info', ]) FileMetadata._all_field_names_ = Metadata._all_field_names_.union(FileMetadata._field_names_) FileMetadata._fields_ = [ @@ -12698,6 +15651,7 @@ def __repr__(self): ('property_groups', FileMetadata._property_groups_validator), ('has_explicit_shared_members', FileMetadata._has_explicit_shared_members_validator), ('content_hash', FileMetadata._content_hash_validator), + ('file_lock_info', FileMetadata._file_lock_info_validator), ] FileMetadata._all_fields_ = Metadata._all_fields_ + FileMetadata._fields_ @@ -12716,6 +15670,19 @@ def __repr__(self): ('modified_by', FileSharingInfo._modified_by_validator), ] +FileStatus._active_validator = bv.Void() +FileStatus._deleted_validator = bv.Void() +FileStatus._other_validator = bv.Void() +FileStatus._tagmap = { + 'active': FileStatus._active_validator, + 'deleted': FileStatus._deleted_validator, + 'other': FileStatus._other_validator, +} + +FileStatus.active = FileStatus('active') +FileStatus.deleted = FileStatus('deleted') +FileStatus.other = FileStatus('other') + FolderMetadata._id_validator = Id_validator FolderMetadata._shared_folder_id_validator = bv.Nullable(common.SharedFolderId_validator) FolderMetadata._sharing_info_validator = bv.Nullable(FolderSharingInfo_validator) @@ -12875,6 +15842,17 @@ def __repr__(self): ('longitude', GpsCoordinates._longitude_validator), ] +HighlightSpan._highlight_str_validator = bv.String() +HighlightSpan._is_highlighted_validator = bv.Boolean() +HighlightSpan._all_field_names_ = set([ + 'highlight_str', + 'is_highlighted', +]) +HighlightSpan._all_fields_ = [ + ('highlight_str', HighlightSpan._highlight_str_validator), + ('is_highlighted', HighlightSpan._is_highlighted_validator), +] + ListFolderArg._path_validator = PathROrId_validator ListFolderArg._recursive_validator = bv.Boolean() ListFolderArg._include_media_info_validator = bv.Boolean() @@ -12927,9 +15905,11 @@ def __repr__(self): ListFolderContinueError.other = ListFolderContinueError('other') ListFolderError._path_validator = LookupError_validator +ListFolderError._template_error_validator = file_properties.TemplateError_validator ListFolderError._other_validator = bv.Void() ListFolderError._tagmap = { 'path': ListFolderError._path_validator, + 'template_error': ListFolderError._template_error_validator, 'other': ListFolderError._other_validator, } @@ -13035,6 +16015,69 @@ def __repr__(self): ('entries', ListRevisionsResult._entries_validator), ] +LockConflictError._lock_validator = FileLock_validator +LockConflictError._all_field_names_ = set(['lock']) +LockConflictError._all_fields_ = [('lock', LockConflictError._lock_validator)] + +LockFileArg._path_validator = WritePathOrId_validator +LockFileArg._all_field_names_ = set(['path']) +LockFileArg._all_fields_ = [('path', LockFileArg._path_validator)] + +LockFileBatchArg._entries_validator = bv.List(LockFileArg_validator) +LockFileBatchArg._all_field_names_ = set(['entries']) +LockFileBatchArg._all_fields_ = [('entries', LockFileBatchArg._entries_validator)] + +LockFileBatchResult._entries_validator = bv.List(LockFileResultEntry_validator) +LockFileBatchResult._all_field_names_ = FileOpsResult._all_field_names_.union(set(['entries'])) +LockFileBatchResult._all_fields_ = FileOpsResult._all_fields_ + [('entries', LockFileBatchResult._entries_validator)] + +LockFileError._path_lookup_validator = LookupError_validator +LockFileError._too_many_write_operations_validator = bv.Void() +LockFileError._too_many_files_validator = bv.Void() +LockFileError._no_write_permission_validator = bv.Void() +LockFileError._cannot_be_locked_validator = bv.Void() +LockFileError._file_not_shared_validator = bv.Void() +LockFileError._lock_conflict_validator = LockConflictError_validator +LockFileError._internal_error_validator = bv.Void() +LockFileError._other_validator = bv.Void() +LockFileError._tagmap = { + 'path_lookup': LockFileError._path_lookup_validator, + 'too_many_write_operations': LockFileError._too_many_write_operations_validator, + 'too_many_files': LockFileError._too_many_files_validator, + 'no_write_permission': LockFileError._no_write_permission_validator, + 'cannot_be_locked': LockFileError._cannot_be_locked_validator, + 'file_not_shared': LockFileError._file_not_shared_validator, + 'lock_conflict': LockFileError._lock_conflict_validator, + 'internal_error': LockFileError._internal_error_validator, + 'other': LockFileError._other_validator, +} + +LockFileError.too_many_write_operations = LockFileError('too_many_write_operations') +LockFileError.too_many_files = LockFileError('too_many_files') +LockFileError.no_write_permission = LockFileError('no_write_permission') +LockFileError.cannot_be_locked = LockFileError('cannot_be_locked') +LockFileError.file_not_shared = LockFileError('file_not_shared') +LockFileError.internal_error = LockFileError('internal_error') +LockFileError.other = LockFileError('other') + +LockFileResult._metadata_validator = Metadata_validator +LockFileResult._lock_validator = FileLock_validator +LockFileResult._all_field_names_ = set([ + 'metadata', + 'lock', +]) +LockFileResult._all_fields_ = [ + ('metadata', LockFileResult._metadata_validator), + ('lock', LockFileResult._lock_validator), +] + +LockFileResultEntry._success_validator = LockFileResult_validator +LockFileResultEntry._failure_validator = LockFileError_validator +LockFileResultEntry._tagmap = { + 'success': LockFileResultEntry._success_validator, + 'failure': LockFileResultEntry._failure_validator, +} + LookupError._malformed_path_validator = MalformedPathError_validator LookupError._not_found_validator = bv.Void() LookupError._not_file_validator = bv.Void() @@ -13094,6 +16137,32 @@ def __repr__(self): } MediaMetadata._is_catch_all_ = False +MetadataV2._metadata_validator = Metadata_validator +MetadataV2._other_validator = bv.Void() +MetadataV2._tagmap = { + 'metadata': MetadataV2._metadata_validator, + 'other': MetadataV2._other_validator, +} + +MetadataV2.other = MetadataV2('other') + +MinimalFileLinkMetadata._url_validator = bv.String() +MinimalFileLinkMetadata._id_validator = bv.Nullable(Id_validator) +MinimalFileLinkMetadata._path_validator = bv.Nullable(bv.String()) +MinimalFileLinkMetadata._rev_validator = Rev_validator +MinimalFileLinkMetadata._all_field_names_ = set([ + 'url', + 'id', + 'path', + 'rev', +]) +MinimalFileLinkMetadata._all_fields_ = [ + ('url', MinimalFileLinkMetadata._url_validator), + ('id', MinimalFileLinkMetadata._id_validator), + ('path', MinimalFileLinkMetadata._path_validator), + ('rev', MinimalFileLinkMetadata._rev_validator), +] + RelocationBatchArgBase._entries_validator = bv.List(RelocationPath_validator, min_items=1) RelocationBatchArgBase._autorename_validator = bv.Boolean() RelocationBatchArgBase._all_field_names_ = set([ @@ -13109,6 +16178,17 @@ def __repr__(self): MoveBatchArg._all_field_names_ = RelocationBatchArgBase._all_field_names_.union(set(['allow_ownership_transfer'])) MoveBatchArg._all_fields_ = RelocationBatchArgBase._all_fields_ + [('allow_ownership_transfer', MoveBatchArg._allow_ownership_transfer_validator)] +PathOrLink._path_validator = ReadPath_validator +PathOrLink._link_validator = SharedLinkFileInfo_validator +PathOrLink._other_validator = bv.Void() +PathOrLink._tagmap = { + 'path': PathOrLink._path_validator, + 'link': PathOrLink._link_validator, + 'other': PathOrLink._other_validator, +} + +PathOrLink.other = PathOrLink('other') + PhotoMetadata._field_names_ = set([]) PhotoMetadata._all_field_names_ = MediaMetadata._all_field_names_.union(PhotoMetadata._field_names_) PhotoMetadata._fields_ = [] @@ -13140,6 +16220,17 @@ def __repr__(self): PreviewError.unsupported_extension = PreviewError('unsupported_extension') PreviewError.unsupported_content = PreviewError('unsupported_content') +PreviewResult._file_metadata_validator = bv.Nullable(FileMetadata_validator) +PreviewResult._link_metadata_validator = bv.Nullable(MinimalFileLinkMetadata_validator) +PreviewResult._all_field_names_ = set([ + 'file_metadata', + 'link_metadata', +]) +PreviewResult._all_fields_ = [ + ('file_metadata', PreviewResult._file_metadata_validator), + ('link_metadata', PreviewResult._link_metadata_validator), +] + RelocationPath._from_path_validator = WritePathOrId_validator RelocationPath._to_path_validator = WritePathOrId_validator RelocationPath._all_field_names_ = set([ @@ -13421,9 +16512,11 @@ def __repr__(self): ] SearchError._path_validator = LookupError_validator +SearchError._invalid_argument_validator = bv.Nullable(bv.String()) SearchError._other_validator = bv.Void() SearchError._tagmap = { 'path': SearchError._path_validator, + 'invalid_argument': SearchError._invalid_argument_validator, 'other': SearchError._other_validator, } @@ -13453,6 +16546,17 @@ def __repr__(self): SearchMatchType.content = SearchMatchType('content') SearchMatchType.both = SearchMatchType('both') +SearchMatchV2._metadata_validator = MetadataV2_validator +SearchMatchV2._highlight_spans_validator = bv.Nullable(bv.List(HighlightSpan_validator)) +SearchMatchV2._all_field_names_ = set([ + 'metadata', + 'highlight_spans', +]) +SearchMatchV2._all_fields_ = [ + ('metadata', SearchMatchV2._metadata_validator), + ('highlight_spans', SearchMatchV2._highlight_spans_validator), +] + SearchMode._filename_validator = bv.Void() SearchMode._filename_and_content_validator = bv.Void() SearchMode._deleted_filename_validator = bv.Void() @@ -13466,6 +16570,29 @@ def __repr__(self): SearchMode.filename_and_content = SearchMode('filename_and_content') SearchMode.deleted_filename = SearchMode('deleted_filename') +SearchOptions._path_validator = bv.Nullable(PathROrId_validator) +SearchOptions._max_results_validator = bv.UInt64(min_value=1, max_value=1000) +SearchOptions._file_status_validator = FileStatus_validator +SearchOptions._filename_only_validator = bv.Boolean() +SearchOptions._file_extensions_validator = bv.Nullable(bv.List(bv.String())) +SearchOptions._file_categories_validator = bv.Nullable(bv.List(FileCategory_validator)) +SearchOptions._all_field_names_ = set([ + 'path', + 'max_results', + 'file_status', + 'filename_only', + 'file_extensions', + 'file_categories', +]) +SearchOptions._all_fields_ = [ + ('path', SearchOptions._path_validator), + ('max_results', SearchOptions._max_results_validator), + ('file_status', SearchOptions._file_status_validator), + ('filename_only', SearchOptions._filename_only_validator), + ('file_extensions', SearchOptions._file_extensions_validator), + ('file_categories', SearchOptions._file_categories_validator), +] + SearchResult._matches_validator = bv.List(SearchMatch_validator) SearchResult._more_validator = bv.Boolean() SearchResult._start_validator = bv.UInt64() @@ -13480,6 +16607,38 @@ def __repr__(self): ('start', SearchResult._start_validator), ] +SearchV2Arg._query_validator = bv.String() +SearchV2Arg._options_validator = bv.Nullable(SearchOptions_validator) +SearchV2Arg._include_highlights_validator = bv.Boolean() +SearchV2Arg._all_field_names_ = set([ + 'query', + 'options', + 'include_highlights', +]) +SearchV2Arg._all_fields_ = [ + ('query', SearchV2Arg._query_validator), + ('options', SearchV2Arg._options_validator), + ('include_highlights', SearchV2Arg._include_highlights_validator), +] + +SearchV2ContinueArg._cursor_validator = SearchV2Cursor_validator +SearchV2ContinueArg._all_field_names_ = set(['cursor']) +SearchV2ContinueArg._all_fields_ = [('cursor', SearchV2ContinueArg._cursor_validator)] + +SearchV2Result._matches_validator = bv.List(SearchMatchV2_validator) +SearchV2Result._has_more_validator = bv.Boolean() +SearchV2Result._cursor_validator = bv.Nullable(SearchV2Cursor_validator) +SearchV2Result._all_field_names_ = set([ + 'matches', + 'has_more', + 'cursor', +]) +SearchV2Result._all_fields_ = [ + ('matches', SearchV2Result._matches_validator), + ('has_more', SearchV2Result._has_more_validator), + ('cursor', SearchV2Result._cursor_validator), +] + SharedLink._url_validator = SharedLinkUrl_validator SharedLink._password_validator = bv.Nullable(bv.String()) SharedLink._all_field_names_ = set([ @@ -13491,6 +16650,34 @@ def __repr__(self): ('password', SharedLink._password_validator), ] +SharedLinkFileInfo._url_validator = bv.String() +SharedLinkFileInfo._path_validator = bv.Nullable(bv.String()) +SharedLinkFileInfo._password_validator = bv.Nullable(bv.String()) +SharedLinkFileInfo._all_field_names_ = set([ + 'url', + 'path', + 'password', +]) +SharedLinkFileInfo._all_fields_ = [ + ('url', SharedLinkFileInfo._url_validator), + ('path', SharedLinkFileInfo._path_validator), + ('password', SharedLinkFileInfo._password_validator), +] + +SingleUserLock._created_validator = common.DropboxTimestamp_validator +SingleUserLock._lock_holder_account_id_validator = users_common.AccountId_validator +SingleUserLock._lock_holder_team_id_validator = bv.Nullable(bv.String()) +SingleUserLock._all_field_names_ = set([ + 'created', + 'lock_holder_account_id', + 'lock_holder_team_id', +]) +SingleUserLock._all_fields_ = [ + ('created', SingleUserLock._created_validator), + ('lock_holder_account_id', SingleUserLock._lock_holder_account_id_validator), + ('lock_holder_team_id', SingleUserLock._lock_holder_team_id_validator), +] + SymlinkInfo._target_validator = bv.String() SymlinkInfo._all_field_names_ = set(['target']) SymlinkInfo._all_fields_ = [('target', SymlinkInfo._target_validator)] @@ -13625,6 +16812,55 @@ def __repr__(self): ThumbnailSize.w1024h768 = ThumbnailSize('w1024h768') ThumbnailSize.w2048h1536 = ThumbnailSize('w2048h1536') +ThumbnailV2Arg._resource_validator = PathOrLink_validator +ThumbnailV2Arg._format_validator = ThumbnailFormat_validator +ThumbnailV2Arg._size_validator = ThumbnailSize_validator +ThumbnailV2Arg._mode_validator = ThumbnailMode_validator +ThumbnailV2Arg._all_field_names_ = set([ + 'resource', + 'format', + 'size', + 'mode', +]) +ThumbnailV2Arg._all_fields_ = [ + ('resource', ThumbnailV2Arg._resource_validator), + ('format', ThumbnailV2Arg._format_validator), + ('size', ThumbnailV2Arg._size_validator), + ('mode', ThumbnailV2Arg._mode_validator), +] + +ThumbnailV2Error._path_validator = LookupError_validator +ThumbnailV2Error._unsupported_extension_validator = bv.Void() +ThumbnailV2Error._unsupported_image_validator = bv.Void() +ThumbnailV2Error._conversion_error_validator = bv.Void() +ThumbnailV2Error._access_denied_validator = bv.Void() +ThumbnailV2Error._not_found_validator = bv.Void() +ThumbnailV2Error._other_validator = bv.Void() +ThumbnailV2Error._tagmap = { + 'path': ThumbnailV2Error._path_validator, + 'unsupported_extension': ThumbnailV2Error._unsupported_extension_validator, + 'unsupported_image': ThumbnailV2Error._unsupported_image_validator, + 'conversion_error': ThumbnailV2Error._conversion_error_validator, + 'access_denied': ThumbnailV2Error._access_denied_validator, + 'not_found': ThumbnailV2Error._not_found_validator, + 'other': ThumbnailV2Error._other_validator, +} + +ThumbnailV2Error.unsupported_extension = ThumbnailV2Error('unsupported_extension') +ThumbnailV2Error.unsupported_image = ThumbnailV2Error('unsupported_image') +ThumbnailV2Error.conversion_error = ThumbnailV2Error('conversion_error') +ThumbnailV2Error.access_denied = ThumbnailV2Error('access_denied') +ThumbnailV2Error.not_found = ThumbnailV2Error('not_found') +ThumbnailV2Error.other = ThumbnailV2Error('other') + +UnlockFileArg._path_validator = WritePathOrId_validator +UnlockFileArg._all_field_names_ = set(['path']) +UnlockFileArg._all_fields_ = [('path', UnlockFileArg._path_validator)] + +UnlockFileBatchArg._entries_validator = bv.List(UnlockFileArg_validator) +UnlockFileBatchArg._all_field_names_ = set(['entries']) +UnlockFileBatchArg._all_fields_ = [('entries', UnlockFileBatchArg._entries_validator)] + UploadError._path_validator = UploadWriteFailed_validator UploadError._properties_error_validator = file_properties.InvalidPropertyGroupError_validator UploadError._other_validator = bv.Void() @@ -14037,6 +17273,16 @@ def __repr__(self): {'host': u'content', 'style': u'download'}, ) +get_file_lock_batch = bb.Route( + 'get_file_lock_batch', + 1, + False, + LockFileBatchArg_validator, + LockFileBatchResult_validator, + LockFileError_validator, + {'host': u'api', + 'style': u'rpc'}, +) get_metadata = bb.Route( 'get_metadata', 1, @@ -14087,6 +17333,16 @@ def __repr__(self): {'host': u'content', 'style': u'download'}, ) +get_thumbnail_v2 = bb.Route( + 'get_thumbnail', + 2, + False, + ThumbnailV2Arg_validator, + PreviewResult_validator, + ThumbnailV2Error_validator, + {'host': u'content', + 'style': u'download'}, +) get_thumbnail_batch = bb.Route( 'get_thumbnail_batch', 1, @@ -14147,6 +17403,16 @@ def __repr__(self): {'host': u'api', 'style': u'rpc'}, ) +lock_file_batch = bb.Route( + 'lock_file_batch', + 1, + False, + LockFileBatchArg_validator, + LockFileBatchResult_validator, + LockFileError_validator, + {'host': u'api', + 'style': u'rpc'}, +) move_v2 = bb.Route( 'move', 2, @@ -14180,7 +17446,7 @@ def __repr__(self): move_batch = bb.Route( 'move_batch', 1, - False, + True, RelocationBatchArg_validator, RelocationBatchLaunch_validator, bv.Void(), @@ -14200,7 +17466,7 @@ def __repr__(self): move_batch_check = bb.Route( 'move_batch/check', 1, - False, + True, async_.PollArg_validator, RelocationBatchJobStatus_validator, async_.PollError_validator, @@ -14310,13 +17576,43 @@ def __repr__(self): search = bb.Route( 'search', 1, - False, + True, SearchArg_validator, SearchResult_validator, SearchError_validator, {'host': u'api', 'style': u'rpc'}, ) +search_v2 = bb.Route( + 'search', + 2, + False, + SearchV2Arg_validator, + SearchV2Result_validator, + SearchError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +search_continue_v2 = bb.Route( + 'search/continue', + 2, + False, + SearchV2ContinueArg_validator, + SearchV2Result_validator, + SearchError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +unlock_file_batch = bb.Route( + 'unlock_file_batch', + 1, + False, + UnlockFileBatchArg_validator, + LockFileBatchResult_validator, + LockFileError_validator, + {'host': u'api', + 'style': u'rpc'}, +) upload = bb.Route( 'upload', 1, @@ -14410,17 +17706,20 @@ def __repr__(self): 'download': download, 'download_zip': download_zip, 'export': export, + 'get_file_lock_batch': get_file_lock_batch, 'get_metadata': get_metadata, 'get_preview': get_preview, 'get_temporary_link': get_temporary_link, 'get_temporary_upload_link': get_temporary_upload_link, 'get_thumbnail': get_thumbnail, + 'get_thumbnail:2': get_thumbnail_v2, 'get_thumbnail_batch': get_thumbnail_batch, 'list_folder': list_folder, 'list_folder/continue': list_folder_continue, 'list_folder/get_latest_cursor': list_folder_get_latest_cursor, 'list_folder/longpoll': list_folder_longpoll, 'list_revisions': list_revisions, + 'lock_file_batch': lock_file_batch, 'move:2': move_v2, 'move': move, 'move_batch:2': move_batch_v2, @@ -14438,6 +17737,9 @@ def __repr__(self): 'save_url': save_url, 'save_url/check_job_status': save_url_check_job_status, 'search': search, + 'search:2': search_v2, + 'search/continue:2': search_continue_v2, + 'unlock_file_batch': unlock_file_batch, 'upload': upload, 'upload_session/append:2': upload_session_append_v2, 'upload_session/append': upload_session_append, diff --git a/script.module.dropbox/lib/dropbox/oauth.py b/script.module.dropbox/lib/dropbox/oauth.py index c51f870d1..80b3d073b 100644 --- a/script.module.dropbox/lib/dropbox/oauth.py +++ b/script.module.dropbox/lib/dropbox/oauth.py @@ -1,3 +1,5 @@ +import hashlib + __all__ = [ 'BadRequestException', 'BadStateException', @@ -14,11 +16,14 @@ import os import six import urllib +import re +from datetime import datetime, timedelta from .session import ( API_HOST, WEB_HOST, pinned_session, + DEFAULT_TIMEOUT, ) if six.PY3: @@ -28,29 +33,52 @@ url_path_quote = urllib.quote # pylint: disable=no-member,useless-suppression url_encode = urllib.urlencode # pylint: disable=no-member,useless-suppression +TOKEN_ACCESS_TYPES = ['offline', 'online', 'legacy'] +INCLUDE_GRANTED_SCOPES_TYPES = ['user', 'team'] +PKCE_VERIFIER_LENGTH = 128 class OAuth2FlowNoRedirectResult(object): """ Authorization information for an OAuth2Flow performed with no redirect. """ - def __init__(self, access_token, account_id, user_id): + def __init__(self, access_token, account_id, user_id, refresh_token, expiration, scope): """ Args: access_token (str): Token to be used to authenticate later requests. + refresh_token (str): Token to be used to acquire new access token + when existing one expires + expiration (int, datetime): Either the number of seconds from now that the token expires + in or the datetime at which the token expires account_id (str): The Dropbox user's account ID. user_id (str): Deprecated (use account_id instead). + refresh_token (str): Token to be used to acquire new access token + when existing one expires + expiration (int, datetime): Either the number of seconds from now that the token expires + in or the datetime at which the token expires + scope (list): list of scopes to request in base oauth flow. """ self.access_token = access_token + if not expiration: + self.expires_at = None + elif isinstance(expiration, datetime): + self.expires_at = expiration + else: + self.expires_at = datetime.utcnow() + timedelta(seconds=int(expiration)) + self.refresh_token = refresh_token self.account_id = account_id self.user_id = user_id + self.scope = scope def __repr__(self): - return 'OAuth2FlowNoRedirectResult(%r, %r, %r)' % ( + return 'OAuth2FlowNoRedirectResult(%s, %s, %s, %s, %s, %s)' % ( self.access_token, self.account_id, self.user_id, + self.refresh_token, + self.expires_at, + self.scope, ) @@ -59,7 +87,8 @@ class OAuth2FlowResult(OAuth2FlowNoRedirectResult): Authorization information for an OAuth2Flow with redirect. """ - def __init__(self, access_token, account_id, user_id, url_state): + def __init__(self, access_token, account_id, user_id, url_state, refresh_token, + expires_in, scope): """ Same as OAuth2FlowNoRedirectResult but with url_state. @@ -68,55 +97,104 @@ def __init__(self, access_token, account_id, user_id, url_state): :meth:`DropboxOAuth2Flow.start`. """ super(OAuth2FlowResult, self).__init__( - access_token, account_id, user_id) + access_token=access_token, + account_id=account_id, + user_id=user_id, + refresh_token=refresh_token, + expiration=expires_in, + scope=scope) self.url_state = url_state @classmethod def from_no_redirect_result(cls, result, url_state): assert isinstance(result, OAuth2FlowNoRedirectResult) - return cls( - result.access_token, result.account_id, result.user_id, url_state) + return cls(result.access_token, result.account_id, result.user_id, + url_state, result.refresh_token, result.expires_at, result.scope) def __repr__(self): - return 'OAuth2FlowResult(%r, %r, %r, %r)' % ( + return 'OAuth2FlowResult(%s, %s, %s, %s, %s, %s, %s, %s, %s)' % ( self.access_token, + self.refresh_token, + self.expires_at, self.account_id, self.user_id, + self.scope, self.url_state, + self.refresh_token, + self.expires_at, ) class DropboxOAuth2FlowBase(object): - def __init__(self, consumer_key, consumer_secret, locale=None): + def __init__(self, consumer_key, consumer_secret=None, locale=None, token_access_type='legacy', + scope=None, include_granted_scopes=None, use_pkce=False, timeout=DEFAULT_TIMEOUT): + if scope is not None and (len(scope) == 0 or not isinstance(scope, list)): + raise BadInputException("Scope list must be of type list") + if token_access_type is not None and token_access_type not in TOKEN_ACCESS_TYPES: + raise BadInputException("Token access type must be from the following enum: {}".format( + TOKEN_ACCESS_TYPES)) + if not (use_pkce or consumer_secret): + raise BadInputException("Must pass in either consumer secret or use PKCE") + if include_granted_scopes and not scope: + raise BadInputException("Must pass in scope to pass include_granted_scopes") + self.consumer_key = consumer_key self.consumer_secret = consumer_secret self.locale = locale + self.token_access_type = token_access_type self.requests_session = pinned_session() + self.scope = scope + self.include_granted_scopes = include_granted_scopes + self._timeout = timeout - def _get_authorize_url(self, redirect_uri, state): + if use_pkce: + self.code_verifier = _generate_pkce_code_verifier() + self.code_challenge = _generate_pkce_code_challenge(self.code_verifier) + else: + self.code_verifier = None + self.code_challenge = None + + def _get_authorize_url(self, redirect_uri, state, token_access_type, scope=None, + include_granted_scopes=None, code_challenge=None): params = dict(response_type='code', client_id=self.consumer_key) if redirect_uri is not None: params['redirect_uri'] = redirect_uri if state is not None: params['state'] = state + if token_access_type is not None: + assert token_access_type in TOKEN_ACCESS_TYPES + if token_access_type != 'legacy': + params['token_access_type'] = token_access_type + if code_challenge: + params['code_challenge'] = code_challenge + params['code_challenge_method'] = 'S256' + + if scope is not None: + params['scope'] = " ".join(scope) + if include_granted_scopes is not None: + assert include_granted_scopes in INCLUDE_GRANTED_SCOPES_TYPES + params['include_granted_scopes'] = include_granted_scopes return self.build_url('/oauth2/authorize', params, WEB_HOST) - def _finish(self, code, redirect_uri): + def _finish(self, code, redirect_uri, code_verifier): url = self.build_url('/oauth2/token') params = {'grant_type': 'authorization_code', 'code': code, 'client_id': self.consumer_key, - 'client_secret': self.consumer_secret, } + if code_verifier: + params['code_verifier'] = code_verifier + else: + params['client_secret'] = self.consumer_secret if self.locale is not None: params['locale'] = self.locale if redirect_uri is not None: params['redirect_uri'] = redirect_uri - resp = self.requests_session.post(url, data=params) + resp = self.requests_session.post(url, data=params, timeout=self._timeout) resp.raise_for_status() d = resp.json() @@ -127,12 +205,31 @@ def _finish(self, code, redirect_uri): account_id = d['account_id'] access_token = d['access_token'] + + if 'refresh_token' in d: + refresh_token = d['refresh_token'] + else: + refresh_token = "" + + if 'expires_in' in d: + expires_in = d['expires_in'] + else: + expires_in = None + + if 'scope' in d: + scope = d['scope'] + else: + scope = None + uid = d['uid'] return OAuth2FlowNoRedirectResult( access_token, account_id, - uid) + uid, + refresh_token, + expires_in, + scope) def build_path(self, target, params=None): """Build the path component for an API URL. @@ -182,28 +279,12 @@ class DropboxOAuth2FlowNoRedirect(DropboxOAuth2FlowBase): OAuth 2 authorization helper for apps that can't provide a redirect URI (such as the command-line example apps). - Example:: + See examples under example/oauth - from dropbox import DropboxOAuth2FlowNoRedirect - - auth_flow = DropboxOAuth2FlowNoRedirect(APP_KEY, APP_SECRET) - - authorize_url = auth_flow.start() - print "1. Go to: " + authorize_url - print "2. Click \\"Allow\\" (you might have to log in first)." - print "3. Copy the authorization code." - auth_code = raw_input("Enter the authorization code here: ").strip() - - try: - oauth_result = auth_flow.finish(auth_code) - except Exception, e: - print('Error: %s' % (e,)) - return - - dbx = Dropbox(oauth_result.access_token) """ - def __init__(self, consumer_key, consumer_secret, locale=None): # noqa: E501; pylint: disable=useless-super-delegation + def __init__(self, consumer_key, consumer_secret=None, locale=None, token_access_type='legacy', + scope=None, include_granted_scopes=None, use_pkce=False, timeout=DEFAULT_TIMEOUT): # noqa: E501; """ Construct an instance. @@ -214,12 +295,36 @@ def __init__(self, consumer_key, consumer_secret, locale=None): # noqa: E501; p example "en" or "en_US". Some API calls return localized data and error messages; this setting tells the server which locale to use. By default, the server uses "en_US". + :param str token_access_type: the type of token to be requested. + From the following enum: + legacy - creates one long-lived token with no expiration + online - create one short-lived token with an expiration + offline - create one short-lived token with an expiration with a refresh token + :param list scope: list of scopes to request in base oauth flow. If left blank, + will default to all scopes for app + :param str include_granted_scopes: which scopes to include from previous grants + From the following enum: + user - include user scopes in the grant + team - include team scopes in the grant + Note: if this user has never linked the app, include_granted_scopes must be None + :param bool use_pkce: Whether or not to use Sha256 based PKCE. PKCE should be only use on + client apps which doesn't call your server. It is less secure than non-PKCE flow but + can be used if you are unable to safely retrieve your app secret + :param Optional[float] timeout: Maximum duration in seconds that + client will wait for any single packet from the + server. After the timeout the client will give up on + connection. If `None`, client will wait forever. Defaults + to 100 seconds. """ - # pylint: disable=useless-super-delegation super(DropboxOAuth2FlowNoRedirect, self).__init__( - consumer_key, - consumer_secret, - locale, + consumer_key=consumer_key, + consumer_secret=consumer_secret, + locale=locale, + token_access_type=token_access_type, + scope=scope, + include_granted_scopes=include_granted_scopes, + use_pkce=use_pkce, + timeout=timeout ) def start(self): @@ -231,7 +336,10 @@ def start(self): access the user's Dropbox account. Tell the user to visit this URL and approve your app. """ - return self._get_authorize_url(None, None) + return self._get_authorize_url(None, None, self.token_access_type, + scope=self.scope, + include_granted_scopes=self.include_granted_scopes, + code_challenge=self.code_challenge) def finish(self, code): """ @@ -244,7 +352,7 @@ def finish(self, code): :rtype: OAuth2FlowNoRedirectResult :raises: The same exceptions as :meth:`DropboxOAuth2Flow.finish()`. """ - return self._finish(code, None) + return self._finish(code, None, self.code_verifier) class DropboxOAuth2Flow(DropboxOAuth2FlowBase): @@ -255,45 +363,14 @@ class DropboxOAuth2Flow(DropboxOAuth2FlowBase): user authorize your app. The second involves getting an OAuth 2 access token from Dropbox. - Example:: - - from dropbox import DropboxOAuth2Flow - - def get_dropbox_auth_flow(web_app_session): - redirect_uri = "https://my-web-server.org/dropbox-auth-finish" - return DropboxOAuth2Flow( - APP_KEY, APP_SECRET, redirect_uri, web_app_session, - "dropbox-auth-csrf-token") - - # URL handler for /dropbox-auth-start - def dropbox_auth_start(web_app_session, request): - authorize_url = get_dropbox_auth_flow(web_app_session).start() - redirect_to(authorize_url) - - # URL handler for /dropbox-auth-finish - def dropbox_auth_finish(web_app_session, request): - try: - oauth_result = \\ - get_dropbox_auth_flow(web_app_session).finish( - request.query_params) - except BadRequestException, e: - http_status(400) - except BadStateException, e: - # Start the auth flow again. - redirect_to("/dropbox-auth-start") - except CsrfException, e: - http_status(403) - except NotApprovedException, e: - flash('Not approved? Why not?') - return redirect_to("/home") - except ProviderException, e: - logger.log("Auth error: %s" % (e,)) - http_status(403) + See examples under example/oauth """ - def __init__(self, consumer_key, consumer_secret, redirect_uri, session, - csrf_token_session_key, locale=None): + def __init__(self, consumer_key, redirect_uri, session, + csrf_token_session_key, consumer_secret=None, locale=None, + token_access_type='legacy', scope=None, + include_granted_scopes=None, use_pkce=False, timeout=DEFAULT_TIMEOUT): """ Construct an instance. @@ -312,8 +389,36 @@ def __init__(self, consumer_key, consumer_secret, redirect_uri, session, example "en" or "en_US". Some API calls return localized data and error messages; this setting tells the server which locale to use. By default, the server uses "en_US". + :param str token_access_type: the type of token to be requested. + From the following enum: + legacy - creates one long-lived token with no expiration + online - create one short-lived token with an expiration + offline - create one short-lived token with an expiration with a refresh token + :param list scope: list of scopes to request in base oauth flow. If left blank, + will default to all scopes for app + :param str include_granted_scopes: which scopes to include from previous grants + From the following enum: + user - include user scopes in the grant + team - include team scopes in the grant + Note: if this user has never linked the app, include_granted_scopes must be None + :param bool use_pkce: Whether or not to use Sha256 based PKCE + :param Optional[float] timeout: Maximum duration in seconds that + client will wait for any single packet from the + server. After the timeout the client will give up on + connection. If `None`, client will wait forever. Defaults + to 100 seconds. """ - super(DropboxOAuth2Flow, self).__init__(consumer_key, consumer_secret, locale) + + super(DropboxOAuth2Flow, self).__init__( + consumer_key=consumer_key, + consumer_secret=consumer_secret, + locale=locale, + token_access_type=token_access_type, + scope=scope, + include_granted_scopes=include_granted_scopes, + use_pkce=use_pkce, + timeout=timeout + ) self.redirect_uri = redirect_uri self.session = session self.csrf_token_session_key = csrf_token_session_key @@ -347,7 +452,10 @@ def start(self, url_state=None): state += "|" + url_state self.session[self.csrf_token_session_key] = csrf_token - return self._get_authorize_url(self.redirect_uri, state) + return self._get_authorize_url(self.redirect_uri, state, self.token_access_type, + scope=self.scope, + include_granted_scopes=self.include_granted_scopes, + code_challenge=self.code_challenge) def finish(self, query_params): """ @@ -431,7 +539,7 @@ def finish(self, query_params): # If everything went ok, make the network call to get an access token. - no_redirect_result = self._finish(code, self.redirect_uri) + no_redirect_result = self._finish(code, self.redirect_uri, self.code_verifier) return OAuth2FlowResult.from_no_redirect_result( no_redirect_result, url_state) @@ -485,6 +593,16 @@ class ProviderException(Exception): pass +class BadInputException(Exception): + """ + Thrown if incorrect types/values are used + + This should only ever be thrown during testing, app should have validation of input prior to + reaching this point + """ + pass + + def _safe_equals(a, b): if len(a) != len(b): return False @@ -513,3 +631,16 @@ def encode(o): utf8_params = {encode(k): encode(v) for k, v in six.iteritems(params)} return url_encode(utf8_params) + +def _generate_pkce_code_verifier(): + code_verifier = base64.urlsafe_b64encode(os.urandom(PKCE_VERIFIER_LENGTH)).decode('utf-8') + code_verifier = re.sub('[^a-zA-Z0-9]+', '', code_verifier) + if len(code_verifier) > PKCE_VERIFIER_LENGTH: + code_verifier = code_verifier[:128] + return code_verifier + +def _generate_pkce_code_challenge(code_verifier): + code_challenge = hashlib.sha256(code_verifier.encode('utf-8')).digest() + code_challenge = base64.urlsafe_b64encode(code_challenge).decode('utf-8') + code_challenge = code_challenge.replace('=', '') + return code_challenge diff --git a/script.module.dropbox/lib/dropbox/paper.py b/script.module.dropbox/lib/dropbox/paper.py index ec73ecf5e..8160edf17 100644 --- a/script.module.dropbox/lib/dropbox/paper.py +++ b/script.module.dropbox/lib/dropbox/paper.py @@ -5,6 +5,7 @@ # pylint: skip-file """ This namespace contains endpoints and data types for managing docs and folders in Dropbox Paper. +New Paper users will see docs they create in their filesystem as '.paper' files alongside their other Dropbox content. The /paper endpoints are being deprecated and you'll need to use /files and /sharing endpoints to interact with their Paper content. Read more in the :link:`Paper Migration Guide https://www.dropbox.com/lp/developers/reference/paper-migration-guide`. """ try: @@ -609,7 +610,10 @@ class PaperApiBaseError(bb.Union): corresponding ``get_*`` method. :ivar paper.PaperApiBaseError.insufficient_permissions: Your account does - not have permissions to perform this action. + not have permissions to perform this action. This may be due to it only + having access to Paper as files in the Dropbox filesystem. For more + information, refer to the `Paper Migration Guide + `_. """ _catch_all = 'other' @@ -879,8 +883,8 @@ def __repr__(self): class FolderSharingPolicyType(bb.Union): """ - The sharing policy of a Paper folder. Note: The sharing policy of - subfolders is inherited from the root folder. + The sharing policy of a Paper folder. The sharing policy of subfolders is + inherited from the root folder. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the @@ -1095,11 +1099,11 @@ class ImportFormat(bb.Union): :ivar paper.ImportFormat.html: The provided data is interpreted as standard HTML. :ivar paper.ImportFormat.markdown: The provided data is interpreted as - markdown. Note: The first line of the provided document will be used as - the doc title. + markdown. The first line of the provided document will be used as the + doc title. :ivar paper.ImportFormat.plain_text: The provided data is interpreted as - plain text. Note: The first line of the provided document will be used - as the doc title. + plain text. The first line of the provided document will be used as the + doc title. """ _catch_all = 'other' @@ -2690,8 +2694,8 @@ class PaperDocCreateError(PaperApiBaseError): :ivar paper.PaperDocCreateError.doc_length_exceeded: The newly created Paper doc would be too large. Please split the content into multiple docs. :ivar paper.PaperDocCreateError.image_size_exceeded: The imported document - contains an image that is too large. The current limit is 1MB. Note: - This only applies to HTML with data uri. + contains an image that is too large. The current limit is 1MB. This only + applies to HTML with data URI. """ # Attribute is overwritten below the class definition @@ -3306,8 +3310,8 @@ class PaperDocUpdateError(DocLookupError): :ivar paper.PaperDocUpdateError.doc_length_exceeded: The newly created Paper doc would be too large, split the content into multiple docs. :ivar paper.PaperDocUpdateError.image_size_exceeded: The imported document - contains an image that is too large. The current limit is 1MB. Note: - This only applies to HTML with data uri. + contains an image that is too large. The current limit is 1MB. This only + applies to HTML with data URI. :ivar paper.PaperDocUpdateError.doc_archived: This operation is not allowed on archived Paper docs. :ivar paper.PaperDocUpdateError.doc_deleted: This operation is not allowed @@ -3392,7 +3396,7 @@ class PaperDocUpdatePolicy(bb.Union): :ivar paper.PaperDocUpdatePolicy.append: The content will be appended to the doc. :ivar paper.PaperDocUpdatePolicy.prepend: The content will be prepended to - the doc. Note: the doc title will not be affected. + the doc. The doc title will not be affected. :ivar paper.PaperDocUpdatePolicy.overwrite_all: The document will be overwitten at the head with the provided content. """ @@ -3447,6 +3451,236 @@ def __repr__(self): PaperDocUpdatePolicy_validator = bv.Union(PaperDocUpdatePolicy) +class PaperFolderCreateArg(bb.Struct): + """ + :ivar paper.PaperFolderCreateArg.name: The name of the new Paper folder. + :ivar paper.PaperFolderCreateArg.parent_folder_id: The encrypted Paper + folder Id where the new Paper folder should be created. The API user has + to have write access to this folder or error is thrown. If not supplied, + the new folder will be created at top level. + :ivar paper.PaperFolderCreateArg.is_team_folder: Whether the folder to be + created should be a team folder. This value will be ignored if + parent_folder_id is supplied, as the new folder will inherit the type + (private or team folder) from its parent. We will by default create a + top-level private folder if both parent_folder_id and is_team_folder are + not supplied. + """ + + __slots__ = [ + '_name_value', + '_name_present', + '_parent_folder_id_value', + '_parent_folder_id_present', + '_is_team_folder_value', + '_is_team_folder_present', + ] + + _has_required_fields = True + + def __init__(self, + name=None, + parent_folder_id=None, + is_team_folder=None): + self._name_value = None + self._name_present = False + self._parent_folder_id_value = None + self._parent_folder_id_present = False + self._is_team_folder_value = None + self._is_team_folder_present = False + if name is not None: + self.name = name + if parent_folder_id is not None: + self.parent_folder_id = parent_folder_id + if is_team_folder is not None: + self.is_team_folder = is_team_folder + + @property + def name(self): + """ + The name of the new Paper folder. + + :rtype: str + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") + + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False + + @property + def parent_folder_id(self): + """ + The encrypted Paper folder Id where the new Paper folder should be + created. The API user has to have write access to this folder or error + is thrown. If not supplied, the new folder will be created at top level. + + :rtype: str + """ + if self._parent_folder_id_present: + return self._parent_folder_id_value + else: + return None + + @parent_folder_id.setter + def parent_folder_id(self, val): + if val is None: + del self.parent_folder_id + return + val = self._parent_folder_id_validator.validate(val) + self._parent_folder_id_value = val + self._parent_folder_id_present = True + + @parent_folder_id.deleter + def parent_folder_id(self): + self._parent_folder_id_value = None + self._parent_folder_id_present = False + + @property + def is_team_folder(self): + """ + Whether the folder to be created should be a team folder. This value + will be ignored if parent_folder_id is supplied, as the new folder will + inherit the type (private or team folder) from its parent. We will by + default create a top-level private folder if both parent_folder_id and + is_team_folder are not supplied. + + :rtype: bool + """ + if self._is_team_folder_present: + return self._is_team_folder_value + else: + return None + + @is_team_folder.setter + def is_team_folder(self, val): + if val is None: + del self.is_team_folder + return + val = self._is_team_folder_validator.validate(val) + self._is_team_folder_value = val + self._is_team_folder_present = True + + @is_team_folder.deleter + def is_team_folder(self): + self._is_team_folder_value = None + self._is_team_folder_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperFolderCreateArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperFolderCreateArg(name={!r}, parent_folder_id={!r}, is_team_folder={!r})'.format( + self._name_value, + self._parent_folder_id_value, + self._is_team_folder_value, + ) + +PaperFolderCreateArg_validator = bv.Struct(PaperFolderCreateArg) + +class PaperFolderCreateError(PaperApiBaseError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar paper.PaperFolderCreateError.folder_not_found: The specified parent + Paper folder cannot be found. + :ivar paper.PaperFolderCreateError.invalid_folder_id: The folder id cannot + be decrypted to valid folder id. + """ + + # Attribute is overwritten below the class definition + folder_not_found = None + # Attribute is overwritten below the class definition + invalid_folder_id = None + + def is_folder_not_found(self): + """ + Check if the union tag is ``folder_not_found``. + + :rtype: bool + """ + return self._tag == 'folder_not_found' + + def is_invalid_folder_id(self): + """ + Check if the union tag is ``invalid_folder_id``. + + :rtype: bool + """ + return self._tag == 'invalid_folder_id' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperFolderCreateError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperFolderCreateError(%r, %r)' % (self._tag, self._value) + +PaperFolderCreateError_validator = bv.Union(PaperFolderCreateError) + +class PaperFolderCreateResult(bb.Struct): + """ + :ivar paper.PaperFolderCreateResult.folder_id: Folder ID of the newly + created folder. + """ + + __slots__ = [ + '_folder_id_value', + '_folder_id_present', + ] + + _has_required_fields = True + + def __init__(self, + folder_id=None): + self._folder_id_value = None + self._folder_id_present = False + if folder_id is not None: + self.folder_id = folder_id + + @property + def folder_id(self): + """ + Folder ID of the newly created folder. + + :rtype: str + """ + if self._folder_id_present: + return self._folder_id_value + else: + raise AttributeError("missing required field 'folder_id'") + + @folder_id.setter + def folder_id(self, val): + val = self._folder_id_validator.validate(val) + self._folder_id_value = val + self._folder_id_present = True + + @folder_id.deleter + def folder_id(self): + self._folder_id_value = None + self._folder_id_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperFolderCreateResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperFolderCreateResult(folder_id={!r})'.format( + self._folder_id_value, + ) + +PaperFolderCreateResult_validator = bv.Struct(PaperFolderCreateResult) + class RemovePaperDocUser(RefPaperDoc): """ :ivar paper.RemovePaperDocUser.member: User which should be removed from the @@ -4333,6 +4567,35 @@ def __repr__(self): PaperDocUpdatePolicy.overwrite_all = PaperDocUpdatePolicy('overwrite_all') PaperDocUpdatePolicy.other = PaperDocUpdatePolicy('other') +PaperFolderCreateArg._name_validator = bv.String() +PaperFolderCreateArg._parent_folder_id_validator = bv.Nullable(bv.String()) +PaperFolderCreateArg._is_team_folder_validator = bv.Nullable(bv.Boolean()) +PaperFolderCreateArg._all_field_names_ = set([ + 'name', + 'parent_folder_id', + 'is_team_folder', +]) +PaperFolderCreateArg._all_fields_ = [ + ('name', PaperFolderCreateArg._name_validator), + ('parent_folder_id', PaperFolderCreateArg._parent_folder_id_validator), + ('is_team_folder', PaperFolderCreateArg._is_team_folder_validator), +] + +PaperFolderCreateError._folder_not_found_validator = bv.Void() +PaperFolderCreateError._invalid_folder_id_validator = bv.Void() +PaperFolderCreateError._tagmap = { + 'folder_not_found': PaperFolderCreateError._folder_not_found_validator, + 'invalid_folder_id': PaperFolderCreateError._invalid_folder_id_validator, +} +PaperFolderCreateError._tagmap.update(PaperApiBaseError._tagmap) + +PaperFolderCreateError.folder_not_found = PaperFolderCreateError('folder_not_found') +PaperFolderCreateError.invalid_folder_id = PaperFolderCreateError('invalid_folder_id') + +PaperFolderCreateResult._folder_id_validator = bv.String() +PaperFolderCreateResult._all_field_names_ = set(['folder_id']) +PaperFolderCreateResult._all_fields_ = [('folder_id', PaperFolderCreateResult._folder_id_validator)] + RemovePaperDocUser._member_validator = sharing.MemberSelector_validator RemovePaperDocUser._all_field_names_ = RefPaperDoc._all_field_names_.union(set(['member'])) RemovePaperDocUser._all_fields_ = RefPaperDoc._all_fields_ + [('member', RemovePaperDocUser._member_validator)] @@ -4396,7 +4659,7 @@ def __repr__(self): docs_archive = bb.Route( 'docs/archive', 1, - False, + True, RefPaperDoc_validator, bv.Void(), DocLookupError_validator, @@ -4406,7 +4669,7 @@ def __repr__(self): docs_create = bb.Route( 'docs/create', 1, - False, + True, PaperDocCreateArgs_validator, PaperDocCreateUpdateResult_validator, PaperDocCreateError_validator, @@ -4416,7 +4679,7 @@ def __repr__(self): docs_download = bb.Route( 'docs/download', 1, - False, + True, PaperDocExport_validator, PaperDocExportResult_validator, DocLookupError_validator, @@ -4426,7 +4689,7 @@ def __repr__(self): docs_folder_users_list = bb.Route( 'docs/folder_users/list', 1, - False, + True, ListUsersOnFolderArgs_validator, ListUsersOnFolderResponse_validator, DocLookupError_validator, @@ -4436,7 +4699,7 @@ def __repr__(self): docs_folder_users_list_continue = bb.Route( 'docs/folder_users/list/continue', 1, - False, + True, ListUsersOnFolderContinueArgs_validator, ListUsersOnFolderResponse_validator, ListUsersCursorError_validator, @@ -4446,7 +4709,7 @@ def __repr__(self): docs_get_folder_info = bb.Route( 'docs/get_folder_info', 1, - False, + True, RefPaperDoc_validator, FoldersContainingPaperDoc_validator, DocLookupError_validator, @@ -4456,7 +4719,7 @@ def __repr__(self): docs_list = bb.Route( 'docs/list', 1, - False, + True, ListPaperDocsArgs_validator, ListPaperDocsResponse_validator, bv.Void(), @@ -4466,7 +4729,7 @@ def __repr__(self): docs_list_continue = bb.Route( 'docs/list/continue', 1, - False, + True, ListPaperDocsContinueArgs_validator, ListPaperDocsResponse_validator, ListDocsCursorError_validator, @@ -4476,7 +4739,7 @@ def __repr__(self): docs_permanently_delete = bb.Route( 'docs/permanently_delete', 1, - False, + True, RefPaperDoc_validator, bv.Void(), DocLookupError_validator, @@ -4486,7 +4749,7 @@ def __repr__(self): docs_sharing_policy_get = bb.Route( 'docs/sharing_policy/get', 1, - False, + True, RefPaperDoc_validator, SharingPolicy_validator, DocLookupError_validator, @@ -4496,7 +4759,7 @@ def __repr__(self): docs_sharing_policy_set = bb.Route( 'docs/sharing_policy/set', 1, - False, + True, PaperDocSharingPolicy_validator, bv.Void(), DocLookupError_validator, @@ -4506,7 +4769,7 @@ def __repr__(self): docs_update = bb.Route( 'docs/update', 1, - False, + True, PaperDocUpdateArgs_validator, PaperDocCreateUpdateResult_validator, PaperDocUpdateError_validator, @@ -4516,7 +4779,7 @@ def __repr__(self): docs_users_add = bb.Route( 'docs/users/add', 1, - False, + True, AddPaperDocUser_validator, bv.List(AddPaperDocUserMemberResult_validator), DocLookupError_validator, @@ -4526,7 +4789,7 @@ def __repr__(self): docs_users_list = bb.Route( 'docs/users/list', 1, - False, + True, ListUsersOnPaperDocArgs_validator, ListUsersOnPaperDocResponse_validator, DocLookupError_validator, @@ -4536,7 +4799,7 @@ def __repr__(self): docs_users_list_continue = bb.Route( 'docs/users/list/continue', 1, - False, + True, ListUsersOnPaperDocContinueArgs_validator, ListUsersOnPaperDocResponse_validator, ListUsersCursorError_validator, @@ -4546,13 +4809,23 @@ def __repr__(self): docs_users_remove = bb.Route( 'docs/users/remove', 1, - False, + True, RemovePaperDocUser_validator, bv.Void(), DocLookupError_validator, {'host': u'api', 'style': u'rpc'}, ) +folders_create = bb.Route( + 'folders/create', + 1, + True, + PaperFolderCreateArg_validator, + PaperFolderCreateResult_validator, + PaperFolderCreateError_validator, + {'host': u'api', + 'style': u'rpc'}, +) ROUTES = { 'docs/archive': docs_archive, @@ -4571,5 +4844,6 @@ def __repr__(self): 'docs/users/list': docs_users_list, 'docs/users/list/continue': docs_users_list_continue, 'docs/users/remove': docs_users_remove, + 'folders/create': folders_create, } diff --git a/script.module.dropbox/lib/dropbox/secondary_emails.py b/script.module.dropbox/lib/dropbox/secondary_emails.py new file mode 100644 index 000000000..11f7a8add --- /dev/null +++ b/script.module.dropbox/lib/dropbox/secondary_emails.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +# Auto-generated by Stone, do not modify. +# @generated +# flake8: noqa +# pylint: skip-file +try: + from . import stone_validators as bv + from . import stone_base as bb +except (ImportError, SystemError, ValueError): + # Catch errors raised when importing a relative module when not in a package. + # This makes testing this file directly (outside of a package) easier. + import stone_validators as bv + import stone_base as bb + +try: + from . import ( + common, + ) +except (ImportError, SystemError, ValueError): + import common + +class SecondaryEmail(bb.Struct): + """ + :ivar secondary_emails.SecondaryEmail.email: Secondary email address. + :ivar secondary_emails.SecondaryEmail.is_verified: Whether or not the + secondary email address is verified to be owned by a user. + """ + + __slots__ = [ + '_email_value', + '_email_present', + '_is_verified_value', + '_is_verified_present', + ] + + _has_required_fields = True + + def __init__(self, + email=None, + is_verified=None): + self._email_value = None + self._email_present = False + self._is_verified_value = None + self._is_verified_present = False + if email is not None: + self.email = email + if is_verified is not None: + self.is_verified = is_verified + + @property + def email(self): + """ + Secondary email address. + + :rtype: str + """ + if self._email_present: + return self._email_value + else: + raise AttributeError("missing required field 'email'") + + @email.setter + def email(self, val): + val = self._email_validator.validate(val) + self._email_value = val + self._email_present = True + + @email.deleter + def email(self): + self._email_value = None + self._email_present = False + + @property + def is_verified(self): + """ + Whether or not the secondary email address is verified to be owned by a + user. + + :rtype: bool + """ + if self._is_verified_present: + return self._is_verified_value + else: + raise AttributeError("missing required field 'is_verified'") + + @is_verified.setter + def is_verified(self, val): + val = self._is_verified_validator.validate(val) + self._is_verified_value = val + self._is_verified_present = True + + @is_verified.deleter + def is_verified(self): + self._is_verified_value = None + self._is_verified_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SecondaryEmail, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SecondaryEmail(email={!r}, is_verified={!r})'.format( + self._email_value, + self._is_verified_value, + ) + +SecondaryEmail_validator = bv.Struct(SecondaryEmail) + +SecondaryEmail._email_validator = common.EmailAddress_validator +SecondaryEmail._is_verified_validator = bv.Boolean() +SecondaryEmail._all_field_names_ = set([ + 'email', + 'is_verified', +]) +SecondaryEmail._all_fields_ = [ + ('email', SecondaryEmail._email_validator), + ('is_verified', SecondaryEmail._is_verified_validator), +] + +ROUTES = { +} + diff --git a/script.module.dropbox/lib/dropbox/session.py b/script.module.dropbox/lib/dropbox/session.py index 0632d461c..fc48b2a5e 100644 --- a/script.module.dropbox/lib/dropbox/session.py +++ b/script.module.dropbox/lib/dropbox/session.py @@ -29,6 +29,9 @@ API_NOTIFICATION_HOST = os.environ.get('DROPBOX_API_NOTIFY_HOST', HOST_NOTIFY + API_DOMAIN) WEB_HOST = os.environ.get('DROPBOX_WEB_HOST', HOST_WWW + WEB_DOMAIN) +# This is the default longest time we'll block on receiving data from the server +DEFAULT_TIMEOUT = 100 + _TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt') # TODO(kelkabany): We probably only want to instantiate this once so that even diff --git a/script.module.dropbox/lib/dropbox/sharing.py b/script.module.dropbox/lib/dropbox/sharing.py index 33852610d..809721c7a 100644 --- a/script.module.dropbox/lib/dropbox/sharing.py +++ b/script.module.dropbox/lib/dropbox/sharing.py @@ -11520,7 +11520,8 @@ class RequestedLinkAccessLevel(bb.Union): :ivar sharing.RequestedLinkAccessLevel.viewer: Users who use the link can view and comment on the content. :ivar sharing.RequestedLinkAccessLevel.editor: Users who use the link can - edit, view and comment on the content. + edit, view and comment on the content. Note not all file types support + edit links yet. :ivar sharing.RequestedLinkAccessLevel.max: Request for the maximum access level you can set the link to. """ @@ -13941,6 +13942,8 @@ class SharedFolderMetadataBase(bb.Struct): contained within another shared folder. :ivar sharing.SharedFolderMetadataBase.path_lower: The lower-cased full path of this shared folder. Absent for unmounted folders. + :ivar sharing.SharedFolderMetadataBase.parent_folder_name: Display name for + the parent folder. """ __slots__ = [ @@ -13958,6 +13961,8 @@ class SharedFolderMetadataBase(bb.Struct): '_parent_shared_folder_id_present', '_path_lower_value', '_path_lower_present', + '_parent_folder_name_value', + '_parent_folder_name_present', ] _has_required_fields = True @@ -13969,7 +13974,8 @@ def __init__(self, owner_display_names=None, owner_team=None, parent_shared_folder_id=None, - path_lower=None): + path_lower=None, + parent_folder_name=None): self._access_type_value = None self._access_type_present = False self._is_inside_team_folder_value = None @@ -13984,6 +13990,8 @@ def __init__(self, self._parent_shared_folder_id_present = False self._path_lower_value = None self._path_lower_present = False + self._parent_folder_name_value = None + self._parent_folder_name_present = False if access_type is not None: self.access_type = access_type if is_inside_team_folder is not None: @@ -13998,6 +14006,8 @@ def __init__(self, self.parent_shared_folder_id = parent_shared_folder_id if path_lower is not None: self.path_lower = path_lower + if parent_folder_name is not None: + self.parent_folder_name = parent_folder_name @property def access_type(self): @@ -14178,11 +14188,37 @@ def path_lower(self): self._path_lower_value = None self._path_lower_present = False + @property + def parent_folder_name(self): + """ + Display name for the parent folder. + + :rtype: str + """ + if self._parent_folder_name_present: + return self._parent_folder_name_value + else: + return None + + @parent_folder_name.setter + def parent_folder_name(self, val): + if val is None: + del self.parent_folder_name + return + val = self._parent_folder_name_validator.validate(val) + self._parent_folder_name_value = val + self._parent_folder_name_present = True + + @parent_folder_name.deleter + def parent_folder_name(self): + self._parent_folder_name_value = None + self._parent_folder_name_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): super(SharedFolderMetadataBase, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderMetadataBase(access_type={!r}, is_inside_team_folder={!r}, is_team_folder={!r}, owner_display_names={!r}, owner_team={!r}, parent_shared_folder_id={!r}, path_lower={!r})'.format( + return 'SharedFolderMetadataBase(access_type={!r}, is_inside_team_folder={!r}, is_team_folder={!r}, owner_display_names={!r}, owner_team={!r}, parent_shared_folder_id={!r}, path_lower={!r}, parent_folder_name={!r})'.format( self._access_type_value, self._is_inside_team_folder_value, self._is_team_folder_value, @@ -14190,6 +14226,7 @@ def __repr__(self): self._owner_team_value, self._parent_shared_folder_id_value, self._path_lower_value, + self._parent_folder_name_value, ) SharedFolderMetadataBase_validator = bv.Struct(SharedFolderMetadataBase) @@ -14251,6 +14288,7 @@ def __init__(self, owner_team=None, parent_shared_folder_id=None, path_lower=None, + parent_folder_name=None, link_metadata=None, permissions=None, access_inheritance=None): @@ -14260,7 +14298,8 @@ def __init__(self, owner_display_names, owner_team, parent_shared_folder_id, - path_lower) + path_lower, + parent_folder_name) self._link_metadata_value = None self._link_metadata_present = False self._name_value = None @@ -14492,7 +14531,7 @@ def _process_custom_annotations(self, annotation_type, field_path, processor): super(SharedFolderMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderMetadata(access_type={!r}, is_inside_team_folder={!r}, is_team_folder={!r}, name={!r}, policy={!r}, preview_url={!r}, shared_folder_id={!r}, time_invited={!r}, owner_display_names={!r}, owner_team={!r}, parent_shared_folder_id={!r}, path_lower={!r}, link_metadata={!r}, permissions={!r}, access_inheritance={!r})'.format( + return 'SharedFolderMetadata(access_type={!r}, is_inside_team_folder={!r}, is_team_folder={!r}, name={!r}, policy={!r}, preview_url={!r}, shared_folder_id={!r}, time_invited={!r}, owner_display_names={!r}, owner_team={!r}, parent_shared_folder_id={!r}, path_lower={!r}, parent_folder_name={!r}, link_metadata={!r}, permissions={!r}, access_inheritance={!r})'.format( self._access_type_value, self._is_inside_team_folder_value, self._is_team_folder_value, @@ -14505,6 +14544,7 @@ def __repr__(self): self._owner_team_value, self._parent_shared_folder_id_value, self._path_lower_value, + self._parent_folder_name_value, self._link_metadata_value, self._permissions_value, self._access_inheritance_value, @@ -14742,7 +14782,8 @@ class SharedLinkSettings(bb.Struct): the final effective audience type in the `effective_audience` field of `LinkPermissions. :ivar sharing.SharedLinkSettings.access: Requested access level you want the - audience to gain from this link. + audience to gain from this link. Note, modifying access level for an + existing link is not supported. """ __slots__ = [ @@ -14900,6 +14941,7 @@ def audience(self): def access(self): """ Requested access level you want the audience to gain from this link. + Note, modifying access level for an existing link is not supported. :rtype: RequestedLinkAccessLevel """ @@ -19004,6 +19046,7 @@ def __repr__(self): SharedFolderMetadataBase._owner_team_validator = bv.Nullable(users.Team_validator) SharedFolderMetadataBase._parent_shared_folder_id_validator = bv.Nullable(common.SharedFolderId_validator) SharedFolderMetadataBase._path_lower_validator = bv.Nullable(bv.String()) +SharedFolderMetadataBase._parent_folder_name_validator = bv.Nullable(bv.String()) SharedFolderMetadataBase._all_field_names_ = set([ 'access_type', 'is_inside_team_folder', @@ -19012,6 +19055,7 @@ def __repr__(self): 'owner_team', 'parent_shared_folder_id', 'path_lower', + 'parent_folder_name', ]) SharedFolderMetadataBase._all_fields_ = [ ('access_type', SharedFolderMetadataBase._access_type_validator), @@ -19021,6 +19065,7 @@ def __repr__(self): ('owner_team', SharedFolderMetadataBase._owner_team_validator), ('parent_shared_folder_id', SharedFolderMetadataBase._parent_shared_folder_id_validator), ('path_lower', SharedFolderMetadataBase._path_lower_validator), + ('parent_folder_name', SharedFolderMetadataBase._parent_folder_name_validator), ] SharedFolderMetadata._link_metadata_validator = bv.Nullable(SharedContentLinkMetadata_validator) diff --git a/script.module.dropbox/lib/dropbox/stone_base.py b/script.module.dropbox/lib/dropbox/stone_base.py index 6fa0fe558..ed6d81c0c 100644 --- a/script.module.dropbox/lib/dropbox/stone_base.py +++ b/script.module.dropbox/lib/dropbox/stone_base.py @@ -31,6 +31,30 @@ class AnnotationType(object): class Struct(object): # This is a base class for all classes representing Stone structs. + + _all_field_names_ = set() # type: typing.Set[str] + + def __eq__(self, other): + # type: (object) -> bool + if not isinstance(other, Struct): + return False + + if self._all_field_names_ != other._all_field_names_: + return False + + if not isinstance(other, self.__class__) and not isinstance(self, other.__class__): + return False + + for field_name in self._all_field_names_: + if getattr(self, field_name) != getattr(other, field_name): + return False + + return True + + def __ne__(self, other): + # type: (object) -> bool + return not self == other + def _process_custom_annotations(self, annotation_type, field_path, processor): # type: (typing.Type[T], typing.Text, typing.Callable[[T, U], U]) -> None pass @@ -39,7 +63,7 @@ class Union(object): # TODO(kelkabany): Possible optimization is to remove _value if a # union is composed of only symbols. __slots__ = ['_tag', '_value'] - _tagmap = {} # type: typing.Dict[typing.Text, bv.Validator] + _tagmap = {} # type: typing.Dict[str, bv.Validator] _permissioned_tagmaps = set() # type: typing.Set[typing.Text] def __init__(self, tag, value=None): @@ -79,7 +103,7 @@ def _process_custom_annotations(self, annotation_type, field_path, processor): @classmethod def _is_tag_present(cls, tag, caller_permissions): - assert tag, 'tag value should not be None' + assert tag is not None, 'tag value should not be None' if tag in cls._tagmap: return True @@ -93,7 +117,7 @@ def _is_tag_present(cls, tag, caller_permissions): @classmethod def _get_val_data_type(cls, tag, caller_permissions): - assert tag, 'tag value should not be None' + assert tag is not None, 'tag value should not be None' for extra_permission in caller_permissions.permissions: tagmap_name = '_{}_tagmap'.format(extra_permission) diff --git a/script.module.dropbox/lib/dropbox/stone_fixtures.py b/script.module.dropbox/lib/dropbox/stone_fixtures.py new file mode 100644 index 000000000..9252e67d2 --- /dev/null +++ b/script.module.dropbox/lib/dropbox/stone_fixtures.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- +# Auto-generated by Stone, do not modify. +# @generated +# flake8: noqa +# pylint: skip-file +try: + from . import stone_validators as bv + from . import stone_base as bb +except (ImportError, SystemError, ValueError): + # Catch errors raised when importing a relative module when not in a package. + # This makes testing this file directly (outside of a package) easier. + import stone_validators as bv + import stone_base as bb + +class EmptyContainer(bb.Struct): + """ + This struct left intentionally empty + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmptyContainer, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EmptyContainer()' + +EmptyContainer_validator = bv.Struct(EmptyContainer) + +class MixedInternalOnlyContainer(bb.Struct): + + __slots__ = [ + '_public_value_value', + '_public_value_present', + ] + + _has_required_fields = False + + def __init__(self, + public_value=None): + self._public_value_value = None + self._public_value_present = False + if public_value is not None: + self.public_value = public_value + + @property + def public_value(self): + """ + :rtype: int + """ + if self._public_value_present: + return self._public_value_value + else: + return 0 + + @public_value.setter + def public_value(self, val): + val = self._public_value_validator.validate(val) + self._public_value_value = val + self._public_value_present = True + + @public_value.deleter + def public_value(self): + self._public_value_value = None + self._public_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MixedInternalOnlyContainer, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MixedInternalOnlyContainer(public_value={!r})'.format( + self._public_value_value, + ) + +MixedInternalOnlyContainer_validator = bv.Struct(MixedInternalOnlyContainer) + +class MixedInternalOnlyEnum(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + public = None + # Attribute is overwritten below the class definition + other = None + + def is_public(self): + """ + Check if the union tag is ``public``. + + :rtype: bool + """ + return self._tag == 'public' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MixedInternalOnlyEnum, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MixedInternalOnlyEnum(%r, %r)' % (self._tag, self._value) + +MixedInternalOnlyEnum_validator = bv.Union(MixedInternalOnlyEnum) + +EmptyContainer._all_field_names_ = set([]) +EmptyContainer._all_fields_ = [] + +MixedInternalOnlyContainer._public_value_validator = bv.Int32() +MixedInternalOnlyContainer._all_field_names_ = set(['public_value']) +MixedInternalOnlyContainer._all_fields_ = [('public_value', MixedInternalOnlyContainer._public_value_validator)] + +MixedInternalOnlyEnum._public_validator = bv.Void() +MixedInternalOnlyEnum._other_validator = bv.Void() +MixedInternalOnlyEnum._tagmap = { + 'public': MixedInternalOnlyEnum._public_validator, + 'other': MixedInternalOnlyEnum._other_validator, +} + +MixedInternalOnlyEnum.public = MixedInternalOnlyEnum('public') +MixedInternalOnlyEnum.other = MixedInternalOnlyEnum('other') + +ROUTES = { +} + diff --git a/script.module.dropbox/lib/dropbox/stone_serializers.py b/script.module.dropbox/lib/dropbox/stone_serializers.py index e8b233230..6f1d117dd 100644 --- a/script.module.dropbox/lib/dropbox/stone_serializers.py +++ b/script.module.dropbox/lib/dropbox/stone_serializers.py @@ -13,6 +13,7 @@ from __future__ import absolute_import, unicode_literals import base64 +import binascii import collections import datetime import functools @@ -657,12 +658,11 @@ def decode_union(self, data_type, obj): else: raise bv.ValidationError("unknown tag '%s'" % tag) elif isinstance(obj, dict): - tag, val = self.decode_union_dict( - data_type, obj) + tag, val = self.decode_union_dict(data_type, obj) else: raise bv.ValidationError("expected string or object, got %s" % bv.generic_type_name(obj)) - return data_type.definition(tag, val) + return data_type.definition(six.ensure_str(tag), val) def decode_union_dict(self, data_type, obj): if '.tag' not in obj: @@ -789,7 +789,7 @@ def decode_union_old(self, data_type, obj): else: raise bv.ValidationError("expected string or object, got %s" % bv.generic_type_name(obj)) - return data_type.definition(tag, val) + return data_type.definition(six.ensure_str(tag), val) def decode_struct_tree(self, data_type, obj): """ @@ -880,12 +880,6 @@ def make_stone_friendly(self, data_type, val, validate): if isinstance(data_type, bv.Timestamp): try: ret = datetime.datetime.strptime(val, data_type.format) - except: - # datetime.datetime.strptime(val, data_type.format) returned NoneType. Trying alterntive - pass - - try: - ret = datetime.datetime(*(time.strptime(val, data_type.format)[0:6])) except (TypeError, ValueError) as e: raise bv.ValidationError(e.args[0]) elif isinstance(data_type, bv.Bytes): @@ -897,7 +891,7 @@ def make_stone_friendly(self, data_type, val, validate): else: try: ret = base64.b64decode(val) - except TypeError: + except (TypeError, binascii.Error): raise bv.ValidationError('invalid base64-encoded bytes') elif isinstance(data_type, bv.Void): if self.strict and val is not None: diff --git a/script.module.dropbox/lib/dropbox/stone_validators.py b/script.module.dropbox/lib/dropbox/stone_validators.py index f51298966..c8534b844 100644 --- a/script.module.dropbox/lib/dropbox/stone_validators.py +++ b/script.module.dropbox/lib/dropbox/stone_validators.py @@ -92,9 +92,8 @@ def generic_type_name(v): return type(v).__name__ -class Validator(object): +class Validator(six.with_metaclass(ABCMeta, object)): """All primitive and composite data types should be a subclass of this.""" - __metaclass__ = ABCMeta @abstractmethod def validate(self, val): @@ -306,7 +305,7 @@ def validate(self, val): try: val = val.decode('utf-8') except UnicodeDecodeError: - raise ValidationError("'%s' was not valid utf-8") + raise ValidationError("'%s' was not valid utf-8" % val) if self.max_length is not None and len(val) > self.max_length: raise ValidationError("'%s' must be at most %d characters, got %d" diff --git a/script.module.dropbox/lib/dropbox/team.py b/script.module.dropbox/lib/dropbox/team.py index a51786f34..a943cbf3a 100644 --- a/script.module.dropbox/lib/dropbox/team.py +++ b/script.module.dropbox/lib/dropbox/team.py @@ -14,20 +14,24 @@ try: from . import ( + account, async_, common, file_properties, files, + secondary_emails, team_common, team_policies, users, users_common, ) except (ImportError, SystemError, ValueError): + import account import async_ import common import file_properties import files + import secondary_emails import team_common import team_policies import users @@ -397,564 +401,427 @@ def __repr__(self): ActiveWebSession_validator = bv.Struct(ActiveWebSession) -class AdminTier(bb.Union): +class AddSecondaryEmailResult(bb.Union): """ - Describes which team-related admin permissions a user has. + Result of trying to add a secondary email to a user. 'success' is the only + value indicating that a secondary email was successfully added to a user. + The other values explain the type of error that occurred, and include the + email for which the error occured. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.AdminTier.team_admin: User is an administrator of the team - has - all permissions. - :ivar team.AdminTier.user_management_admin: User can do most user - provisioning, de-provisioning and management. - :ivar team.AdminTier.support_admin: User can do a limited set of common - support tasks for existing users. - :ivar team.AdminTier.member_only: User is not an admin of the team. + :ivar secondary_emails.SecondaryEmail team.AddSecondaryEmailResult.success: + Describes a secondary email that was successfully added to a user. + :ivar str team.AddSecondaryEmailResult.unavailable: Secondary email is not + available to be claimed by the user. + :ivar str team.AddSecondaryEmailResult.already_pending: Secondary email is + already a pending email for the user. + :ivar str team.AddSecondaryEmailResult.already_owned_by_user: Secondary + email is already a verified email for the user. + :ivar str team.AddSecondaryEmailResult.reached_limit: User already has the + maximum number of secondary emails allowed. + :ivar str team.AddSecondaryEmailResult.transient_error: A transient error + occurred. Please try again later. + :ivar str team.AddSecondaryEmailResult.too_many_updates: An error occurred + due to conflicting updates. Please try again later. + :ivar str team.AddSecondaryEmailResult.unknown_error: An unknown error + occurred. + :ivar str team.AddSecondaryEmailResult.rate_limited: Too many emails are + being sent to this email address. Please try again later. """ - _catch_all = None - # Attribute is overwritten below the class definition - team_admin = None - # Attribute is overwritten below the class definition - user_management_admin = None - # Attribute is overwritten below the class definition - support_admin = None + _catch_all = 'other' # Attribute is overwritten below the class definition - member_only = None + other = None - def is_team_admin(self): + @classmethod + def success(cls, val): """ - Check if the union tag is ``team_admin``. + Create an instance of this class set to the ``success`` tag with value + ``val``. - :rtype: bool + :param secondary_emails.SecondaryEmail val: + :rtype: AddSecondaryEmailResult """ - return self._tag == 'team_admin' + return cls('success', val) - def is_user_management_admin(self): + @classmethod + def unavailable(cls, val): """ - Check if the union tag is ``user_management_admin``. + Create an instance of this class set to the ``unavailable`` tag with + value ``val``. - :rtype: bool + :param str val: + :rtype: AddSecondaryEmailResult """ - return self._tag == 'user_management_admin' + return cls('unavailable', val) - def is_support_admin(self): + @classmethod + def already_pending(cls, val): """ - Check if the union tag is ``support_admin``. + Create an instance of this class set to the ``already_pending`` tag with + value ``val``. - :rtype: bool + :param str val: + :rtype: AddSecondaryEmailResult """ - return self._tag == 'support_admin' + return cls('already_pending', val) - def is_member_only(self): + @classmethod + def already_owned_by_user(cls, val): """ - Check if the union tag is ``member_only``. + Create an instance of this class set to the ``already_owned_by_user`` + tag with value ``val``. - :rtype: bool + :param str val: + :rtype: AddSecondaryEmailResult """ - return self._tag == 'member_only' + return cls('already_owned_by_user', val) - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(AdminTier, self)._process_custom_annotations(annotation_type, field_path, processor) + @classmethod + def reached_limit(cls, val): + """ + Create an instance of this class set to the ``reached_limit`` tag with + value ``val``. - def __repr__(self): - return 'AdminTier(%r, %r)' % (self._tag, self._value) + :param str val: + :rtype: AddSecondaryEmailResult + """ + return cls('reached_limit', val) -AdminTier_validator = bv.Union(AdminTier) + @classmethod + def transient_error(cls, val): + """ + Create an instance of this class set to the ``transient_error`` tag with + value ``val``. -class ApiApp(bb.Struct): - """ - Information on linked third party applications. + :param str val: + :rtype: AddSecondaryEmailResult + """ + return cls('transient_error', val) - :ivar team.ApiApp.app_id: The application unique id. - :ivar team.ApiApp.app_name: The application name. - :ivar team.ApiApp.publisher: The application publisher name. - :ivar team.ApiApp.publisher_url: The publisher's URL. - :ivar team.ApiApp.linked: The time this application was linked. - :ivar team.ApiApp.is_app_folder: Whether the linked application uses a - dedicated folder. - """ + @classmethod + def too_many_updates(cls, val): + """ + Create an instance of this class set to the ``too_many_updates`` tag + with value ``val``. - __slots__ = [ - '_app_id_value', - '_app_id_present', - '_app_name_value', - '_app_name_present', - '_publisher_value', - '_publisher_present', - '_publisher_url_value', - '_publisher_url_present', - '_linked_value', - '_linked_present', - '_is_app_folder_value', - '_is_app_folder_present', - ] + :param str val: + :rtype: AddSecondaryEmailResult + """ + return cls('too_many_updates', val) - _has_required_fields = True + @classmethod + def unknown_error(cls, val): + """ + Create an instance of this class set to the ``unknown_error`` tag with + value ``val``. - def __init__(self, - app_id=None, - app_name=None, - is_app_folder=None, - publisher=None, - publisher_url=None, - linked=None): - self._app_id_value = None - self._app_id_present = False - self._app_name_value = None - self._app_name_present = False - self._publisher_value = None - self._publisher_present = False - self._publisher_url_value = None - self._publisher_url_present = False - self._linked_value = None - self._linked_present = False - self._is_app_folder_value = None - self._is_app_folder_present = False - if app_id is not None: - self.app_id = app_id - if app_name is not None: - self.app_name = app_name - if publisher is not None: - self.publisher = publisher - if publisher_url is not None: - self.publisher_url = publisher_url - if linked is not None: - self.linked = linked - if is_app_folder is not None: - self.is_app_folder = is_app_folder + :param str val: + :rtype: AddSecondaryEmailResult + """ + return cls('unknown_error', val) - @property - def app_id(self): + @classmethod + def rate_limited(cls, val): """ - The application unique id. + Create an instance of this class set to the ``rate_limited`` tag with + value ``val``. - :rtype: str + :param str val: + :rtype: AddSecondaryEmailResult """ - if self._app_id_present: - return self._app_id_value - else: - raise AttributeError("missing required field 'app_id'") + return cls('rate_limited', val) - @app_id.setter - def app_id(self, val): - val = self._app_id_validator.validate(val) - self._app_id_value = val - self._app_id_present = True + def is_success(self): + """ + Check if the union tag is ``success``. - @app_id.deleter - def app_id(self): - self._app_id_value = None - self._app_id_present = False + :rtype: bool + """ + return self._tag == 'success' - @property - def app_name(self): + def is_unavailable(self): """ - The application name. + Check if the union tag is ``unavailable``. - :rtype: str + :rtype: bool """ - if self._app_name_present: - return self._app_name_value - else: - raise AttributeError("missing required field 'app_name'") + return self._tag == 'unavailable' - @app_name.setter - def app_name(self, val): - val = self._app_name_validator.validate(val) - self._app_name_value = val - self._app_name_present = True + def is_already_pending(self): + """ + Check if the union tag is ``already_pending``. - @app_name.deleter - def app_name(self): - self._app_name_value = None - self._app_name_present = False + :rtype: bool + """ + return self._tag == 'already_pending' - @property - def publisher(self): + def is_already_owned_by_user(self): """ - The application publisher name. + Check if the union tag is ``already_owned_by_user``. - :rtype: str + :rtype: bool """ - if self._publisher_present: - return self._publisher_value - else: - return None + return self._tag == 'already_owned_by_user' - @publisher.setter - def publisher(self, val): - if val is None: - del self.publisher - return - val = self._publisher_validator.validate(val) - self._publisher_value = val - self._publisher_present = True + def is_reached_limit(self): + """ + Check if the union tag is ``reached_limit``. - @publisher.deleter - def publisher(self): - self._publisher_value = None - self._publisher_present = False + :rtype: bool + """ + return self._tag == 'reached_limit' - @property - def publisher_url(self): + def is_transient_error(self): """ - The publisher's URL. + Check if the union tag is ``transient_error``. - :rtype: str + :rtype: bool """ - if self._publisher_url_present: - return self._publisher_url_value - else: - return None + return self._tag == 'transient_error' - @publisher_url.setter - def publisher_url(self, val): - if val is None: - del self.publisher_url - return - val = self._publisher_url_validator.validate(val) - self._publisher_url_value = val - self._publisher_url_present = True + def is_too_many_updates(self): + """ + Check if the union tag is ``too_many_updates``. - @publisher_url.deleter - def publisher_url(self): - self._publisher_url_value = None - self._publisher_url_present = False + :rtype: bool + """ + return self._tag == 'too_many_updates' - @property - def linked(self): + def is_unknown_error(self): """ - The time this application was linked. + Check if the union tag is ``unknown_error``. - :rtype: datetime.datetime + :rtype: bool """ - if self._linked_present: - return self._linked_value - else: - return None + return self._tag == 'unknown_error' - @linked.setter - def linked(self, val): - if val is None: - del self.linked - return - val = self._linked_validator.validate(val) - self._linked_value = val - self._linked_present = True + def is_rate_limited(self): + """ + Check if the union tag is ``rate_limited``. - @linked.deleter - def linked(self): - self._linked_value = None - self._linked_present = False + :rtype: bool + """ + return self._tag == 'rate_limited' - @property - def is_app_folder(self): + def is_other(self): """ - Whether the linked application uses a dedicated folder. + Check if the union tag is ``other``. :rtype: bool """ - if self._is_app_folder_present: - return self._is_app_folder_value - else: - raise AttributeError("missing required field 'is_app_folder'") - - @is_app_folder.setter - def is_app_folder(self, val): - val = self._is_app_folder_validator.validate(val) - self._is_app_folder_value = val - self._is_app_folder_present = True - - @is_app_folder.deleter - def is_app_folder(self): - self._is_app_folder_value = None - self._is_app_folder_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ApiApp, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ApiApp(app_id={!r}, app_name={!r}, is_app_folder={!r}, publisher={!r}, publisher_url={!r}, linked={!r})'.format( - self._app_id_value, - self._app_name_value, - self._is_app_folder_value, - self._publisher_value, - self._publisher_url_value, - self._linked_value, - ) - -ApiApp_validator = bv.Struct(ApiApp) - -class BaseDfbReport(bb.Struct): - """ - Base report structure. - - :ivar team.BaseDfbReport.start_date: First date present in the results as - 'YYYY-MM-DD' or None. - """ - - __slots__ = [ - '_start_date_value', - '_start_date_present', - ] + return self._tag == 'other' - _has_required_fields = True + def get_success(self): + """ + Describes a secondary email that was successfully added to a user. - def __init__(self, - start_date=None): - self._start_date_value = None - self._start_date_present = False - if start_date is not None: - self.start_date = start_date + Only call this if :meth:`is_success` is true. - @property - def start_date(self): + :rtype: secondary_emails.SecondaryEmail """ - First date present in the results as 'YYYY-MM-DD' or None. + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value - :rtype: str + def get_unavailable(self): """ - if self._start_date_present: - return self._start_date_value - else: - raise AttributeError("missing required field 'start_date'") + Secondary email is not available to be claimed by the user. - @start_date.setter - def start_date(self, val): - val = self._start_date_validator.validate(val) - self._start_date_value = val - self._start_date_present = True - - @start_date.deleter - def start_date(self): - self._start_date_value = None - self._start_date_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(BaseDfbReport, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'BaseDfbReport(start_date={!r})'.format( - self._start_date_value, - ) - -BaseDfbReport_validator = bv.Struct(BaseDfbReport) - -class BaseTeamFolderError(bb.Union): - """ - Base error that all errors for existing team folders should extend. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + Only call this if :meth:`is_unavailable` is true. - @classmethod - def access_error(cls, val): + :rtype: str """ - Create an instance of this class set to the ``access_error`` tag with - value ``val``. + if not self.is_unavailable(): + raise AttributeError("tag 'unavailable' not set") + return self._value - :param TeamFolderAccessError val: - :rtype: BaseTeamFolderError + def get_already_pending(self): """ - return cls('access_error', val) + Secondary email is already a pending email for the user. - @classmethod - def status_error(cls, val): - """ - Create an instance of this class set to the ``status_error`` tag with - value ``val``. + Only call this if :meth:`is_already_pending` is true. - :param TeamFolderInvalidStatusError val: - :rtype: BaseTeamFolderError + :rtype: str """ - return cls('status_error', val) + if not self.is_already_pending(): + raise AttributeError("tag 'already_pending' not set") + return self._value - @classmethod - def team_shared_dropbox_error(cls, val): + def get_already_owned_by_user(self): """ - Create an instance of this class set to the - ``team_shared_dropbox_error`` tag with value ``val``. + Secondary email is already a verified email for the user. - :param TeamFolderTeamSharedDropboxError val: - :rtype: BaseTeamFolderError - """ - return cls('team_shared_dropbox_error', val) + Only call this if :meth:`is_already_owned_by_user` is true. - def is_access_error(self): + :rtype: str """ - Check if the union tag is ``access_error``. + if not self.is_already_owned_by_user(): + raise AttributeError("tag 'already_owned_by_user' not set") + return self._value - :rtype: bool + def get_reached_limit(self): """ - return self._tag == 'access_error' + User already has the maximum number of secondary emails allowed. - def is_status_error(self): - """ - Check if the union tag is ``status_error``. + Only call this if :meth:`is_reached_limit` is true. - :rtype: bool + :rtype: str """ - return self._tag == 'status_error' + if not self.is_reached_limit(): + raise AttributeError("tag 'reached_limit' not set") + return self._value - def is_team_shared_dropbox_error(self): + def get_transient_error(self): """ - Check if the union tag is ``team_shared_dropbox_error``. + A transient error occurred. Please try again later. - :rtype: bool - """ - return self._tag == 'team_shared_dropbox_error' + Only call this if :meth:`is_transient_error` is true. - def is_other(self): + :rtype: str """ - Check if the union tag is ``other``. + if not self.is_transient_error(): + raise AttributeError("tag 'transient_error' not set") + return self._value - :rtype: bool + def get_too_many_updates(self): """ - return self._tag == 'other' + An error occurred due to conflicting updates. Please try again later. - def get_access_error(self): - """ - Only call this if :meth:`is_access_error` is true. + Only call this if :meth:`is_too_many_updates` is true. - :rtype: TeamFolderAccessError + :rtype: str """ - if not self.is_access_error(): - raise AttributeError("tag 'access_error' not set") + if not self.is_too_many_updates(): + raise AttributeError("tag 'too_many_updates' not set") return self._value - def get_status_error(self): + def get_unknown_error(self): """ - Only call this if :meth:`is_status_error` is true. + An unknown error occurred. - :rtype: TeamFolderInvalidStatusError + Only call this if :meth:`is_unknown_error` is true. + + :rtype: str """ - if not self.is_status_error(): - raise AttributeError("tag 'status_error' not set") + if not self.is_unknown_error(): + raise AttributeError("tag 'unknown_error' not set") return self._value - def get_team_shared_dropbox_error(self): + def get_rate_limited(self): """ - Only call this if :meth:`is_team_shared_dropbox_error` is true. + Too many emails are being sent to this email address. Please try again + later. - :rtype: TeamFolderTeamSharedDropboxError + Only call this if :meth:`is_rate_limited` is true. + + :rtype: str """ - if not self.is_team_shared_dropbox_error(): - raise AttributeError("tag 'team_shared_dropbox_error' not set") + if not self.is_rate_limited(): + raise AttributeError("tag 'rate_limited' not set") return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(BaseTeamFolderError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(AddSecondaryEmailResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'BaseTeamFolderError(%r, %r)' % (self._tag, self._value) + return 'AddSecondaryEmailResult(%r, %r)' % (self._tag, self._value) -BaseTeamFolderError_validator = bv.Union(BaseTeamFolderError) +AddSecondaryEmailResult_validator = bv.Union(AddSecondaryEmailResult) -class CustomQuotaError(bb.Union): +class AddSecondaryEmailsArg(bb.Struct): + """ + :ivar team.AddSecondaryEmailsArg.new_secondary_emails: List of users and + secondary emails to add. """ - Error returned when getting member custom quota. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + __slots__ = [ + '_new_secondary_emails_value', + '_new_secondary_emails_present', + ] - :ivar team.CustomQuotaError.too_many_users: A maximum of 1000 users can be - set for a single call. - """ + _has_required_fields = True - _catch_all = 'other' - # Attribute is overwritten below the class definition - too_many_users = None - # Attribute is overwritten below the class definition - other = None + def __init__(self, + new_secondary_emails=None): + self._new_secondary_emails_value = None + self._new_secondary_emails_present = False + if new_secondary_emails is not None: + self.new_secondary_emails = new_secondary_emails - def is_too_many_users(self): + @property + def new_secondary_emails(self): """ - Check if the union tag is ``too_many_users``. + List of users and secondary emails to add. - :rtype: bool + :rtype: list of [UserSecondaryEmailsArg] """ - return self._tag == 'too_many_users' + if self._new_secondary_emails_present: + return self._new_secondary_emails_value + else: + raise AttributeError("missing required field 'new_secondary_emails'") - def is_other(self): - """ - Check if the union tag is ``other``. + @new_secondary_emails.setter + def new_secondary_emails(self, val): + val = self._new_secondary_emails_validator.validate(val) + self._new_secondary_emails_value = val + self._new_secondary_emails_present = True - :rtype: bool - """ - return self._tag == 'other' + @new_secondary_emails.deleter + def new_secondary_emails(self): + self._new_secondary_emails_value = None + self._new_secondary_emails_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CustomQuotaError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(AddSecondaryEmailsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CustomQuotaError(%r, %r)' % (self._tag, self._value) + return 'AddSecondaryEmailsArg(new_secondary_emails={!r})'.format( + self._new_secondary_emails_value, + ) -CustomQuotaError_validator = bv.Union(CustomQuotaError) +AddSecondaryEmailsArg_validator = bv.Struct(AddSecondaryEmailsArg) -class CustomQuotaResult(bb.Union): +class AddSecondaryEmailsError(bb.Union): """ - User custom quota. + Error returned when adding secondary emails fails. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar UserCustomQuotaResult CustomQuotaResult.success: User's custom quota. - :ivar UserSelectorArg CustomQuotaResult.invalid_user: Invalid user (not in - team). + :ivar team.AddSecondaryEmailsError.secondary_emails_disabled: Secondary + emails are disabled for the team. + :ivar team.AddSecondaryEmailsError.too_many_emails: A maximum of 20 + secondary emails can be added in a single call. """ _catch_all = 'other' # Attribute is overwritten below the class definition + secondary_emails_disabled = None + # Attribute is overwritten below the class definition + too_many_emails = None + # Attribute is overwritten below the class definition other = None - @classmethod - def success(cls, val): - """ - Create an instance of this class set to the ``success`` tag with value - ``val``. - - :param UserCustomQuotaResult val: - :rtype: CustomQuotaResult - """ - return cls('success', val) - - @classmethod - def invalid_user(cls, val): - """ - Create an instance of this class set to the ``invalid_user`` tag with - value ``val``. - - :param UserSelectorArg val: - :rtype: CustomQuotaResult + def is_secondary_emails_disabled(self): """ - return cls('invalid_user', val) - - def is_success(self): - """ - Check if the union tag is ``success``. + Check if the union tag is ``secondary_emails_disabled``. :rtype: bool """ - return self._tag == 'success' + return self._tag == 'secondary_emails_disabled' - def is_invalid_user(self): + def is_too_many_emails(self): """ - Check if the union tag is ``invalid_user``. + Check if the union tag is ``too_many_emails``. :rtype: bool """ - return self._tag == 'invalid_user' + return self._tag == 'too_many_emails' def is_other(self): """ @@ -964,455 +831,482 @@ def is_other(self): """ return self._tag == 'other' - def get_success(self): - """ - User's custom quota. - - Only call this if :meth:`is_success` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(AddSecondaryEmailsError, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: UserCustomQuotaResult - """ - if not self.is_success(): - raise AttributeError("tag 'success' not set") - return self._value + def __repr__(self): + return 'AddSecondaryEmailsError(%r, %r)' % (self._tag, self._value) - def get_invalid_user(self): - """ - Invalid user (not in team). +AddSecondaryEmailsError_validator = bv.Union(AddSecondaryEmailsError) - Only call this if :meth:`is_invalid_user` is true. - - :rtype: UserSelectorArg - """ - if not self.is_invalid_user(): - raise AttributeError("tag 'invalid_user' not set") - return self._value - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CustomQuotaResult, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'CustomQuotaResult(%r, %r)' % (self._tag, self._value) - -CustomQuotaResult_validator = bv.Union(CustomQuotaResult) - -class CustomQuotaUsersArg(bb.Struct): +class AddSecondaryEmailsResult(bb.Struct): """ - :ivar team.CustomQuotaUsersArg.users: List of users. + :ivar team.AddSecondaryEmailsResult.results: List of users and secondary + email results. """ __slots__ = [ - '_users_value', - '_users_present', + '_results_value', + '_results_present', ] _has_required_fields = True def __init__(self, - users=None): - self._users_value = None - self._users_present = False - if users is not None: - self.users = users + results=None): + self._results_value = None + self._results_present = False + if results is not None: + self.results = results @property - def users(self): + def results(self): """ - List of users. + List of users and secondary email results. - :rtype: list of [UserSelectorArg] + :rtype: list of [UserAddResult] """ - if self._users_present: - return self._users_value + if self._results_present: + return self._results_value else: - raise AttributeError("missing required field 'users'") + raise AttributeError("missing required field 'results'") - @users.setter - def users(self, val): - val = self._users_validator.validate(val) - self._users_value = val - self._users_present = True + @results.setter + def results(self, val): + val = self._results_validator.validate(val) + self._results_value = val + self._results_present = True - @users.deleter - def users(self): - self._users_value = None - self._users_present = False + @results.deleter + def results(self): + self._results_value = None + self._results_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CustomQuotaUsersArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(AddSecondaryEmailsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CustomQuotaUsersArg(users={!r})'.format( - self._users_value, + return 'AddSecondaryEmailsResult(results={!r})'.format( + self._results_value, ) -CustomQuotaUsersArg_validator = bv.Struct(CustomQuotaUsersArg) - -class DateRange(bb.Struct): - """ - Input arguments that can be provided for most reports. +AddSecondaryEmailsResult_validator = bv.Struct(AddSecondaryEmailsResult) - :ivar team.DateRange.start_date: Optional starting date (inclusive). - :ivar team.DateRange.end_date: Optional ending date (exclusive). +class AdminTier(bb.Union): """ + Describes which team-related admin permissions a user has. - __slots__ = [ - '_start_date_value', - '_start_date_present', - '_end_date_value', - '_end_date_present', - ] + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - _has_required_fields = False + :ivar team.AdminTier.team_admin: User is an administrator of the team - has + all permissions. + :ivar team.AdminTier.user_management_admin: User can do most user + provisioning, de-provisioning and management. + :ivar team.AdminTier.support_admin: User can do a limited set of common + support tasks for existing users. + :ivar team.AdminTier.member_only: User is not an admin of the team. + """ - def __init__(self, - start_date=None, - end_date=None): - self._start_date_value = None - self._start_date_present = False - self._end_date_value = None - self._end_date_present = False - if start_date is not None: - self.start_date = start_date - if end_date is not None: - self.end_date = end_date + _catch_all = None + # Attribute is overwritten below the class definition + team_admin = None + # Attribute is overwritten below the class definition + user_management_admin = None + # Attribute is overwritten below the class definition + support_admin = None + # Attribute is overwritten below the class definition + member_only = None - @property - def start_date(self): + def is_team_admin(self): """ - Optional starting date (inclusive). + Check if the union tag is ``team_admin``. - :rtype: datetime.datetime + :rtype: bool """ - if self._start_date_present: - return self._start_date_value - else: - return None - - @start_date.setter - def start_date(self, val): - if val is None: - del self.start_date - return - val = self._start_date_validator.validate(val) - self._start_date_value = val - self._start_date_present = True - - @start_date.deleter - def start_date(self): - self._start_date_value = None - self._start_date_present = False + return self._tag == 'team_admin' - @property - def end_date(self): + def is_user_management_admin(self): """ - Optional ending date (exclusive). + Check if the union tag is ``user_management_admin``. - :rtype: datetime.datetime + :rtype: bool """ - if self._end_date_present: - return self._end_date_value - else: - return None - - @end_date.setter - def end_date(self, val): - if val is None: - del self.end_date - return - val = self._end_date_validator.validate(val) - self._end_date_value = val - self._end_date_present = True - - @end_date.deleter - def end_date(self): - self._end_date_value = None - self._end_date_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DateRange, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DateRange(start_date={!r}, end_date={!r})'.format( - self._start_date_value, - self._end_date_value, - ) - -DateRange_validator = bv.Struct(DateRange) - -class DateRangeError(bb.Union): - """ - Errors that can originate from problems in input arguments to reports. + return self._tag == 'user_management_admin' - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + def is_support_admin(self): + """ + Check if the union tag is ``support_admin``. - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + :rtype: bool + """ + return self._tag == 'support_admin' - def is_other(self): + def is_member_only(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``member_only``. :rtype: bool """ - return self._tag == 'other' + return self._tag == 'member_only' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DateRangeError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(AdminTier, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DateRangeError(%r, %r)' % (self._tag, self._value) + return 'AdminTier(%r, %r)' % (self._tag, self._value) -DateRangeError_validator = bv.Union(DateRangeError) +AdminTier_validator = bv.Union(AdminTier) -class DesktopClientSession(DeviceSession): +class ApiApp(bb.Struct): """ - Information about linked Dropbox desktop client sessions. + Information on linked third party applications. - :ivar team.DesktopClientSession.host_name: Name of the hosting desktop. - :ivar team.DesktopClientSession.client_type: The Dropbox desktop client - type. - :ivar team.DesktopClientSession.client_version: The Dropbox client version. - :ivar team.DesktopClientSession.platform: Information on the hosting - platform. - :ivar team.DesktopClientSession.is_delete_on_unlink_supported: Whether it's - possible to delete all of the account files upon unlinking. + :ivar team.ApiApp.app_id: The application unique id. + :ivar team.ApiApp.app_name: The application name. + :ivar team.ApiApp.publisher: The application publisher name. + :ivar team.ApiApp.publisher_url: The publisher's URL. + :ivar team.ApiApp.linked: The time this application was linked. + :ivar team.ApiApp.is_app_folder: Whether the linked application uses a + dedicated folder. """ __slots__ = [ - '_host_name_value', - '_host_name_present', - '_client_type_value', - '_client_type_present', - '_client_version_value', - '_client_version_present', - '_platform_value', - '_platform_present', - '_is_delete_on_unlink_supported_value', - '_is_delete_on_unlink_supported_present', + '_app_id_value', + '_app_id_present', + '_app_name_value', + '_app_name_present', + '_publisher_value', + '_publisher_present', + '_publisher_url_value', + '_publisher_url_present', + '_linked_value', + '_linked_present', + '_is_app_folder_value', + '_is_app_folder_present', ] _has_required_fields = True def __init__(self, - session_id=None, - host_name=None, - client_type=None, - client_version=None, - platform=None, - is_delete_on_unlink_supported=None, - ip_address=None, - country=None, - created=None, - updated=None): - super(DesktopClientSession, self).__init__(session_id, - ip_address, - country, - created, - updated) - self._host_name_value = None - self._host_name_present = False - self._client_type_value = None - self._client_type_present = False - self._client_version_value = None - self._client_version_present = False - self._platform_value = None - self._platform_present = False - self._is_delete_on_unlink_supported_value = None - self._is_delete_on_unlink_supported_present = False - if host_name is not None: - self.host_name = host_name - if client_type is not None: - self.client_type = client_type - if client_version is not None: - self.client_version = client_version - if platform is not None: - self.platform = platform - if is_delete_on_unlink_supported is not None: - self.is_delete_on_unlink_supported = is_delete_on_unlink_supported + app_id=None, + app_name=None, + is_app_folder=None, + publisher=None, + publisher_url=None, + linked=None): + self._app_id_value = None + self._app_id_present = False + self._app_name_value = None + self._app_name_present = False + self._publisher_value = None + self._publisher_present = False + self._publisher_url_value = None + self._publisher_url_present = False + self._linked_value = None + self._linked_present = False + self._is_app_folder_value = None + self._is_app_folder_present = False + if app_id is not None: + self.app_id = app_id + if app_name is not None: + self.app_name = app_name + if publisher is not None: + self.publisher = publisher + if publisher_url is not None: + self.publisher_url = publisher_url + if linked is not None: + self.linked = linked + if is_app_folder is not None: + self.is_app_folder = is_app_folder @property - def host_name(self): + def app_id(self): """ - Name of the hosting desktop. + The application unique id. :rtype: str """ - if self._host_name_present: - return self._host_name_value + if self._app_id_present: + return self._app_id_value else: - raise AttributeError("missing required field 'host_name'") + raise AttributeError("missing required field 'app_id'") - @host_name.setter - def host_name(self, val): - val = self._host_name_validator.validate(val) - self._host_name_value = val - self._host_name_present = True + @app_id.setter + def app_id(self, val): + val = self._app_id_validator.validate(val) + self._app_id_value = val + self._app_id_present = True - @host_name.deleter - def host_name(self): - self._host_name_value = None - self._host_name_present = False + @app_id.deleter + def app_id(self): + self._app_id_value = None + self._app_id_present = False @property - def client_type(self): + def app_name(self): """ - The Dropbox desktop client type. + The application name. - :rtype: DesktopPlatform + :rtype: str """ - if self._client_type_present: - return self._client_type_value + if self._app_name_present: + return self._app_name_value else: - raise AttributeError("missing required field 'client_type'") + raise AttributeError("missing required field 'app_name'") - @client_type.setter - def client_type(self, val): - self._client_type_validator.validate_type_only(val) - self._client_type_value = val - self._client_type_present = True + @app_name.setter + def app_name(self, val): + val = self._app_name_validator.validate(val) + self._app_name_value = val + self._app_name_present = True - @client_type.deleter - def client_type(self): - self._client_type_value = None - self._client_type_present = False + @app_name.deleter + def app_name(self): + self._app_name_value = None + self._app_name_present = False @property - def client_version(self): + def publisher(self): """ - The Dropbox client version. + The application publisher name. :rtype: str """ - if self._client_version_present: - return self._client_version_value + if self._publisher_present: + return self._publisher_value else: - raise AttributeError("missing required field 'client_version'") + return None - @client_version.setter - def client_version(self, val): - val = self._client_version_validator.validate(val) - self._client_version_value = val - self._client_version_present = True + @publisher.setter + def publisher(self, val): + if val is None: + del self.publisher + return + val = self._publisher_validator.validate(val) + self._publisher_value = val + self._publisher_present = True - @client_version.deleter - def client_version(self): - self._client_version_value = None - self._client_version_present = False + @publisher.deleter + def publisher(self): + self._publisher_value = None + self._publisher_present = False @property - def platform(self): + def publisher_url(self): """ - Information on the hosting platform. + The publisher's URL. :rtype: str """ - if self._platform_present: - return self._platform_value + if self._publisher_url_present: + return self._publisher_url_value else: - raise AttributeError("missing required field 'platform'") + return None - @platform.setter - def platform(self, val): - val = self._platform_validator.validate(val) - self._platform_value = val - self._platform_present = True + @publisher_url.setter + def publisher_url(self, val): + if val is None: + del self.publisher_url + return + val = self._publisher_url_validator.validate(val) + self._publisher_url_value = val + self._publisher_url_present = True - @platform.deleter - def platform(self): - self._platform_value = None - self._platform_present = False + @publisher_url.deleter + def publisher_url(self): + self._publisher_url_value = None + self._publisher_url_present = False @property - def is_delete_on_unlink_supported(self): + def linked(self): """ - Whether it's possible to delete all of the account files upon unlinking. + The time this application was linked. + + :rtype: datetime.datetime + """ + if self._linked_present: + return self._linked_value + else: + return None + + @linked.setter + def linked(self, val): + if val is None: + del self.linked + return + val = self._linked_validator.validate(val) + self._linked_value = val + self._linked_present = True + + @linked.deleter + def linked(self): + self._linked_value = None + self._linked_present = False + + @property + def is_app_folder(self): + """ + Whether the linked application uses a dedicated folder. :rtype: bool """ - if self._is_delete_on_unlink_supported_present: - return self._is_delete_on_unlink_supported_value + if self._is_app_folder_present: + return self._is_app_folder_value else: - raise AttributeError("missing required field 'is_delete_on_unlink_supported'") + raise AttributeError("missing required field 'is_app_folder'") - @is_delete_on_unlink_supported.setter - def is_delete_on_unlink_supported(self, val): - val = self._is_delete_on_unlink_supported_validator.validate(val) - self._is_delete_on_unlink_supported_value = val - self._is_delete_on_unlink_supported_present = True + @is_app_folder.setter + def is_app_folder(self, val): + val = self._is_app_folder_validator.validate(val) + self._is_app_folder_value = val + self._is_app_folder_present = True - @is_delete_on_unlink_supported.deleter - def is_delete_on_unlink_supported(self): - self._is_delete_on_unlink_supported_value = None - self._is_delete_on_unlink_supported_present = False + @is_app_folder.deleter + def is_app_folder(self): + self._is_app_folder_value = None + self._is_app_folder_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DesktopClientSession, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ApiApp, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DesktopClientSession(session_id={!r}, host_name={!r}, client_type={!r}, client_version={!r}, platform={!r}, is_delete_on_unlink_supported={!r}, ip_address={!r}, country={!r}, created={!r}, updated={!r})'.format( - self._session_id_value, - self._host_name_value, - self._client_type_value, - self._client_version_value, - self._platform_value, - self._is_delete_on_unlink_supported_value, - self._ip_address_value, - self._country_value, - self._created_value, - self._updated_value, + return 'ApiApp(app_id={!r}, app_name={!r}, is_app_folder={!r}, publisher={!r}, publisher_url={!r}, linked={!r})'.format( + self._app_id_value, + self._app_name_value, + self._is_app_folder_value, + self._publisher_value, + self._publisher_url_value, + self._linked_value, ) -DesktopClientSession_validator = bv.Struct(DesktopClientSession) +ApiApp_validator = bv.Struct(ApiApp) -class DesktopPlatform(bb.Union): +class BaseDfbReport(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Base report structure. - :ivar team.DesktopPlatform.windows: Official Windows Dropbox desktop client. - :ivar team.DesktopPlatform.mac: Official Mac Dropbox desktop client. - :ivar team.DesktopPlatform.linux: Official Linux Dropbox desktop client. + :ivar team.BaseDfbReport.start_date: First date present in the results as + 'YYYY-MM-DD' or None. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - windows = None - # Attribute is overwritten below the class definition - mac = None - # Attribute is overwritten below the class definition - linux = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_start_date_value', + '_start_date_present', + ] - def is_windows(self): - """ - Check if the union tag is ``windows``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'windows' + def __init__(self, + start_date=None): + self._start_date_value = None + self._start_date_present = False + if start_date is not None: + self.start_date = start_date - def is_mac(self): + @property + def start_date(self): """ - Check if the union tag is ``mac``. + First date present in the results as 'YYYY-MM-DD' or None. + + :rtype: str + """ + if self._start_date_present: + return self._start_date_value + else: + raise AttributeError("missing required field 'start_date'") + + @start_date.setter + def start_date(self, val): + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True + + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(BaseDfbReport, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'BaseDfbReport(start_date={!r})'.format( + self._start_date_value, + ) + +BaseDfbReport_validator = bv.Struct(BaseDfbReport) + +class BaseTeamFolderError(bb.Union): + """ + Base error that all errors for existing team folders should extend. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def access_error(cls, val): + """ + Create an instance of this class set to the ``access_error`` tag with + value ``val``. + + :param TeamFolderAccessError val: + :rtype: BaseTeamFolderError + """ + return cls('access_error', val) + + @classmethod + def status_error(cls, val): + """ + Create an instance of this class set to the ``status_error`` tag with + value ``val``. + + :param TeamFolderInvalidStatusError val: + :rtype: BaseTeamFolderError + """ + return cls('status_error', val) + + @classmethod + def team_shared_dropbox_error(cls, val): + """ + Create an instance of this class set to the + ``team_shared_dropbox_error`` tag with value ``val``. + + :param TeamFolderTeamSharedDropboxError val: + :rtype: BaseTeamFolderError + """ + return cls('team_shared_dropbox_error', val) + + def is_access_error(self): + """ + Check if the union tag is ``access_error``. :rtype: bool """ - return self._tag == 'mac' + return self._tag == 'access_error' - def is_linux(self): + def is_status_error(self): """ - Check if the union tag is ``linux``. + Check if the union tag is ``status_error``. :rtype: bool """ - return self._tag == 'linux' + return self._tag == 'status_error' + + def is_team_shared_dropbox_error(self): + """ + Check if the union tag is ``team_shared_dropbox_error``. + + :rtype: bool + """ + return self._tag == 'team_shared_dropbox_error' def is_other(self): """ @@ -1422,490 +1316,341 @@ def is_other(self): """ return self._tag == 'other' + def get_access_error(self): + """ + Only call this if :meth:`is_access_error` is true. + + :rtype: TeamFolderAccessError + """ + if not self.is_access_error(): + raise AttributeError("tag 'access_error' not set") + return self._value + + def get_status_error(self): + """ + Only call this if :meth:`is_status_error` is true. + + :rtype: TeamFolderInvalidStatusError + """ + if not self.is_status_error(): + raise AttributeError("tag 'status_error' not set") + return self._value + + def get_team_shared_dropbox_error(self): + """ + Only call this if :meth:`is_team_shared_dropbox_error` is true. + + :rtype: TeamFolderTeamSharedDropboxError + """ + if not self.is_team_shared_dropbox_error(): + raise AttributeError("tag 'team_shared_dropbox_error' not set") + return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DesktopPlatform, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BaseTeamFolderError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DesktopPlatform(%r, %r)' % (self._tag, self._value) + return 'BaseTeamFolderError(%r, %r)' % (self._tag, self._value) -DesktopPlatform_validator = bv.Union(DesktopPlatform) +BaseTeamFolderError_validator = bv.Union(BaseTeamFolderError) -class DeviceSessionArg(bb.Struct): - """ - :ivar team.DeviceSessionArg.session_id: The session id. - :ivar team.DeviceSessionArg.team_member_id: The unique id of the member - owning the device. +class CustomQuotaError(bb.Union): """ + Error returned when getting member custom quota. - __slots__ = [ - '_session_id_value', - '_session_id_present', - '_team_member_id_value', - '_team_member_id_present', - ] + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - _has_required_fields = True + :ivar team.CustomQuotaError.too_many_users: A maximum of 1000 users can be + set for a single call. + """ - def __init__(self, - session_id=None, - team_member_id=None): - self._session_id_value = None - self._session_id_present = False - self._team_member_id_value = None - self._team_member_id_present = False - if session_id is not None: - self.session_id = session_id - if team_member_id is not None: - self.team_member_id = team_member_id + _catch_all = 'other' + # Attribute is overwritten below the class definition + too_many_users = None + # Attribute is overwritten below the class definition + other = None - @property - def session_id(self): + def is_too_many_users(self): """ - The session id. + Check if the union tag is ``too_many_users``. - :rtype: str + :rtype: bool """ - if self._session_id_present: - return self._session_id_value - else: - raise AttributeError("missing required field 'session_id'") - - @session_id.setter - def session_id(self, val): - val = self._session_id_validator.validate(val) - self._session_id_value = val - self._session_id_present = True - - @session_id.deleter - def session_id(self): - self._session_id_value = None - self._session_id_present = False + return self._tag == 'too_many_users' - @property - def team_member_id(self): + def is_other(self): """ - The unique id of the member owning the device. + Check if the union tag is ``other``. - :rtype: str + :rtype: bool """ - if self._team_member_id_present: - return self._team_member_id_value - else: - raise AttributeError("missing required field 'team_member_id'") - - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True - - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceSessionArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CustomQuotaError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceSessionArg(session_id={!r}, team_member_id={!r})'.format( - self._session_id_value, - self._team_member_id_value, - ) - -DeviceSessionArg_validator = bv.Struct(DeviceSessionArg) + return 'CustomQuotaError(%r, %r)' % (self._tag, self._value) -class DevicesActive(bb.Struct): - """ - Each of the items is an array of values, one value per day. The value is the - number of devices active within a time window, ending with that day. If - there is no data for a day, then the value will be None. +CustomQuotaError_validator = bv.Union(CustomQuotaError) - :ivar team.DevicesActive.windows: Array of number of linked windows - (desktop) clients with activity. - :ivar team.DevicesActive.macos: Array of number of linked mac (desktop) - clients with activity. - :ivar team.DevicesActive.linux: Array of number of linked linus (desktop) - clients with activity. - :ivar team.DevicesActive.ios: Array of number of linked ios devices with - activity. - :ivar team.DevicesActive.android: Array of number of linked android devices - with activity. - :ivar team.DevicesActive.other: Array of number of other linked devices - (blackberry, windows phone, etc) with activity. - :ivar team.DevicesActive.total: Array of total number of linked clients with - activity. +class CustomQuotaResult(bb.Union): """ + User custom quota. - __slots__ = [ - '_windows_value', - '_windows_present', - '_macos_value', - '_macos_present', - '_linux_value', - '_linux_present', - '_ios_value', - '_ios_present', - '_android_value', - '_android_present', - '_other_value', - '_other_present', - '_total_value', - '_total_present', - ] + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - _has_required_fields = True + :ivar UserCustomQuotaResult CustomQuotaResult.success: User's custom quota. + :ivar UserSelectorArg CustomQuotaResult.invalid_user: Invalid user (not in + team). + """ - def __init__(self, - windows=None, - macos=None, - linux=None, - ios=None, - android=None, - other=None, - total=None): - self._windows_value = None - self._windows_present = False - self._macos_value = None - self._macos_present = False - self._linux_value = None - self._linux_present = False - self._ios_value = None - self._ios_present = False - self._android_value = None - self._android_present = False - self._other_value = None - self._other_present = False - self._total_value = None - self._total_present = False - if windows is not None: - self.windows = windows - if macos is not None: - self.macos = macos - if linux is not None: - self.linux = linux - if ios is not None: - self.ios = ios - if android is not None: - self.android = android - if other is not None: - self.other = other - if total is not None: - self.total = total + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None - @property - def windows(self): + @classmethod + def success(cls, val): """ - Array of number of linked windows (desktop) clients with activity. + Create an instance of this class set to the ``success`` tag with value + ``val``. - :rtype: list of [Optional[int]] + :param UserCustomQuotaResult val: + :rtype: CustomQuotaResult """ - if self._windows_present: - return self._windows_value - else: - raise AttributeError("missing required field 'windows'") + return cls('success', val) - @windows.setter - def windows(self, val): - val = self._windows_validator.validate(val) - self._windows_value = val - self._windows_present = True + @classmethod + def invalid_user(cls, val): + """ + Create an instance of this class set to the ``invalid_user`` tag with + value ``val``. - @windows.deleter - def windows(self): - self._windows_value = None - self._windows_present = False + :param UserSelectorArg val: + :rtype: CustomQuotaResult + """ + return cls('invalid_user', val) - @property - def macos(self): + def is_success(self): """ - Array of number of linked mac (desktop) clients with activity. + Check if the union tag is ``success``. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._macos_present: - return self._macos_value - else: - raise AttributeError("missing required field 'macos'") + return self._tag == 'success' - @macos.setter - def macos(self, val): - val = self._macos_validator.validate(val) - self._macos_value = val - self._macos_present = True + def is_invalid_user(self): + """ + Check if the union tag is ``invalid_user``. - @macos.deleter - def macos(self): - self._macos_value = None - self._macos_present = False + :rtype: bool + """ + return self._tag == 'invalid_user' - @property - def linux(self): + def is_other(self): """ - Array of number of linked linus (desktop) clients with activity. + Check if the union tag is ``other``. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._linux_present: - return self._linux_value - else: - raise AttributeError("missing required field 'linux'") + return self._tag == 'other' - @linux.setter - def linux(self, val): - val = self._linux_validator.validate(val) - self._linux_value = val - self._linux_present = True + def get_success(self): + """ + User's custom quota. - @linux.deleter - def linux(self): - self._linux_value = None - self._linux_present = False + Only call this if :meth:`is_success` is true. - @property - def ios(self): + :rtype: UserCustomQuotaResult """ - Array of number of linked ios devices with activity. + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value - :rtype: list of [Optional[int]] + def get_invalid_user(self): """ - if self._ios_present: - return self._ios_value - else: - raise AttributeError("missing required field 'ios'") - - @ios.setter - def ios(self, val): - val = self._ios_validator.validate(val) - self._ios_value = val - self._ios_present = True + Invalid user (not in team). - @ios.deleter - def ios(self): - self._ios_value = None - self._ios_present = False + Only call this if :meth:`is_invalid_user` is true. - @property - def android(self): + :rtype: UserSelectorArg """ - Array of number of linked android devices with activity. + if not self.is_invalid_user(): + raise AttributeError("tag 'invalid_user' not set") + return self._value - :rtype: list of [Optional[int]] - """ - if self._android_present: - return self._android_value - else: - raise AttributeError("missing required field 'android'") + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(CustomQuotaResult, self)._process_custom_annotations(annotation_type, field_path, processor) - @android.setter - def android(self, val): - val = self._android_validator.validate(val) - self._android_value = val - self._android_present = True + def __repr__(self): + return 'CustomQuotaResult(%r, %r)' % (self._tag, self._value) - @android.deleter - def android(self): - self._android_value = None - self._android_present = False +CustomQuotaResult_validator = bv.Union(CustomQuotaResult) - @property - def other(self): - """ - Array of number of other linked devices (blackberry, windows phone, etc) - with activity. +class CustomQuotaUsersArg(bb.Struct): + """ + :ivar team.CustomQuotaUsersArg.users: List of users. + """ - :rtype: list of [Optional[int]] - """ - if self._other_present: - return self._other_value - else: - raise AttributeError("missing required field 'other'") + __slots__ = [ + '_users_value', + '_users_present', + ] - @other.setter - def other(self, val): - val = self._other_validator.validate(val) - self._other_value = val - self._other_present = True + _has_required_fields = True - @other.deleter - def other(self): - self._other_value = None - self._other_present = False + def __init__(self, + users=None): + self._users_value = None + self._users_present = False + if users is not None: + self.users = users @property - def total(self): + def users(self): """ - Array of total number of linked clients with activity. + List of users. - :rtype: list of [Optional[int]] + :rtype: list of [UserSelectorArg] """ - if self._total_present: - return self._total_value + if self._users_present: + return self._users_value else: - raise AttributeError("missing required field 'total'") + raise AttributeError("missing required field 'users'") - @total.setter - def total(self, val): - val = self._total_validator.validate(val) - self._total_value = val - self._total_present = True + @users.setter + def users(self, val): + val = self._users_validator.validate(val) + self._users_value = val + self._users_present = True - @total.deleter - def total(self): - self._total_value = None - self._total_present = False + @users.deleter + def users(self): + self._users_value = None + self._users_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DevicesActive, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CustomQuotaUsersArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DevicesActive(windows={!r}, macos={!r}, linux={!r}, ios={!r}, android={!r}, other={!r}, total={!r})'.format( - self._windows_value, - self._macos_value, - self._linux_value, - self._ios_value, - self._android_value, - self._other_value, - self._total_value, + return 'CustomQuotaUsersArg(users={!r})'.format( + self._users_value, ) -DevicesActive_validator = bv.Struct(DevicesActive) +CustomQuotaUsersArg_validator = bv.Struct(CustomQuotaUsersArg) -class ExcludedUsersListArg(bb.Struct): +class DateRange(bb.Struct): """ - Excluded users list argument. + Input arguments that can be provided for most reports. - :ivar team.ExcludedUsersListArg.limit: Number of results to return per call. + :ivar team.DateRange.start_date: Optional starting date (inclusive). If + start_date is None or too long ago, this field will be set to 6 months + ago. + :ivar team.DateRange.end_date: Optional ending date (exclusive). """ __slots__ = [ - '_limit_value', - '_limit_present', + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', ] _has_required_fields = False def __init__(self, - limit=None): - self._limit_value = None - self._limit_present = False - if limit is not None: - self.limit = limit + start_date=None, + end_date=None): + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date @property - def limit(self): + def start_date(self): """ - Number of results to return per call. + Optional starting date (inclusive). If start_date is None or too long + ago, this field will be set to 6 months ago. - :rtype: int + :rtype: datetime.datetime """ - if self._limit_present: - return self._limit_value + if self._start_date_present: + return self._start_date_value else: - return 1000 - - @limit.setter - def limit(self, val): - val = self._limit_validator.validate(val) - self._limit_value = val - self._limit_present = True - - @limit.deleter - def limit(self): - self._limit_value = None - self._limit_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersListArg, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ExcludedUsersListArg(limit={!r})'.format( - self._limit_value, - ) - -ExcludedUsersListArg_validator = bv.Struct(ExcludedUsersListArg) - -class ExcludedUsersListContinueArg(bb.Struct): - """ - Excluded users list continue argument. - - :ivar team.ExcludedUsersListContinueArg.cursor: Indicates from what point to - get the next set of users. - """ - - __slots__ = [ - '_cursor_value', - '_cursor_present', - ] + return None - _has_required_fields = True + @start_date.setter + def start_date(self, val): + if val is None: + del self.start_date + return + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True - def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False @property - def cursor(self): + def end_date(self): """ - Indicates from what point to get the next set of users. + Optional ending date (exclusive). - :rtype: str + :rtype: datetime.datetime """ - if self._cursor_present: - return self._cursor_value + if self._end_date_present: + return self._end_date_value else: - raise AttributeError("missing required field 'cursor'") + return None - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @end_date.setter + def end_date(self, val): + if val is None: + del self.end_date + return + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DateRange, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExcludedUsersListContinueArg(cursor={!r})'.format( - self._cursor_value, + return 'DateRange(start_date={!r}, end_date={!r})'.format( + self._start_date_value, + self._end_date_value, ) -ExcludedUsersListContinueArg_validator = bv.Struct(ExcludedUsersListContinueArg) +DateRange_validator = bv.Struct(DateRange) -class ExcludedUsersListContinueError(bb.Union): +class DateRangeError(bb.Union): """ - Excluded users list continue error. + Errors that can originate from problems in input arguments to reports. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - - :ivar team.ExcludedUsersListContinueError.invalid_cursor: The cursor is - invalid. """ _catch_all = 'other' # Attribute is overwritten below the class definition - invalid_cursor = None - # Attribute is overwritten below the class definition other = None - def is_invalid_cursor(self): - """ - Check if the union tag is ``invalid_cursor``. - - :rtype: bool - """ - return self._tag == 'invalid_cursor' - def is_other(self): """ Check if the union tag is ``other``. @@ -1915,37 +1660,92 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DateRangeError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExcludedUsersListContinueError(%r, %r)' % (self._tag, self._value) + return 'DateRangeError(%r, %r)' % (self._tag, self._value) -ExcludedUsersListContinueError_validator = bv.Union(ExcludedUsersListContinueError) +DateRangeError_validator = bv.Union(DateRangeError) -class ExcludedUsersListError(bb.Union): +class DeleteSecondaryEmailResult(bb.Union): """ - Excluded users list error. + Result of trying to delete a secondary email address. 'success' is the only + value indicating that a secondary email was successfully deleted. The other + values explain the type of error that occurred, and include the email for + which the error occured. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.ExcludedUsersListError.list_error: An error occurred. + :ivar str team.DeleteSecondaryEmailResult.success: The secondary email was + successfully deleted. + :ivar str team.DeleteSecondaryEmailResult.not_found: The email address was + not found for the user. + :ivar str team.DeleteSecondaryEmailResult.cannot_remove_primary: The email + address is the primary email address of the user, and cannot be removed. """ _catch_all = 'other' # Attribute is overwritten below the class definition - list_error = None - # Attribute is overwritten below the class definition other = None - def is_list_error(self): + @classmethod + def success(cls, val): """ - Check if the union tag is ``list_error``. + Create an instance of this class set to the ``success`` tag with value + ``val``. + + :param str val: + :rtype: DeleteSecondaryEmailResult + """ + return cls('success', val) + + @classmethod + def not_found(cls, val): + """ + Create an instance of this class set to the ``not_found`` tag with value + ``val``. + + :param str val: + :rtype: DeleteSecondaryEmailResult + """ + return cls('not_found', val) + + @classmethod + def cannot_remove_primary(cls, val): + """ + Create an instance of this class set to the ``cannot_remove_primary`` + tag with value ``val``. + + :param str val: + :rtype: DeleteSecondaryEmailResult + """ + return cls('cannot_remove_primary', val) + + def is_success(self): + """ + Check if the union tag is ``success``. :rtype: bool """ - return self._tag == 'list_error' + return self._tag == 'success' + + def is_not_found(self): + """ + Check if the union tag is ``not_found``. + + :rtype: bool + """ + return self._tag == 'not_found' + + def is_cannot_remove_primary(self): + """ + Check if the union tag is ``cannot_remove_primary``. + + :rtype: bool + """ + return self._tag == 'cannot_remove_primary' def is_other(self): """ @@ -1955,410 +1755,395 @@ def is_other(self): """ return self._tag == 'other' + def get_success(self): + """ + The secondary email was successfully deleted. + + Only call this if :meth:`is_success` is true. + + :rtype: str + """ + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value + + def get_not_found(self): + """ + The email address was not found for the user. + + Only call this if :meth:`is_not_found` is true. + + :rtype: str + """ + if not self.is_not_found(): + raise AttributeError("tag 'not_found' not set") + return self._value + + def get_cannot_remove_primary(self): + """ + The email address is the primary email address of the user, and cannot + be removed. + + Only call this if :meth:`is_cannot_remove_primary` is true. + + :rtype: str + """ + if not self.is_cannot_remove_primary(): + raise AttributeError("tag 'cannot_remove_primary' not set") + return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersListError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeleteSecondaryEmailResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExcludedUsersListError(%r, %r)' % (self._tag, self._value) + return 'DeleteSecondaryEmailResult(%r, %r)' % (self._tag, self._value) -ExcludedUsersListError_validator = bv.Union(ExcludedUsersListError) +DeleteSecondaryEmailResult_validator = bv.Union(DeleteSecondaryEmailResult) -class ExcludedUsersListResult(bb.Struct): - """ - Excluded users list result. - - :ivar team.ExcludedUsersListResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` - to obtain additional excluded users. - :ivar team.ExcludedUsersListResult.has_more: Is true if there are additional - excluded users that have not been returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` - can retrieve them. +class DeleteSecondaryEmailsArg(bb.Struct): + """ + :ivar team.DeleteSecondaryEmailsArg.emails_to_delete: List of users and + their secondary emails to delete. """ __slots__ = [ - '_users_value', - '_users_present', - '_cursor_value', - '_cursor_present', - '_has_more_value', - '_has_more_present', + '_emails_to_delete_value', + '_emails_to_delete_present', ] _has_required_fields = True def __init__(self, - users=None, - has_more=None, - cursor=None): - self._users_value = None - self._users_present = False - self._cursor_value = None - self._cursor_present = False - self._has_more_value = None - self._has_more_present = False - if users is not None: - self.users = users - if cursor is not None: - self.cursor = cursor - if has_more is not None: - self.has_more = has_more - - @property - def users(self): - """ - :rtype: list of [MemberProfile] - """ - if self._users_present: - return self._users_value - else: - raise AttributeError("missing required field 'users'") - - @users.setter - def users(self, val): - val = self._users_validator.validate(val) - self._users_value = val - self._users_present = True - - @users.deleter - def users(self): - self._users_value = None - self._users_present = False - - @property - def cursor(self): - """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` - to obtain additional excluded users. - - :rtype: str - """ - if self._cursor_present: - return self._cursor_value - else: - return None - - @cursor.setter - def cursor(self, val): - if val is None: - del self.cursor - return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True - - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + emails_to_delete=None): + self._emails_to_delete_value = None + self._emails_to_delete_present = False + if emails_to_delete is not None: + self.emails_to_delete = emails_to_delete @property - def has_more(self): + def emails_to_delete(self): """ - Is true if there are additional excluded users that have not been - returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` - can retrieve them. + List of users and their secondary emails to delete. - :rtype: bool + :rtype: list of [UserSecondaryEmailsArg] """ - if self._has_more_present: - return self._has_more_value + if self._emails_to_delete_present: + return self._emails_to_delete_value else: - raise AttributeError("missing required field 'has_more'") + raise AttributeError("missing required field 'emails_to_delete'") - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + @emails_to_delete.setter + def emails_to_delete(self, val): + val = self._emails_to_delete_validator.validate(val) + self._emails_to_delete_value = val + self._emails_to_delete_present = True - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + @emails_to_delete.deleter + def emails_to_delete(self): + self._emails_to_delete_value = None + self._emails_to_delete_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeleteSecondaryEmailsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExcludedUsersListResult(users={!r}, has_more={!r}, cursor={!r})'.format( - self._users_value, - self._has_more_value, - self._cursor_value, + return 'DeleteSecondaryEmailsArg(emails_to_delete={!r})'.format( + self._emails_to_delete_value, ) -ExcludedUsersListResult_validator = bv.Struct(ExcludedUsersListResult) - -class ExcludedUsersUpdateArg(bb.Struct): - """ - Argument of excluded users update operation. Should include a list of users - to add/remove (according to endpoint), Maximum size of the list is 1000 - users. +DeleteSecondaryEmailsArg_validator = bv.Struct(DeleteSecondaryEmailsArg) - :ivar team.ExcludedUsersUpdateArg.users: List of users to be added/removed. - """ +class DeleteSecondaryEmailsResult(bb.Struct): __slots__ = [ - '_users_value', - '_users_present', + '_results_value', + '_results_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - users=None): - self._users_value = None - self._users_present = False - if users is not None: - self.users = users + results=None): + self._results_value = None + self._results_present = False + if results is not None: + self.results = results @property - def users(self): + def results(self): """ - List of users to be added/removed. - - :rtype: list of [UserSelectorArg] + :rtype: list of [UserDeleteResult] """ - if self._users_present: - return self._users_value + if self._results_present: + return self._results_value else: - return None + raise AttributeError("missing required field 'results'") - @users.setter - def users(self, val): - if val is None: - del self.users - return - val = self._users_validator.validate(val) - self._users_value = val - self._users_present = True + @results.setter + def results(self, val): + val = self._results_validator.validate(val) + self._results_value = val + self._results_present = True - @users.deleter - def users(self): - self._users_value = None - self._users_present = False + @results.deleter + def results(self): + self._results_value = None + self._results_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersUpdateArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeleteSecondaryEmailsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExcludedUsersUpdateArg(users={!r})'.format( - self._users_value, + return 'DeleteSecondaryEmailsResult(results={!r})'.format( + self._results_value, ) -ExcludedUsersUpdateArg_validator = bv.Struct(ExcludedUsersUpdateArg) +DeleteSecondaryEmailsResult_validator = bv.Struct(DeleteSecondaryEmailsResult) -class ExcludedUsersUpdateError(bb.Union): +class DesktopClientSession(DeviceSession): """ - Excluded users update error. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Information about linked Dropbox desktop client sessions. - :ivar team.ExcludedUsersUpdateError.users_not_in_team: At least one of the - users is not part of your team. - :ivar team.ExcludedUsersUpdateError.too_many_users: A maximum of 1000 users - for each of addition/removal can be supplied. + :ivar team.DesktopClientSession.host_name: Name of the hosting desktop. + :ivar team.DesktopClientSession.client_type: The Dropbox desktop client + type. + :ivar team.DesktopClientSession.client_version: The Dropbox client version. + :ivar team.DesktopClientSession.platform: Information on the hosting + platform. + :ivar team.DesktopClientSession.is_delete_on_unlink_supported: Whether it's + possible to delete all of the account files upon unlinking. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - users_not_in_team = None - # Attribute is overwritten below the class definition - too_many_users = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_host_name_value', + '_host_name_present', + '_client_type_value', + '_client_type_present', + '_client_version_value', + '_client_version_present', + '_platform_value', + '_platform_present', + '_is_delete_on_unlink_supported_value', + '_is_delete_on_unlink_supported_present', + ] - def is_users_not_in_team(self): - """ - Check if the union tag is ``users_not_in_team``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'users_not_in_team' + def __init__(self, + session_id=None, + host_name=None, + client_type=None, + client_version=None, + platform=None, + is_delete_on_unlink_supported=None, + ip_address=None, + country=None, + created=None, + updated=None): + super(DesktopClientSession, self).__init__(session_id, + ip_address, + country, + created, + updated) + self._host_name_value = None + self._host_name_present = False + self._client_type_value = None + self._client_type_present = False + self._client_version_value = None + self._client_version_present = False + self._platform_value = None + self._platform_present = False + self._is_delete_on_unlink_supported_value = None + self._is_delete_on_unlink_supported_present = False + if host_name is not None: + self.host_name = host_name + if client_type is not None: + self.client_type = client_type + if client_version is not None: + self.client_version = client_version + if platform is not None: + self.platform = platform + if is_delete_on_unlink_supported is not None: + self.is_delete_on_unlink_supported = is_delete_on_unlink_supported - def is_too_many_users(self): + @property + def host_name(self): """ - Check if the union tag is ``too_many_users``. + Name of the hosting desktop. - :rtype: bool + :rtype: str """ - return self._tag == 'too_many_users' + if self._host_name_present: + return self._host_name_value + else: + raise AttributeError("missing required field 'host_name'") - def is_other(self): - """ - Check if the union tag is ``other``. + @host_name.setter + def host_name(self, val): + val = self._host_name_validator.validate(val) + self._host_name_value = val + self._host_name_present = True - :rtype: bool - """ - return self._tag == 'other' + @host_name.deleter + def host_name(self): + self._host_name_value = None + self._host_name_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersUpdateError, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def client_type(self): + """ + The Dropbox desktop client type. - def __repr__(self): - return 'ExcludedUsersUpdateError(%r, %r)' % (self._tag, self._value) - -ExcludedUsersUpdateError_validator = bv.Union(ExcludedUsersUpdateError) - -class ExcludedUsersUpdateResult(bb.Struct): - """ - Excluded users update result. - - :ivar team.ExcludedUsersUpdateResult.status: Update status. - """ - - __slots__ = [ - '_status_value', - '_status_present', - ] + :rtype: DesktopPlatform + """ + if self._client_type_present: + return self._client_type_value + else: + raise AttributeError("missing required field 'client_type'") - _has_required_fields = True + @client_type.setter + def client_type(self, val): + self._client_type_validator.validate_type_only(val) + self._client_type_value = val + self._client_type_present = True - def __init__(self, - status=None): - self._status_value = None - self._status_present = False - if status is not None: - self.status = status + @client_type.deleter + def client_type(self): + self._client_type_value = None + self._client_type_present = False @property - def status(self): + def client_version(self): """ - Update status. + The Dropbox client version. - :rtype: ExcludedUsersUpdateStatus + :rtype: str """ - if self._status_present: - return self._status_value + if self._client_version_present: + return self._client_version_value else: - raise AttributeError("missing required field 'status'") - - @status.setter - def status(self, val): - self._status_validator.validate_type_only(val) - self._status_value = val - self._status_present = True - - @status.deleter - def status(self): - self._status_value = None - self._status_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersUpdateResult, self)._process_custom_annotations(annotation_type, field_path, processor) + raise AttributeError("missing required field 'client_version'") - def __repr__(self): - return 'ExcludedUsersUpdateResult(status={!r})'.format( - self._status_value, - ) + @client_version.setter + def client_version(self, val): + val = self._client_version_validator.validate(val) + self._client_version_value = val + self._client_version_present = True -ExcludedUsersUpdateResult_validator = bv.Struct(ExcludedUsersUpdateResult) + @client_version.deleter + def client_version(self): + self._client_version_value = None + self._client_version_present = False -class ExcludedUsersUpdateStatus(bb.Union): - """ - Excluded users update operation status. + @property + def platform(self): + """ + Information on the hosting platform. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :rtype: str + """ + if self._platform_present: + return self._platform_value + else: + raise AttributeError("missing required field 'platform'") - :ivar team.ExcludedUsersUpdateStatus.success: Update successful. - """ + @platform.setter + def platform(self, val): + val = self._platform_validator.validate(val) + self._platform_value = val + self._platform_present = True - _catch_all = 'other' - # Attribute is overwritten below the class definition - success = None - # Attribute is overwritten below the class definition - other = None + @platform.deleter + def platform(self): + self._platform_value = None + self._platform_present = False - def is_success(self): + @property + def is_delete_on_unlink_supported(self): """ - Check if the union tag is ``success``. + Whether it's possible to delete all of the account files upon unlinking. :rtype: bool """ - return self._tag == 'success' + if self._is_delete_on_unlink_supported_present: + return self._is_delete_on_unlink_supported_value + else: + raise AttributeError("missing required field 'is_delete_on_unlink_supported'") - def is_other(self): - """ - Check if the union tag is ``other``. + @is_delete_on_unlink_supported.setter + def is_delete_on_unlink_supported(self, val): + val = self._is_delete_on_unlink_supported_validator.validate(val) + self._is_delete_on_unlink_supported_value = val + self._is_delete_on_unlink_supported_present = True - :rtype: bool - """ - return self._tag == 'other' + @is_delete_on_unlink_supported.deleter + def is_delete_on_unlink_supported(self): + self._is_delete_on_unlink_supported_value = None + self._is_delete_on_unlink_supported_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExcludedUsersUpdateStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DesktopClientSession, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExcludedUsersUpdateStatus(%r, %r)' % (self._tag, self._value) + return 'DesktopClientSession(session_id={!r}, host_name={!r}, client_type={!r}, client_version={!r}, platform={!r}, is_delete_on_unlink_supported={!r}, ip_address={!r}, country={!r}, created={!r}, updated={!r})'.format( + self._session_id_value, + self._host_name_value, + self._client_type_value, + self._client_version_value, + self._platform_value, + self._is_delete_on_unlink_supported_value, + self._ip_address_value, + self._country_value, + self._created_value, + self._updated_value, + ) -ExcludedUsersUpdateStatus_validator = bv.Union(ExcludedUsersUpdateStatus) +DesktopClientSession_validator = bv.Struct(DesktopClientSession) -class Feature(bb.Union): +class DesktopPlatform(bb.Union): """ - A set of features that a Dropbox Business account may support. - This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.Feature.upload_api_rate_limit: The number of upload API calls - allowed per month. - :ivar team.Feature.has_team_shared_dropbox: Does this team have a shared - team root. - :ivar team.Feature.has_team_file_events: Does this team have file events. - :ivar team.Feature.has_team_selective_sync: Does this team have team - selective sync enabled. + :ivar team.DesktopPlatform.windows: Official Windows Dropbox desktop client. + :ivar team.DesktopPlatform.mac: Official Mac Dropbox desktop client. + :ivar team.DesktopPlatform.linux: Official Linux Dropbox desktop client. """ _catch_all = 'other' # Attribute is overwritten below the class definition - upload_api_rate_limit = None - # Attribute is overwritten below the class definition - has_team_shared_dropbox = None + windows = None # Attribute is overwritten below the class definition - has_team_file_events = None + mac = None # Attribute is overwritten below the class definition - has_team_selective_sync = None + linux = None # Attribute is overwritten below the class definition other = None - def is_upload_api_rate_limit(self): - """ - Check if the union tag is ``upload_api_rate_limit``. - - :rtype: bool - """ - return self._tag == 'upload_api_rate_limit' - - def is_has_team_shared_dropbox(self): + def is_windows(self): """ - Check if the union tag is ``has_team_shared_dropbox``. + Check if the union tag is ``windows``. :rtype: bool """ - return self._tag == 'has_team_shared_dropbox' + return self._tag == 'windows' - def is_has_team_file_events(self): + def is_mac(self): """ - Check if the union tag is ``has_team_file_events``. + Check if the union tag is ``mac``. :rtype: bool """ - return self._tag == 'has_team_file_events' + return self._tag == 'mac' - def is_has_team_selective_sync(self): + def is_linux(self): """ - Check if the union tag is ``has_team_selective_sync``. + Check if the union tag is ``linux``. :rtype: bool """ - return self._tag == 'has_team_selective_sync' + return self._tag == 'linux' def is_other(self): """ @@ -2369,319 +2154,1265 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(Feature, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DesktopPlatform, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'Feature(%r, %r)' % (self._tag, self._value) + return 'DesktopPlatform(%r, %r)' % (self._tag, self._value) -Feature_validator = bv.Union(Feature) +DesktopPlatform_validator = bv.Union(DesktopPlatform) -class FeatureValue(bb.Union): +class DeviceSessionArg(bb.Struct): """ - The values correspond to entries in :class:`Feature`. You may get different - value according to your Dropbox Business plan. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team.DeviceSessionArg.session_id: The session id. + :ivar team.DeviceSessionArg.team_member_id: The unique id of the member + owning the device. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_session_id_value', + '_session_id_present', + '_team_member_id_value', + '_team_member_id_present', + ] - @classmethod - def upload_api_rate_limit(cls, val): - """ - Create an instance of this class set to the ``upload_api_rate_limit`` - tag with value ``val``. + _has_required_fields = True - :param UploadApiRateLimitValue val: - :rtype: FeatureValue - """ - return cls('upload_api_rate_limit', val) + def __init__(self, + session_id=None, + team_member_id=None): + self._session_id_value = None + self._session_id_present = False + self._team_member_id_value = None + self._team_member_id_present = False + if session_id is not None: + self.session_id = session_id + if team_member_id is not None: + self.team_member_id = team_member_id - @classmethod - def has_team_shared_dropbox(cls, val): + @property + def session_id(self): """ - Create an instance of this class set to the ``has_team_shared_dropbox`` - tag with value ``val``. + The session id. - :param HasTeamSharedDropboxValue val: - :rtype: FeatureValue + :rtype: str """ - return cls('has_team_shared_dropbox', val) + if self._session_id_present: + return self._session_id_value + else: + raise AttributeError("missing required field 'session_id'") - @classmethod - def has_team_file_events(cls, val): - """ - Create an instance of this class set to the ``has_team_file_events`` tag - with value ``val``. + @session_id.setter + def session_id(self, val): + val = self._session_id_validator.validate(val) + self._session_id_value = val + self._session_id_present = True - :param HasTeamFileEventsValue val: - :rtype: FeatureValue - """ - return cls('has_team_file_events', val) + @session_id.deleter + def session_id(self): + self._session_id_value = None + self._session_id_present = False - @classmethod - def has_team_selective_sync(cls, val): + @property + def team_member_id(self): """ - Create an instance of this class set to the ``has_team_selective_sync`` - tag with value ``val``. + The unique id of the member owning the device. - :param HasTeamSelectiveSyncValue val: - :rtype: FeatureValue + :rtype: str """ - return cls('has_team_selective_sync', val) + if self._team_member_id_present: + return self._team_member_id_value + else: + raise AttributeError("missing required field 'team_member_id'") - def is_upload_api_rate_limit(self): - """ - Check if the union tag is ``upload_api_rate_limit``. + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - :rtype: bool - """ - return self._tag == 'upload_api_rate_limit' + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False - def is_has_team_shared_dropbox(self): - """ - Check if the union tag is ``has_team_shared_dropbox``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DeviceSessionArg, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'has_team_shared_dropbox' + def __repr__(self): + return 'DeviceSessionArg(session_id={!r}, team_member_id={!r})'.format( + self._session_id_value, + self._team_member_id_value, + ) - def is_has_team_file_events(self): - """ - Check if the union tag is ``has_team_file_events``. +DeviceSessionArg_validator = bv.Struct(DeviceSessionArg) - :rtype: bool - """ - return self._tag == 'has_team_file_events' +class DevicesActive(bb.Struct): + """ + Each of the items is an array of values, one value per day. The value is the + number of devices active within a time window, ending with that day. If + there is no data for a day, then the value will be None. - def is_has_team_selective_sync(self): - """ - Check if the union tag is ``has_team_selective_sync``. + :ivar team.DevicesActive.windows: Array of number of linked windows + (desktop) clients with activity. + :ivar team.DevicesActive.macos: Array of number of linked mac (desktop) + clients with activity. + :ivar team.DevicesActive.linux: Array of number of linked linus (desktop) + clients with activity. + :ivar team.DevicesActive.ios: Array of number of linked ios devices with + activity. + :ivar team.DevicesActive.android: Array of number of linked android devices + with activity. + :ivar team.DevicesActive.other: Array of number of other linked devices + (blackberry, windows phone, etc) with activity. + :ivar team.DevicesActive.total: Array of total number of linked clients with + activity. + """ - :rtype: bool - """ - return self._tag == 'has_team_selective_sync' + __slots__ = [ + '_windows_value', + '_windows_present', + '_macos_value', + '_macos_present', + '_linux_value', + '_linux_present', + '_ios_value', + '_ios_present', + '_android_value', + '_android_present', + '_other_value', + '_other_present', + '_total_value', + '_total_present', + ] - def is_other(self): - """ - Check if the union tag is ``other``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'other' + def __init__(self, + windows=None, + macos=None, + linux=None, + ios=None, + android=None, + other=None, + total=None): + self._windows_value = None + self._windows_present = False + self._macos_value = None + self._macos_present = False + self._linux_value = None + self._linux_present = False + self._ios_value = None + self._ios_present = False + self._android_value = None + self._android_present = False + self._other_value = None + self._other_present = False + self._total_value = None + self._total_present = False + if windows is not None: + self.windows = windows + if macos is not None: + self.macos = macos + if linux is not None: + self.linux = linux + if ios is not None: + self.ios = ios + if android is not None: + self.android = android + if other is not None: + self.other = other + if total is not None: + self.total = total - def get_upload_api_rate_limit(self): + @property + def windows(self): """ - Only call this if :meth:`is_upload_api_rate_limit` is true. + Array of number of linked windows (desktop) clients with activity. - :rtype: UploadApiRateLimitValue + :rtype: list of [Optional[int]] """ - if not self.is_upload_api_rate_limit(): - raise AttributeError("tag 'upload_api_rate_limit' not set") - return self._value + if self._windows_present: + return self._windows_value + else: + raise AttributeError("missing required field 'windows'") - def get_has_team_shared_dropbox(self): - """ - Only call this if :meth:`is_has_team_shared_dropbox` is true. + @windows.setter + def windows(self, val): + val = self._windows_validator.validate(val) + self._windows_value = val + self._windows_present = True - :rtype: HasTeamSharedDropboxValue - """ - if not self.is_has_team_shared_dropbox(): - raise AttributeError("tag 'has_team_shared_dropbox' not set") - return self._value + @windows.deleter + def windows(self): + self._windows_value = None + self._windows_present = False - def get_has_team_file_events(self): + @property + def macos(self): """ - Only call this if :meth:`is_has_team_file_events` is true. + Array of number of linked mac (desktop) clients with activity. - :rtype: HasTeamFileEventsValue + :rtype: list of [Optional[int]] """ - if not self.is_has_team_file_events(): - raise AttributeError("tag 'has_team_file_events' not set") - return self._value + if self._macos_present: + return self._macos_value + else: + raise AttributeError("missing required field 'macos'") - def get_has_team_selective_sync(self): - """ - Only call this if :meth:`is_has_team_selective_sync` is true. + @macos.setter + def macos(self, val): + val = self._macos_validator.validate(val) + self._macos_value = val + self._macos_present = True - :rtype: HasTeamSelectiveSyncValue + @macos.deleter + def macos(self): + self._macos_value = None + self._macos_present = False + + @property + def linux(self): """ - if not self.is_has_team_selective_sync(): - raise AttributeError("tag 'has_team_selective_sync' not set") - return self._value + Array of number of linked linus (desktop) clients with activity. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FeatureValue, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: list of [Optional[int]] + """ + if self._linux_present: + return self._linux_value + else: + raise AttributeError("missing required field 'linux'") - def __repr__(self): - return 'FeatureValue(%r, %r)' % (self._tag, self._value) + @linux.setter + def linux(self, val): + val = self._linux_validator.validate(val) + self._linux_value = val + self._linux_present = True -FeatureValue_validator = bv.Union(FeatureValue) + @linux.deleter + def linux(self): + self._linux_value = None + self._linux_present = False -class FeaturesGetValuesBatchArg(bb.Struct): - """ - :ivar team.FeaturesGetValuesBatchArg.features: A list of features in - :class:`Feature`. If the list is empty, this route will return - :class:`FeaturesGetValuesBatchError`. - """ + @property + def ios(self): + """ + Array of number of linked ios devices with activity. - __slots__ = [ - '_features_value', - '_features_present', - ] + :rtype: list of [Optional[int]] + """ + if self._ios_present: + return self._ios_value + else: + raise AttributeError("missing required field 'ios'") - _has_required_fields = True + @ios.setter + def ios(self, val): + val = self._ios_validator.validate(val) + self._ios_value = val + self._ios_present = True - def __init__(self, - features=None): - self._features_value = None - self._features_present = False - if features is not None: - self.features = features + @ios.deleter + def ios(self): + self._ios_value = None + self._ios_present = False @property - def features(self): + def android(self): """ - A list of features in :class:`Feature`. If the list is empty, this route - will return :class:`FeaturesGetValuesBatchError`. + Array of number of linked android devices with activity. - :rtype: list of [Feature] + :rtype: list of [Optional[int]] """ - if self._features_present: - return self._features_value + if self._android_present: + return self._android_value else: - raise AttributeError("missing required field 'features'") + raise AttributeError("missing required field 'android'") - @features.setter - def features(self, val): - val = self._features_validator.validate(val) - self._features_value = val - self._features_present = True + @android.setter + def android(self, val): + val = self._android_validator.validate(val) + self._android_value = val + self._android_present = True - @features.deleter - def features(self): - self._features_value = None - self._features_present = False + @android.deleter + def android(self): + self._android_value = None + self._android_present = False + + @property + def other(self): + """ + Array of number of other linked devices (blackberry, windows phone, etc) + with activity. + + :rtype: list of [Optional[int]] + """ + if self._other_present: + return self._other_value + else: + raise AttributeError("missing required field 'other'") + + @other.setter + def other(self, val): + val = self._other_validator.validate(val) + self._other_value = val + self._other_present = True + + @other.deleter + def other(self): + self._other_value = None + self._other_present = False + + @property + def total(self): + """ + Array of total number of linked clients with activity. + + :rtype: list of [Optional[int]] + """ + if self._total_present: + return self._total_value + else: + raise AttributeError("missing required field 'total'") + + @total.setter + def total(self, val): + val = self._total_validator.validate(val) + self._total_value = val + self._total_present = True + + @total.deleter + def total(self): + self._total_value = None + self._total_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FeaturesGetValuesBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DevicesActive, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FeaturesGetValuesBatchArg(features={!r})'.format( - self._features_value, + return 'DevicesActive(windows={!r}, macos={!r}, linux={!r}, ios={!r}, android={!r}, other={!r}, total={!r})'.format( + self._windows_value, + self._macos_value, + self._linux_value, + self._ios_value, + self._android_value, + self._other_value, + self._total_value, ) -FeaturesGetValuesBatchArg_validator = bv.Struct(FeaturesGetValuesBatchArg) +DevicesActive_validator = bv.Struct(DevicesActive) -class FeaturesGetValuesBatchError(bb.Union): +class ExcludedUsersListArg(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Excluded users list argument. - :ivar team.FeaturesGetValuesBatchError.empty_features_list: At least one - :class:`Feature` must be included in the - :class:`FeaturesGetValuesBatchArg`.features list. + :ivar team.ExcludedUsersListArg.limit: Number of results to return per call. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - empty_features_list = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_limit_value', + '_limit_present', + ] - def is_empty_features_list(self): - """ - Check if the union tag is ``empty_features_list``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'empty_features_list' + def __init__(self, + limit=None): + self._limit_value = None + self._limit_present = False + if limit is not None: + self.limit = limit - def is_other(self): + @property + def limit(self): """ - Check if the union tag is ``other``. + Number of results to return per call. - :rtype: bool + :rtype: int """ - return self._tag == 'other' + if self._limit_present: + return self._limit_value + else: + return 1000 + + @limit.setter + def limit(self, val): + val = self._limit_validator.validate(val) + self._limit_value = val + self._limit_present = True + + @limit.deleter + def limit(self): + self._limit_value = None + self._limit_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FeaturesGetValuesBatchError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ExcludedUsersListArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FeaturesGetValuesBatchError(%r, %r)' % (self._tag, self._value) + return 'ExcludedUsersListArg(limit={!r})'.format( + self._limit_value, + ) -FeaturesGetValuesBatchError_validator = bv.Union(FeaturesGetValuesBatchError) +ExcludedUsersListArg_validator = bv.Struct(ExcludedUsersListArg) -class FeaturesGetValuesBatchResult(bb.Struct): +class ExcludedUsersListContinueArg(bb.Struct): + """ + Excluded users list continue argument. + + :ivar team.ExcludedUsersListContinueArg.cursor: Indicates from what point to + get the next set of users. + """ __slots__ = [ - '_values_value', - '_values_present', + '_cursor_value', + '_cursor_present', ] _has_required_fields = True def __init__(self, - values=None): - self._values_value = None - self._values_present = False - if values is not None: - self.values = values + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def values(self): + def cursor(self): """ - :rtype: list of [FeatureValue] + Indicates from what point to get the next set of users. + + :rtype: str """ - if self._values_present: - return self._values_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'values'") + raise AttributeError("missing required field 'cursor'") - @values.setter - def values(self, val): - val = self._values_validator.validate(val) - self._values_value = val - self._values_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @values.deleter - def values(self): - self._values_value = None - self._values_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FeaturesGetValuesBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ExcludedUsersListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FeaturesGetValuesBatchResult(values={!r})'.format( - self._values_value, + return 'ExcludedUsersListContinueArg(cursor={!r})'.format( + self._cursor_value, ) -FeaturesGetValuesBatchResult_validator = bv.Struct(FeaturesGetValuesBatchResult) +ExcludedUsersListContinueArg_validator = bv.Struct(ExcludedUsersListContinueArg) -class GetActivityReport(BaseDfbReport): +class ExcludedUsersListContinueError(bb.Union): """ - Activity Report Result. Each of the items in the storage report is an array - of values, one value per day. If there is no data for a day, then the value - will be None. + Excluded users list continue error. - :ivar team.GetActivityReport.adds: Array of total number of adds by team - members. - :ivar team.GetActivityReport.edits: Array of number of edits by team - members. If the same user edits the same file multiple times this is - counted as a single edit. - :ivar team.GetActivityReport.deletes: Array of total number of deletes by - team members. - :ivar team.GetActivityReport.active_users_28_day: Array of the number of - users who have been active in the last 28 days. - :ivar team.GetActivityReport.active_users_7_day: Array of the number of - users who have been active in the last week. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.ExcludedUsersListContinueError.invalid_cursor: The cursor is + invalid. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_cursor = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_cursor(self): + """ + Check if the union tag is ``invalid_cursor``. + + :rtype: bool + """ + return self._tag == 'invalid_cursor' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExcludedUsersListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExcludedUsersListContinueError(%r, %r)' % (self._tag, self._value) + +ExcludedUsersListContinueError_validator = bv.Union(ExcludedUsersListContinueError) + +class ExcludedUsersListError(bb.Union): + """ + Excluded users list error. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.ExcludedUsersListError.list_error: An error occurred. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + list_error = None + # Attribute is overwritten below the class definition + other = None + + def is_list_error(self): + """ + Check if the union tag is ``list_error``. + + :rtype: bool + """ + return self._tag == 'list_error' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExcludedUsersListError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExcludedUsersListError(%r, %r)' % (self._tag, self._value) + +ExcludedUsersListError_validator = bv.Union(ExcludedUsersListError) + +class ExcludedUsersListResult(bb.Struct): + """ + Excluded users list result. + + :ivar team.ExcludedUsersListResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` + to obtain additional excluded users. + :ivar team.ExcludedUsersListResult.has_more: Is true if there are additional + excluded users that have not been returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` + can retrieve them. + """ + + __slots__ = [ + '_users_value', + '_users_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', + ] + + _has_required_fields = True + + def __init__(self, + users=None, + has_more=None, + cursor=None): + self._users_value = None + self._users_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if users is not None: + self.users = users + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more + + @property + def users(self): + """ + :rtype: list of [MemberProfile] + """ + if self._users_present: + return self._users_value + else: + raise AttributeError("missing required field 'users'") + + @users.setter + def users(self, val): + val = self._users_validator.validate(val) + self._users_value = val + self._users_present = True + + @users.deleter + def users(self): + self._users_value = None + self._users_present = False + + @property + def cursor(self): + """ + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` + to obtain additional excluded users. + + :rtype: str + """ + if self._cursor_present: + return self._cursor_value + else: + return None + + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True + + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False + + @property + def has_more(self): + """ + Is true if there are additional excluded users that have not been + returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_member_space_limits_excluded_users_list_continue` + can retrieve them. + + :rtype: bool + """ + if self._has_more_present: + return self._has_more_value + else: + raise AttributeError("missing required field 'has_more'") + + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True + + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExcludedUsersListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExcludedUsersListResult(users={!r}, has_more={!r}, cursor={!r})'.format( + self._users_value, + self._has_more_value, + self._cursor_value, + ) + +ExcludedUsersListResult_validator = bv.Struct(ExcludedUsersListResult) + +class ExcludedUsersUpdateArg(bb.Struct): + """ + Argument of excluded users update operation. Should include a list of users + to add/remove (according to endpoint), Maximum size of the list is 1000 + users. + + :ivar team.ExcludedUsersUpdateArg.users: List of users to be added/removed. + """ + + __slots__ = [ + '_users_value', + '_users_present', + ] + + _has_required_fields = False + + def __init__(self, + users=None): + self._users_value = None + self._users_present = False + if users is not None: + self.users = users + + @property + def users(self): + """ + List of users to be added/removed. + + :rtype: list of [UserSelectorArg] + """ + if self._users_present: + return self._users_value + else: + return None + + @users.setter + def users(self, val): + if val is None: + del self.users + return + val = self._users_validator.validate(val) + self._users_value = val + self._users_present = True + + @users.deleter + def users(self): + self._users_value = None + self._users_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExcludedUsersUpdateArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExcludedUsersUpdateArg(users={!r})'.format( + self._users_value, + ) + +ExcludedUsersUpdateArg_validator = bv.Struct(ExcludedUsersUpdateArg) + +class ExcludedUsersUpdateError(bb.Union): + """ + Excluded users update error. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.ExcludedUsersUpdateError.users_not_in_team: At least one of the + users is not part of your team. + :ivar team.ExcludedUsersUpdateError.too_many_users: A maximum of 1000 users + for each of addition/removal can be supplied. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + users_not_in_team = None + # Attribute is overwritten below the class definition + too_many_users = None + # Attribute is overwritten below the class definition + other = None + + def is_users_not_in_team(self): + """ + Check if the union tag is ``users_not_in_team``. + + :rtype: bool + """ + return self._tag == 'users_not_in_team' + + def is_too_many_users(self): + """ + Check if the union tag is ``too_many_users``. + + :rtype: bool + """ + return self._tag == 'too_many_users' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExcludedUsersUpdateError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExcludedUsersUpdateError(%r, %r)' % (self._tag, self._value) + +ExcludedUsersUpdateError_validator = bv.Union(ExcludedUsersUpdateError) + +class ExcludedUsersUpdateResult(bb.Struct): + """ + Excluded users update result. + + :ivar team.ExcludedUsersUpdateResult.status: Update status. + """ + + __slots__ = [ + '_status_value', + '_status_present', + ] + + _has_required_fields = True + + def __init__(self, + status=None): + self._status_value = None + self._status_present = False + if status is not None: + self.status = status + + @property + def status(self): + """ + Update status. + + :rtype: ExcludedUsersUpdateStatus + """ + if self._status_present: + return self._status_value + else: + raise AttributeError("missing required field 'status'") + + @status.setter + def status(self, val): + self._status_validator.validate_type_only(val) + self._status_value = val + self._status_present = True + + @status.deleter + def status(self): + self._status_value = None + self._status_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExcludedUsersUpdateResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExcludedUsersUpdateResult(status={!r})'.format( + self._status_value, + ) + +ExcludedUsersUpdateResult_validator = bv.Struct(ExcludedUsersUpdateResult) + +class ExcludedUsersUpdateStatus(bb.Union): + """ + Excluded users update operation status. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.ExcludedUsersUpdateStatus.success: Update successful. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + success = None + # Attribute is overwritten below the class definition + other = None + + def is_success(self): + """ + Check if the union tag is ``success``. + + :rtype: bool + """ + return self._tag == 'success' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExcludedUsersUpdateStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExcludedUsersUpdateStatus(%r, %r)' % (self._tag, self._value) + +ExcludedUsersUpdateStatus_validator = bv.Union(ExcludedUsersUpdateStatus) + +class Feature(bb.Union): + """ + A set of features that a Dropbox Business account may support. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.Feature.upload_api_rate_limit: The number of upload API calls + allowed per month. + :ivar team.Feature.has_team_shared_dropbox: Does this team have a shared + team root. + :ivar team.Feature.has_team_file_events: Does this team have file events. + :ivar team.Feature.has_team_selective_sync: Does this team have team + selective sync enabled. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + upload_api_rate_limit = None + # Attribute is overwritten below the class definition + has_team_shared_dropbox = None + # Attribute is overwritten below the class definition + has_team_file_events = None + # Attribute is overwritten below the class definition + has_team_selective_sync = None + # Attribute is overwritten below the class definition + other = None + + def is_upload_api_rate_limit(self): + """ + Check if the union tag is ``upload_api_rate_limit``. + + :rtype: bool + """ + return self._tag == 'upload_api_rate_limit' + + def is_has_team_shared_dropbox(self): + """ + Check if the union tag is ``has_team_shared_dropbox``. + + :rtype: bool + """ + return self._tag == 'has_team_shared_dropbox' + + def is_has_team_file_events(self): + """ + Check if the union tag is ``has_team_file_events``. + + :rtype: bool + """ + return self._tag == 'has_team_file_events' + + def is_has_team_selective_sync(self): + """ + Check if the union tag is ``has_team_selective_sync``. + + :rtype: bool + """ + return self._tag == 'has_team_selective_sync' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(Feature, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'Feature(%r, %r)' % (self._tag, self._value) + +Feature_validator = bv.Union(Feature) + +class FeatureValue(bb.Union): + """ + The values correspond to entries in :class:`Feature`. You may get different + value according to your Dropbox Business plan. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def upload_api_rate_limit(cls, val): + """ + Create an instance of this class set to the ``upload_api_rate_limit`` + tag with value ``val``. + + :param UploadApiRateLimitValue val: + :rtype: FeatureValue + """ + return cls('upload_api_rate_limit', val) + + @classmethod + def has_team_shared_dropbox(cls, val): + """ + Create an instance of this class set to the ``has_team_shared_dropbox`` + tag with value ``val``. + + :param HasTeamSharedDropboxValue val: + :rtype: FeatureValue + """ + return cls('has_team_shared_dropbox', val) + + @classmethod + def has_team_file_events(cls, val): + """ + Create an instance of this class set to the ``has_team_file_events`` tag + with value ``val``. + + :param HasTeamFileEventsValue val: + :rtype: FeatureValue + """ + return cls('has_team_file_events', val) + + @classmethod + def has_team_selective_sync(cls, val): + """ + Create an instance of this class set to the ``has_team_selective_sync`` + tag with value ``val``. + + :param HasTeamSelectiveSyncValue val: + :rtype: FeatureValue + """ + return cls('has_team_selective_sync', val) + + def is_upload_api_rate_limit(self): + """ + Check if the union tag is ``upload_api_rate_limit``. + + :rtype: bool + """ + return self._tag == 'upload_api_rate_limit' + + def is_has_team_shared_dropbox(self): + """ + Check if the union tag is ``has_team_shared_dropbox``. + + :rtype: bool + """ + return self._tag == 'has_team_shared_dropbox' + + def is_has_team_file_events(self): + """ + Check if the union tag is ``has_team_file_events``. + + :rtype: bool + """ + return self._tag == 'has_team_file_events' + + def is_has_team_selective_sync(self): + """ + Check if the union tag is ``has_team_selective_sync``. + + :rtype: bool + """ + return self._tag == 'has_team_selective_sync' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_upload_api_rate_limit(self): + """ + Only call this if :meth:`is_upload_api_rate_limit` is true. + + :rtype: UploadApiRateLimitValue + """ + if not self.is_upload_api_rate_limit(): + raise AttributeError("tag 'upload_api_rate_limit' not set") + return self._value + + def get_has_team_shared_dropbox(self): + """ + Only call this if :meth:`is_has_team_shared_dropbox` is true. + + :rtype: HasTeamSharedDropboxValue + """ + if not self.is_has_team_shared_dropbox(): + raise AttributeError("tag 'has_team_shared_dropbox' not set") + return self._value + + def get_has_team_file_events(self): + """ + Only call this if :meth:`is_has_team_file_events` is true. + + :rtype: HasTeamFileEventsValue + """ + if not self.is_has_team_file_events(): + raise AttributeError("tag 'has_team_file_events' not set") + return self._value + + def get_has_team_selective_sync(self): + """ + Only call this if :meth:`is_has_team_selective_sync` is true. + + :rtype: HasTeamSelectiveSyncValue + """ + if not self.is_has_team_selective_sync(): + raise AttributeError("tag 'has_team_selective_sync' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FeatureValue, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FeatureValue(%r, %r)' % (self._tag, self._value) + +FeatureValue_validator = bv.Union(FeatureValue) + +class FeaturesGetValuesBatchArg(bb.Struct): + """ + :ivar team.FeaturesGetValuesBatchArg.features: A list of features in + :class:`Feature`. If the list is empty, this route will return + :class:`FeaturesGetValuesBatchError`. + """ + + __slots__ = [ + '_features_value', + '_features_present', + ] + + _has_required_fields = True + + def __init__(self, + features=None): + self._features_value = None + self._features_present = False + if features is not None: + self.features = features + + @property + def features(self): + """ + A list of features in :class:`Feature`. If the list is empty, this route + will return :class:`FeaturesGetValuesBatchError`. + + :rtype: list of [Feature] + """ + if self._features_present: + return self._features_value + else: + raise AttributeError("missing required field 'features'") + + @features.setter + def features(self, val): + val = self._features_validator.validate(val) + self._features_value = val + self._features_present = True + + @features.deleter + def features(self): + self._features_value = None + self._features_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FeaturesGetValuesBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FeaturesGetValuesBatchArg(features={!r})'.format( + self._features_value, + ) + +FeaturesGetValuesBatchArg_validator = bv.Struct(FeaturesGetValuesBatchArg) + +class FeaturesGetValuesBatchError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.FeaturesGetValuesBatchError.empty_features_list: At least one + :class:`Feature` must be included in the + :class:`FeaturesGetValuesBatchArg`.features list. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + empty_features_list = None + # Attribute is overwritten below the class definition + other = None + + def is_empty_features_list(self): + """ + Check if the union tag is ``empty_features_list``. + + :rtype: bool + """ + return self._tag == 'empty_features_list' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FeaturesGetValuesBatchError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FeaturesGetValuesBatchError(%r, %r)' % (self._tag, self._value) + +FeaturesGetValuesBatchError_validator = bv.Union(FeaturesGetValuesBatchError) + +class FeaturesGetValuesBatchResult(bb.Struct): + + __slots__ = [ + '_values_value', + '_values_present', + ] + + _has_required_fields = True + + def __init__(self, + values=None): + self._values_value = None + self._values_present = False + if values is not None: + self.values = values + + @property + def values(self): + """ + :rtype: list of [FeatureValue] + """ + if self._values_present: + return self._values_value + else: + raise AttributeError("missing required field 'values'") + + @values.setter + def values(self, val): + val = self._values_validator.validate(val) + self._values_value = val + self._values_present = True + + @values.deleter + def values(self): + self._values_value = None + self._values_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FeaturesGetValuesBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FeaturesGetValuesBatchResult(values={!r})'.format( + self._values_value, + ) + +FeaturesGetValuesBatchResult_validator = bv.Struct(FeaturesGetValuesBatchResult) + +class GetActivityReport(BaseDfbReport): + """ + Activity Report Result. Each of the items in the storage report is an array + of values, one value per day. If there is no data for a day, then the value + will be None. + + :ivar team.GetActivityReport.adds: Array of total number of adds by team + members. + :ivar team.GetActivityReport.edits: Array of number of edits by team + members. If the same user edits the same file multiple times this is + counted as a single edit. + :ivar team.GetActivityReport.deletes: Array of total number of deletes by + team members. + :ivar team.GetActivityReport.active_users_28_day: Array of the number of + users who have been active in the last 28 days. + :ivar team.GetActivityReport.active_users_7_day: Array of the number of + users who have been active in the last week. :ivar team.GetActivityReport.active_users_1_day: Array of the number of users who have been active in the last day. :ivar team.GetActivityReport.active_shared_folders_28_day: Array of the @@ -2700,1799 +3431,4358 @@ class GetActivityReport(BaseDfbReport): :ivar team.GetActivityReport.shared_links_viewed_by_not_logged_in: Array of the number of views by non-logged-in users to shared links created by the team. - :ivar team.GetActivityReport.shared_links_viewed_total: Array of the total - number of views to shared links created by the team. + :ivar team.GetActivityReport.shared_links_viewed_total: Array of the total + number of views to shared links created by the team. + """ + + __slots__ = [ + '_adds_value', + '_adds_present', + '_edits_value', + '_edits_present', + '_deletes_value', + '_deletes_present', + '_active_users_28_day_value', + '_active_users_28_day_present', + '_active_users_7_day_value', + '_active_users_7_day_present', + '_active_users_1_day_value', + '_active_users_1_day_present', + '_active_shared_folders_28_day_value', + '_active_shared_folders_28_day_present', + '_active_shared_folders_7_day_value', + '_active_shared_folders_7_day_present', + '_active_shared_folders_1_day_value', + '_active_shared_folders_1_day_present', + '_shared_links_created_value', + '_shared_links_created_present', + '_shared_links_viewed_by_team_value', + '_shared_links_viewed_by_team_present', + '_shared_links_viewed_by_outside_user_value', + '_shared_links_viewed_by_outside_user_present', + '_shared_links_viewed_by_not_logged_in_value', + '_shared_links_viewed_by_not_logged_in_present', + '_shared_links_viewed_total_value', + '_shared_links_viewed_total_present', + ] + + _has_required_fields = True + + def __init__(self, + start_date=None, + adds=None, + edits=None, + deletes=None, + active_users_28_day=None, + active_users_7_day=None, + active_users_1_day=None, + active_shared_folders_28_day=None, + active_shared_folders_7_day=None, + active_shared_folders_1_day=None, + shared_links_created=None, + shared_links_viewed_by_team=None, + shared_links_viewed_by_outside_user=None, + shared_links_viewed_by_not_logged_in=None, + shared_links_viewed_total=None): + super(GetActivityReport, self).__init__(start_date) + self._adds_value = None + self._adds_present = False + self._edits_value = None + self._edits_present = False + self._deletes_value = None + self._deletes_present = False + self._active_users_28_day_value = None + self._active_users_28_day_present = False + self._active_users_7_day_value = None + self._active_users_7_day_present = False + self._active_users_1_day_value = None + self._active_users_1_day_present = False + self._active_shared_folders_28_day_value = None + self._active_shared_folders_28_day_present = False + self._active_shared_folders_7_day_value = None + self._active_shared_folders_7_day_present = False + self._active_shared_folders_1_day_value = None + self._active_shared_folders_1_day_present = False + self._shared_links_created_value = None + self._shared_links_created_present = False + self._shared_links_viewed_by_team_value = None + self._shared_links_viewed_by_team_present = False + self._shared_links_viewed_by_outside_user_value = None + self._shared_links_viewed_by_outside_user_present = False + self._shared_links_viewed_by_not_logged_in_value = None + self._shared_links_viewed_by_not_logged_in_present = False + self._shared_links_viewed_total_value = None + self._shared_links_viewed_total_present = False + if adds is not None: + self.adds = adds + if edits is not None: + self.edits = edits + if deletes is not None: + self.deletes = deletes + if active_users_28_day is not None: + self.active_users_28_day = active_users_28_day + if active_users_7_day is not None: + self.active_users_7_day = active_users_7_day + if active_users_1_day is not None: + self.active_users_1_day = active_users_1_day + if active_shared_folders_28_day is not None: + self.active_shared_folders_28_day = active_shared_folders_28_day + if active_shared_folders_7_day is not None: + self.active_shared_folders_7_day = active_shared_folders_7_day + if active_shared_folders_1_day is not None: + self.active_shared_folders_1_day = active_shared_folders_1_day + if shared_links_created is not None: + self.shared_links_created = shared_links_created + if shared_links_viewed_by_team is not None: + self.shared_links_viewed_by_team = shared_links_viewed_by_team + if shared_links_viewed_by_outside_user is not None: + self.shared_links_viewed_by_outside_user = shared_links_viewed_by_outside_user + if shared_links_viewed_by_not_logged_in is not None: + self.shared_links_viewed_by_not_logged_in = shared_links_viewed_by_not_logged_in + if shared_links_viewed_total is not None: + self.shared_links_viewed_total = shared_links_viewed_total + + @property + def adds(self): + """ + Array of total number of adds by team members. + + :rtype: list of [Optional[int]] + """ + if self._adds_present: + return self._adds_value + else: + raise AttributeError("missing required field 'adds'") + + @adds.setter + def adds(self, val): + val = self._adds_validator.validate(val) + self._adds_value = val + self._adds_present = True + + @adds.deleter + def adds(self): + self._adds_value = None + self._adds_present = False + + @property + def edits(self): + """ + Array of number of edits by team members. If the same user edits the + same file multiple times this is counted as a single edit. + + :rtype: list of [Optional[int]] + """ + if self._edits_present: + return self._edits_value + else: + raise AttributeError("missing required field 'edits'") + + @edits.setter + def edits(self, val): + val = self._edits_validator.validate(val) + self._edits_value = val + self._edits_present = True + + @edits.deleter + def edits(self): + self._edits_value = None + self._edits_present = False + + @property + def deletes(self): + """ + Array of total number of deletes by team members. + + :rtype: list of [Optional[int]] + """ + if self._deletes_present: + return self._deletes_value + else: + raise AttributeError("missing required field 'deletes'") + + @deletes.setter + def deletes(self, val): + val = self._deletes_validator.validate(val) + self._deletes_value = val + self._deletes_present = True + + @deletes.deleter + def deletes(self): + self._deletes_value = None + self._deletes_present = False + + @property + def active_users_28_day(self): + """ + Array of the number of users who have been active in the last 28 days. + + :rtype: list of [Optional[int]] + """ + if self._active_users_28_day_present: + return self._active_users_28_day_value + else: + raise AttributeError("missing required field 'active_users_28_day'") + + @active_users_28_day.setter + def active_users_28_day(self, val): + val = self._active_users_28_day_validator.validate(val) + self._active_users_28_day_value = val + self._active_users_28_day_present = True + + @active_users_28_day.deleter + def active_users_28_day(self): + self._active_users_28_day_value = None + self._active_users_28_day_present = False + + @property + def active_users_7_day(self): + """ + Array of the number of users who have been active in the last week. + + :rtype: list of [Optional[int]] + """ + if self._active_users_7_day_present: + return self._active_users_7_day_value + else: + raise AttributeError("missing required field 'active_users_7_day'") + + @active_users_7_day.setter + def active_users_7_day(self, val): + val = self._active_users_7_day_validator.validate(val) + self._active_users_7_day_value = val + self._active_users_7_day_present = True + + @active_users_7_day.deleter + def active_users_7_day(self): + self._active_users_7_day_value = None + self._active_users_7_day_present = False + + @property + def active_users_1_day(self): + """ + Array of the number of users who have been active in the last day. + + :rtype: list of [Optional[int]] + """ + if self._active_users_1_day_present: + return self._active_users_1_day_value + else: + raise AttributeError("missing required field 'active_users_1_day'") + + @active_users_1_day.setter + def active_users_1_day(self, val): + val = self._active_users_1_day_validator.validate(val) + self._active_users_1_day_value = val + self._active_users_1_day_present = True + + @active_users_1_day.deleter + def active_users_1_day(self): + self._active_users_1_day_value = None + self._active_users_1_day_present = False + + @property + def active_shared_folders_28_day(self): + """ + Array of the number of shared folders with some activity in the last 28 + days. + + :rtype: list of [Optional[int]] + """ + if self._active_shared_folders_28_day_present: + return self._active_shared_folders_28_day_value + else: + raise AttributeError("missing required field 'active_shared_folders_28_day'") + + @active_shared_folders_28_day.setter + def active_shared_folders_28_day(self, val): + val = self._active_shared_folders_28_day_validator.validate(val) + self._active_shared_folders_28_day_value = val + self._active_shared_folders_28_day_present = True + + @active_shared_folders_28_day.deleter + def active_shared_folders_28_day(self): + self._active_shared_folders_28_day_value = None + self._active_shared_folders_28_day_present = False + + @property + def active_shared_folders_7_day(self): + """ + Array of the number of shared folders with some activity in the last + week. + + :rtype: list of [Optional[int]] + """ + if self._active_shared_folders_7_day_present: + return self._active_shared_folders_7_day_value + else: + raise AttributeError("missing required field 'active_shared_folders_7_day'") + + @active_shared_folders_7_day.setter + def active_shared_folders_7_day(self, val): + val = self._active_shared_folders_7_day_validator.validate(val) + self._active_shared_folders_7_day_value = val + self._active_shared_folders_7_day_present = True + + @active_shared_folders_7_day.deleter + def active_shared_folders_7_day(self): + self._active_shared_folders_7_day_value = None + self._active_shared_folders_7_day_present = False + + @property + def active_shared_folders_1_day(self): + """ + Array of the number of shared folders with some activity in the last + day. + + :rtype: list of [Optional[int]] + """ + if self._active_shared_folders_1_day_present: + return self._active_shared_folders_1_day_value + else: + raise AttributeError("missing required field 'active_shared_folders_1_day'") + + @active_shared_folders_1_day.setter + def active_shared_folders_1_day(self, val): + val = self._active_shared_folders_1_day_validator.validate(val) + self._active_shared_folders_1_day_value = val + self._active_shared_folders_1_day_present = True + + @active_shared_folders_1_day.deleter + def active_shared_folders_1_day(self): + self._active_shared_folders_1_day_value = None + self._active_shared_folders_1_day_present = False + + @property + def shared_links_created(self): + """ + Array of the number of shared links created. + + :rtype: list of [Optional[int]] + """ + if self._shared_links_created_present: + return self._shared_links_created_value + else: + raise AttributeError("missing required field 'shared_links_created'") + + @shared_links_created.setter + def shared_links_created(self, val): + val = self._shared_links_created_validator.validate(val) + self._shared_links_created_value = val + self._shared_links_created_present = True + + @shared_links_created.deleter + def shared_links_created(self): + self._shared_links_created_value = None + self._shared_links_created_present = False + + @property + def shared_links_viewed_by_team(self): + """ + Array of the number of views by team users to shared links created by + the team. + + :rtype: list of [Optional[int]] + """ + if self._shared_links_viewed_by_team_present: + return self._shared_links_viewed_by_team_value + else: + raise AttributeError("missing required field 'shared_links_viewed_by_team'") + + @shared_links_viewed_by_team.setter + def shared_links_viewed_by_team(self, val): + val = self._shared_links_viewed_by_team_validator.validate(val) + self._shared_links_viewed_by_team_value = val + self._shared_links_viewed_by_team_present = True + + @shared_links_viewed_by_team.deleter + def shared_links_viewed_by_team(self): + self._shared_links_viewed_by_team_value = None + self._shared_links_viewed_by_team_present = False + + @property + def shared_links_viewed_by_outside_user(self): + """ + Array of the number of views by users outside of the team to shared + links created by the team. + + :rtype: list of [Optional[int]] + """ + if self._shared_links_viewed_by_outside_user_present: + return self._shared_links_viewed_by_outside_user_value + else: + raise AttributeError("missing required field 'shared_links_viewed_by_outside_user'") + + @shared_links_viewed_by_outside_user.setter + def shared_links_viewed_by_outside_user(self, val): + val = self._shared_links_viewed_by_outside_user_validator.validate(val) + self._shared_links_viewed_by_outside_user_value = val + self._shared_links_viewed_by_outside_user_present = True + + @shared_links_viewed_by_outside_user.deleter + def shared_links_viewed_by_outside_user(self): + self._shared_links_viewed_by_outside_user_value = None + self._shared_links_viewed_by_outside_user_present = False + + @property + def shared_links_viewed_by_not_logged_in(self): + """ + Array of the number of views by non-logged-in users to shared links + created by the team. + + :rtype: list of [Optional[int]] + """ + if self._shared_links_viewed_by_not_logged_in_present: + return self._shared_links_viewed_by_not_logged_in_value + else: + raise AttributeError("missing required field 'shared_links_viewed_by_not_logged_in'") + + @shared_links_viewed_by_not_logged_in.setter + def shared_links_viewed_by_not_logged_in(self, val): + val = self._shared_links_viewed_by_not_logged_in_validator.validate(val) + self._shared_links_viewed_by_not_logged_in_value = val + self._shared_links_viewed_by_not_logged_in_present = True + + @shared_links_viewed_by_not_logged_in.deleter + def shared_links_viewed_by_not_logged_in(self): + self._shared_links_viewed_by_not_logged_in_value = None + self._shared_links_viewed_by_not_logged_in_present = False + + @property + def shared_links_viewed_total(self): + """ + Array of the total number of views to shared links created by the team. + + :rtype: list of [Optional[int]] + """ + if self._shared_links_viewed_total_present: + return self._shared_links_viewed_total_value + else: + raise AttributeError("missing required field 'shared_links_viewed_total'") + + @shared_links_viewed_total.setter + def shared_links_viewed_total(self, val): + val = self._shared_links_viewed_total_validator.validate(val) + self._shared_links_viewed_total_value = val + self._shared_links_viewed_total_present = True + + @shared_links_viewed_total.deleter + def shared_links_viewed_total(self): + self._shared_links_viewed_total_value = None + self._shared_links_viewed_total_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetActivityReport, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetActivityReport(start_date={!r}, adds={!r}, edits={!r}, deletes={!r}, active_users_28_day={!r}, active_users_7_day={!r}, active_users_1_day={!r}, active_shared_folders_28_day={!r}, active_shared_folders_7_day={!r}, active_shared_folders_1_day={!r}, shared_links_created={!r}, shared_links_viewed_by_team={!r}, shared_links_viewed_by_outside_user={!r}, shared_links_viewed_by_not_logged_in={!r}, shared_links_viewed_total={!r})'.format( + self._start_date_value, + self._adds_value, + self._edits_value, + self._deletes_value, + self._active_users_28_day_value, + self._active_users_7_day_value, + self._active_users_1_day_value, + self._active_shared_folders_28_day_value, + self._active_shared_folders_7_day_value, + self._active_shared_folders_1_day_value, + self._shared_links_created_value, + self._shared_links_viewed_by_team_value, + self._shared_links_viewed_by_outside_user_value, + self._shared_links_viewed_by_not_logged_in_value, + self._shared_links_viewed_total_value, + ) + +GetActivityReport_validator = bv.Struct(GetActivityReport) + +class GetDevicesReport(BaseDfbReport): + """ + Devices Report Result. Contains subsections for different time ranges of + activity. Each of the items in each subsection of the storage report is an + array of values, one value per day. If there is no data for a day, then the + value will be None. + + :ivar team.GetDevicesReport.active_1_day: Report of the number of devices + active in the last day. + :ivar team.GetDevicesReport.active_7_day: Report of the number of devices + active in the last 7 days. + :ivar team.GetDevicesReport.active_28_day: Report of the number of devices + active in the last 28 days. + """ + + __slots__ = [ + '_active_1_day_value', + '_active_1_day_present', + '_active_7_day_value', + '_active_7_day_present', + '_active_28_day_value', + '_active_28_day_present', + ] + + _has_required_fields = True + + def __init__(self, + start_date=None, + active_1_day=None, + active_7_day=None, + active_28_day=None): + super(GetDevicesReport, self).__init__(start_date) + self._active_1_day_value = None + self._active_1_day_present = False + self._active_7_day_value = None + self._active_7_day_present = False + self._active_28_day_value = None + self._active_28_day_present = False + if active_1_day is not None: + self.active_1_day = active_1_day + if active_7_day is not None: + self.active_7_day = active_7_day + if active_28_day is not None: + self.active_28_day = active_28_day + + @property + def active_1_day(self): + """ + Report of the number of devices active in the last day. + + :rtype: DevicesActive + """ + if self._active_1_day_present: + return self._active_1_day_value + else: + raise AttributeError("missing required field 'active_1_day'") + + @active_1_day.setter + def active_1_day(self, val): + self._active_1_day_validator.validate_type_only(val) + self._active_1_day_value = val + self._active_1_day_present = True + + @active_1_day.deleter + def active_1_day(self): + self._active_1_day_value = None + self._active_1_day_present = False + + @property + def active_7_day(self): + """ + Report of the number of devices active in the last 7 days. + + :rtype: DevicesActive + """ + if self._active_7_day_present: + return self._active_7_day_value + else: + raise AttributeError("missing required field 'active_7_day'") + + @active_7_day.setter + def active_7_day(self, val): + self._active_7_day_validator.validate_type_only(val) + self._active_7_day_value = val + self._active_7_day_present = True + + @active_7_day.deleter + def active_7_day(self): + self._active_7_day_value = None + self._active_7_day_present = False + + @property + def active_28_day(self): + """ + Report of the number of devices active in the last 28 days. + + :rtype: DevicesActive + """ + if self._active_28_day_present: + return self._active_28_day_value + else: + raise AttributeError("missing required field 'active_28_day'") + + @active_28_day.setter + def active_28_day(self, val): + self._active_28_day_validator.validate_type_only(val) + self._active_28_day_value = val + self._active_28_day_present = True + + @active_28_day.deleter + def active_28_day(self): + self._active_28_day_value = None + self._active_28_day_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetDevicesReport, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetDevicesReport(start_date={!r}, active_1_day={!r}, active_7_day={!r}, active_28_day={!r})'.format( + self._start_date_value, + self._active_1_day_value, + self._active_7_day_value, + self._active_28_day_value, + ) + +GetDevicesReport_validator = bv.Struct(GetDevicesReport) + +class GetMembershipReport(BaseDfbReport): + """ + Membership Report Result. Each of the items in the storage report is an + array of values, one value per day. If there is no data for a day, then the + value will be None. + + :ivar team.GetMembershipReport.team_size: Team size, for each day. + :ivar team.GetMembershipReport.pending_invites: The number of pending + invites to the team, for each day. + :ivar team.GetMembershipReport.members_joined: The number of members that + joined the team, for each day. + :ivar team.GetMembershipReport.suspended_members: The number of suspended + team members, for each day. + :ivar team.GetMembershipReport.licenses: The total number of licenses the + team has, for each day. + """ + + __slots__ = [ + '_team_size_value', + '_team_size_present', + '_pending_invites_value', + '_pending_invites_present', + '_members_joined_value', + '_members_joined_present', + '_suspended_members_value', + '_suspended_members_present', + '_licenses_value', + '_licenses_present', + ] + + _has_required_fields = True + + def __init__(self, + start_date=None, + team_size=None, + pending_invites=None, + members_joined=None, + suspended_members=None, + licenses=None): + super(GetMembershipReport, self).__init__(start_date) + self._team_size_value = None + self._team_size_present = False + self._pending_invites_value = None + self._pending_invites_present = False + self._members_joined_value = None + self._members_joined_present = False + self._suspended_members_value = None + self._suspended_members_present = False + self._licenses_value = None + self._licenses_present = False + if team_size is not None: + self.team_size = team_size + if pending_invites is not None: + self.pending_invites = pending_invites + if members_joined is not None: + self.members_joined = members_joined + if suspended_members is not None: + self.suspended_members = suspended_members + if licenses is not None: + self.licenses = licenses + + @property + def team_size(self): + """ + Team size, for each day. + + :rtype: list of [Optional[int]] + """ + if self._team_size_present: + return self._team_size_value + else: + raise AttributeError("missing required field 'team_size'") + + @team_size.setter + def team_size(self, val): + val = self._team_size_validator.validate(val) + self._team_size_value = val + self._team_size_present = True + + @team_size.deleter + def team_size(self): + self._team_size_value = None + self._team_size_present = False + + @property + def pending_invites(self): + """ + The number of pending invites to the team, for each day. + + :rtype: list of [Optional[int]] + """ + if self._pending_invites_present: + return self._pending_invites_value + else: + raise AttributeError("missing required field 'pending_invites'") + + @pending_invites.setter + def pending_invites(self, val): + val = self._pending_invites_validator.validate(val) + self._pending_invites_value = val + self._pending_invites_present = True + + @pending_invites.deleter + def pending_invites(self): + self._pending_invites_value = None + self._pending_invites_present = False + + @property + def members_joined(self): + """ + The number of members that joined the team, for each day. + + :rtype: list of [Optional[int]] + """ + if self._members_joined_present: + return self._members_joined_value + else: + raise AttributeError("missing required field 'members_joined'") + + @members_joined.setter + def members_joined(self, val): + val = self._members_joined_validator.validate(val) + self._members_joined_value = val + self._members_joined_present = True + + @members_joined.deleter + def members_joined(self): + self._members_joined_value = None + self._members_joined_present = False + + @property + def suspended_members(self): + """ + The number of suspended team members, for each day. + + :rtype: list of [Optional[int]] + """ + if self._suspended_members_present: + return self._suspended_members_value + else: + raise AttributeError("missing required field 'suspended_members'") + + @suspended_members.setter + def suspended_members(self, val): + val = self._suspended_members_validator.validate(val) + self._suspended_members_value = val + self._suspended_members_present = True + + @suspended_members.deleter + def suspended_members(self): + self._suspended_members_value = None + self._suspended_members_present = False + + @property + def licenses(self): + """ + The total number of licenses the team has, for each day. + + :rtype: list of [Optional[int]] + """ + if self._licenses_present: + return self._licenses_value + else: + raise AttributeError("missing required field 'licenses'") + + @licenses.setter + def licenses(self, val): + val = self._licenses_validator.validate(val) + self._licenses_value = val + self._licenses_present = True + + @licenses.deleter + def licenses(self): + self._licenses_value = None + self._licenses_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetMembershipReport, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetMembershipReport(start_date={!r}, team_size={!r}, pending_invites={!r}, members_joined={!r}, suspended_members={!r}, licenses={!r})'.format( + self._start_date_value, + self._team_size_value, + self._pending_invites_value, + self._members_joined_value, + self._suspended_members_value, + self._licenses_value, + ) + +GetMembershipReport_validator = bv.Struct(GetMembershipReport) + +class GetStorageReport(BaseDfbReport): + """ + Storage Report Result. Each of the items in the storage report is an array + of values, one value per day. If there is no data for a day, then the value + will be None. + + :ivar team.GetStorageReport.total_usage: Sum of the shared, unshared, and + datastore usages, for each day. + :ivar team.GetStorageReport.shared_usage: Array of the combined size (bytes) + of team members' shared folders, for each day. + :ivar team.GetStorageReport.unshared_usage: Array of the combined size + (bytes) of team members' root namespaces, for each day. + :ivar team.GetStorageReport.shared_folders: Array of the number of shared + folders owned by team members, for each day. + :ivar team.GetStorageReport.member_storage_map: Array of storage summaries + of team members' account sizes. Each storage summary is an array of key, + value pairs, where each pair describes a storage bucket. The key + indicates the upper bound of the bucket and the value is the number of + users in that bucket. There is one such summary per day. If there is no + data for a day, the storage summary will be empty. + """ + + __slots__ = [ + '_total_usage_value', + '_total_usage_present', + '_shared_usage_value', + '_shared_usage_present', + '_unshared_usage_value', + '_unshared_usage_present', + '_shared_folders_value', + '_shared_folders_present', + '_member_storage_map_value', + '_member_storage_map_present', + ] + + _has_required_fields = True + + def __init__(self, + start_date=None, + total_usage=None, + shared_usage=None, + unshared_usage=None, + shared_folders=None, + member_storage_map=None): + super(GetStorageReport, self).__init__(start_date) + self._total_usage_value = None + self._total_usage_present = False + self._shared_usage_value = None + self._shared_usage_present = False + self._unshared_usage_value = None + self._unshared_usage_present = False + self._shared_folders_value = None + self._shared_folders_present = False + self._member_storage_map_value = None + self._member_storage_map_present = False + if total_usage is not None: + self.total_usage = total_usage + if shared_usage is not None: + self.shared_usage = shared_usage + if unshared_usage is not None: + self.unshared_usage = unshared_usage + if shared_folders is not None: + self.shared_folders = shared_folders + if member_storage_map is not None: + self.member_storage_map = member_storage_map + + @property + def total_usage(self): + """ + Sum of the shared, unshared, and datastore usages, for each day. + + :rtype: list of [Optional[int]] + """ + if self._total_usage_present: + return self._total_usage_value + else: + raise AttributeError("missing required field 'total_usage'") + + @total_usage.setter + def total_usage(self, val): + val = self._total_usage_validator.validate(val) + self._total_usage_value = val + self._total_usage_present = True + + @total_usage.deleter + def total_usage(self): + self._total_usage_value = None + self._total_usage_present = False + + @property + def shared_usage(self): + """ + Array of the combined size (bytes) of team members' shared folders, for + each day. + + :rtype: list of [Optional[int]] + """ + if self._shared_usage_present: + return self._shared_usage_value + else: + raise AttributeError("missing required field 'shared_usage'") + + @shared_usage.setter + def shared_usage(self, val): + val = self._shared_usage_validator.validate(val) + self._shared_usage_value = val + self._shared_usage_present = True + + @shared_usage.deleter + def shared_usage(self): + self._shared_usage_value = None + self._shared_usage_present = False + + @property + def unshared_usage(self): + """ + Array of the combined size (bytes) of team members' root namespaces, for + each day. + + :rtype: list of [Optional[int]] + """ + if self._unshared_usage_present: + return self._unshared_usage_value + else: + raise AttributeError("missing required field 'unshared_usage'") + + @unshared_usage.setter + def unshared_usage(self, val): + val = self._unshared_usage_validator.validate(val) + self._unshared_usage_value = val + self._unshared_usage_present = True + + @unshared_usage.deleter + def unshared_usage(self): + self._unshared_usage_value = None + self._unshared_usage_present = False + + @property + def shared_folders(self): + """ + Array of the number of shared folders owned by team members, for each + day. + + :rtype: list of [Optional[int]] + """ + if self._shared_folders_present: + return self._shared_folders_value + else: + raise AttributeError("missing required field 'shared_folders'") + + @shared_folders.setter + def shared_folders(self, val): + val = self._shared_folders_validator.validate(val) + self._shared_folders_value = val + self._shared_folders_present = True + + @shared_folders.deleter + def shared_folders(self): + self._shared_folders_value = None + self._shared_folders_present = False + + @property + def member_storage_map(self): + """ + Array of storage summaries of team members' account sizes. Each storage + summary is an array of key, value pairs, where each pair describes a + storage bucket. The key indicates the upper bound of the bucket and the + value is the number of users in that bucket. There is one such summary + per day. If there is no data for a day, the storage summary will be + empty. + + :rtype: list of [list of [StorageBucket]] + """ + if self._member_storage_map_present: + return self._member_storage_map_value + else: + raise AttributeError("missing required field 'member_storage_map'") + + @member_storage_map.setter + def member_storage_map(self, val): + val = self._member_storage_map_validator.validate(val) + self._member_storage_map_value = val + self._member_storage_map_present = True + + @member_storage_map.deleter + def member_storage_map(self): + self._member_storage_map_value = None + self._member_storage_map_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetStorageReport, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetStorageReport(start_date={!r}, total_usage={!r}, shared_usage={!r}, unshared_usage={!r}, shared_folders={!r}, member_storage_map={!r})'.format( + self._start_date_value, + self._total_usage_value, + self._shared_usage_value, + self._unshared_usage_value, + self._shared_folders_value, + self._member_storage_map_value, + ) + +GetStorageReport_validator = bv.Struct(GetStorageReport) + +class GroupAccessType(bb.Union): + """ + Role of a user in group. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupAccessType.member: User is a member of the group, but has no + special permissions. + :ivar team.GroupAccessType.owner: User can rename the group, and add/remove + members. + """ + + _catch_all = None + # Attribute is overwritten below the class definition + member = None + # Attribute is overwritten below the class definition + owner = None + + def is_member(self): + """ + Check if the union tag is ``member``. + + :rtype: bool + """ + return self._tag == 'member' + + def is_owner(self): + """ + Check if the union tag is ``owner``. + + :rtype: bool + """ + return self._tag == 'owner' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupAccessType(%r, %r)' % (self._tag, self._value) + +GroupAccessType_validator = bv.Union(GroupAccessType) + +class GroupCreateArg(bb.Struct): + """ + :ivar team.GroupCreateArg.group_name: Group name. + :ivar team.GroupCreateArg.add_creator_as_owner: Automatically add the + creator of the group. + :ivar team.GroupCreateArg.group_external_id: The creator of a team can + associate an arbitrary external ID to the group. + :ivar team.GroupCreateArg.group_management_type: Whether the team can be + managed by selected users, or only by team admins. + """ + + __slots__ = [ + '_group_name_value', + '_group_name_present', + '_add_creator_as_owner_value', + '_add_creator_as_owner_present', + '_group_external_id_value', + '_group_external_id_present', + '_group_management_type_value', + '_group_management_type_present', + ] + + _has_required_fields = True + + def __init__(self, + group_name=None, + add_creator_as_owner=None, + group_external_id=None, + group_management_type=None): + self._group_name_value = None + self._group_name_present = False + self._add_creator_as_owner_value = None + self._add_creator_as_owner_present = False + self._group_external_id_value = None + self._group_external_id_present = False + self._group_management_type_value = None + self._group_management_type_present = False + if group_name is not None: + self.group_name = group_name + if add_creator_as_owner is not None: + self.add_creator_as_owner = add_creator_as_owner + if group_external_id is not None: + self.group_external_id = group_external_id + if group_management_type is not None: + self.group_management_type = group_management_type + + @property + def group_name(self): + """ + Group name. + + :rtype: str + """ + if self._group_name_present: + return self._group_name_value + else: + raise AttributeError("missing required field 'group_name'") + + @group_name.setter + def group_name(self, val): + val = self._group_name_validator.validate(val) + self._group_name_value = val + self._group_name_present = True + + @group_name.deleter + def group_name(self): + self._group_name_value = None + self._group_name_present = False + + @property + def add_creator_as_owner(self): + """ + Automatically add the creator of the group. + + :rtype: bool + """ + if self._add_creator_as_owner_present: + return self._add_creator_as_owner_value + else: + return False + + @add_creator_as_owner.setter + def add_creator_as_owner(self, val): + val = self._add_creator_as_owner_validator.validate(val) + self._add_creator_as_owner_value = val + self._add_creator_as_owner_present = True + + @add_creator_as_owner.deleter + def add_creator_as_owner(self): + self._add_creator_as_owner_value = None + self._add_creator_as_owner_present = False + + @property + def group_external_id(self): + """ + The creator of a team can associate an arbitrary external ID to the + group. + + :rtype: str + """ + if self._group_external_id_present: + return self._group_external_id_value + else: + return None + + @group_external_id.setter + def group_external_id(self, val): + if val is None: + del self.group_external_id + return + val = self._group_external_id_validator.validate(val) + self._group_external_id_value = val + self._group_external_id_present = True + + @group_external_id.deleter + def group_external_id(self): + self._group_external_id_value = None + self._group_external_id_present = False + + @property + def group_management_type(self): + """ + Whether the team can be managed by selected users, or only by team + admins. + + :rtype: team_common.GroupManagementType + """ + if self._group_management_type_present: + return self._group_management_type_value + else: + return None + + @group_management_type.setter + def group_management_type(self, val): + if val is None: + del self.group_management_type + return + self._group_management_type_validator.validate_type_only(val) + self._group_management_type_value = val + self._group_management_type_present = True + + @group_management_type.deleter + def group_management_type(self): + self._group_management_type_value = None + self._group_management_type_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupCreateArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupCreateArg(group_name={!r}, add_creator_as_owner={!r}, group_external_id={!r}, group_management_type={!r})'.format( + self._group_name_value, + self._add_creator_as_owner_value, + self._group_external_id_value, + self._group_management_type_value, + ) + +GroupCreateArg_validator = bv.Struct(GroupCreateArg) + +class GroupCreateError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupCreateError.group_name_already_used: The requested group + name is already being used by another group. + :ivar team.GroupCreateError.group_name_invalid: Group name is empty or has + invalid characters. + :ivar team.GroupCreateError.external_id_already_in_use: The requested + external ID is already being used by another group. + :ivar team.GroupCreateError.system_managed_group_disallowed: System-managed + group cannot be manually created. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + group_name_already_used = None + # Attribute is overwritten below the class definition + group_name_invalid = None + # Attribute is overwritten below the class definition + external_id_already_in_use = None + # Attribute is overwritten below the class definition + system_managed_group_disallowed = None + # Attribute is overwritten below the class definition + other = None + + def is_group_name_already_used(self): + """ + Check if the union tag is ``group_name_already_used``. + + :rtype: bool + """ + return self._tag == 'group_name_already_used' + + def is_group_name_invalid(self): + """ + Check if the union tag is ``group_name_invalid``. + + :rtype: bool + """ + return self._tag == 'group_name_invalid' + + def is_external_id_already_in_use(self): + """ + Check if the union tag is ``external_id_already_in_use``. + + :rtype: bool + """ + return self._tag == 'external_id_already_in_use' + + def is_system_managed_group_disallowed(self): + """ + Check if the union tag is ``system_managed_group_disallowed``. + + :rtype: bool + """ + return self._tag == 'system_managed_group_disallowed' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupCreateError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupCreateError(%r, %r)' % (self._tag, self._value) + +GroupCreateError_validator = bv.Union(GroupCreateError) + +class GroupSelectorError(bb.Union): + """ + Error that can be raised when :class:`GroupSelector` is used. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupSelectorError.group_not_found: No matching group found. No + groups match the specified group ID. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + group_not_found = None + # Attribute is overwritten below the class definition + other = None + + def is_group_not_found(self): + """ + Check if the union tag is ``group_not_found``. + + :rtype: bool + """ + return self._tag == 'group_not_found' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupSelectorError(%r, %r)' % (self._tag, self._value) + +GroupSelectorError_validator = bv.Union(GroupSelectorError) + +class GroupSelectorWithTeamGroupError(GroupSelectorError): + """ + Error that can be raised when :class:`GroupSelector` is used and team groups + are disallowed from being used. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupSelectorWithTeamGroupError.system_managed_group_disallowed: + This operation is not supported on system-managed groups. + """ + + # Attribute is overwritten below the class definition + system_managed_group_disallowed = None + + def is_system_managed_group_disallowed(self): + """ + Check if the union tag is ``system_managed_group_disallowed``. + + :rtype: bool + """ + return self._tag == 'system_managed_group_disallowed' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupSelectorWithTeamGroupError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupSelectorWithTeamGroupError(%r, %r)' % (self._tag, self._value) + +GroupSelectorWithTeamGroupError_validator = bv.Union(GroupSelectorWithTeamGroupError) + +class GroupDeleteError(GroupSelectorWithTeamGroupError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupDeleteError.group_already_deleted: This group has already + been deleted. + """ + + # Attribute is overwritten below the class definition + group_already_deleted = None + + def is_group_already_deleted(self): + """ + Check if the union tag is ``group_already_deleted``. + + :rtype: bool + """ + return self._tag == 'group_already_deleted' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupDeleteError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupDeleteError(%r, %r)' % (self._tag, self._value) + +GroupDeleteError_validator = bv.Union(GroupDeleteError) + +class GroupFullInfo(team_common.GroupSummary): + """ + Full description of a group. + + :ivar team.GroupFullInfo.members: List of group members. + :ivar team.GroupFullInfo.created: The group creation time as a UTC timestamp + in milliseconds since the Unix epoch. + """ + + __slots__ = [ + '_members_value', + '_members_present', + '_created_value', + '_created_present', + ] + + _has_required_fields = True + + def __init__(self, + group_name=None, + group_id=None, + group_management_type=None, + created=None, + group_external_id=None, + member_count=None, + members=None): + super(GroupFullInfo, self).__init__(group_name, + group_id, + group_management_type, + group_external_id, + member_count) + self._members_value = None + self._members_present = False + self._created_value = None + self._created_present = False + if members is not None: + self.members = members + if created is not None: + self.created = created + + @property + def members(self): + """ + List of group members. + + :rtype: list of [GroupMemberInfo] + """ + if self._members_present: + return self._members_value + else: + return None + + @members.setter + def members(self, val): + if val is None: + del self.members + return + val = self._members_validator.validate(val) + self._members_value = val + self._members_present = True + + @members.deleter + def members(self): + self._members_value = None + self._members_present = False + + @property + def created(self): + """ + The group creation time as a UTC timestamp in milliseconds since the + Unix epoch. + + :rtype: int + """ + if self._created_present: + return self._created_value + else: + raise AttributeError("missing required field 'created'") + + @created.setter + def created(self, val): + val = self._created_validator.validate(val) + self._created_value = val + self._created_present = True + + @created.deleter + def created(self): + self._created_value = None + self._created_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupFullInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupFullInfo(group_name={!r}, group_id={!r}, group_management_type={!r}, created={!r}, group_external_id={!r}, member_count={!r}, members={!r})'.format( + self._group_name_value, + self._group_id_value, + self._group_management_type_value, + self._created_value, + self._group_external_id_value, + self._member_count_value, + self._members_value, + ) + +GroupFullInfo_validator = bv.Struct(GroupFullInfo) + +class GroupMemberInfo(bb.Struct): + """ + Profile of group member, and role in group. + + :ivar team.GroupMemberInfo.profile: Profile of group member. + :ivar team.GroupMemberInfo.access_type: The role that the user has in the + group. + """ + + __slots__ = [ + '_profile_value', + '_profile_present', + '_access_type_value', + '_access_type_present', + ] + + _has_required_fields = True + + def __init__(self, + profile=None, + access_type=None): + self._profile_value = None + self._profile_present = False + self._access_type_value = None + self._access_type_present = False + if profile is not None: + self.profile = profile + if access_type is not None: + self.access_type = access_type + + @property + def profile(self): + """ + Profile of group member. + + :rtype: MemberProfile + """ + if self._profile_present: + return self._profile_value + else: + raise AttributeError("missing required field 'profile'") + + @profile.setter + def profile(self, val): + self._profile_validator.validate_type_only(val) + self._profile_value = val + self._profile_present = True + + @profile.deleter + def profile(self): + self._profile_value = None + self._profile_present = False + + @property + def access_type(self): + """ + The role that the user has in the group. + + :rtype: GroupAccessType + """ + if self._access_type_present: + return self._access_type_value + else: + raise AttributeError("missing required field 'access_type'") + + @access_type.setter + def access_type(self, val): + self._access_type_validator.validate_type_only(val) + self._access_type_value = val + self._access_type_present = True + + @access_type.deleter + def access_type(self): + self._access_type_value = None + self._access_type_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMemberInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMemberInfo(profile={!r}, access_type={!r})'.format( + self._profile_value, + self._access_type_value, + ) + +GroupMemberInfo_validator = bv.Struct(GroupMemberInfo) + +class GroupMemberSelector(bb.Struct): + """ + Argument for selecting a group and a single user. + + :ivar team.GroupMemberSelector.group: Specify a group. + :ivar team.GroupMemberSelector.user: Identity of a user that is a member of + ``group``. + """ + + __slots__ = [ + '_group_value', + '_group_present', + '_user_value', + '_user_present', + ] + + _has_required_fields = True + + def __init__(self, + group=None, + user=None): + self._group_value = None + self._group_present = False + self._user_value = None + self._user_present = False + if group is not None: + self.group = group + if user is not None: + self.user = user + + @property + def group(self): + """ + Specify a group. + + :rtype: GroupSelector + """ + if self._group_present: + return self._group_value + else: + raise AttributeError("missing required field 'group'") + + @group.setter + def group(self, val): + self._group_validator.validate_type_only(val) + self._group_value = val + self._group_present = True + + @group.deleter + def group(self): + self._group_value = None + self._group_present = False + + @property + def user(self): + """ + Identity of a user that is a member of ``group``. + + :rtype: UserSelectorArg + """ + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") + + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMemberSelector, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMemberSelector(group={!r}, user={!r})'.format( + self._group_value, + self._user_value, + ) + +GroupMemberSelector_validator = bv.Struct(GroupMemberSelector) + +class GroupMemberSelectorError(GroupSelectorWithTeamGroupError): + """ + Error that can be raised when :class:`GroupMemberSelector` is used, and the + user is required to be a member of the specified group. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupMemberSelectorError.member_not_in_group: The specified user + is not a member of this group. + """ + + # Attribute is overwritten below the class definition + member_not_in_group = None + + def is_member_not_in_group(self): + """ + Check if the union tag is ``member_not_in_group``. + + :rtype: bool + """ + return self._tag == 'member_not_in_group' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMemberSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMemberSelectorError(%r, %r)' % (self._tag, self._value) + +GroupMemberSelectorError_validator = bv.Union(GroupMemberSelectorError) + +class GroupMemberSetAccessTypeError(GroupMemberSelectorError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar + team.GroupMemberSetAccessTypeError.user_cannot_be_manager_of_company_managed_group: + A company managed group cannot be managed by a user. + """ + + # Attribute is overwritten below the class definition + user_cannot_be_manager_of_company_managed_group = None + + def is_user_cannot_be_manager_of_company_managed_group(self): + """ + Check if the union tag is ``user_cannot_be_manager_of_company_managed_group``. + + :rtype: bool + """ + return self._tag == 'user_cannot_be_manager_of_company_managed_group' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMemberSetAccessTypeError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMemberSetAccessTypeError(%r, %r)' % (self._tag, self._value) + +GroupMemberSetAccessTypeError_validator = bv.Union(GroupMemberSetAccessTypeError) + +class IncludeMembersArg(bb.Struct): + """ + :ivar team.IncludeMembersArg.return_members: Whether to return the list of + members in the group. Note that the default value will cause all the + group members to be returned in the response. This may take a long time + for large groups. + """ + + __slots__ = [ + '_return_members_value', + '_return_members_present', + ] + + _has_required_fields = False + + def __init__(self, + return_members=None): + self._return_members_value = None + self._return_members_present = False + if return_members is not None: + self.return_members = return_members + + @property + def return_members(self): + """ + Whether to return the list of members in the group. Note that the + default value will cause all the group members to be returned in the + response. This may take a long time for large groups. + + :rtype: bool + """ + if self._return_members_present: + return self._return_members_value + else: + return True + + @return_members.setter + def return_members(self, val): + val = self._return_members_validator.validate(val) + self._return_members_value = val + self._return_members_present = True + + @return_members.deleter + def return_members(self): + self._return_members_value = None + self._return_members_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(IncludeMembersArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'IncludeMembersArg(return_members={!r})'.format( + self._return_members_value, + ) + +IncludeMembersArg_validator = bv.Struct(IncludeMembersArg) + +class GroupMembersAddArg(IncludeMembersArg): + """ + :ivar team.GroupMembersAddArg.group: Group to which users will be added. + :ivar team.GroupMembersAddArg.members: List of users to be added to the + group. + """ + + __slots__ = [ + '_group_value', + '_group_present', + '_members_value', + '_members_present', + ] + + _has_required_fields = True + + def __init__(self, + group=None, + members=None, + return_members=None): + super(GroupMembersAddArg, self).__init__(return_members) + self._group_value = None + self._group_present = False + self._members_value = None + self._members_present = False + if group is not None: + self.group = group + if members is not None: + self.members = members + + @property + def group(self): + """ + Group to which users will be added. + + :rtype: GroupSelector + """ + if self._group_present: + return self._group_value + else: + raise AttributeError("missing required field 'group'") + + @group.setter + def group(self, val): + self._group_validator.validate_type_only(val) + self._group_value = val + self._group_present = True + + @group.deleter + def group(self): + self._group_value = None + self._group_present = False + + @property + def members(self): + """ + List of users to be added to the group. + + :rtype: list of [MemberAccess] + """ + if self._members_present: + return self._members_value + else: + raise AttributeError("missing required field 'members'") + + @members.setter + def members(self, val): + val = self._members_validator.validate(val) + self._members_value = val + self._members_present = True + + @members.deleter + def members(self): + self._members_value = None + self._members_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersAddArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersAddArg(group={!r}, members={!r}, return_members={!r})'.format( + self._group_value, + self._members_value, + self._return_members_value, + ) + +GroupMembersAddArg_validator = bv.Struct(GroupMembersAddArg) + +class GroupMembersAddError(GroupSelectorWithTeamGroupError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupMembersAddError.duplicate_user: You cannot add duplicate + users. One or more of the members you are trying to add is already a + member of the group. + :ivar team.GroupMembersAddError.group_not_in_team: Group is not in this + team. You cannot add members to a group that is outside of your team. + :ivar list of [str] team.GroupMembersAddError.members_not_in_team: These + members are not part of your team. Currently, you cannot add members to + a group if they are not part of your team, though this may change in a + subsequent version. To add new members to your Dropbox Business team, + use the :route:`members/add` endpoint. + :ivar list of [str] team.GroupMembersAddError.users_not_found: These users + were not found in Dropbox. + :ivar team.GroupMembersAddError.user_must_be_active_to_be_owner: A suspended + user cannot be added to a group as ``GroupAccessType.owner``. + :ivar list of [str] + team.GroupMembersAddError.user_cannot_be_manager_of_company_managed_group: + A company-managed group cannot be managed by a user. + """ + + # Attribute is overwritten below the class definition + duplicate_user = None + # Attribute is overwritten below the class definition + group_not_in_team = None + # Attribute is overwritten below the class definition + user_must_be_active_to_be_owner = None + + @classmethod + def members_not_in_team(cls, val): + """ + Create an instance of this class set to the ``members_not_in_team`` tag + with value ``val``. + + :param list of [str] val: + :rtype: GroupMembersAddError + """ + return cls('members_not_in_team', val) + + @classmethod + def users_not_found(cls, val): + """ + Create an instance of this class set to the ``users_not_found`` tag with + value ``val``. + + :param list of [str] val: + :rtype: GroupMembersAddError + """ + return cls('users_not_found', val) + + @classmethod + def user_cannot_be_manager_of_company_managed_group(cls, val): + """ + Create an instance of this class set to the + ``user_cannot_be_manager_of_company_managed_group`` tag with value + ``val``. + + :param list of [str] val: + :rtype: GroupMembersAddError + """ + return cls('user_cannot_be_manager_of_company_managed_group', val) + + def is_duplicate_user(self): + """ + Check if the union tag is ``duplicate_user``. + + :rtype: bool + """ + return self._tag == 'duplicate_user' + + def is_group_not_in_team(self): + """ + Check if the union tag is ``group_not_in_team``. + + :rtype: bool + """ + return self._tag == 'group_not_in_team' + + def is_members_not_in_team(self): + """ + Check if the union tag is ``members_not_in_team``. + + :rtype: bool + """ + return self._tag == 'members_not_in_team' + + def is_users_not_found(self): + """ + Check if the union tag is ``users_not_found``. + + :rtype: bool + """ + return self._tag == 'users_not_found' + + def is_user_must_be_active_to_be_owner(self): + """ + Check if the union tag is ``user_must_be_active_to_be_owner``. + + :rtype: bool + """ + return self._tag == 'user_must_be_active_to_be_owner' + + def is_user_cannot_be_manager_of_company_managed_group(self): + """ + Check if the union tag is ``user_cannot_be_manager_of_company_managed_group``. + + :rtype: bool + """ + return self._tag == 'user_cannot_be_manager_of_company_managed_group' + + def get_members_not_in_team(self): + """ + These members are not part of your team. Currently, you cannot add + members to a group if they are not part of your team, though this may + change in a subsequent version. To add new members to your Dropbox + Business team, use the :meth:`dropbox.dropbox.Dropbox.team_members_add` + endpoint. + + Only call this if :meth:`is_members_not_in_team` is true. + + :rtype: list of [str] + """ + if not self.is_members_not_in_team(): + raise AttributeError("tag 'members_not_in_team' not set") + return self._value + + def get_users_not_found(self): + """ + These users were not found in Dropbox. + + Only call this if :meth:`is_users_not_found` is true. + + :rtype: list of [str] + """ + if not self.is_users_not_found(): + raise AttributeError("tag 'users_not_found' not set") + return self._value + + def get_user_cannot_be_manager_of_company_managed_group(self): + """ + A company-managed group cannot be managed by a user. + + Only call this if :meth:`is_user_cannot_be_manager_of_company_managed_group` is true. + + :rtype: list of [str] + """ + if not self.is_user_cannot_be_manager_of_company_managed_group(): + raise AttributeError("tag 'user_cannot_be_manager_of_company_managed_group' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersAddError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersAddError(%r, %r)' % (self._tag, self._value) + +GroupMembersAddError_validator = bv.Union(GroupMembersAddError) + +class GroupMembersChangeResult(bb.Struct): + """ + Result returned by :meth:`dropbox.dropbox.Dropbox.team_groups_members_add` + and :meth:`dropbox.dropbox.Dropbox.team_groups_members_remove`. + + :ivar team.GroupMembersChangeResult.group_info: The group info after member + change operation has been performed. + :ivar team.GroupMembersChangeResult.async_job_id: For legacy purposes + async_job_id will always return one space ' '. Formerly, it was an ID + that was used to obtain the status of granting/revoking group-owned + resources. It's no longer necessary because the async processing now + happens automatically. + """ + + __slots__ = [ + '_group_info_value', + '_group_info_present', + '_async_job_id_value', + '_async_job_id_present', + ] + + _has_required_fields = True + + def __init__(self, + group_info=None, + async_job_id=None): + self._group_info_value = None + self._group_info_present = False + self._async_job_id_value = None + self._async_job_id_present = False + if group_info is not None: + self.group_info = group_info + if async_job_id is not None: + self.async_job_id = async_job_id + + @property + def group_info(self): + """ + The group info after member change operation has been performed. + + :rtype: GroupFullInfo + """ + if self._group_info_present: + return self._group_info_value + else: + raise AttributeError("missing required field 'group_info'") + + @group_info.setter + def group_info(self, val): + self._group_info_validator.validate_type_only(val) + self._group_info_value = val + self._group_info_present = True + + @group_info.deleter + def group_info(self): + self._group_info_value = None + self._group_info_present = False + + @property + def async_job_id(self): + """ + For legacy purposes async_job_id will always return one space ' '. + Formerly, it was an ID that was used to obtain the status of + granting/revoking group-owned resources. It's no longer necessary + because the async processing now happens automatically. + + :rtype: str + """ + if self._async_job_id_present: + return self._async_job_id_value + else: + raise AttributeError("missing required field 'async_job_id'") + + @async_job_id.setter + def async_job_id(self, val): + val = self._async_job_id_validator.validate(val) + self._async_job_id_value = val + self._async_job_id_present = True + + @async_job_id.deleter + def async_job_id(self): + self._async_job_id_value = None + self._async_job_id_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersChangeResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersChangeResult(group_info={!r}, async_job_id={!r})'.format( + self._group_info_value, + self._async_job_id_value, + ) + +GroupMembersChangeResult_validator = bv.Struct(GroupMembersChangeResult) + +class GroupMembersRemoveArg(IncludeMembersArg): + """ + :ivar team.GroupMembersRemoveArg.group: Group from which users will be + removed. + :ivar team.GroupMembersRemoveArg.users: List of users to be removed from the + group. + """ + + __slots__ = [ + '_group_value', + '_group_present', + '_users_value', + '_users_present', + ] + + _has_required_fields = True + + def __init__(self, + group=None, + users=None, + return_members=None): + super(GroupMembersRemoveArg, self).__init__(return_members) + self._group_value = None + self._group_present = False + self._users_value = None + self._users_present = False + if group is not None: + self.group = group + if users is not None: + self.users = users + + @property + def group(self): + """ + Group from which users will be removed. + + :rtype: GroupSelector + """ + if self._group_present: + return self._group_value + else: + raise AttributeError("missing required field 'group'") + + @group.setter + def group(self, val): + self._group_validator.validate_type_only(val) + self._group_value = val + self._group_present = True + + @group.deleter + def group(self): + self._group_value = None + self._group_present = False + + @property + def users(self): + """ + List of users to be removed from the group. + + :rtype: list of [UserSelectorArg] + """ + if self._users_present: + return self._users_value + else: + raise AttributeError("missing required field 'users'") + + @users.setter + def users(self, val): + val = self._users_validator.validate(val) + self._users_value = val + self._users_present = True + + @users.deleter + def users(self): + self._users_value = None + self._users_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersRemoveArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersRemoveArg(group={!r}, users={!r}, return_members={!r})'.format( + self._group_value, + self._users_value, + self._return_members_value, + ) + +GroupMembersRemoveArg_validator = bv.Struct(GroupMembersRemoveArg) + +class GroupMembersSelectorError(GroupSelectorWithTeamGroupError): + """ + Error that can be raised when :class:`GroupMembersSelector` is used, and the + users are required to be members of the specified group. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupMembersSelectorError.member_not_in_group: At least one of + the specified users is not a member of the group. + """ + + # Attribute is overwritten below the class definition + member_not_in_group = None + + def is_member_not_in_group(self): + """ + Check if the union tag is ``member_not_in_group``. + + :rtype: bool + """ + return self._tag == 'member_not_in_group' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersSelectorError(%r, %r)' % (self._tag, self._value) + +GroupMembersSelectorError_validator = bv.Union(GroupMembersSelectorError) + +class GroupMembersRemoveError(GroupMembersSelectorError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupMembersRemoveError.group_not_in_team: Group is not in this + team. You cannot remove members from a group that is outside of your + team. + :ivar list of [str] team.GroupMembersRemoveError.members_not_in_team: These + members are not part of your team. + :ivar list of [str] team.GroupMembersRemoveError.users_not_found: These + users were not found in Dropbox. + """ + + # Attribute is overwritten below the class definition + group_not_in_team = None + + @classmethod + def members_not_in_team(cls, val): + """ + Create an instance of this class set to the ``members_not_in_team`` tag + with value ``val``. + + :param list of [str] val: + :rtype: GroupMembersRemoveError + """ + return cls('members_not_in_team', val) + + @classmethod + def users_not_found(cls, val): + """ + Create an instance of this class set to the ``users_not_found`` tag with + value ``val``. + + :param list of [str] val: + :rtype: GroupMembersRemoveError + """ + return cls('users_not_found', val) + + def is_group_not_in_team(self): + """ + Check if the union tag is ``group_not_in_team``. + + :rtype: bool + """ + return self._tag == 'group_not_in_team' + + def is_members_not_in_team(self): + """ + Check if the union tag is ``members_not_in_team``. + + :rtype: bool + """ + return self._tag == 'members_not_in_team' + + def is_users_not_found(self): + """ + Check if the union tag is ``users_not_found``. + + :rtype: bool + """ + return self._tag == 'users_not_found' + + def get_members_not_in_team(self): + """ + These members are not part of your team. + + Only call this if :meth:`is_members_not_in_team` is true. + + :rtype: list of [str] + """ + if not self.is_members_not_in_team(): + raise AttributeError("tag 'members_not_in_team' not set") + return self._value + + def get_users_not_found(self): + """ + These users were not found in Dropbox. + + Only call this if :meth:`is_users_not_found` is true. + + :rtype: list of [str] + """ + if not self.is_users_not_found(): + raise AttributeError("tag 'users_not_found' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersRemoveError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersRemoveError(%r, %r)' % (self._tag, self._value) + +GroupMembersRemoveError_validator = bv.Union(GroupMembersRemoveError) + +class GroupMembersSelector(bb.Struct): + """ + Argument for selecting a group and a list of users. + + :ivar team.GroupMembersSelector.group: Specify a group. + :ivar team.GroupMembersSelector.users: A list of users that are members of + ``group``. """ __slots__ = [ - '_adds_value', - '_adds_present', - '_edits_value', - '_edits_present', - '_deletes_value', - '_deletes_present', - '_active_users_28_day_value', - '_active_users_28_day_present', - '_active_users_7_day_value', - '_active_users_7_day_present', - '_active_users_1_day_value', - '_active_users_1_day_present', - '_active_shared_folders_28_day_value', - '_active_shared_folders_28_day_present', - '_active_shared_folders_7_day_value', - '_active_shared_folders_7_day_present', - '_active_shared_folders_1_day_value', - '_active_shared_folders_1_day_present', - '_shared_links_created_value', - '_shared_links_created_present', - '_shared_links_viewed_by_team_value', - '_shared_links_viewed_by_team_present', - '_shared_links_viewed_by_outside_user_value', - '_shared_links_viewed_by_outside_user_present', - '_shared_links_viewed_by_not_logged_in_value', - '_shared_links_viewed_by_not_logged_in_present', - '_shared_links_viewed_total_value', - '_shared_links_viewed_total_present', + '_group_value', + '_group_present', + '_users_value', + '_users_present', + ] + + _has_required_fields = True + + def __init__(self, + group=None, + users=None): + self._group_value = None + self._group_present = False + self._users_value = None + self._users_present = False + if group is not None: + self.group = group + if users is not None: + self.users = users + + @property + def group(self): + """ + Specify a group. + + :rtype: GroupSelector + """ + if self._group_present: + return self._group_value + else: + raise AttributeError("missing required field 'group'") + + @group.setter + def group(self, val): + self._group_validator.validate_type_only(val) + self._group_value = val + self._group_present = True + + @group.deleter + def group(self): + self._group_value = None + self._group_present = False + + @property + def users(self): + """ + A list of users that are members of ``group``. + + :rtype: UsersSelectorArg + """ + if self._users_present: + return self._users_value + else: + raise AttributeError("missing required field 'users'") + + @users.setter + def users(self, val): + self._users_validator.validate_type_only(val) + self._users_value = val + self._users_present = True + + @users.deleter + def users(self): + self._users_value = None + self._users_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersSelector, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersSelector(group={!r}, users={!r})'.format( + self._group_value, + self._users_value, + ) + +GroupMembersSelector_validator = bv.Struct(GroupMembersSelector) + +class GroupMembersSetAccessTypeArg(GroupMemberSelector): + """ + :ivar team.GroupMembersSetAccessTypeArg.access_type: New group access type + the user will have. + :ivar team.GroupMembersSetAccessTypeArg.return_members: Whether to return + the list of members in the group. Note that the default value will + cause all the group members to be returned in the response. This may + take a long time for large groups. + """ + + __slots__ = [ + '_access_type_value', + '_access_type_present', + '_return_members_value', + '_return_members_present', ] _has_required_fields = True def __init__(self, - start_date=None, - adds=None, - edits=None, - deletes=None, - active_users_28_day=None, - active_users_7_day=None, - active_users_1_day=None, - active_shared_folders_28_day=None, - active_shared_folders_7_day=None, - active_shared_folders_1_day=None, - shared_links_created=None, - shared_links_viewed_by_team=None, - shared_links_viewed_by_outside_user=None, - shared_links_viewed_by_not_logged_in=None, - shared_links_viewed_total=None): - super(GetActivityReport, self).__init__(start_date) - self._adds_value = None - self._adds_present = False - self._edits_value = None - self._edits_present = False - self._deletes_value = None - self._deletes_present = False - self._active_users_28_day_value = None - self._active_users_28_day_present = False - self._active_users_7_day_value = None - self._active_users_7_day_present = False - self._active_users_1_day_value = None - self._active_users_1_day_present = False - self._active_shared_folders_28_day_value = None - self._active_shared_folders_28_day_present = False - self._active_shared_folders_7_day_value = None - self._active_shared_folders_7_day_present = False - self._active_shared_folders_1_day_value = None - self._active_shared_folders_1_day_present = False - self._shared_links_created_value = None - self._shared_links_created_present = False - self._shared_links_viewed_by_team_value = None - self._shared_links_viewed_by_team_present = False - self._shared_links_viewed_by_outside_user_value = None - self._shared_links_viewed_by_outside_user_present = False - self._shared_links_viewed_by_not_logged_in_value = None - self._shared_links_viewed_by_not_logged_in_present = False - self._shared_links_viewed_total_value = None - self._shared_links_viewed_total_present = False - if adds is not None: - self.adds = adds - if edits is not None: - self.edits = edits - if deletes is not None: - self.deletes = deletes - if active_users_28_day is not None: - self.active_users_28_day = active_users_28_day - if active_users_7_day is not None: - self.active_users_7_day = active_users_7_day - if active_users_1_day is not None: - self.active_users_1_day = active_users_1_day - if active_shared_folders_28_day is not None: - self.active_shared_folders_28_day = active_shared_folders_28_day - if active_shared_folders_7_day is not None: - self.active_shared_folders_7_day = active_shared_folders_7_day - if active_shared_folders_1_day is not None: - self.active_shared_folders_1_day = active_shared_folders_1_day - if shared_links_created is not None: - self.shared_links_created = shared_links_created - if shared_links_viewed_by_team is not None: - self.shared_links_viewed_by_team = shared_links_viewed_by_team - if shared_links_viewed_by_outside_user is not None: - self.shared_links_viewed_by_outside_user = shared_links_viewed_by_outside_user - if shared_links_viewed_by_not_logged_in is not None: - self.shared_links_viewed_by_not_logged_in = shared_links_viewed_by_not_logged_in - if shared_links_viewed_total is not None: - self.shared_links_viewed_total = shared_links_viewed_total + group=None, + user=None, + access_type=None, + return_members=None): + super(GroupMembersSetAccessTypeArg, self).__init__(group, + user) + self._access_type_value = None + self._access_type_present = False + self._return_members_value = None + self._return_members_present = False + if access_type is not None: + self.access_type = access_type + if return_members is not None: + self.return_members = return_members @property - def adds(self): + def access_type(self): """ - Array of total number of adds by team members. + New group access type the user will have. - :rtype: list of [Optional[int]] + :rtype: GroupAccessType """ - if self._adds_present: - return self._adds_value + if self._access_type_present: + return self._access_type_value else: - raise AttributeError("missing required field 'adds'") + raise AttributeError("missing required field 'access_type'") - @adds.setter - def adds(self, val): - val = self._adds_validator.validate(val) - self._adds_value = val - self._adds_present = True + @access_type.setter + def access_type(self, val): + self._access_type_validator.validate_type_only(val) + self._access_type_value = val + self._access_type_present = True - @adds.deleter - def adds(self): - self._adds_value = None - self._adds_present = False + @access_type.deleter + def access_type(self): + self._access_type_value = None + self._access_type_present = False @property - def edits(self): + def return_members(self): """ - Array of number of edits by team members. If the same user edits the - same file multiple times this is counted as a single edit. + Whether to return the list of members in the group. Note that the + default value will cause all the group members to be returned in the + response. This may take a long time for large groups. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._edits_present: - return self._edits_value + if self._return_members_present: + return self._return_members_value else: - raise AttributeError("missing required field 'edits'") + return True - @edits.setter - def edits(self, val): - val = self._edits_validator.validate(val) - self._edits_value = val - self._edits_present = True + @return_members.setter + def return_members(self, val): + val = self._return_members_validator.validate(val) + self._return_members_value = val + self._return_members_present = True - @edits.deleter - def edits(self): - self._edits_value = None - self._edits_present = False + @return_members.deleter + def return_members(self): + self._return_members_value = None + self._return_members_present = False - @property - def deletes(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupMembersSetAccessTypeArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupMembersSetAccessTypeArg(group={!r}, user={!r}, access_type={!r}, return_members={!r})'.format( + self._group_value, + self._user_value, + self._access_type_value, + self._return_members_value, + ) + +GroupMembersSetAccessTypeArg_validator = bv.Struct(GroupMembersSetAccessTypeArg) + +class GroupSelector(bb.Union): + """ + Argument for selecting a single group, either by group_id or by external + group ID. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar str team.GroupSelector.group_id: Group ID. + :ivar str team.GroupSelector.group_external_id: External ID of the group. + """ + + _catch_all = None + + @classmethod + def group_id(cls, val): """ - Array of total number of deletes by team members. + Create an instance of this class set to the ``group_id`` tag with value + ``val``. - :rtype: list of [Optional[int]] + :param str val: + :rtype: GroupSelector """ - if self._deletes_present: - return self._deletes_value - else: - raise AttributeError("missing required field 'deletes'") + return cls('group_id', val) - @deletes.setter - def deletes(self, val): - val = self._deletes_validator.validate(val) - self._deletes_value = val - self._deletes_present = True + @classmethod + def group_external_id(cls, val): + """ + Create an instance of this class set to the ``group_external_id`` tag + with value ``val``. - @deletes.deleter - def deletes(self): - self._deletes_value = None - self._deletes_present = False + :param str val: + :rtype: GroupSelector + """ + return cls('group_external_id', val) - @property - def active_users_28_day(self): + def is_group_id(self): """ - Array of the number of users who have been active in the last 28 days. + Check if the union tag is ``group_id``. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._active_users_28_day_present: - return self._active_users_28_day_value - else: - raise AttributeError("missing required field 'active_users_28_day'") + return self._tag == 'group_id' + + def is_group_external_id(self): + """ + Check if the union tag is ``group_external_id``. + + :rtype: bool + """ + return self._tag == 'group_external_id' + + def get_group_id(self): + """ + Group ID. + + Only call this if :meth:`is_group_id` is true. + + :rtype: str + """ + if not self.is_group_id(): + raise AttributeError("tag 'group_id' not set") + return self._value + + def get_group_external_id(self): + """ + External ID of the group. + + Only call this if :meth:`is_group_external_id` is true. + + :rtype: str + """ + if not self.is_group_external_id(): + raise AttributeError("tag 'group_external_id' not set") + return self._value - @active_users_28_day.setter - def active_users_28_day(self, val): - val = self._active_users_28_day_validator.validate(val) - self._active_users_28_day_value = val - self._active_users_28_day_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupSelector, self)._process_custom_annotations(annotation_type, field_path, processor) - @active_users_28_day.deleter - def active_users_28_day(self): - self._active_users_28_day_value = None - self._active_users_28_day_present = False + def __repr__(self): + return 'GroupSelector(%r, %r)' % (self._tag, self._value) - @property - def active_users_7_day(self): - """ - Array of the number of users who have been active in the last week. +GroupSelector_validator = bv.Union(GroupSelector) - :rtype: list of [Optional[int]] - """ - if self._active_users_7_day_present: - return self._active_users_7_day_value - else: - raise AttributeError("missing required field 'active_users_7_day'") +class GroupUpdateArgs(IncludeMembersArg): + """ + :ivar team.GroupUpdateArgs.group: Specify a group. + :ivar team.GroupUpdateArgs.new_group_name: Optional argument. Set group name + to this if provided. + :ivar team.GroupUpdateArgs.new_group_external_id: Optional argument. New + group external ID. If the argument is None, the group's external_id + won't be updated. If the argument is empty string, the group's external + id will be cleared. + :ivar team.GroupUpdateArgs.new_group_management_type: Set new group + management type, if provided. + """ - @active_users_7_day.setter - def active_users_7_day(self, val): - val = self._active_users_7_day_validator.validate(val) - self._active_users_7_day_value = val - self._active_users_7_day_present = True + __slots__ = [ + '_group_value', + '_group_present', + '_new_group_name_value', + '_new_group_name_present', + '_new_group_external_id_value', + '_new_group_external_id_present', + '_new_group_management_type_value', + '_new_group_management_type_present', + ] - @active_users_7_day.deleter - def active_users_7_day(self): - self._active_users_7_day_value = None - self._active_users_7_day_present = False + _has_required_fields = True + + def __init__(self, + group=None, + return_members=None, + new_group_name=None, + new_group_external_id=None, + new_group_management_type=None): + super(GroupUpdateArgs, self).__init__(return_members) + self._group_value = None + self._group_present = False + self._new_group_name_value = None + self._new_group_name_present = False + self._new_group_external_id_value = None + self._new_group_external_id_present = False + self._new_group_management_type_value = None + self._new_group_management_type_present = False + if group is not None: + self.group = group + if new_group_name is not None: + self.new_group_name = new_group_name + if new_group_external_id is not None: + self.new_group_external_id = new_group_external_id + if new_group_management_type is not None: + self.new_group_management_type = new_group_management_type @property - def active_users_1_day(self): + def group(self): """ - Array of the number of users who have been active in the last day. + Specify a group. - :rtype: list of [Optional[int]] + :rtype: GroupSelector """ - if self._active_users_1_day_present: - return self._active_users_1_day_value + if self._group_present: + return self._group_value else: - raise AttributeError("missing required field 'active_users_1_day'") + raise AttributeError("missing required field 'group'") - @active_users_1_day.setter - def active_users_1_day(self, val): - val = self._active_users_1_day_validator.validate(val) - self._active_users_1_day_value = val - self._active_users_1_day_present = True + @group.setter + def group(self, val): + self._group_validator.validate_type_only(val) + self._group_value = val + self._group_present = True - @active_users_1_day.deleter - def active_users_1_day(self): - self._active_users_1_day_value = None - self._active_users_1_day_present = False + @group.deleter + def group(self): + self._group_value = None + self._group_present = False @property - def active_shared_folders_28_day(self): + def new_group_name(self): """ - Array of the number of shared folders with some activity in the last 28 - days. + Optional argument. Set group name to this if provided. - :rtype: list of [Optional[int]] + :rtype: str """ - if self._active_shared_folders_28_day_present: - return self._active_shared_folders_28_day_value + if self._new_group_name_present: + return self._new_group_name_value else: - raise AttributeError("missing required field 'active_shared_folders_28_day'") + return None - @active_shared_folders_28_day.setter - def active_shared_folders_28_day(self, val): - val = self._active_shared_folders_28_day_validator.validate(val) - self._active_shared_folders_28_day_value = val - self._active_shared_folders_28_day_present = True + @new_group_name.setter + def new_group_name(self, val): + if val is None: + del self.new_group_name + return + val = self._new_group_name_validator.validate(val) + self._new_group_name_value = val + self._new_group_name_present = True - @active_shared_folders_28_day.deleter - def active_shared_folders_28_day(self): - self._active_shared_folders_28_day_value = None - self._active_shared_folders_28_day_present = False + @new_group_name.deleter + def new_group_name(self): + self._new_group_name_value = None + self._new_group_name_present = False @property - def active_shared_folders_7_day(self): + def new_group_external_id(self): """ - Array of the number of shared folders with some activity in the last - week. + Optional argument. New group external ID. If the argument is None, the + group's external_id won't be updated. If the argument is empty string, + the group's external id will be cleared. - :rtype: list of [Optional[int]] + :rtype: str """ - if self._active_shared_folders_7_day_present: - return self._active_shared_folders_7_day_value + if self._new_group_external_id_present: + return self._new_group_external_id_value else: - raise AttributeError("missing required field 'active_shared_folders_7_day'") + return None - @active_shared_folders_7_day.setter - def active_shared_folders_7_day(self, val): - val = self._active_shared_folders_7_day_validator.validate(val) - self._active_shared_folders_7_day_value = val - self._active_shared_folders_7_day_present = True + @new_group_external_id.setter + def new_group_external_id(self, val): + if val is None: + del self.new_group_external_id + return + val = self._new_group_external_id_validator.validate(val) + self._new_group_external_id_value = val + self._new_group_external_id_present = True - @active_shared_folders_7_day.deleter - def active_shared_folders_7_day(self): - self._active_shared_folders_7_day_value = None - self._active_shared_folders_7_day_present = False + @new_group_external_id.deleter + def new_group_external_id(self): + self._new_group_external_id_value = None + self._new_group_external_id_present = False @property - def active_shared_folders_1_day(self): + def new_group_management_type(self): """ - Array of the number of shared folders with some activity in the last - day. + Set new group management type, if provided. - :rtype: list of [Optional[int]] + :rtype: team_common.GroupManagementType """ - if self._active_shared_folders_1_day_present: - return self._active_shared_folders_1_day_value + if self._new_group_management_type_present: + return self._new_group_management_type_value else: - raise AttributeError("missing required field 'active_shared_folders_1_day'") + return None - @active_shared_folders_1_day.setter - def active_shared_folders_1_day(self, val): - val = self._active_shared_folders_1_day_validator.validate(val) - self._active_shared_folders_1_day_value = val - self._active_shared_folders_1_day_present = True + @new_group_management_type.setter + def new_group_management_type(self, val): + if val is None: + del self.new_group_management_type + return + self._new_group_management_type_validator.validate_type_only(val) + self._new_group_management_type_value = val + self._new_group_management_type_present = True - @active_shared_folders_1_day.deleter - def active_shared_folders_1_day(self): - self._active_shared_folders_1_day_value = None - self._active_shared_folders_1_day_present = False + @new_group_management_type.deleter + def new_group_management_type(self): + self._new_group_management_type_value = None + self._new_group_management_type_present = False - @property - def shared_links_created(self): - """ - Array of the number of shared links created. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupUpdateArgs, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: list of [Optional[int]] - """ - if self._shared_links_created_present: - return self._shared_links_created_value - else: - raise AttributeError("missing required field 'shared_links_created'") + def __repr__(self): + return 'GroupUpdateArgs(group={!r}, return_members={!r}, new_group_name={!r}, new_group_external_id={!r}, new_group_management_type={!r})'.format( + self._group_value, + self._return_members_value, + self._new_group_name_value, + self._new_group_external_id_value, + self._new_group_management_type_value, + ) - @shared_links_created.setter - def shared_links_created(self, val): - val = self._shared_links_created_validator.validate(val) - self._shared_links_created_value = val - self._shared_links_created_present = True +GroupUpdateArgs_validator = bv.Struct(GroupUpdateArgs) - @shared_links_created.deleter - def shared_links_created(self): - self._shared_links_created_value = None - self._shared_links_created_present = False +class GroupUpdateError(GroupSelectorWithTeamGroupError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupUpdateError.group_name_already_used: The requested group + name is already being used by another group. + :ivar team.GroupUpdateError.group_name_invalid: Group name is empty or has + invalid characters. + :ivar team.GroupUpdateError.external_id_already_in_use: The requested + external ID is already being used by another group. + """ - @property - def shared_links_viewed_by_team(self): + # Attribute is overwritten below the class definition + group_name_already_used = None + # Attribute is overwritten below the class definition + group_name_invalid = None + # Attribute is overwritten below the class definition + external_id_already_in_use = None + + def is_group_name_already_used(self): """ - Array of the number of views by team users to shared links created by - the team. + Check if the union tag is ``group_name_already_used``. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._shared_links_viewed_by_team_present: - return self._shared_links_viewed_by_team_value - else: - raise AttributeError("missing required field 'shared_links_viewed_by_team'") + return self._tag == 'group_name_already_used' - @shared_links_viewed_by_team.setter - def shared_links_viewed_by_team(self, val): - val = self._shared_links_viewed_by_team_validator.validate(val) - self._shared_links_viewed_by_team_value = val - self._shared_links_viewed_by_team_present = True + def is_group_name_invalid(self): + """ + Check if the union tag is ``group_name_invalid``. - @shared_links_viewed_by_team.deleter - def shared_links_viewed_by_team(self): - self._shared_links_viewed_by_team_value = None - self._shared_links_viewed_by_team_present = False + :rtype: bool + """ + return self._tag == 'group_name_invalid' - @property - def shared_links_viewed_by_outside_user(self): + def is_external_id_already_in_use(self): """ - Array of the number of views by users outside of the team to shared - links created by the team. + Check if the union tag is ``external_id_already_in_use``. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._shared_links_viewed_by_outside_user_present: - return self._shared_links_viewed_by_outside_user_value - else: - raise AttributeError("missing required field 'shared_links_viewed_by_outside_user'") + return self._tag == 'external_id_already_in_use' - @shared_links_viewed_by_outside_user.setter - def shared_links_viewed_by_outside_user(self, val): - val = self._shared_links_viewed_by_outside_user_validator.validate(val) - self._shared_links_viewed_by_outside_user_value = val - self._shared_links_viewed_by_outside_user_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupUpdateError, self)._process_custom_annotations(annotation_type, field_path, processor) - @shared_links_viewed_by_outside_user.deleter - def shared_links_viewed_by_outside_user(self): - self._shared_links_viewed_by_outside_user_value = None - self._shared_links_viewed_by_outside_user_present = False + def __repr__(self): + return 'GroupUpdateError(%r, %r)' % (self._tag, self._value) - @property - def shared_links_viewed_by_not_logged_in(self): - """ - Array of the number of views by non-logged-in users to shared links - created by the team. +GroupUpdateError_validator = bv.Union(GroupUpdateError) - :rtype: list of [Optional[int]] - """ - if self._shared_links_viewed_by_not_logged_in_present: - return self._shared_links_viewed_by_not_logged_in_value - else: - raise AttributeError("missing required field 'shared_links_viewed_by_not_logged_in'") +class GroupsGetInfoError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - @shared_links_viewed_by_not_logged_in.setter - def shared_links_viewed_by_not_logged_in(self, val): - val = self._shared_links_viewed_by_not_logged_in_validator.validate(val) - self._shared_links_viewed_by_not_logged_in_value = val - self._shared_links_viewed_by_not_logged_in_present = True + :ivar team.GroupsGetInfoError.group_not_on_team: The group is not on your + team. + """ - @shared_links_viewed_by_not_logged_in.deleter - def shared_links_viewed_by_not_logged_in(self): - self._shared_links_viewed_by_not_logged_in_value = None - self._shared_links_viewed_by_not_logged_in_present = False + _catch_all = 'other' + # Attribute is overwritten below the class definition + group_not_on_team = None + # Attribute is overwritten below the class definition + other = None - @property - def shared_links_viewed_total(self): + def is_group_not_on_team(self): """ - Array of the total number of views to shared links created by the team. + Check if the union tag is ``group_not_on_team``. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._shared_links_viewed_total_present: - return self._shared_links_viewed_total_value - else: - raise AttributeError("missing required field 'shared_links_viewed_total'") + return self._tag == 'group_not_on_team' - @shared_links_viewed_total.setter - def shared_links_viewed_total(self, val): - val = self._shared_links_viewed_total_validator.validate(val) - self._shared_links_viewed_total_value = val - self._shared_links_viewed_total_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @shared_links_viewed_total.deleter - def shared_links_viewed_total(self): - self._shared_links_viewed_total_value = None - self._shared_links_viewed_total_present = False + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetActivityReport, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupsGetInfoError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetActivityReport(start_date={!r}, adds={!r}, edits={!r}, deletes={!r}, active_users_28_day={!r}, active_users_7_day={!r}, active_users_1_day={!r}, active_shared_folders_28_day={!r}, active_shared_folders_7_day={!r}, active_shared_folders_1_day={!r}, shared_links_created={!r}, shared_links_viewed_by_team={!r}, shared_links_viewed_by_outside_user={!r}, shared_links_viewed_by_not_logged_in={!r}, shared_links_viewed_total={!r})'.format( - self._start_date_value, - self._adds_value, - self._edits_value, - self._deletes_value, - self._active_users_28_day_value, - self._active_users_7_day_value, - self._active_users_1_day_value, - self._active_shared_folders_28_day_value, - self._active_shared_folders_7_day_value, - self._active_shared_folders_1_day_value, - self._shared_links_created_value, - self._shared_links_viewed_by_team_value, - self._shared_links_viewed_by_outside_user_value, - self._shared_links_viewed_by_not_logged_in_value, - self._shared_links_viewed_total_value, - ) + return 'GroupsGetInfoError(%r, %r)' % (self._tag, self._value) -GetActivityReport_validator = bv.Struct(GetActivityReport) +GroupsGetInfoError_validator = bv.Union(GroupsGetInfoError) -class GetDevicesReport(BaseDfbReport): +class GroupsGetInfoItem(bb.Union): """ - Devices Report Result. Contains subsections for different time ranges of - activity. Each of the items in each subsection of the storage report is an - array of values, one value per day. If there is no data for a day, then the - value will be None. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - :ivar team.GetDevicesReport.active_1_day: Report of the number of devices - active in the last day. - :ivar team.GetDevicesReport.active_7_day: Report of the number of devices - active in the last 7 days. - :ivar team.GetDevicesReport.active_28_day: Report of the number of devices - active in the last 28 days. + :ivar str team.GroupsGetInfoItem.id_not_found: An ID that was provided as a + parameter to :route:`groups/get_info`, and did not match a corresponding + group. The ID can be a group ID, or an external ID, depending on how the + method was called. + :ivar GroupFullInfo GroupsGetInfoItem.group_info: Info about a group. """ - __slots__ = [ - '_active_1_day_value', - '_active_1_day_present', - '_active_7_day_value', - '_active_7_day_present', - '_active_28_day_value', - '_active_28_day_present', - ] + _catch_all = None - _has_required_fields = True + @classmethod + def id_not_found(cls, val): + """ + Create an instance of this class set to the ``id_not_found`` tag with + value ``val``. - def __init__(self, - start_date=None, - active_1_day=None, - active_7_day=None, - active_28_day=None): - super(GetDevicesReport, self).__init__(start_date) - self._active_1_day_value = None - self._active_1_day_present = False - self._active_7_day_value = None - self._active_7_day_present = False - self._active_28_day_value = None - self._active_28_day_present = False - if active_1_day is not None: - self.active_1_day = active_1_day - if active_7_day is not None: - self.active_7_day = active_7_day - if active_28_day is not None: - self.active_28_day = active_28_day + :param str val: + :rtype: GroupsGetInfoItem + """ + return cls('id_not_found', val) - @property - def active_1_day(self): + @classmethod + def group_info(cls, val): """ - Report of the number of devices active in the last day. + Create an instance of this class set to the ``group_info`` tag with + value ``val``. + + :param GroupFullInfo val: + :rtype: GroupsGetInfoItem + """ + return cls('group_info', val) + + def is_id_not_found(self): + """ + Check if the union tag is ``id_not_found``. + + :rtype: bool + """ + return self._tag == 'id_not_found' + + def is_group_info(self): + """ + Check if the union tag is ``group_info``. + + :rtype: bool + """ + return self._tag == 'group_info' + + def get_id_not_found(self): + """ + An ID that was provided as a parameter to + :meth:`dropbox.dropbox.Dropbox.team_groups_get_info`, and did not match + a corresponding group. The ID can be a group ID, or an external ID, + depending on how the method was called. + + Only call this if :meth:`is_id_not_found` is true. + + :rtype: str + """ + if not self.is_id_not_found(): + raise AttributeError("tag 'id_not_found' not set") + return self._value + + def get_group_info(self): + """ + Info about a group. + + Only call this if :meth:`is_group_info` is true. + + :rtype: GroupFullInfo + """ + if not self.is_group_info(): + raise AttributeError("tag 'group_info' not set") + return self._value - :rtype: DevicesActive - """ - if self._active_1_day_present: - return self._active_1_day_value - else: - raise AttributeError("missing required field 'active_1_day'") + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupsGetInfoItem, self)._process_custom_annotations(annotation_type, field_path, processor) - @active_1_day.setter - def active_1_day(self, val): - self._active_1_day_validator.validate_type_only(val) - self._active_1_day_value = val - self._active_1_day_present = True + def __repr__(self): + return 'GroupsGetInfoItem(%r, %r)' % (self._tag, self._value) - @active_1_day.deleter - def active_1_day(self): - self._active_1_day_value = None - self._active_1_day_present = False +GroupsGetInfoItem_validator = bv.Union(GroupsGetInfoItem) - @property - def active_7_day(self): - """ - Report of the number of devices active in the last 7 days. +class GroupsListArg(bb.Struct): + """ + :ivar team.GroupsListArg.limit: Number of results to return per call. + """ - :rtype: DevicesActive - """ - if self._active_7_day_present: - return self._active_7_day_value - else: - raise AttributeError("missing required field 'active_7_day'") + __slots__ = [ + '_limit_value', + '_limit_present', + ] - @active_7_day.setter - def active_7_day(self, val): - self._active_7_day_validator.validate_type_only(val) - self._active_7_day_value = val - self._active_7_day_present = True + _has_required_fields = False - @active_7_day.deleter - def active_7_day(self): - self._active_7_day_value = None - self._active_7_day_present = False + def __init__(self, + limit=None): + self._limit_value = None + self._limit_present = False + if limit is not None: + self.limit = limit @property - def active_28_day(self): + def limit(self): """ - Report of the number of devices active in the last 28 days. + Number of results to return per call. - :rtype: DevicesActive + :rtype: int """ - if self._active_28_day_present: - return self._active_28_day_value + if self._limit_present: + return self._limit_value else: - raise AttributeError("missing required field 'active_28_day'") + return 1000 - @active_28_day.setter - def active_28_day(self, val): - self._active_28_day_validator.validate_type_only(val) - self._active_28_day_value = val - self._active_28_day_present = True + @limit.setter + def limit(self, val): + val = self._limit_validator.validate(val) + self._limit_value = val + self._limit_present = True - @active_28_day.deleter - def active_28_day(self): - self._active_28_day_value = None - self._active_28_day_present = False + @limit.deleter + def limit(self): + self._limit_value = None + self._limit_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetDevicesReport, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupsListArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetDevicesReport(start_date={!r}, active_1_day={!r}, active_7_day={!r}, active_28_day={!r})'.format( - self._start_date_value, - self._active_1_day_value, - self._active_7_day_value, - self._active_28_day_value, + return 'GroupsListArg(limit={!r})'.format( + self._limit_value, ) -GetDevicesReport_validator = bv.Struct(GetDevicesReport) +GroupsListArg_validator = bv.Struct(GroupsListArg) -class GetMembershipReport(BaseDfbReport): +class GroupsListContinueArg(bb.Struct): """ - Membership Report Result. Each of the items in the storage report is an - array of values, one value per day. If there is no data for a day, then the - value will be None. - - :ivar team.GetMembershipReport.team_size: Team size, for each day. - :ivar team.GetMembershipReport.pending_invites: The number of pending - invites to the team, for each day. - :ivar team.GetMembershipReport.members_joined: The number of members that - joined the team, for each day. - :ivar team.GetMembershipReport.suspended_members: The number of suspended - team members, for each day. - :ivar team.GetMembershipReport.licenses: The total number of licenses the - team has, for each day. + :ivar team.GroupsListContinueArg.cursor: Indicates from what point to get + the next set of groups. """ __slots__ = [ - '_team_size_value', - '_team_size_present', - '_pending_invites_value', - '_pending_invites_present', - '_members_joined_value', - '_members_joined_present', - '_suspended_members_value', - '_suspended_members_present', - '_licenses_value', - '_licenses_present', + '_cursor_value', + '_cursor_present', ] _has_required_fields = True def __init__(self, - start_date=None, - team_size=None, - pending_invites=None, - members_joined=None, - suspended_members=None, - licenses=None): - super(GetMembershipReport, self).__init__(start_date) - self._team_size_value = None - self._team_size_present = False - self._pending_invites_value = None - self._pending_invites_present = False - self._members_joined_value = None - self._members_joined_present = False - self._suspended_members_value = None - self._suspended_members_present = False - self._licenses_value = None - self._licenses_present = False - if team_size is not None: - self.team_size = team_size - if pending_invites is not None: - self.pending_invites = pending_invites - if members_joined is not None: - self.members_joined = members_joined - if suspended_members is not None: - self.suspended_members = suspended_members - if licenses is not None: - self.licenses = licenses + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def team_size(self): + def cursor(self): """ - Team size, for each day. + Indicates from what point to get the next set of groups. - :rtype: list of [Optional[int]] + :rtype: str """ - if self._team_size_present: - return self._team_size_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'team_size'") + raise AttributeError("missing required field 'cursor'") - @team_size.setter - def team_size(self, val): - val = self._team_size_validator.validate(val) - self._team_size_value = val - self._team_size_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @team_size.deleter - def team_size(self): - self._team_size_value = None - self._team_size_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False - @property - def pending_invites(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupsListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupsListContinueArg(cursor={!r})'.format( + self._cursor_value, + ) + +GroupsListContinueArg_validator = bv.Struct(GroupsListContinueArg) + +class GroupsListContinueError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.GroupsListContinueError.invalid_cursor: The cursor is invalid. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_cursor = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_cursor(self): """ - The number of pending invites to the team, for each day. + Check if the union tag is ``invalid_cursor``. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._pending_invites_present: - return self._pending_invites_value - else: - raise AttributeError("missing required field 'pending_invites'") + return self._tag == 'invalid_cursor' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupsListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupsListContinueError(%r, %r)' % (self._tag, self._value) + +GroupsListContinueError_validator = bv.Union(GroupsListContinueError) + +class GroupsListResult(bb.Struct): + """ + :ivar team.GroupsListResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` to obtain the + additional groups. + :ivar team.GroupsListResult.has_more: Is true if there are additional groups + that have not been returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` can retrieve + them. + """ + + __slots__ = [ + '_groups_value', + '_groups_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', + ] - @pending_invites.setter - def pending_invites(self, val): - val = self._pending_invites_validator.validate(val) - self._pending_invites_value = val - self._pending_invites_present = True + _has_required_fields = True - @pending_invites.deleter - def pending_invites(self): - self._pending_invites_value = None - self._pending_invites_present = False + def __init__(self, + groups=None, + cursor=None, + has_more=None): + self._groups_value = None + self._groups_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if groups is not None: + self.groups = groups + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more @property - def members_joined(self): + def groups(self): """ - The number of members that joined the team, for each day. - - :rtype: list of [Optional[int]] + :rtype: list of [team_common.GroupSummary] """ - if self._members_joined_present: - return self._members_joined_value + if self._groups_present: + return self._groups_value else: - raise AttributeError("missing required field 'members_joined'") + raise AttributeError("missing required field 'groups'") - @members_joined.setter - def members_joined(self, val): - val = self._members_joined_validator.validate(val) - self._members_joined_value = val - self._members_joined_present = True + @groups.setter + def groups(self, val): + val = self._groups_validator.validate(val) + self._groups_value = val + self._groups_present = True - @members_joined.deleter - def members_joined(self): - self._members_joined_value = None - self._members_joined_present = False + @groups.deleter + def groups(self): + self._groups_value = None + self._groups_present = False @property - def suspended_members(self): + def cursor(self): """ - The number of suspended team members, for each day. + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` to obtain the + additional groups. - :rtype: list of [Optional[int]] + :rtype: str """ - if self._suspended_members_present: - return self._suspended_members_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'suspended_members'") + raise AttributeError("missing required field 'cursor'") - @suspended_members.setter - def suspended_members(self, val): - val = self._suspended_members_validator.validate(val) - self._suspended_members_value = val - self._suspended_members_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @suspended_members.deleter - def suspended_members(self): - self._suspended_members_value = None - self._suspended_members_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False @property - def licenses(self): + def has_more(self): """ - The total number of licenses the team has, for each day. + Is true if there are additional groups that have not been returned yet. + An additional call to + :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` can retrieve + them. - :rtype: list of [Optional[int]] + :rtype: bool """ - if self._licenses_present: - return self._licenses_value + if self._has_more_present: + return self._has_more_value else: - raise AttributeError("missing required field 'licenses'") + raise AttributeError("missing required field 'has_more'") - @licenses.setter - def licenses(self, val): - val = self._licenses_validator.validate(val) - self._licenses_value = val - self._licenses_present = True + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - @licenses.deleter - def licenses(self): - self._licenses_value = None - self._licenses_present = False + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetMembershipReport, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupsListResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetMembershipReport(start_date={!r}, team_size={!r}, pending_invites={!r}, members_joined={!r}, suspended_members={!r}, licenses={!r})'.format( - self._start_date_value, - self._team_size_value, - self._pending_invites_value, - self._members_joined_value, - self._suspended_members_value, - self._licenses_value, + return 'GroupsListResult(groups={!r}, cursor={!r}, has_more={!r})'.format( + self._groups_value, + self._cursor_value, + self._has_more_value, ) -GetMembershipReport_validator = bv.Struct(GetMembershipReport) +GroupsListResult_validator = bv.Struct(GroupsListResult) -class GetStorageReport(BaseDfbReport): +class GroupsMembersListArg(bb.Struct): """ - Storage Report Result. Each of the items in the storage report is an array - of values, one value per day. If there is no data for a day, then the value - will be None. - - :ivar team.GetStorageReport.total_usage: Sum of the shared, unshared, and - datastore usages, for each day. - :ivar team.GetStorageReport.shared_usage: Array of the combined size (bytes) - of team members' shared folders, for each day. - :ivar team.GetStorageReport.unshared_usage: Array of the combined size - (bytes) of team members' root namespaces, for each day. - :ivar team.GetStorageReport.shared_folders: Array of the number of shared - folders owned by team members, for each day. - :ivar team.GetStorageReport.member_storage_map: Array of storage summaries - of team members' account sizes. Each storage summary is an array of key, - value pairs, where each pair describes a storage bucket. The key - indicates the upper bound of the bucket and the value is the number of - users in that bucket. There is one such summary per day. If there is no - data for a day, the storage summary will be empty. + :ivar team.GroupsMembersListArg.group: The group whose members are to be + listed. + :ivar team.GroupsMembersListArg.limit: Number of results to return per call. """ __slots__ = [ - '_total_usage_value', - '_total_usage_present', - '_shared_usage_value', - '_shared_usage_present', - '_unshared_usage_value', - '_unshared_usage_present', - '_shared_folders_value', - '_shared_folders_present', - '_member_storage_map_value', - '_member_storage_map_present', + '_group_value', + '_group_present', + '_limit_value', + '_limit_present', ] _has_required_fields = True def __init__(self, - start_date=None, - total_usage=None, - shared_usage=None, - unshared_usage=None, - shared_folders=None, - member_storage_map=None): - super(GetStorageReport, self).__init__(start_date) - self._total_usage_value = None - self._total_usage_present = False - self._shared_usage_value = None - self._shared_usage_present = False - self._unshared_usage_value = None - self._unshared_usage_present = False - self._shared_folders_value = None - self._shared_folders_present = False - self._member_storage_map_value = None - self._member_storage_map_present = False - if total_usage is not None: - self.total_usage = total_usage - if shared_usage is not None: - self.shared_usage = shared_usage - if unshared_usage is not None: - self.unshared_usage = unshared_usage - if shared_folders is not None: - self.shared_folders = shared_folders - if member_storage_map is not None: - self.member_storage_map = member_storage_map - - @property - def total_usage(self): - """ - Sum of the shared, unshared, and datastore usages, for each day. - - :rtype: list of [Optional[int]] - """ - if self._total_usage_present: - return self._total_usage_value - else: - raise AttributeError("missing required field 'total_usage'") - - @total_usage.setter - def total_usage(self, val): - val = self._total_usage_validator.validate(val) - self._total_usage_value = val - self._total_usage_present = True - - @total_usage.deleter - def total_usage(self): - self._total_usage_value = None - self._total_usage_present = False - - @property - def shared_usage(self): - """ - Array of the combined size (bytes) of team members' shared folders, for - each day. - - :rtype: list of [Optional[int]] - """ - if self._shared_usage_present: - return self._shared_usage_value - else: - raise AttributeError("missing required field 'shared_usage'") - - @shared_usage.setter - def shared_usage(self, val): - val = self._shared_usage_validator.validate(val) - self._shared_usage_value = val - self._shared_usage_present = True - - @shared_usage.deleter - def shared_usage(self): - self._shared_usage_value = None - self._shared_usage_present = False + group=None, + limit=None): + self._group_value = None + self._group_present = False + self._limit_value = None + self._limit_present = False + if group is not None: + self.group = group + if limit is not None: + self.limit = limit @property - def unshared_usage(self): + def group(self): """ - Array of the combined size (bytes) of team members' root namespaces, for - each day. + The group whose members are to be listed. - :rtype: list of [Optional[int]] + :rtype: GroupSelector """ - if self._unshared_usage_present: - return self._unshared_usage_value + if self._group_present: + return self._group_value else: - raise AttributeError("missing required field 'unshared_usage'") + raise AttributeError("missing required field 'group'") - @unshared_usage.setter - def unshared_usage(self, val): - val = self._unshared_usage_validator.validate(val) - self._unshared_usage_value = val - self._unshared_usage_present = True + @group.setter + def group(self, val): + self._group_validator.validate_type_only(val) + self._group_value = val + self._group_present = True - @unshared_usage.deleter - def unshared_usage(self): - self._unshared_usage_value = None - self._unshared_usage_present = False + @group.deleter + def group(self): + self._group_value = None + self._group_present = False @property - def shared_folders(self): + def limit(self): """ - Array of the number of shared folders owned by team members, for each - day. + Number of results to return per call. - :rtype: list of [Optional[int]] + :rtype: int """ - if self._shared_folders_present: - return self._shared_folders_value + if self._limit_present: + return self._limit_value else: - raise AttributeError("missing required field 'shared_folders'") + return 1000 - @shared_folders.setter - def shared_folders(self, val): - val = self._shared_folders_validator.validate(val) - self._shared_folders_value = val - self._shared_folders_present = True + @limit.setter + def limit(self, val): + val = self._limit_validator.validate(val) + self._limit_value = val + self._limit_present = True - @shared_folders.deleter - def shared_folders(self): - self._shared_folders_value = None - self._shared_folders_present = False + @limit.deleter + def limit(self): + self._limit_value = None + self._limit_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupsMembersListArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupsMembersListArg(group={!r}, limit={!r})'.format( + self._group_value, + self._limit_value, + ) + +GroupsMembersListArg_validator = bv.Struct(GroupsMembersListArg) + +class GroupsMembersListContinueArg(bb.Struct): + """ + :ivar team.GroupsMembersListContinueArg.cursor: Indicates from what point to + get the next set of groups. + """ + + __slots__ = [ + '_cursor_value', + '_cursor_present', + ] + + _has_required_fields = True + + def __init__(self, + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def member_storage_map(self): + def cursor(self): """ - Array of storage summaries of team members' account sizes. Each storage - summary is an array of key, value pairs, where each pair describes a - storage bucket. The key indicates the upper bound of the bucket and the - value is the number of users in that bucket. There is one such summary - per day. If there is no data for a day, the storage summary will be - empty. + Indicates from what point to get the next set of groups. - :rtype: list of [list of [StorageBucket]] + :rtype: str """ - if self._member_storage_map_present: - return self._member_storage_map_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'member_storage_map'") + raise AttributeError("missing required field 'cursor'") - @member_storage_map.setter - def member_storage_map(self, val): - val = self._member_storage_map_validator.validate(val) - self._member_storage_map_value = val - self._member_storage_map_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @member_storage_map.deleter - def member_storage_map(self): - self._member_storage_map_value = None - self._member_storage_map_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetStorageReport, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupsMembersListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetStorageReport(start_date={!r}, total_usage={!r}, shared_usage={!r}, unshared_usage={!r}, shared_folders={!r}, member_storage_map={!r})'.format( - self._start_date_value, - self._total_usage_value, - self._shared_usage_value, - self._unshared_usage_value, - self._shared_folders_value, - self._member_storage_map_value, + return 'GroupsMembersListContinueArg(cursor={!r})'.format( + self._cursor_value, ) -GetStorageReport_validator = bv.Struct(GetStorageReport) +GroupsMembersListContinueArg_validator = bv.Struct(GroupsMembersListContinueArg) -class GroupAccessType(bb.Union): +class GroupsMembersListContinueError(bb.Union): """ - Role of a user in group. - This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupAccessType.member: User is a member of the group, but has no - special permissions. - :ivar team.GroupAccessType.owner: User can rename the group, and add/remove - members. + :ivar team.GroupsMembersListContinueError.invalid_cursor: The cursor is + invalid. """ - _catch_all = None + _catch_all = 'other' # Attribute is overwritten below the class definition - member = None + invalid_cursor = None # Attribute is overwritten below the class definition - owner = None + other = None - def is_member(self): + def is_invalid_cursor(self): """ - Check if the union tag is ``member``. + Check if the union tag is ``invalid_cursor``. :rtype: bool """ - return self._tag == 'member' + return self._tag == 'invalid_cursor' - def is_owner(self): + def is_other(self): """ - Check if the union tag is ``owner``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'owner' + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupsMembersListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupAccessType(%r, %r)' % (self._tag, self._value) + return 'GroupsMembersListContinueError(%r, %r)' % (self._tag, self._value) -GroupAccessType_validator = bv.Union(GroupAccessType) +GroupsMembersListContinueError_validator = bv.Union(GroupsMembersListContinueError) -class GroupCreateArg(bb.Struct): +class GroupsMembersListResult(bb.Struct): """ - :ivar team.GroupCreateArg.group_name: Group name. - :ivar team.GroupCreateArg.group_external_id: The creator of a team can - associate an arbitrary external ID to the group. - :ivar team.GroupCreateArg.group_management_type: Whether the team can be - managed by selected users, or only by team admins. + :ivar team.GroupsMembersListResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` to + obtain additional group members. + :ivar team.GroupsMembersListResult.has_more: Is true if there are additional + group members that have not been returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` can + retrieve them. """ __slots__ = [ - '_group_name_value', - '_group_name_present', - '_group_external_id_value', - '_group_external_id_present', - '_group_management_type_value', - '_group_management_type_present', + '_members_value', + '_members_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', ] _has_required_fields = True def __init__(self, - group_name=None, - group_external_id=None, - group_management_type=None): - self._group_name_value = None - self._group_name_present = False - self._group_external_id_value = None - self._group_external_id_present = False - self._group_management_type_value = None - self._group_management_type_present = False - if group_name is not None: - self.group_name = group_name - if group_external_id is not None: - self.group_external_id = group_external_id - if group_management_type is not None: - self.group_management_type = group_management_type + members=None, + cursor=None, + has_more=None): + self._members_value = None + self._members_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if members is not None: + self.members = members + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more @property - def group_name(self): + def members(self): """ - Group name. - - :rtype: str + :rtype: list of [GroupMemberInfo] """ - if self._group_name_present: - return self._group_name_value + if self._members_present: + return self._members_value else: - raise AttributeError("missing required field 'group_name'") + raise AttributeError("missing required field 'members'") - @group_name.setter - def group_name(self, val): - val = self._group_name_validator.validate(val) - self._group_name_value = val - self._group_name_present = True + @members.setter + def members(self, val): + val = self._members_validator.validate(val) + self._members_value = val + self._members_present = True - @group_name.deleter - def group_name(self): - self._group_name_value = None - self._group_name_present = False + @members.deleter + def members(self): + self._members_value = None + self._members_present = False @property - def group_external_id(self): + def cursor(self): """ - The creator of a team can associate an arbitrary external ID to the - group. + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` to + obtain additional group members. :rtype: str """ - if self._group_external_id_present: - return self._group_external_id_value + if self._cursor_present: + return self._cursor_value else: - return None + raise AttributeError("missing required field 'cursor'") - @group_external_id.setter - def group_external_id(self, val): - if val is None: - del self.group_external_id - return - val = self._group_external_id_validator.validate(val) - self._group_external_id_value = val - self._group_external_id_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @group_external_id.deleter - def group_external_id(self): - self._group_external_id_value = None - self._group_external_id_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False @property - def group_management_type(self): + def has_more(self): """ - Whether the team can be managed by selected users, or only by team - admins. + Is true if there are additional group members that have not been + returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` can + retrieve them. - :rtype: team_common.GroupManagementType + :rtype: bool """ - if self._group_management_type_present: - return self._group_management_type_value + if self._has_more_present: + return self._has_more_value else: - return None + raise AttributeError("missing required field 'has_more'") - @group_management_type.setter - def group_management_type(self, val): - if val is None: - del self.group_management_type - return - self._group_management_type_validator.validate_type_only(val) - self._group_management_type_value = val - self._group_management_type_present = True + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - @group_management_type.deleter - def group_management_type(self): - self._group_management_type_value = None - self._group_management_type_present = False + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupCreateArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupsMembersListResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupCreateArg(group_name={!r}, group_external_id={!r}, group_management_type={!r})'.format( - self._group_name_value, - self._group_external_id_value, - self._group_management_type_value, + return 'GroupsMembersListResult(members={!r}, cursor={!r}, has_more={!r})'.format( + self._members_value, + self._cursor_value, + self._has_more_value, ) -GroupCreateArg_validator = bv.Struct(GroupCreateArg) +GroupsMembersListResult_validator = bv.Struct(GroupsMembersListResult) -class GroupCreateError(bb.Union): +class GroupsPollError(async_.PollError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupCreateError.group_name_already_used: The requested group - name is already being used by another group. - :ivar team.GroupCreateError.group_name_invalid: Group name is empty or has - invalid characters. - :ivar team.GroupCreateError.external_id_already_in_use: The requested - external ID is already being used by another group. - :ivar team.GroupCreateError.system_managed_group_disallowed: System-managed - group cannot be manually created. + :ivar team.GroupsPollError.access_denied: You are not allowed to poll this + job. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - group_name_already_used = None - # Attribute is overwritten below the class definition - group_name_invalid = None - # Attribute is overwritten below the class definition - external_id_already_in_use = None - # Attribute is overwritten below the class definition - system_managed_group_disallowed = None # Attribute is overwritten below the class definition - other = None + access_denied = None - def is_group_name_already_used(self): + def is_access_denied(self): """ - Check if the union tag is ``group_name_already_used``. + Check if the union tag is ``access_denied``. :rtype: bool """ - return self._tag == 'group_name_already_used' + return self._tag == 'access_denied' - def is_group_name_invalid(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupsPollError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupsPollError(%r, %r)' % (self._tag, self._value) + +GroupsPollError_validator = bv.Union(GroupsPollError) + +class GroupsSelector(bb.Union): + """ + Argument for selecting a list of groups, either by group_ids, or external + group IDs. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar list of [str] team.GroupsSelector.group_ids: List of group IDs. + :ivar list of [str] team.GroupsSelector.group_external_ids: List of external + IDs of groups. + """ + + _catch_all = None + + @classmethod + def group_ids(cls, val): """ - Check if the union tag is ``group_name_invalid``. + Create an instance of this class set to the ``group_ids`` tag with value + ``val``. - :rtype: bool + :param list of [str] val: + :rtype: GroupsSelector """ - return self._tag == 'group_name_invalid' + return cls('group_ids', val) - def is_external_id_already_in_use(self): + @classmethod + def group_external_ids(cls, val): """ - Check if the union tag is ``external_id_already_in_use``. + Create an instance of this class set to the ``group_external_ids`` tag + with value ``val``. - :rtype: bool + :param list of [str] val: + :rtype: GroupsSelector """ - return self._tag == 'external_id_already_in_use' + return cls('group_external_ids', val) - def is_system_managed_group_disallowed(self): + def is_group_ids(self): """ - Check if the union tag is ``system_managed_group_disallowed``. + Check if the union tag is ``group_ids``. :rtype: bool """ - return self._tag == 'system_managed_group_disallowed' + return self._tag == 'group_ids' - def is_other(self): + def is_group_external_ids(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``group_external_ids``. :rtype: bool """ - return self._tag == 'other' + return self._tag == 'group_external_ids' + + def get_group_ids(self): + """ + List of group IDs. + + Only call this if :meth:`is_group_ids` is true. + + :rtype: list of [str] + """ + if not self.is_group_ids(): + raise AttributeError("tag 'group_ids' not set") + return self._value + + def get_group_external_ids(self): + """ + List of external IDs of groups. + + Only call this if :meth:`is_group_external_ids` is true. + + :rtype: list of [str] + """ + if not self.is_group_external_ids(): + raise AttributeError("tag 'group_external_ids' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupCreateError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupsSelector, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupCreateError(%r, %r)' % (self._tag, self._value) + return 'GroupsSelector(%r, %r)' % (self._tag, self._value) -GroupCreateError_validator = bv.Union(GroupCreateError) +GroupsSelector_validator = bv.Union(GroupsSelector) -class GroupSelectorError(bb.Union): +class HasTeamFileEventsValue(bb.Union): """ - Error that can be raised when :class:`GroupSelector` is used. + The value for ``Feature.has_team_file_events``. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupSelectorError.group_not_found: No matching group found. No - groups match the specified group ID. + :ivar bool team.HasTeamFileEventsValue.enabled: Does this team have file + events. """ _catch_all = 'other' # Attribute is overwritten below the class definition - group_not_found = None - # Attribute is overwritten below the class definition other = None - def is_group_not_found(self): + @classmethod + def enabled(cls, val): """ - Check if the union tag is ``group_not_found``. + Create an instance of this class set to the ``enabled`` tag with value + ``val``. - :rtype: bool + :param bool val: + :rtype: HasTeamFileEventsValue """ - return self._tag == 'group_not_found' + return cls('enabled', val) - def is_other(self): + def is_enabled(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``enabled``. :rtype: bool """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'GroupSelectorError(%r, %r)' % (self._tag, self._value) - -GroupSelectorError_validator = bv.Union(GroupSelectorError) - -class GroupSelectorWithTeamGroupError(GroupSelectorError): - """ - Error that can be raised when :class:`GroupSelector` is used and team groups - are disallowed from being used. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.GroupSelectorWithTeamGroupError.system_managed_group_disallowed: - This operation is not supported on system-managed groups. - """ + return self._tag == 'enabled' - # Attribute is overwritten below the class definition - system_managed_group_disallowed = None + def is_other(self): + """ + Check if the union tag is ``other``. - def is_system_managed_group_disallowed(self): + :rtype: bool """ - Check if the union tag is ``system_managed_group_disallowed``. + return self._tag == 'other' + + def get_enabled(self): + """ + Does this team have file events. + + Only call this if :meth:`is_enabled` is true. :rtype: bool """ - return self._tag == 'system_managed_group_disallowed' + if not self.is_enabled(): + raise AttributeError("tag 'enabled' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupSelectorWithTeamGroupError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(HasTeamFileEventsValue, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupSelectorWithTeamGroupError(%r, %r)' % (self._tag, self._value) + return 'HasTeamFileEventsValue(%r, %r)' % (self._tag, self._value) -GroupSelectorWithTeamGroupError_validator = bv.Union(GroupSelectorWithTeamGroupError) +HasTeamFileEventsValue_validator = bv.Union(HasTeamFileEventsValue) -class GroupDeleteError(GroupSelectorWithTeamGroupError): +class HasTeamSelectiveSyncValue(bb.Union): """ + The value for ``Feature.has_team_selective_sync``. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupDeleteError.group_already_deleted: This group has already - been deleted. + :ivar bool team.HasTeamSelectiveSyncValue.has_team_selective_sync: Does this + team have team selective sync enabled. """ + _catch_all = 'other' # Attribute is overwritten below the class definition - group_already_deleted = None + other = None - def is_group_already_deleted(self): + @classmethod + def has_team_selective_sync(cls, val): """ - Check if the union tag is ``group_already_deleted``. + Create an instance of this class set to the ``has_team_selective_sync`` + tag with value ``val``. - :rtype: bool + :param bool val: + :rtype: HasTeamSelectiveSyncValue """ - return self._tag == 'group_already_deleted' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupDeleteError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'GroupDeleteError(%r, %r)' % (self._tag, self._value) - -GroupDeleteError_validator = bv.Union(GroupDeleteError) - -class GroupFullInfo(team_common.GroupSummary): - """ - Full description of a group. - - :ivar team.GroupFullInfo.members: List of group members. - :ivar team.GroupFullInfo.created: The group creation time as a UTC timestamp - in milliseconds since the Unix epoch. - """ - - __slots__ = [ - '_members_value', - '_members_present', - '_created_value', - '_created_present', - ] - - _has_required_fields = True - - def __init__(self, - group_name=None, - group_id=None, - group_management_type=None, - created=None, - group_external_id=None, - member_count=None, - members=None): - super(GroupFullInfo, self).__init__(group_name, - group_id, - group_management_type, - group_external_id, - member_count) - self._members_value = None - self._members_present = False - self._created_value = None - self._created_present = False - if members is not None: - self.members = members - if created is not None: - self.created = created + return cls('has_team_selective_sync', val) - @property - def members(self): + def is_has_team_selective_sync(self): """ - List of group members. + Check if the union tag is ``has_team_selective_sync``. - :rtype: list of [GroupMemberInfo] + :rtype: bool """ - if self._members_present: - return self._members_value - else: - return None - - @members.setter - def members(self, val): - if val is None: - del self.members - return - val = self._members_validator.validate(val) - self._members_value = val - self._members_present = True + return self._tag == 'has_team_selective_sync' - @members.deleter - def members(self): - self._members_value = None - self._members_present = False + def is_other(self): + """ + Check if the union tag is ``other``. - @property - def created(self): + :rtype: bool """ - The group creation time as a UTC timestamp in milliseconds since the - Unix epoch. + return self._tag == 'other' - :rtype: int + def get_has_team_selective_sync(self): """ - if self._created_present: - return self._created_value - else: - raise AttributeError("missing required field 'created'") + Does this team have team selective sync enabled. - @created.setter - def created(self, val): - val = self._created_validator.validate(val) - self._created_value = val - self._created_present = True + Only call this if :meth:`is_has_team_selective_sync` is true. - @created.deleter - def created(self): - self._created_value = None - self._created_present = False + :rtype: bool + """ + if not self.is_has_team_selective_sync(): + raise AttributeError("tag 'has_team_selective_sync' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupFullInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(HasTeamSelectiveSyncValue, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupFullInfo(group_name={!r}, group_id={!r}, group_management_type={!r}, created={!r}, group_external_id={!r}, member_count={!r}, members={!r})'.format( - self._group_name_value, - self._group_id_value, - self._group_management_type_value, - self._created_value, - self._group_external_id_value, - self._member_count_value, - self._members_value, - ) + return 'HasTeamSelectiveSyncValue(%r, %r)' % (self._tag, self._value) -GroupFullInfo_validator = bv.Struct(GroupFullInfo) +HasTeamSelectiveSyncValue_validator = bv.Union(HasTeamSelectiveSyncValue) -class GroupMemberInfo(bb.Struct): +class HasTeamSharedDropboxValue(bb.Union): """ - Profile of group member, and role in group. + The value for ``Feature.has_team_shared_dropbox``. - :ivar team.GroupMemberInfo.profile: Profile of group member. - :ivar team.GroupMemberInfo.access_type: The role that the user has in the - group. - """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - __slots__ = [ - '_profile_value', - '_profile_present', - '_access_type_value', - '_access_type_present', - ] + :ivar bool team.HasTeamSharedDropboxValue.has_team_shared_dropbox: Does this + team have a shared team root. + """ - _has_required_fields = True + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None - def __init__(self, - profile=None, - access_type=None): - self._profile_value = None - self._profile_present = False - self._access_type_value = None - self._access_type_present = False - if profile is not None: - self.profile = profile - if access_type is not None: - self.access_type = access_type + @classmethod + def has_team_shared_dropbox(cls, val): + """ + Create an instance of this class set to the ``has_team_shared_dropbox`` + tag with value ``val``. - @property - def profile(self): + :param bool val: + :rtype: HasTeamSharedDropboxValue """ - Profile of group member. + return cls('has_team_shared_dropbox', val) - :rtype: MemberProfile + def is_has_team_shared_dropbox(self): """ - if self._profile_present: - return self._profile_value - else: - raise AttributeError("missing required field 'profile'") + Check if the union tag is ``has_team_shared_dropbox``. - @profile.setter - def profile(self, val): - self._profile_validator.validate_type_only(val) - self._profile_value = val - self._profile_present = True + :rtype: bool + """ + return self._tag == 'has_team_shared_dropbox' - @profile.deleter - def profile(self): - self._profile_value = None - self._profile_present = False + def is_other(self): + """ + Check if the union tag is ``other``. - @property - def access_type(self): + :rtype: bool """ - The role that the user has in the group. + return self._tag == 'other' - :rtype: GroupAccessType + def get_has_team_shared_dropbox(self): """ - if self._access_type_present: - return self._access_type_value - else: - raise AttributeError("missing required field 'access_type'") + Does this team have a shared team root. - @access_type.setter - def access_type(self, val): - self._access_type_validator.validate_type_only(val) - self._access_type_value = val - self._access_type_present = True + Only call this if :meth:`is_has_team_shared_dropbox` is true. - @access_type.deleter - def access_type(self): - self._access_type_value = None - self._access_type_present = False + :rtype: bool + """ + if not self.is_has_team_shared_dropbox(): + raise AttributeError("tag 'has_team_shared_dropbox' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMemberInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(HasTeamSharedDropboxValue, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMemberInfo(profile={!r}, access_type={!r})'.format( - self._profile_value, - self._access_type_value, - ) - -GroupMemberInfo_validator = bv.Struct(GroupMemberInfo) + return 'HasTeamSharedDropboxValue(%r, %r)' % (self._tag, self._value) -class GroupMemberSelector(bb.Struct): - """ - Argument for selecting a group and a single user. +HasTeamSharedDropboxValue_validator = bv.Union(HasTeamSharedDropboxValue) - :ivar team.GroupMemberSelector.group: Specify a group. - :ivar team.GroupMemberSelector.user: Identity of a user that is a member of - ``group``. +class LegalHoldHeldRevisionMetadata(bb.Struct): + """ + :ivar team.LegalHoldHeldRevisionMetadata.new_filename: The held revision + filename. + :ivar team.LegalHoldHeldRevisionMetadata.original_revision_id: The id of the + held revision. + :ivar team.LegalHoldHeldRevisionMetadata.original_file_path: The original + path of the held revision. + :ivar team.LegalHoldHeldRevisionMetadata.server_modified: The last time the + file was modified on Dropbox. + :ivar team.LegalHoldHeldRevisionMetadata.author_member_id: The member id of + the revision's author. + :ivar team.LegalHoldHeldRevisionMetadata.author_member_status: The member + status of the revision's author. + :ivar team.LegalHoldHeldRevisionMetadata.author_email: The email address of + the held revision author. + :ivar team.LegalHoldHeldRevisionMetadata.file_type: The type of the held + revision's file. + :ivar team.LegalHoldHeldRevisionMetadata.size: The file size in bytes. + :ivar team.LegalHoldHeldRevisionMetadata.content_hash: A hash of the file + content. This field can be used to verify data integrity. For more + information see our `Content hash + `_ page. """ __slots__ = [ - '_group_value', - '_group_present', - '_user_value', - '_user_present', + '_new_filename_value', + '_new_filename_present', + '_original_revision_id_value', + '_original_revision_id_present', + '_original_file_path_value', + '_original_file_path_present', + '_server_modified_value', + '_server_modified_present', + '_author_member_id_value', + '_author_member_id_present', + '_author_member_status_value', + '_author_member_status_present', + '_author_email_value', + '_author_email_present', + '_file_type_value', + '_file_type_present', + '_size_value', + '_size_present', + '_content_hash_value', + '_content_hash_present', ] _has_required_fields = True def __init__(self, - group=None, - user=None): - self._group_value = None - self._group_present = False - self._user_value = None - self._user_present = False - if group is not None: - self.group = group - if user is not None: - self.user = user + new_filename=None, + original_revision_id=None, + original_file_path=None, + server_modified=None, + author_member_id=None, + author_member_status=None, + author_email=None, + file_type=None, + size=None, + content_hash=None): + self._new_filename_value = None + self._new_filename_present = False + self._original_revision_id_value = None + self._original_revision_id_present = False + self._original_file_path_value = None + self._original_file_path_present = False + self._server_modified_value = None + self._server_modified_present = False + self._author_member_id_value = None + self._author_member_id_present = False + self._author_member_status_value = None + self._author_member_status_present = False + self._author_email_value = None + self._author_email_present = False + self._file_type_value = None + self._file_type_present = False + self._size_value = None + self._size_present = False + self._content_hash_value = None + self._content_hash_present = False + if new_filename is not None: + self.new_filename = new_filename + if original_revision_id is not None: + self.original_revision_id = original_revision_id + if original_file_path is not None: + self.original_file_path = original_file_path + if server_modified is not None: + self.server_modified = server_modified + if author_member_id is not None: + self.author_member_id = author_member_id + if author_member_status is not None: + self.author_member_status = author_member_status + if author_email is not None: + self.author_email = author_email + if file_type is not None: + self.file_type = file_type + if size is not None: + self.size = size + if content_hash is not None: + self.content_hash = content_hash + + @property + def new_filename(self): + """ + The held revision filename. + + :rtype: str + """ + if self._new_filename_present: + return self._new_filename_value + else: + raise AttributeError("missing required field 'new_filename'") + + @new_filename.setter + def new_filename(self, val): + val = self._new_filename_validator.validate(val) + self._new_filename_value = val + self._new_filename_present = True + + @new_filename.deleter + def new_filename(self): + self._new_filename_value = None + self._new_filename_present = False @property - def group(self): + def original_revision_id(self): """ - Specify a group. + The id of the held revision. - :rtype: GroupSelector + :rtype: str """ - if self._group_present: - return self._group_value + if self._original_revision_id_present: + return self._original_revision_id_value else: - raise AttributeError("missing required field 'group'") + raise AttributeError("missing required field 'original_revision_id'") - @group.setter - def group(self, val): - self._group_validator.validate_type_only(val) - self._group_value = val - self._group_present = True + @original_revision_id.setter + def original_revision_id(self, val): + val = self._original_revision_id_validator.validate(val) + self._original_revision_id_value = val + self._original_revision_id_present = True - @group.deleter - def group(self): - self._group_value = None - self._group_present = False + @original_revision_id.deleter + def original_revision_id(self): + self._original_revision_id_value = None + self._original_revision_id_present = False @property - def user(self): + def original_file_path(self): """ - Identity of a user that is a member of ``group``. + The original path of the held revision. - :rtype: UserSelectorArg + :rtype: str """ - if self._user_present: - return self._user_value + if self._original_file_path_present: + return self._original_file_path_value else: - raise AttributeError("missing required field 'user'") + raise AttributeError("missing required field 'original_file_path'") - @user.setter - def user(self, val): - self._user_validator.validate_type_only(val) - self._user_value = val - self._user_present = True + @original_file_path.setter + def original_file_path(self, val): + val = self._original_file_path_validator.validate(val) + self._original_file_path_value = val + self._original_file_path_present = True - @user.deleter - def user(self): - self._user_value = None - self._user_present = False + @original_file_path.deleter + def original_file_path(self): + self._original_file_path_value = None + self._original_file_path_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMemberSelector, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def server_modified(self): + """ + The last time the file was modified on Dropbox. - def __repr__(self): - return 'GroupMemberSelector(group={!r}, user={!r})'.format( - self._group_value, - self._user_value, - ) + :rtype: datetime.datetime + """ + if self._server_modified_present: + return self._server_modified_value + else: + raise AttributeError("missing required field 'server_modified'") -GroupMemberSelector_validator = bv.Struct(GroupMemberSelector) + @server_modified.setter + def server_modified(self, val): + val = self._server_modified_validator.validate(val) + self._server_modified_value = val + self._server_modified_present = True -class GroupMemberSelectorError(GroupSelectorWithTeamGroupError): - """ - Error that can be raised when :class:`GroupMemberSelector` is used, and the - user is required to be a member of the specified group. + @server_modified.deleter + def server_modified(self): + self._server_modified_value = None + self._server_modified_present = False - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + @property + def author_member_id(self): + """ + The member id of the revision's author. - :ivar team.GroupMemberSelectorError.member_not_in_group: The specified user - is not a member of this group. - """ + :rtype: str + """ + if self._author_member_id_present: + return self._author_member_id_value + else: + raise AttributeError("missing required field 'author_member_id'") - # Attribute is overwritten below the class definition - member_not_in_group = None + @author_member_id.setter + def author_member_id(self, val): + val = self._author_member_id_validator.validate(val) + self._author_member_id_value = val + self._author_member_id_present = True - def is_member_not_in_group(self): + @author_member_id.deleter + def author_member_id(self): + self._author_member_id_value = None + self._author_member_id_present = False + + @property + def author_member_status(self): """ - Check if the union tag is ``member_not_in_group``. + The member status of the revision's author. - :rtype: bool + :rtype: TeamMemberStatus """ - return self._tag == 'member_not_in_group' + if self._author_member_status_present: + return self._author_member_status_value + else: + raise AttributeError("missing required field 'author_member_status'") - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMemberSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) + @author_member_status.setter + def author_member_status(self, val): + self._author_member_status_validator.validate_type_only(val) + self._author_member_status_value = val + self._author_member_status_present = True - def __repr__(self): - return 'GroupMemberSelectorError(%r, %r)' % (self._tag, self._value) + @author_member_status.deleter + def author_member_status(self): + self._author_member_status_value = None + self._author_member_status_present = False -GroupMemberSelectorError_validator = bv.Union(GroupMemberSelectorError) + @property + def author_email(self): + """ + The email address of the held revision author. -class GroupMemberSetAccessTypeError(GroupMemberSelectorError): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :rtype: str + """ + if self._author_email_present: + return self._author_email_value + else: + raise AttributeError("missing required field 'author_email'") - :ivar - team.GroupMemberSetAccessTypeError.user_cannot_be_manager_of_company_managed_group: - A company managed group cannot be managed by a user. - """ + @author_email.setter + def author_email(self, val): + val = self._author_email_validator.validate(val) + self._author_email_value = val + self._author_email_present = True - # Attribute is overwritten below the class definition - user_cannot_be_manager_of_company_managed_group = None + @author_email.deleter + def author_email(self): + self._author_email_value = None + self._author_email_present = False - def is_user_cannot_be_manager_of_company_managed_group(self): + @property + def file_type(self): """ - Check if the union tag is ``user_cannot_be_manager_of_company_managed_group``. + The type of the held revision's file. - :rtype: bool + :rtype: str """ - return self._tag == 'user_cannot_be_manager_of_company_managed_group' + if self._file_type_present: + return self._file_type_value + else: + raise AttributeError("missing required field 'file_type'") + + @file_type.setter + def file_type(self, val): + val = self._file_type_validator.validate(val) + self._file_type_value = val + self._file_type_present = True + + @file_type.deleter + def file_type(self): + self._file_type_value = None + self._file_type_present = False + + @property + def size(self): + """ + The file size in bytes. + + :rtype: int + """ + if self._size_present: + return self._size_value + else: + raise AttributeError("missing required field 'size'") + + @size.setter + def size(self, val): + val = self._size_validator.validate(val) + self._size_value = val + self._size_present = True + + @size.deleter + def size(self): + self._size_value = None + self._size_present = False + + @property + def content_hash(self): + """ + A hash of the file content. This field can be used to verify data + integrity. For more information see our `Content hash + `_ page. + + :rtype: str + """ + if self._content_hash_present: + return self._content_hash_value + else: + raise AttributeError("missing required field 'content_hash'") + + @content_hash.setter + def content_hash(self, val): + val = self._content_hash_validator.validate(val) + self._content_hash_value = val + self._content_hash_present = True + + @content_hash.deleter + def content_hash(self): + self._content_hash_value = None + self._content_hash_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMemberSetAccessTypeError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldHeldRevisionMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMemberSetAccessTypeError(%r, %r)' % (self._tag, self._value) + return 'LegalHoldHeldRevisionMetadata(new_filename={!r}, original_revision_id={!r}, original_file_path={!r}, server_modified={!r}, author_member_id={!r}, author_member_status={!r}, author_email={!r}, file_type={!r}, size={!r}, content_hash={!r})'.format( + self._new_filename_value, + self._original_revision_id_value, + self._original_file_path_value, + self._server_modified_value, + self._author_member_id_value, + self._author_member_status_value, + self._author_email_value, + self._file_type_value, + self._size_value, + self._content_hash_value, + ) -GroupMemberSetAccessTypeError_validator = bv.Union(GroupMemberSetAccessTypeError) +LegalHoldHeldRevisionMetadata_validator = bv.Struct(LegalHoldHeldRevisionMetadata) -class IncludeMembersArg(bb.Struct): +class LegalHoldPolicy(bb.Struct): """ - :ivar team.IncludeMembersArg.return_members: Whether to return the list of - members in the group. Note that the default value will cause all the - group members to be returned in the response. This may take a long time - for large groups. + :ivar team.LegalHoldPolicy.id: The legal hold id. + :ivar team.LegalHoldPolicy.name: Policy name. + :ivar team.LegalHoldPolicy.description: A description of the legal hold + policy. + :ivar team.LegalHoldPolicy.activation_time: The time at which the legal hold + was activated. + :ivar team.LegalHoldPolicy.members: Team members IDs and number of + permanetly deleted members under hold. + :ivar team.LegalHoldPolicy.status: The current state of the hold. + :ivar team.LegalHoldPolicy.start_date: Start date of the legal hold policy. + :ivar team.LegalHoldPolicy.end_date: End date of the legal hold policy. """ __slots__ = [ - '_return_members_value', - '_return_members_present', + '_id_value', + '_id_present', + '_name_value', + '_name_present', + '_description_value', + '_description_present', + '_activation_time_value', + '_activation_time_present', + '_members_value', + '_members_present', + '_status_value', + '_status_present', + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - return_members=None): - self._return_members_value = None - self._return_members_present = False - if return_members is not None: - self.return_members = return_members + id=None, + name=None, + members=None, + status=None, + start_date=None, + description=None, + activation_time=None, + end_date=None): + self._id_value = None + self._id_present = False + self._name_value = None + self._name_present = False + self._description_value = None + self._description_present = False + self._activation_time_value = None + self._activation_time_present = False + self._members_value = None + self._members_present = False + self._status_value = None + self._status_present = False + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if id is not None: + self.id = id + if name is not None: + self.name = name + if description is not None: + self.description = description + if activation_time is not None: + self.activation_time = activation_time + if members is not None: + self.members = members + if status is not None: + self.status = status + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date @property - def return_members(self): + def id(self): """ - Whether to return the list of members in the group. Note that the - default value will cause all the group members to be returned in the - response. This may take a long time for large groups. + The legal hold id. - :rtype: bool + :rtype: str """ - if self._return_members_present: - return self._return_members_value + if self._id_present: + return self._id_value else: - return True + raise AttributeError("missing required field 'id'") - @return_members.setter - def return_members(self, val): - val = self._return_members_validator.validate(val) - self._return_members_value = val - self._return_members_present = True + @id.setter + def id(self, val): + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True - @return_members.deleter - def return_members(self): - self._return_members_value = None - self._return_members_present = False + @id.deleter + def id(self): + self._id_value = None + self._id_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IncludeMembersArg, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def name(self): + """ + Policy name. - def __repr__(self): - return 'IncludeMembersArg(return_members={!r})'.format( - self._return_members_value, - ) + :rtype: str + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") -IncludeMembersArg_validator = bv.Struct(IncludeMembersArg) + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False -class GroupMembersAddArg(IncludeMembersArg): - """ - :ivar team.GroupMembersAddArg.group: Group to which users will be added. - :ivar team.GroupMembersAddArg.members: List of users to be added to the - group. - """ + @property + def description(self): + """ + A description of the legal hold policy. - __slots__ = [ - '_group_value', - '_group_present', - '_members_value', - '_members_present', - ] + :rtype: str + """ + if self._description_present: + return self._description_value + else: + return None - _has_required_fields = True + @description.setter + def description(self, val): + if val is None: + del self.description + return + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - def __init__(self, - group=None, - members=None, - return_members=None): - super(GroupMembersAddArg, self).__init__(return_members) - self._group_value = None - self._group_present = False - self._members_value = None - self._members_present = False - if group is not None: - self.group = group - if members is not None: - self.members = members + @description.deleter + def description(self): + self._description_value = None + self._description_present = False @property - def group(self): + def activation_time(self): """ - Group to which users will be added. + The time at which the legal hold was activated. - :rtype: GroupSelector + :rtype: datetime.datetime """ - if self._group_present: - return self._group_value + if self._activation_time_present: + return self._activation_time_value else: - raise AttributeError("missing required field 'group'") + return None - @group.setter - def group(self, val): - self._group_validator.validate_type_only(val) - self._group_value = val - self._group_present = True + @activation_time.setter + def activation_time(self, val): + if val is None: + del self.activation_time + return + val = self._activation_time_validator.validate(val) + self._activation_time_value = val + self._activation_time_present = True - @group.deleter - def group(self): - self._group_value = None - self._group_present = False + @activation_time.deleter + def activation_time(self): + self._activation_time_value = None + self._activation_time_present = False @property def members(self): """ - List of users to be added to the group. + Team members IDs and number of permanetly deleted members under hold. - :rtype: list of [MemberAccess] + :rtype: MembersInfo """ if self._members_present: return self._members_value @@ -4501,7 +7791,7 @@ def members(self): @members.setter def members(self, val): - val = self._members_validator.validate(val) + self._members_validator.validate_type_only(val) self._members_value = val self._members_present = True @@ -4510,1230 +7800,1579 @@ def members(self): self._members_value = None self._members_present = False + @property + def status(self): + """ + The current state of the hold. + + :rtype: LegalHoldStatus + """ + if self._status_present: + return self._status_value + else: + raise AttributeError("missing required field 'status'") + + @status.setter + def status(self, val): + self._status_validator.validate_type_only(val) + self._status_value = val + self._status_present = True + + @status.deleter + def status(self): + self._status_value = None + self._status_present = False + + @property + def start_date(self): + """ + Start date of the legal hold policy. + + :rtype: datetime.datetime + """ + if self._start_date_present: + return self._start_date_value + else: + raise AttributeError("missing required field 'start_date'") + + @start_date.setter + def start_date(self, val): + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True + + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False + + @property + def end_date(self): + """ + End date of the legal hold policy. + + :rtype: datetime.datetime + """ + if self._end_date_present: + return self._end_date_value + else: + return None + + @end_date.setter + def end_date(self, val): + if val is None: + del self.end_date + return + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True + + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersAddArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersAddArg(group={!r}, members={!r}, return_members={!r})'.format( - self._group_value, + return 'LegalHoldPolicy(id={!r}, name={!r}, members={!r}, status={!r}, start_date={!r}, description={!r}, activation_time={!r}, end_date={!r})'.format( + self._id_value, + self._name_value, self._members_value, - self._return_members_value, + self._status_value, + self._start_date_value, + self._description_value, + self._activation_time_value, + self._end_date_value, ) -GroupMembersAddArg_validator = bv.Struct(GroupMembersAddArg) +LegalHoldPolicy_validator = bv.Struct(LegalHoldPolicy) -class GroupMembersAddError(GroupSelectorWithTeamGroupError): +class LegalHoldStatus(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupMembersAddError.duplicate_user: You cannot add duplicate - users. One or more of the members you are trying to add is already a - member of the group. - :ivar team.GroupMembersAddError.group_not_in_team: Group is not in this - team. You cannot add members to a group that is outside of your team. - :ivar list of [str] team.GroupMembersAddError.members_not_in_team: These - members are not part of your team. Currently, you cannot add members to - a group if they are not part of your team, though this may change in a - subsequent version. To add new members to your Dropbox Business team, - use the :route:`members/add` endpoint. - :ivar list of [str] team.GroupMembersAddError.users_not_found: These users - were not found in Dropbox. - :ivar team.GroupMembersAddError.user_must_be_active_to_be_owner: A suspended - user cannot be added to a group as ``GroupAccessType.owner``. - :ivar list of [str] - team.GroupMembersAddError.user_cannot_be_manager_of_company_managed_group: - A company-managed group cannot be managed by a user. + :ivar team.LegalHoldStatus.active: The legal hold policy is active. + :ivar team.LegalHoldStatus.released: The legal hold policy was released. + :ivar team.LegalHoldStatus.activating: The legal hold policy is activating. + :ivar team.LegalHoldStatus.updating: The legal hold policy is updating. + :ivar team.LegalHoldStatus.exporting: The legal hold policy is exporting. + :ivar team.LegalHoldStatus.releasing: The legal hold policy is releasing. """ + _catch_all = 'other' # Attribute is overwritten below the class definition - duplicate_user = None + active = None # Attribute is overwritten below the class definition - group_not_in_team = None + released = None # Attribute is overwritten below the class definition - user_must_be_active_to_be_owner = None + activating = None + # Attribute is overwritten below the class definition + updating = None + # Attribute is overwritten below the class definition + exporting = None + # Attribute is overwritten below the class definition + releasing = None + # Attribute is overwritten below the class definition + other = None - @classmethod - def members_not_in_team(cls, val): + def is_active(self): """ - Create an instance of this class set to the ``members_not_in_team`` tag - with value ``val``. + Check if the union tag is ``active``. - :param list of [str] val: - :rtype: GroupMembersAddError + :rtype: bool """ - return cls('members_not_in_team', val) + return self._tag == 'active' - @classmethod - def users_not_found(cls, val): + def is_released(self): """ - Create an instance of this class set to the ``users_not_found`` tag with - value ``val``. + Check if the union tag is ``released``. - :param list of [str] val: - :rtype: GroupMembersAddError + :rtype: bool """ - return cls('users_not_found', val) + return self._tag == 'released' - @classmethod - def user_cannot_be_manager_of_company_managed_group(cls, val): + def is_activating(self): """ - Create an instance of this class set to the - ``user_cannot_be_manager_of_company_managed_group`` tag with value - ``val``. + Check if the union tag is ``activating``. - :param list of [str] val: - :rtype: GroupMembersAddError + :rtype: bool """ - return cls('user_cannot_be_manager_of_company_managed_group', val) + return self._tag == 'activating' - def is_duplicate_user(self): + def is_updating(self): """ - Check if the union tag is ``duplicate_user``. + Check if the union tag is ``updating``. :rtype: bool """ - return self._tag == 'duplicate_user' + return self._tag == 'updating' - def is_group_not_in_team(self): + def is_exporting(self): """ - Check if the union tag is ``group_not_in_team``. + Check if the union tag is ``exporting``. :rtype: bool """ - return self._tag == 'group_not_in_team' + return self._tag == 'exporting' - def is_members_not_in_team(self): + def is_releasing(self): """ - Check if the union tag is ``members_not_in_team``. + Check if the union tag is ``releasing``. :rtype: bool """ - return self._tag == 'members_not_in_team' + return self._tag == 'releasing' - def is_users_not_found(self): + def is_other(self): """ - Check if the union tag is ``users_not_found``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'users_not_found' + return self._tag == 'other' - def is_user_must_be_active_to_be_owner(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LegalHoldStatus(%r, %r)' % (self._tag, self._value) + +LegalHoldStatus_validator = bv.Union(LegalHoldStatus) + +class LegalHoldsError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.LegalHoldsError.unknown_legal_hold_error: There has been an + unknown legal hold error. + :ivar team.LegalHoldsError.insufficient_permissions: You don't have + permissions to perform this action. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + unknown_legal_hold_error = None + # Attribute is overwritten below the class definition + insufficient_permissions = None + # Attribute is overwritten below the class definition + other = None + + def is_unknown_legal_hold_error(self): """ - Check if the union tag is ``user_must_be_active_to_be_owner``. + Check if the union tag is ``unknown_legal_hold_error``. :rtype: bool """ - return self._tag == 'user_must_be_active_to_be_owner' + return self._tag == 'unknown_legal_hold_error' - def is_user_cannot_be_manager_of_company_managed_group(self): + def is_insufficient_permissions(self): """ - Check if the union tag is ``user_cannot_be_manager_of_company_managed_group``. + Check if the union tag is ``insufficient_permissions``. :rtype: bool """ - return self._tag == 'user_cannot_be_manager_of_company_managed_group' + return self._tag == 'insufficient_permissions' - def get_members_not_in_team(self): + def is_other(self): """ - These members are not part of your team. Currently, you cannot add - members to a group if they are not part of your team, though this may - change in a subsequent version. To add new members to your Dropbox - Business team, use the :meth:`dropbox.dropbox.Dropbox.team_members_add` - endpoint. + Check if the union tag is ``other``. - Only call this if :meth:`is_members_not_in_team` is true. + :rtype: bool + """ + return self._tag == 'other' - :rtype: list of [str] + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldsError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LegalHoldsError(%r, %r)' % (self._tag, self._value) + +LegalHoldsError_validator = bv.Union(LegalHoldsError) + +class LegalHoldsGetPolicyArg(bb.Struct): + """ + :ivar team.LegalHoldsGetPolicyArg.id: The legal hold Id. + """ + + __slots__ = [ + '_id_value', + '_id_present', + ] + + _has_required_fields = True + + def __init__(self, + id=None): + self._id_value = None + self._id_present = False + if id is not None: + self.id = id + + @property + def id(self): """ - if not self.is_members_not_in_team(): - raise AttributeError("tag 'members_not_in_team' not set") - return self._value + The legal hold Id. - def get_users_not_found(self): + :rtype: str """ - These users were not found in Dropbox. + if self._id_present: + return self._id_value + else: + raise AttributeError("missing required field 'id'") - Only call this if :meth:`is_users_not_found` is true. + @id.setter + def id(self, val): + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True - :rtype: list of [str] - """ - if not self.is_users_not_found(): - raise AttributeError("tag 'users_not_found' not set") - return self._value + @id.deleter + def id(self): + self._id_value = None + self._id_present = False - def get_user_cannot_be_manager_of_company_managed_group(self): - """ - A company-managed group cannot be managed by a user. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldsGetPolicyArg, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_user_cannot_be_manager_of_company_managed_group` is true. + def __repr__(self): + return 'LegalHoldsGetPolicyArg(id={!r})'.format( + self._id_value, + ) - :rtype: list of [str] +LegalHoldsGetPolicyArg_validator = bv.Struct(LegalHoldsGetPolicyArg) + +class LegalHoldsGetPolicyError(LegalHoldsError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.LegalHoldsGetPolicyError.legal_hold_policy_not_found: Legal hold + policy does not exist for ``LegalHoldsGetPolicyArg.id``. + """ + + # Attribute is overwritten below the class definition + legal_hold_policy_not_found = None + + def is_legal_hold_policy_not_found(self): """ - if not self.is_user_cannot_be_manager_of_company_managed_group(): - raise AttributeError("tag 'user_cannot_be_manager_of_company_managed_group' not set") - return self._value + Check if the union tag is ``legal_hold_policy_not_found``. + + :rtype: bool + """ + return self._tag == 'legal_hold_policy_not_found' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersAddError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsGetPolicyError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersAddError(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsGetPolicyError(%r, %r)' % (self._tag, self._value) -GroupMembersAddError_validator = bv.Union(GroupMembersAddError) +LegalHoldsGetPolicyError_validator = bv.Union(LegalHoldsGetPolicyError) -class GroupMembersChangeResult(bb.Struct): +class LegalHoldsListHeldRevisionResult(bb.Struct): """ - Result returned by :meth:`dropbox.dropbox.Dropbox.team_groups_members_add` - and :meth:`dropbox.dropbox.Dropbox.team_groups_members_remove`. - - :ivar team.GroupMembersChangeResult.group_info: The group info after member - change operation has been performed. - :ivar team.GroupMembersChangeResult.async_job_id: An ID that can be used to - obtain the status of granting/revoking group-owned resources. + :ivar team.LegalHoldsListHeldRevisionResult.entries: List of file entries + that under the hold. + :ivar team.LegalHoldsListHeldRevisionResult.cursor: The cursor idicates + where to continue reading file metadata entries for the next API call. + When there are no more entries, the cursor will return none. Pass the + cursor into /2/team/legal_holds/list_held_revisions/continue. + :ivar team.LegalHoldsListHeldRevisionResult.has_more: True if there are more + file entries that haven't been returned. You can retrieve them with a + call to /legal_holds/list_held_revisions_continue. """ __slots__ = [ - '_group_info_value', - '_group_info_present', - '_async_job_id_value', - '_async_job_id_present', + '_entries_value', + '_entries_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', ] _has_required_fields = True def __init__(self, - group_info=None, - async_job_id=None): - self._group_info_value = None - self._group_info_present = False - self._async_job_id_value = None - self._async_job_id_present = False - if group_info is not None: - self.group_info = group_info - if async_job_id is not None: - self.async_job_id = async_job_id + entries=None, + has_more=None, + cursor=None): + self._entries_value = None + self._entries_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if entries is not None: + self.entries = entries + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more @property - def group_info(self): + def entries(self): """ - The group info after member change operation has been performed. + List of file entries that under the hold. - :rtype: GroupFullInfo + :rtype: list of [LegalHoldHeldRevisionMetadata] """ - if self._group_info_present: - return self._group_info_value + if self._entries_present: + return self._entries_value else: - raise AttributeError("missing required field 'group_info'") + raise AttributeError("missing required field 'entries'") - @group_info.setter - def group_info(self, val): - self._group_info_validator.validate_type_only(val) - self._group_info_value = val - self._group_info_present = True + @entries.setter + def entries(self, val): + val = self._entries_validator.validate(val) + self._entries_value = val + self._entries_present = True - @group_info.deleter - def group_info(self): - self._group_info_value = None - self._group_info_present = False + @entries.deleter + def entries(self): + self._entries_value = None + self._entries_present = False @property - def async_job_id(self): + def cursor(self): """ - An ID that can be used to obtain the status of granting/revoking - group-owned resources. + The cursor idicates where to continue reading file metadata entries for + the next API call. When there are no more entries, the cursor will + return none. Pass the cursor into + /2/team/legal_holds/list_held_revisions/continue. :rtype: str """ - if self._async_job_id_present: - return self._async_job_id_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'async_job_id'") + return None - @async_job_id.setter - def async_job_id(self, val): - val = self._async_job_id_validator.validate(val) - self._async_job_id_value = val - self._async_job_id_present = True + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @async_job_id.deleter - def async_job_id(self): - self._async_job_id_value = None - self._async_job_id_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False + + @property + def has_more(self): + """ + True if there are more file entries that haven't been returned. You can + retrieve them with a call to /legal_holds/list_held_revisions_continue. + + :rtype: bool + """ + if self._has_more_present: + return self._has_more_value + else: + raise AttributeError("missing required field 'has_more'") + + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True + + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersChangeResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsListHeldRevisionResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersChangeResult(group_info={!r}, async_job_id={!r})'.format( - self._group_info_value, - self._async_job_id_value, + return 'LegalHoldsListHeldRevisionResult(entries={!r}, has_more={!r}, cursor={!r})'.format( + self._entries_value, + self._has_more_value, + self._cursor_value, ) -GroupMembersChangeResult_validator = bv.Struct(GroupMembersChangeResult) +LegalHoldsListHeldRevisionResult_validator = bv.Struct(LegalHoldsListHeldRevisionResult) -class GroupMembersRemoveArg(IncludeMembersArg): +class LegalHoldsListHeldRevisionsArg(bb.Struct): """ - :ivar team.GroupMembersRemoveArg.group: Group from which users will be - removed. - :ivar team.GroupMembersRemoveArg.users: List of users to be removed from the - group. + :ivar team.LegalHoldsListHeldRevisionsArg.id: The legal hold Id. """ __slots__ = [ - '_group_value', - '_group_present', - '_users_value', - '_users_present', + '_id_value', + '_id_present', ] _has_required_fields = True def __init__(self, - group=None, - users=None, - return_members=None): - super(GroupMembersRemoveArg, self).__init__(return_members) - self._group_value = None - self._group_present = False - self._users_value = None - self._users_present = False - if group is not None: - self.group = group - if users is not None: - self.users = users - - @property - def group(self): - """ - Group from which users will be removed. - - :rtype: GroupSelector - """ - if self._group_present: - return self._group_value - else: - raise AttributeError("missing required field 'group'") - - @group.setter - def group(self, val): - self._group_validator.validate_type_only(val) - self._group_value = val - self._group_present = True - - @group.deleter - def group(self): - self._group_value = None - self._group_present = False + id=None): + self._id_value = None + self._id_present = False + if id is not None: + self.id = id @property - def users(self): + def id(self): """ - List of users to be removed from the group. + The legal hold Id. - :rtype: list of [UserSelectorArg] + :rtype: str """ - if self._users_present: - return self._users_value + if self._id_present: + return self._id_value else: - raise AttributeError("missing required field 'users'") + raise AttributeError("missing required field 'id'") - @users.setter - def users(self, val): - val = self._users_validator.validate(val) - self._users_value = val - self._users_present = True + @id.setter + def id(self, val): + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True - @users.deleter - def users(self): - self._users_value = None - self._users_present = False + @id.deleter + def id(self): + self._id_value = None + self._id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersRemoveArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsListHeldRevisionsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersRemoveArg(group={!r}, users={!r}, return_members={!r})'.format( - self._group_value, - self._users_value, - self._return_members_value, + return 'LegalHoldsListHeldRevisionsArg(id={!r})'.format( + self._id_value, ) -GroupMembersRemoveArg_validator = bv.Struct(GroupMembersRemoveArg) +LegalHoldsListHeldRevisionsArg_validator = bv.Struct(LegalHoldsListHeldRevisionsArg) -class GroupMembersSelectorError(GroupSelectorWithTeamGroupError): +class LegalHoldsListHeldRevisionsContinueArg(bb.Struct): + """ + :ivar team.LegalHoldsListHeldRevisionsContinueArg.id: The legal hold Id. + :ivar team.LegalHoldsListHeldRevisionsContinueArg.cursor: The cursor + idicates where to continue reading file metadata entries for the next + API call. When there are no more entries, the cursor will return none. """ - Error that can be raised when :class:`GroupMembersSelector` is used, and the - users are required to be members of the specified group. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + __slots__ = [ + '_id_value', + '_id_present', + '_cursor_value', + '_cursor_present', + ] - :ivar team.GroupMembersSelectorError.member_not_in_group: At least one of - the specified users is not a member of the group. - """ + _has_required_fields = True - # Attribute is overwritten below the class definition - member_not_in_group = None + def __init__(self, + id=None, + cursor=None): + self._id_value = None + self._id_present = False + self._cursor_value = None + self._cursor_present = False + if id is not None: + self.id = id + if cursor is not None: + self.cursor = cursor + + @property + def id(self): + """ + The legal hold Id. + + :rtype: str + """ + if self._id_present: + return self._id_value + else: + raise AttributeError("missing required field 'id'") + + @id.setter + def id(self, val): + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True + + @id.deleter + def id(self): + self._id_value = None + self._id_present = False + + @property + def cursor(self): + """ + The cursor idicates where to continue reading file metadata entries for + the next API call. When there are no more entries, the cursor will + return none. + + :rtype: str + """ + if self._cursor_present: + return self._cursor_value + else: + return None - def is_member_not_in_group(self): - """ - Check if the union tag is ``member_not_in_group``. + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - :rtype: bool - """ - return self._tag == 'member_not_in_group' + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsListHeldRevisionsContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersSelectorError(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsListHeldRevisionsContinueArg(id={!r}, cursor={!r})'.format( + self._id_value, + self._cursor_value, + ) -GroupMembersSelectorError_validator = bv.Union(GroupMembersSelectorError) +LegalHoldsListHeldRevisionsContinueArg_validator = bv.Struct(LegalHoldsListHeldRevisionsContinueArg) -class GroupMembersRemoveError(GroupMembersSelectorError): +class LegalHoldsListHeldRevisionsContinueError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupMembersRemoveError.group_not_in_team: Group is not in this - team. You cannot remove members from a group that is outside of your - team. - :ivar list of [str] team.GroupMembersRemoveError.members_not_in_team: These - members are not part of your team. - :ivar list of [str] team.GroupMembersRemoveError.users_not_found: These - users were not found in Dropbox. + :ivar + team.LegalHoldsListHeldRevisionsContinueError.unknown_legal_hold_error: + There has been an unknown legal hold error. + :ivar team.LegalHoldsListHeldRevisionsContinueError.transient_error: + Temporary infrastructure failure, please retry. + :ivar team.LegalHoldsListHeldRevisionsContinueError.reset: Indicates that + the cursor has been invalidated. Call + :meth:`dropbox.dropbox.Dropbox.team_legal_holds_list_held_revisions_continue` + again with an empty cursor to obtain a new cursor. """ + _catch_all = 'other' # Attribute is overwritten below the class definition - group_not_in_team = None + unknown_legal_hold_error = None + # Attribute is overwritten below the class definition + transient_error = None + # Attribute is overwritten below the class definition + reset = None + # Attribute is overwritten below the class definition + other = None - @classmethod - def members_not_in_team(cls, val): + def is_unknown_legal_hold_error(self): """ - Create an instance of this class set to the ``members_not_in_team`` tag - with value ``val``. + Check if the union tag is ``unknown_legal_hold_error``. - :param list of [str] val: - :rtype: GroupMembersRemoveError + :rtype: bool """ - return cls('members_not_in_team', val) + return self._tag == 'unknown_legal_hold_error' - @classmethod - def users_not_found(cls, val): + def is_transient_error(self): """ - Create an instance of this class set to the ``users_not_found`` tag with - value ``val``. + Check if the union tag is ``transient_error``. - :param list of [str] val: - :rtype: GroupMembersRemoveError + :rtype: bool """ - return cls('users_not_found', val) + return self._tag == 'transient_error' - def is_group_not_in_team(self): + def is_reset(self): """ - Check if the union tag is ``group_not_in_team``. + Check if the union tag is ``reset``. :rtype: bool """ - return self._tag == 'group_not_in_team' + return self._tag == 'reset' - def is_members_not_in_team(self): + def is_other(self): """ - Check if the union tag is ``members_not_in_team``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'members_not_in_team' + return self._tag == 'other' - def is_users_not_found(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldsListHeldRevisionsContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LegalHoldsListHeldRevisionsContinueError(%r, %r)' % (self._tag, self._value) + +LegalHoldsListHeldRevisionsContinueError_validator = bv.Union(LegalHoldsListHeldRevisionsContinueError) + +class LegalHoldsListHeldRevisionsError(LegalHoldsError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.LegalHoldsListHeldRevisionsError.transient_error: Temporary + infrastructure failure, please retry. + :ivar team.LegalHoldsListHeldRevisionsError.legal_hold_still_empty: The + legal hold is not holding any revisions yet. + :ivar team.LegalHoldsListHeldRevisionsError.inactive_legal_hold: Trying to + list revisions for an inactive legal hold. + """ + + # Attribute is overwritten below the class definition + transient_error = None + # Attribute is overwritten below the class definition + legal_hold_still_empty = None + # Attribute is overwritten below the class definition + inactive_legal_hold = None + + def is_transient_error(self): """ - Check if the union tag is ``users_not_found``. + Check if the union tag is ``transient_error``. :rtype: bool """ - return self._tag == 'users_not_found' + return self._tag == 'transient_error' - def get_members_not_in_team(self): + def is_legal_hold_still_empty(self): """ - These members are not part of your team. - - Only call this if :meth:`is_members_not_in_team` is true. + Check if the union tag is ``legal_hold_still_empty``. - :rtype: list of [str] + :rtype: bool """ - if not self.is_members_not_in_team(): - raise AttributeError("tag 'members_not_in_team' not set") - return self._value + return self._tag == 'legal_hold_still_empty' - def get_users_not_found(self): + def is_inactive_legal_hold(self): """ - These users were not found in Dropbox. - - Only call this if :meth:`is_users_not_found` is true. + Check if the union tag is ``inactive_legal_hold``. - :rtype: list of [str] + :rtype: bool """ - if not self.is_users_not_found(): - raise AttributeError("tag 'users_not_found' not set") - return self._value + return self._tag == 'inactive_legal_hold' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersRemoveError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsListHeldRevisionsError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersRemoveError(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsListHeldRevisionsError(%r, %r)' % (self._tag, self._value) -GroupMembersRemoveError_validator = bv.Union(GroupMembersRemoveError) +LegalHoldsListHeldRevisionsError_validator = bv.Union(LegalHoldsListHeldRevisionsError) -class GroupMembersSelector(bb.Struct): +class LegalHoldsListPoliciesArg(bb.Struct): """ - Argument for selecting a group and a list of users. - - :ivar team.GroupMembersSelector.group: Specify a group. - :ivar team.GroupMembersSelector.users: A list of users that are members of - ``group``. + :ivar team.LegalHoldsListPoliciesArg.include_released: Whether to return + holds that were released. """ __slots__ = [ - '_group_value', - '_group_present', - '_users_value', - '_users_present', + '_include_released_value', + '_include_released_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - group=None, - users=None): - self._group_value = None - self._group_present = False - self._users_value = None - self._users_present = False - if group is not None: - self.group = group - if users is not None: - self.users = users + include_released=None): + self._include_released_value = None + self._include_released_present = False + if include_released is not None: + self.include_released = include_released @property - def group(self): + def include_released(self): """ - Specify a group. + Whether to return holds that were released. - :rtype: GroupSelector + :rtype: bool """ - if self._group_present: - return self._group_value + if self._include_released_present: + return self._include_released_value else: - raise AttributeError("missing required field 'group'") + return False - @group.setter - def group(self, val): - self._group_validator.validate_type_only(val) - self._group_value = val - self._group_present = True + @include_released.setter + def include_released(self, val): + val = self._include_released_validator.validate(val) + self._include_released_value = val + self._include_released_present = True - @group.deleter - def group(self): - self._group_value = None - self._group_present = False + @include_released.deleter + def include_released(self): + self._include_released_value = None + self._include_released_present = False - @property - def users(self): - """ - A list of users that are members of ``group``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldsListPoliciesArg, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: UsersSelectorArg - """ - if self._users_present: - return self._users_value - else: - raise AttributeError("missing required field 'users'") + def __repr__(self): + return 'LegalHoldsListPoliciesArg(include_released={!r})'.format( + self._include_released_value, + ) - @users.setter - def users(self, val): - self._users_validator.validate_type_only(val) - self._users_value = val - self._users_present = True +LegalHoldsListPoliciesArg_validator = bv.Struct(LegalHoldsListPoliciesArg) - @users.deleter - def users(self): - self._users_value = None - self._users_present = False +class LegalHoldsListPoliciesError(LegalHoldsError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.LegalHoldsListPoliciesError.transient_error: Temporary + infrastructure failure, please retry. + """ + + # Attribute is overwritten below the class definition + transient_error = None + + def is_transient_error(self): + """ + Check if the union tag is ``transient_error``. + + :rtype: bool + """ + return self._tag == 'transient_error' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersSelector, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsListPoliciesError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersSelector(group={!r}, users={!r})'.format( - self._group_value, - self._users_value, - ) + return 'LegalHoldsListPoliciesError(%r, %r)' % (self._tag, self._value) -GroupMembersSelector_validator = bv.Struct(GroupMembersSelector) +LegalHoldsListPoliciesError_validator = bv.Union(LegalHoldsListPoliciesError) -class GroupMembersSetAccessTypeArg(GroupMemberSelector): - """ - :ivar team.GroupMembersSetAccessTypeArg.access_type: New group access type - the user will have. - :ivar team.GroupMembersSetAccessTypeArg.return_members: Whether to return - the list of members in the group. Note that the default value will - cause all the group members to be returned in the response. This may - take a long time for large groups. - """ +class LegalHoldsListPoliciesResult(bb.Struct): __slots__ = [ - '_access_type_value', - '_access_type_present', - '_return_members_value', - '_return_members_present', + '_policies_value', + '_policies_present', ] _has_required_fields = True def __init__(self, - group=None, - user=None, - access_type=None, - return_members=None): - super(GroupMembersSetAccessTypeArg, self).__init__(group, - user) - self._access_type_value = None - self._access_type_present = False - self._return_members_value = None - self._return_members_present = False - if access_type is not None: - self.access_type = access_type - if return_members is not None: - self.return_members = return_members - - @property - def access_type(self): - """ - New group access type the user will have. - - :rtype: GroupAccessType - """ - if self._access_type_present: - return self._access_type_value - else: - raise AttributeError("missing required field 'access_type'") - - @access_type.setter - def access_type(self, val): - self._access_type_validator.validate_type_only(val) - self._access_type_value = val - self._access_type_present = True - - @access_type.deleter - def access_type(self): - self._access_type_value = None - self._access_type_present = False + policies=None): + self._policies_value = None + self._policies_present = False + if policies is not None: + self.policies = policies @property - def return_members(self): - """ - Whether to return the list of members in the group. Note that the - default value will cause all the group members to be returned in the - response. This may take a long time for large groups. - - :rtype: bool + def policies(self): """ - if self._return_members_present: - return self._return_members_value + :rtype: list of [LegalHoldPolicy] + """ + if self._policies_present: + return self._policies_value else: - return True + raise AttributeError("missing required field 'policies'") - @return_members.setter - def return_members(self, val): - val = self._return_members_validator.validate(val) - self._return_members_value = val - self._return_members_present = True + @policies.setter + def policies(self, val): + val = self._policies_validator.validate(val) + self._policies_value = val + self._policies_present = True - @return_members.deleter - def return_members(self): - self._return_members_value = None - self._return_members_present = False + @policies.deleter + def policies(self): + self._policies_value = None + self._policies_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMembersSetAccessTypeArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsListPoliciesResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMembersSetAccessTypeArg(group={!r}, user={!r}, access_type={!r}, return_members={!r})'.format( - self._group_value, - self._user_value, - self._access_type_value, - self._return_members_value, + return 'LegalHoldsListPoliciesResult(policies={!r})'.format( + self._policies_value, ) -GroupMembersSetAccessTypeArg_validator = bv.Struct(GroupMembersSetAccessTypeArg) +LegalHoldsListPoliciesResult_validator = bv.Struct(LegalHoldsListPoliciesResult) -class GroupSelector(bb.Union): +class LegalHoldsPolicyCreateArg(bb.Struct): + """ + :ivar team.LegalHoldsPolicyCreateArg.name: Policy name. + :ivar team.LegalHoldsPolicyCreateArg.description: A description of the legal + hold policy. + :ivar team.LegalHoldsPolicyCreateArg.members: List of team members added to + the hold. + :ivar team.LegalHoldsPolicyCreateArg.start_date: start date of the legal + hold policy. + :ivar team.LegalHoldsPolicyCreateArg.end_date: end date of the legal hold + policy. """ - Argument for selecting a single group, either by group_id or by external - group ID. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + __slots__ = [ + '_name_value', + '_name_present', + '_description_value', + '_description_present', + '_members_value', + '_members_present', + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', + ] - :ivar str team.GroupSelector.group_id: Group ID. - :ivar str team.GroupSelector.group_external_id: External ID of the group. - """ + _has_required_fields = True - _catch_all = None + def __init__(self, + name=None, + members=None, + description=None, + start_date=None, + end_date=None): + self._name_value = None + self._name_present = False + self._description_value = None + self._description_present = False + self._members_value = None + self._members_present = False + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if name is not None: + self.name = name + if description is not None: + self.description = description + if members is not None: + self.members = members + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date - @classmethod - def group_id(cls, val): + @property + def name(self): """ - Create an instance of this class set to the ``group_id`` tag with value - ``val``. + Policy name. - :param str val: - :rtype: GroupSelector + :rtype: str """ - return cls('group_id', val) + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") - @classmethod - def group_external_id(cls, val): - """ - Create an instance of this class set to the ``group_external_id`` tag - with value ``val``. + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True - :param str val: - :rtype: GroupSelector + @name.deleter + def name(self): + self._name_value = None + self._name_present = False + + @property + def description(self): """ - return cls('group_external_id', val) + A description of the legal hold policy. - def is_group_id(self): + :rtype: str """ - Check if the union tag is ``group_id``. + if self._description_present: + return self._description_value + else: + return None - :rtype: bool + @description.setter + def description(self, val): + if val is None: + del self.description + return + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + @property + def members(self): """ - return self._tag == 'group_id' + List of team members added to the hold. - def is_group_external_id(self): + :rtype: list of [str] """ - Check if the union tag is ``group_external_id``. + if self._members_present: + return self._members_value + else: + raise AttributeError("missing required field 'members'") - :rtype: bool + @members.setter + def members(self, val): + val = self._members_validator.validate(val) + self._members_value = val + self._members_present = True + + @members.deleter + def members(self): + self._members_value = None + self._members_present = False + + @property + def start_date(self): """ - return self._tag == 'group_external_id' + start date of the legal hold policy. - def get_group_id(self): + :rtype: datetime.datetime """ - Group ID. + if self._start_date_present: + return self._start_date_value + else: + return None - Only call this if :meth:`is_group_id` is true. + @start_date.setter + def start_date(self, val): + if val is None: + del self.start_date + return + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True - :rtype: str + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False + + @property + def end_date(self): """ - if not self.is_group_id(): - raise AttributeError("tag 'group_id' not set") - return self._value + end date of the legal hold policy. - def get_group_external_id(self): + :rtype: datetime.datetime """ - External ID of the group. + if self._end_date_present: + return self._end_date_value + else: + return None - Only call this if :meth:`is_group_external_id` is true. + @end_date.setter + def end_date(self, val): + if val is None: + del self.end_date + return + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True - :rtype: str - """ - if not self.is_group_external_id(): - raise AttributeError("tag 'group_external_id' not set") - return self._value + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupSelector, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsPolicyCreateArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupSelector(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsPolicyCreateArg(name={!r}, members={!r}, description={!r}, start_date={!r}, end_date={!r})'.format( + self._name_value, + self._members_value, + self._description_value, + self._start_date_value, + self._end_date_value, + ) -GroupSelector_validator = bv.Union(GroupSelector) +LegalHoldsPolicyCreateArg_validator = bv.Struct(LegalHoldsPolicyCreateArg) -class GroupUpdateArgs(IncludeMembersArg): - """ - :ivar team.GroupUpdateArgs.group: Specify a group. - :ivar team.GroupUpdateArgs.new_group_name: Optional argument. Set group name - to this if provided. - :ivar team.GroupUpdateArgs.new_group_external_id: Optional argument. New - group external ID. If the argument is None, the group's external_id - won't be updated. If the argument is empty string, the group's external - id will be cleared. - :ivar team.GroupUpdateArgs.new_group_management_type: Set new group - management type, if provided. +class LegalHoldsPolicyCreateError(LegalHoldsError): """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - __slots__ = [ - '_group_value', - '_group_present', - '_new_group_name_value', - '_new_group_name_present', - '_new_group_external_id_value', - '_new_group_external_id_present', - '_new_group_management_type_value', - '_new_group_management_type_present', - ] - - _has_required_fields = True + :ivar team.LegalHoldsPolicyCreateError.start_date_is_later_than_end_date: + Start date must be earlier than end date. + :ivar team.LegalHoldsPolicyCreateError.empty_members_list: The users list + must have at least one user. + :ivar team.LegalHoldsPolicyCreateError.invalid_members: Some members in the + members list are not valid to be placed under legal hold. + :ivar + team.LegalHoldsPolicyCreateError.number_of_users_on_hold_is_greater_than_hold_limitation: + You cannot add more than 5 users in a legal hold. + :ivar team.LegalHoldsPolicyCreateError.transient_error: Temporary + infrastructure failure, please retry. + :ivar team.LegalHoldsPolicyCreateError.name_must_be_unique: The name + provided is already in use by another legal hold. + :ivar team.LegalHoldsPolicyCreateError.team_exceeded_legal_hold_quota: Team + exceeded legal hold quota. + """ - def __init__(self, - group=None, - return_members=None, - new_group_name=None, - new_group_external_id=None, - new_group_management_type=None): - super(GroupUpdateArgs, self).__init__(return_members) - self._group_value = None - self._group_present = False - self._new_group_name_value = None - self._new_group_name_present = False - self._new_group_external_id_value = None - self._new_group_external_id_present = False - self._new_group_management_type_value = None - self._new_group_management_type_present = False - if group is not None: - self.group = group - if new_group_name is not None: - self.new_group_name = new_group_name - if new_group_external_id is not None: - self.new_group_external_id = new_group_external_id - if new_group_management_type is not None: - self.new_group_management_type = new_group_management_type + # Attribute is overwritten below the class definition + start_date_is_later_than_end_date = None + # Attribute is overwritten below the class definition + empty_members_list = None + # Attribute is overwritten below the class definition + invalid_members = None + # Attribute is overwritten below the class definition + number_of_users_on_hold_is_greater_than_hold_limitation = None + # Attribute is overwritten below the class definition + transient_error = None + # Attribute is overwritten below the class definition + name_must_be_unique = None + # Attribute is overwritten below the class definition + team_exceeded_legal_hold_quota = None - @property - def group(self): + def is_start_date_is_later_than_end_date(self): """ - Specify a group. + Check if the union tag is ``start_date_is_later_than_end_date``. - :rtype: GroupSelector + :rtype: bool """ - if self._group_present: - return self._group_value - else: - raise AttributeError("missing required field 'group'") + return self._tag == 'start_date_is_later_than_end_date' - @group.setter - def group(self, val): - self._group_validator.validate_type_only(val) - self._group_value = val - self._group_present = True + def is_empty_members_list(self): + """ + Check if the union tag is ``empty_members_list``. - @group.deleter - def group(self): - self._group_value = None - self._group_present = False + :rtype: bool + """ + return self._tag == 'empty_members_list' - @property - def new_group_name(self): + def is_invalid_members(self): """ - Optional argument. Set group name to this if provided. + Check if the union tag is ``invalid_members``. - :rtype: str + :rtype: bool """ - if self._new_group_name_present: - return self._new_group_name_value - else: - return None + return self._tag == 'invalid_members' - @new_group_name.setter - def new_group_name(self, val): - if val is None: - del self.new_group_name - return - val = self._new_group_name_validator.validate(val) - self._new_group_name_value = val - self._new_group_name_present = True + def is_number_of_users_on_hold_is_greater_than_hold_limitation(self): + """ + Check if the union tag is ``number_of_users_on_hold_is_greater_than_hold_limitation``. - @new_group_name.deleter - def new_group_name(self): - self._new_group_name_value = None - self._new_group_name_present = False + :rtype: bool + """ + return self._tag == 'number_of_users_on_hold_is_greater_than_hold_limitation' - @property - def new_group_external_id(self): + def is_transient_error(self): """ - Optional argument. New group external ID. If the argument is None, the - group's external_id won't be updated. If the argument is empty string, - the group's external id will be cleared. + Check if the union tag is ``transient_error``. - :rtype: str + :rtype: bool """ - if self._new_group_external_id_present: - return self._new_group_external_id_value - else: - return None + return self._tag == 'transient_error' - @new_group_external_id.setter - def new_group_external_id(self, val): - if val is None: - del self.new_group_external_id - return - val = self._new_group_external_id_validator.validate(val) - self._new_group_external_id_value = val - self._new_group_external_id_present = True + def is_name_must_be_unique(self): + """ + Check if the union tag is ``name_must_be_unique``. - @new_group_external_id.deleter - def new_group_external_id(self): - self._new_group_external_id_value = None - self._new_group_external_id_present = False + :rtype: bool + """ + return self._tag == 'name_must_be_unique' + + def is_team_exceeded_legal_hold_quota(self): + """ + Check if the union tag is ``team_exceeded_legal_hold_quota``. + + :rtype: bool + """ + return self._tag == 'team_exceeded_legal_hold_quota' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldsPolicyCreateError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LegalHoldsPolicyCreateError(%r, %r)' % (self._tag, self._value) + +LegalHoldsPolicyCreateError_validator = bv.Union(LegalHoldsPolicyCreateError) + +class LegalHoldsPolicyReleaseArg(bb.Struct): + """ + :ivar team.LegalHoldsPolicyReleaseArg.id: The legal hold Id. + """ + + __slots__ = [ + '_id_value', + '_id_present', + ] + + _has_required_fields = True + + def __init__(self, + id=None): + self._id_value = None + self._id_present = False + if id is not None: + self.id = id @property - def new_group_management_type(self): + def id(self): """ - Set new group management type, if provided. + The legal hold Id. - :rtype: team_common.GroupManagementType + :rtype: str """ - if self._new_group_management_type_present: - return self._new_group_management_type_value + if self._id_present: + return self._id_value else: - return None + raise AttributeError("missing required field 'id'") - @new_group_management_type.setter - def new_group_management_type(self, val): - if val is None: - del self.new_group_management_type - return - self._new_group_management_type_validator.validate_type_only(val) - self._new_group_management_type_value = val - self._new_group_management_type_present = True + @id.setter + def id(self, val): + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True - @new_group_management_type.deleter - def new_group_management_type(self): - self._new_group_management_type_value = None - self._new_group_management_type_present = False + @id.deleter + def id(self): + self._id_value = None + self._id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupUpdateArgs, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsPolicyReleaseArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupUpdateArgs(group={!r}, return_members={!r}, new_group_name={!r}, new_group_external_id={!r}, new_group_management_type={!r})'.format( - self._group_value, - self._return_members_value, - self._new_group_name_value, - self._new_group_external_id_value, - self._new_group_management_type_value, + return 'LegalHoldsPolicyReleaseArg(id={!r})'.format( + self._id_value, ) -GroupUpdateArgs_validator = bv.Struct(GroupUpdateArgs) +LegalHoldsPolicyReleaseArg_validator = bv.Struct(LegalHoldsPolicyReleaseArg) -class GroupUpdateError(GroupSelectorWithTeamGroupError): +class LegalHoldsPolicyReleaseError(LegalHoldsError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupUpdateError.group_name_already_used: The requested group - name is already being used by another group. - :ivar team.GroupUpdateError.group_name_invalid: Group name is empty or has - invalid characters. - :ivar team.GroupUpdateError.external_id_already_in_use: The requested - external ID is already being used by another group. + :ivar + team.LegalHoldsPolicyReleaseError.legal_hold_performing_another_operation: + Legal hold is currently performing another operation. + :ivar team.LegalHoldsPolicyReleaseError.legal_hold_already_releasing: Legal + hold is currently performing a release or is already released. + :ivar team.LegalHoldsPolicyReleaseError.legal_hold_policy_not_found: Legal + hold policy does not exist for ``LegalHoldsPolicyReleaseArg.id``. """ # Attribute is overwritten below the class definition - group_name_already_used = None + legal_hold_performing_another_operation = None # Attribute is overwritten below the class definition - group_name_invalid = None + legal_hold_already_releasing = None # Attribute is overwritten below the class definition - external_id_already_in_use = None + legal_hold_policy_not_found = None - def is_group_name_already_used(self): + def is_legal_hold_performing_another_operation(self): """ - Check if the union tag is ``group_name_already_used``. + Check if the union tag is ``legal_hold_performing_another_operation``. :rtype: bool """ - return self._tag == 'group_name_already_used' + return self._tag == 'legal_hold_performing_another_operation' - def is_group_name_invalid(self): + def is_legal_hold_already_releasing(self): """ - Check if the union tag is ``group_name_invalid``. + Check if the union tag is ``legal_hold_already_releasing``. :rtype: bool """ - return self._tag == 'group_name_invalid' + return self._tag == 'legal_hold_already_releasing' - def is_external_id_already_in_use(self): + def is_legal_hold_policy_not_found(self): """ - Check if the union tag is ``external_id_already_in_use``. + Check if the union tag is ``legal_hold_policy_not_found``. :rtype: bool """ - return self._tag == 'external_id_already_in_use' + return self._tag == 'legal_hold_policy_not_found' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupUpdateError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsPolicyReleaseError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupUpdateError(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsPolicyReleaseError(%r, %r)' % (self._tag, self._value) -GroupUpdateError_validator = bv.Union(GroupUpdateError) +LegalHoldsPolicyReleaseError_validator = bv.Union(LegalHoldsPolicyReleaseError) -class GroupsGetInfoError(bb.Union): +class LegalHoldsPolicyUpdateArg(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.GroupsGetInfoError.group_not_on_team: The group is not on your - team. + :ivar team.LegalHoldsPolicyUpdateArg.id: The legal hold Id. + :ivar team.LegalHoldsPolicyUpdateArg.name: Policy new name. + :ivar team.LegalHoldsPolicyUpdateArg.description: Policy new description. + :ivar team.LegalHoldsPolicyUpdateArg.members: List of team members to apply + the policy on. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - group_not_on_team = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_id_value', + '_id_present', + '_name_value', + '_name_present', + '_description_value', + '_description_present', + '_members_value', + '_members_present', + ] - def is_group_not_on_team(self): + _has_required_fields = True + + def __init__(self, + id=None, + members=None, + name=None, + description=None): + self._id_value = None + self._id_present = False + self._name_value = None + self._name_present = False + self._description_value = None + self._description_present = False + self._members_value = None + self._members_present = False + if id is not None: + self.id = id + if name is not None: + self.name = name + if description is not None: + self.description = description + if members is not None: + self.members = members + + @property + def id(self): """ - Check if the union tag is ``group_not_on_team``. + The legal hold Id. - :rtype: bool + :rtype: str """ - return self._tag == 'group_not_on_team' + if self._id_present: + return self._id_value + else: + raise AttributeError("missing required field 'id'") - def is_other(self): + @id.setter + def id(self, val): + val = self._id_validator.validate(val) + self._id_value = val + self._id_present = True + + @id.deleter + def id(self): + self._id_value = None + self._id_present = False + + @property + def name(self): """ - Check if the union tag is ``other``. + Policy new name. - :rtype: bool + :rtype: str """ - return self._tag == 'other' + if self._name_present: + return self._name_value + else: + return None + + @name.setter + def name(self, val): + if val is None: + del self.name + return + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False + + @property + def description(self): + """ + Policy new description. + + :rtype: str + """ + if self._description_present: + return self._description_value + else: + return None + + @description.setter + def description(self, val): + if val is None: + del self.description + return + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + @property + def members(self): + """ + List of team members to apply the policy on. + + :rtype: list of [str] + """ + if self._members_present: + return self._members_value + else: + raise AttributeError("missing required field 'members'") + + @members.setter + def members(self, val): + val = self._members_validator.validate(val) + self._members_value = val + self._members_present = True + + @members.deleter + def members(self): + self._members_value = None + self._members_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsGetInfoError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsPolicyUpdateArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsGetInfoError(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsPolicyUpdateArg(id={!r}, members={!r}, name={!r}, description={!r})'.format( + self._id_value, + self._members_value, + self._name_value, + self._description_value, + ) -GroupsGetInfoError_validator = bv.Union(GroupsGetInfoError) +LegalHoldsPolicyUpdateArg_validator = bv.Struct(LegalHoldsPolicyUpdateArg) -class GroupsGetInfoItem(bb.Union): +class LegalHoldsPolicyUpdateError(LegalHoldsError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - - :ivar str team.GroupsGetInfoItem.id_not_found: An ID that was provided as a - parameter to :route:`groups/get_info`, and did not match a corresponding - group. The ID can be a group ID, or an external ID, depending on how the - method was called. - :ivar GroupFullInfo GroupsGetInfoItem.group_info: Info about a group. + + :ivar team.LegalHoldsPolicyUpdateError.inactive_legal_hold: Trying to + release an inactive legal hold. + :ivar + team.LegalHoldsPolicyUpdateError.legal_hold_performing_another_operation: + Legal hold is currently performing another operation. + :ivar team.LegalHoldsPolicyUpdateError.invalid_members: Some members in the + members list are not valid to be placed under legal hold. + :ivar + team.LegalHoldsPolicyUpdateError.number_of_users_on_hold_is_greater_than_hold_limitation: + You cannot add more than 5 users in a legal hold. + :ivar team.LegalHoldsPolicyUpdateError.empty_members_list: The users list + must have at least one user. + :ivar team.LegalHoldsPolicyUpdateError.name_must_be_unique: The name + provided is already in use by another legal hold. + :ivar team.LegalHoldsPolicyUpdateError.legal_hold_policy_not_found: Legal + hold policy does not exist for ``LegalHoldsPolicyUpdateArg.id``. """ - _catch_all = None + # Attribute is overwritten below the class definition + inactive_legal_hold = None + # Attribute is overwritten below the class definition + legal_hold_performing_another_operation = None + # Attribute is overwritten below the class definition + invalid_members = None + # Attribute is overwritten below the class definition + number_of_users_on_hold_is_greater_than_hold_limitation = None + # Attribute is overwritten below the class definition + empty_members_list = None + # Attribute is overwritten below the class definition + name_must_be_unique = None + # Attribute is overwritten below the class definition + legal_hold_policy_not_found = None - @classmethod - def id_not_found(cls, val): + def is_inactive_legal_hold(self): """ - Create an instance of this class set to the ``id_not_found`` tag with - value ``val``. + Check if the union tag is ``inactive_legal_hold``. - :param str val: - :rtype: GroupsGetInfoItem + :rtype: bool """ - return cls('id_not_found', val) + return self._tag == 'inactive_legal_hold' - @classmethod - def group_info(cls, val): + def is_legal_hold_performing_another_operation(self): """ - Create an instance of this class set to the ``group_info`` tag with - value ``val``. + Check if the union tag is ``legal_hold_performing_another_operation``. - :param GroupFullInfo val: - :rtype: GroupsGetInfoItem + :rtype: bool """ - return cls('group_info', val) + return self._tag == 'legal_hold_performing_another_operation' - def is_id_not_found(self): + def is_invalid_members(self): """ - Check if the union tag is ``id_not_found``. + Check if the union tag is ``invalid_members``. :rtype: bool """ - return self._tag == 'id_not_found' + return self._tag == 'invalid_members' - def is_group_info(self): + def is_number_of_users_on_hold_is_greater_than_hold_limitation(self): """ - Check if the union tag is ``group_info``. + Check if the union tag is ``number_of_users_on_hold_is_greater_than_hold_limitation``. :rtype: bool """ - return self._tag == 'group_info' + return self._tag == 'number_of_users_on_hold_is_greater_than_hold_limitation' - def get_id_not_found(self): + def is_empty_members_list(self): """ - An ID that was provided as a parameter to - :meth:`dropbox.dropbox.Dropbox.team_groups_get_info`, and did not match - a corresponding group. The ID can be a group ID, or an external ID, - depending on how the method was called. - - Only call this if :meth:`is_id_not_found` is true. + Check if the union tag is ``empty_members_list``. - :rtype: str + :rtype: bool """ - if not self.is_id_not_found(): - raise AttributeError("tag 'id_not_found' not set") - return self._value + return self._tag == 'empty_members_list' - def get_group_info(self): + def is_name_must_be_unique(self): """ - Info about a group. - - Only call this if :meth:`is_group_info` is true. + Check if the union tag is ``name_must_be_unique``. - :rtype: GroupFullInfo + :rtype: bool """ - if not self.is_group_info(): - raise AttributeError("tag 'group_info' not set") - return self._value - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsGetInfoItem, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'GroupsGetInfoItem(%r, %r)' % (self._tag, self._value) - -GroupsGetInfoItem_validator = bv.Union(GroupsGetInfoItem) - -class GroupsListArg(bb.Struct): - """ - :ivar team.GroupsListArg.limit: Number of results to return per call. - """ - - __slots__ = [ - '_limit_value', - '_limit_present', - ] - - _has_required_fields = False - - def __init__(self, - limit=None): - self._limit_value = None - self._limit_present = False - if limit is not None: - self.limit = limit + return self._tag == 'name_must_be_unique' - @property - def limit(self): + def is_legal_hold_policy_not_found(self): """ - Number of results to return per call. + Check if the union tag is ``legal_hold_policy_not_found``. - :rtype: int + :rtype: bool """ - if self._limit_present: - return self._limit_value - else: - return 1000 - - @limit.setter - def limit(self, val): - val = self._limit_validator.validate(val) - self._limit_value = val - self._limit_present = True - - @limit.deleter - def limit(self): - self._limit_value = None - self._limit_present = False + return self._tag == 'legal_hold_policy_not_found' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsListArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsPolicyUpdateError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsListArg(limit={!r})'.format( - self._limit_value, - ) + return 'LegalHoldsPolicyUpdateError(%r, %r)' % (self._tag, self._value) -GroupsListArg_validator = bv.Struct(GroupsListArg) +LegalHoldsPolicyUpdateError_validator = bv.Union(LegalHoldsPolicyUpdateError) -class GroupsListContinueArg(bb.Struct): +class ListMemberAppsArg(bb.Struct): """ - :ivar team.GroupsListContinueArg.cursor: Indicates from what point to get - the next set of groups. + :ivar team.ListMemberAppsArg.team_member_id: The team member id. """ __slots__ = [ - '_cursor_value', - '_cursor_present', + '_team_member_id_value', + '_team_member_id_present', ] _has_required_fields = True def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + team_member_id=None): + self._team_member_id_value = None + self._team_member_id_present = False + if team_member_id is not None: + self.team_member_id = team_member_id @property - def cursor(self): + def team_member_id(self): """ - Indicates from what point to get the next set of groups. + The team member id. :rtype: str """ - if self._cursor_present: - return self._cursor_value + if self._team_member_id_present: + return self._team_member_id_value else: - raise AttributeError("missing required field 'cursor'") + raise AttributeError("missing required field 'team_member_id'") - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMemberAppsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsListContinueArg(cursor={!r})'.format( - self._cursor_value, + return 'ListMemberAppsArg(team_member_id={!r})'.format( + self._team_member_id_value, ) -GroupsListContinueArg_validator = bv.Struct(GroupsListContinueArg) +ListMemberAppsArg_validator = bv.Struct(ListMemberAppsArg) -class GroupsListContinueError(bb.Union): +class ListMemberAppsError(bb.Union): """ + Error returned by + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_member_linked_apps`. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupsListContinueError.invalid_cursor: The cursor is invalid. + :ivar team.ListMemberAppsError.member_not_found: Member not found. """ _catch_all = 'other' # Attribute is overwritten below the class definition - invalid_cursor = None + member_not_found = None # Attribute is overwritten below the class definition other = None - def is_invalid_cursor(self): + def is_member_not_found(self): """ - Check if the union tag is ``invalid_cursor``. + Check if the union tag is ``member_not_found``. :rtype: bool """ - return self._tag == 'invalid_cursor' + return self._tag == 'member_not_found' def is_other(self): """ @@ -5744,297 +9383,239 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMemberAppsError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsListContinueError(%r, %r)' % (self._tag, self._value) + return 'ListMemberAppsError(%r, %r)' % (self._tag, self._value) -GroupsListContinueError_validator = bv.Union(GroupsListContinueError) +ListMemberAppsError_validator = bv.Union(ListMemberAppsError) -class GroupsListResult(bb.Struct): - """ - :ivar team.GroupsListResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` to obtain the - additional groups. - :ivar team.GroupsListResult.has_more: Is true if there are additional groups - that have not been returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` can retrieve - them. +class ListMemberAppsResult(bb.Struct): + """ + :ivar team.ListMemberAppsResult.linked_api_apps: List of third party + applications linked by this team member. """ - __slots__ = [ - '_groups_value', - '_groups_present', - '_cursor_value', - '_cursor_present', - '_has_more_value', - '_has_more_present', - ] - - _has_required_fields = True - - def __init__(self, - groups=None, - cursor=None, - has_more=None): - self._groups_value = None - self._groups_present = False - self._cursor_value = None - self._cursor_present = False - self._has_more_value = None - self._has_more_present = False - if groups is not None: - self.groups = groups - if cursor is not None: - self.cursor = cursor - if has_more is not None: - self.has_more = has_more - - @property - def groups(self): - """ - :rtype: list of [team_common.GroupSummary] - """ - if self._groups_present: - return self._groups_value - else: - raise AttributeError("missing required field 'groups'") - - @groups.setter - def groups(self, val): - val = self._groups_validator.validate(val) - self._groups_value = val - self._groups_present = True - - @groups.deleter - def groups(self): - self._groups_value = None - self._groups_present = False - - @property - def cursor(self): - """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` to obtain the - additional groups. - - :rtype: str - """ - if self._cursor_present: - return self._cursor_value - else: - raise AttributeError("missing required field 'cursor'") - - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + __slots__ = [ + '_linked_api_apps_value', + '_linked_api_apps_present', + ] - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + _has_required_fields = True + + def __init__(self, + linked_api_apps=None): + self._linked_api_apps_value = None + self._linked_api_apps_present = False + if linked_api_apps is not None: + self.linked_api_apps = linked_api_apps @property - def has_more(self): + def linked_api_apps(self): """ - Is true if there are additional groups that have not been returned yet. - An additional call to - :meth:`dropbox.dropbox.Dropbox.team_groups_list_continue` can retrieve - them. + List of third party applications linked by this team member. - :rtype: bool + :rtype: list of [ApiApp] """ - if self._has_more_present: - return self._has_more_value + if self._linked_api_apps_present: + return self._linked_api_apps_value else: - raise AttributeError("missing required field 'has_more'") + raise AttributeError("missing required field 'linked_api_apps'") - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + @linked_api_apps.setter + def linked_api_apps(self, val): + val = self._linked_api_apps_validator.validate(val) + self._linked_api_apps_value = val + self._linked_api_apps_present = True - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + @linked_api_apps.deleter + def linked_api_apps(self): + self._linked_api_apps_value = None + self._linked_api_apps_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMemberAppsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsListResult(groups={!r}, cursor={!r}, has_more={!r})'.format( - self._groups_value, - self._cursor_value, - self._has_more_value, + return 'ListMemberAppsResult(linked_api_apps={!r})'.format( + self._linked_api_apps_value, ) -GroupsListResult_validator = bv.Struct(GroupsListResult) +ListMemberAppsResult_validator = bv.Struct(ListMemberAppsResult) -class GroupsMembersListArg(bb.Struct): +class ListMemberDevicesArg(bb.Struct): """ - :ivar team.GroupsMembersListArg.group: The group whose members are to be - listed. - :ivar team.GroupsMembersListArg.limit: Number of results to return per call. + :ivar team.ListMemberDevicesArg.team_member_id: The team's member id. + :ivar team.ListMemberDevicesArg.include_web_sessions: Whether to list web + sessions of the team's member. + :ivar team.ListMemberDevicesArg.include_desktop_clients: Whether to list + linked desktop devices of the team's member. + :ivar team.ListMemberDevicesArg.include_mobile_clients: Whether to list + linked mobile devices of the team's member. """ __slots__ = [ - '_group_value', - '_group_present', - '_limit_value', - '_limit_present', + '_team_member_id_value', + '_team_member_id_present', + '_include_web_sessions_value', + '_include_web_sessions_present', + '_include_desktop_clients_value', + '_include_desktop_clients_present', + '_include_mobile_clients_value', + '_include_mobile_clients_present', ] _has_required_fields = True def __init__(self, - group=None, - limit=None): - self._group_value = None - self._group_present = False - self._limit_value = None - self._limit_present = False - if group is not None: - self.group = group - if limit is not None: - self.limit = limit + team_member_id=None, + include_web_sessions=None, + include_desktop_clients=None, + include_mobile_clients=None): + self._team_member_id_value = None + self._team_member_id_present = False + self._include_web_sessions_value = None + self._include_web_sessions_present = False + self._include_desktop_clients_value = None + self._include_desktop_clients_present = False + self._include_mobile_clients_value = None + self._include_mobile_clients_present = False + if team_member_id is not None: + self.team_member_id = team_member_id + if include_web_sessions is not None: + self.include_web_sessions = include_web_sessions + if include_desktop_clients is not None: + self.include_desktop_clients = include_desktop_clients + if include_mobile_clients is not None: + self.include_mobile_clients = include_mobile_clients @property - def group(self): + def team_member_id(self): """ - The group whose members are to be listed. + The team's member id. - :rtype: GroupSelector + :rtype: str """ - if self._group_present: - return self._group_value + if self._team_member_id_present: + return self._team_member_id_value else: - raise AttributeError("missing required field 'group'") + raise AttributeError("missing required field 'team_member_id'") - @group.setter - def group(self, val): - self._group_validator.validate_type_only(val) - self._group_value = val - self._group_present = True + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - @group.deleter - def group(self): - self._group_value = None - self._group_present = False + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False @property - def limit(self): + def include_web_sessions(self): """ - Number of results to return per call. + Whether to list web sessions of the team's member. - :rtype: int + :rtype: bool """ - if self._limit_present: - return self._limit_value + if self._include_web_sessions_present: + return self._include_web_sessions_value else: - return 1000 - - @limit.setter - def limit(self, val): - val = self._limit_validator.validate(val) - self._limit_value = val - self._limit_present = True - - @limit.deleter - def limit(self): - self._limit_value = None - self._limit_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsMembersListArg, self)._process_custom_annotations(annotation_type, field_path, processor) + return True - def __repr__(self): - return 'GroupsMembersListArg(group={!r}, limit={!r})'.format( - self._group_value, - self._limit_value, - ) + @include_web_sessions.setter + def include_web_sessions(self, val): + val = self._include_web_sessions_validator.validate(val) + self._include_web_sessions_value = val + self._include_web_sessions_present = True -GroupsMembersListArg_validator = bv.Struct(GroupsMembersListArg) + @include_web_sessions.deleter + def include_web_sessions(self): + self._include_web_sessions_value = None + self._include_web_sessions_present = False -class GroupsMembersListContinueArg(bb.Struct): - """ - :ivar team.GroupsMembersListContinueArg.cursor: Indicates from what point to - get the next set of groups. - """ + @property + def include_desktop_clients(self): + """ + Whether to list linked desktop devices of the team's member. - __slots__ = [ - '_cursor_value', - '_cursor_present', - ] + :rtype: bool + """ + if self._include_desktop_clients_present: + return self._include_desktop_clients_value + else: + return True - _has_required_fields = True + @include_desktop_clients.setter + def include_desktop_clients(self, val): + val = self._include_desktop_clients_validator.validate(val) + self._include_desktop_clients_value = val + self._include_desktop_clients_present = True - def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + @include_desktop_clients.deleter + def include_desktop_clients(self): + self._include_desktop_clients_value = None + self._include_desktop_clients_present = False @property - def cursor(self): + def include_mobile_clients(self): """ - Indicates from what point to get the next set of groups. + Whether to list linked mobile devices of the team's member. - :rtype: str + :rtype: bool """ - if self._cursor_present: - return self._cursor_value + if self._include_mobile_clients_present: + return self._include_mobile_clients_value else: - raise AttributeError("missing required field 'cursor'") + return True - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @include_mobile_clients.setter + def include_mobile_clients(self, val): + val = self._include_mobile_clients_validator.validate(val) + self._include_mobile_clients_value = val + self._include_mobile_clients_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @include_mobile_clients.deleter + def include_mobile_clients(self): + self._include_mobile_clients_value = None + self._include_mobile_clients_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsMembersListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMemberDevicesArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsMembersListContinueArg(cursor={!r})'.format( - self._cursor_value, + return 'ListMemberDevicesArg(team_member_id={!r}, include_web_sessions={!r}, include_desktop_clients={!r}, include_mobile_clients={!r})'.format( + self._team_member_id_value, + self._include_web_sessions_value, + self._include_desktop_clients_value, + self._include_mobile_clients_value, ) -GroupsMembersListContinueArg_validator = bv.Struct(GroupsMembersListContinueArg) +ListMemberDevicesArg_validator = bv.Struct(ListMemberDevicesArg) -class GroupsMembersListContinueError(bb.Union): +class ListMemberDevicesError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupsMembersListContinueError.invalid_cursor: The cursor is - invalid. + :ivar team.ListMemberDevicesError.member_not_found: Member not found. """ _catch_all = 'other' # Attribute is overwritten below the class definition - invalid_cursor = None + member_not_found = None # Attribute is overwritten below the class definition other = None - def is_invalid_cursor(self): + def is_member_not_found(self): """ - Check if the union tag is ``invalid_cursor``. + Check if the union tag is ``member_not_found``. :rtype: bool """ - return self._tag == 'invalid_cursor' + return self._tag == 'member_not_found' def is_other(self): """ @@ -6045,89 +9626,188 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsMembersListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMemberDevicesError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsMembersListContinueError(%r, %r)' % (self._tag, self._value) + return 'ListMemberDevicesError(%r, %r)' % (self._tag, self._value) -GroupsMembersListContinueError_validator = bv.Union(GroupsMembersListContinueError) +ListMemberDevicesError_validator = bv.Union(ListMemberDevicesError) -class GroupsMembersListResult(bb.Struct): +class ListMemberDevicesResult(bb.Struct): """ - :ivar team.GroupsMembersListResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` to - obtain additional group members. - :ivar team.GroupsMembersListResult.has_more: Is true if there are additional - group members that have not been returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` can - retrieve them. + :ivar team.ListMemberDevicesResult.active_web_sessions: List of web sessions + made by this team member. + :ivar team.ListMemberDevicesResult.desktop_client_sessions: List of desktop + clients used by this team member. + :ivar team.ListMemberDevicesResult.mobile_client_sessions: List of mobile + client used by this team member. """ __slots__ = [ - '_members_value', - '_members_present', - '_cursor_value', - '_cursor_present', - '_has_more_value', - '_has_more_present', + '_active_web_sessions_value', + '_active_web_sessions_present', + '_desktop_client_sessions_value', + '_desktop_client_sessions_present', + '_mobile_client_sessions_value', + '_mobile_client_sessions_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - members=None, - cursor=None, - has_more=None): - self._members_value = None - self._members_present = False - self._cursor_value = None - self._cursor_present = False - self._has_more_value = None - self._has_more_present = False - if members is not None: - self.members = members - if cursor is not None: - self.cursor = cursor - if has_more is not None: - self.has_more = has_more + active_web_sessions=None, + desktop_client_sessions=None, + mobile_client_sessions=None): + self._active_web_sessions_value = None + self._active_web_sessions_present = False + self._desktop_client_sessions_value = None + self._desktop_client_sessions_present = False + self._mobile_client_sessions_value = None + self._mobile_client_sessions_present = False + if active_web_sessions is not None: + self.active_web_sessions = active_web_sessions + if desktop_client_sessions is not None: + self.desktop_client_sessions = desktop_client_sessions + if mobile_client_sessions is not None: + self.mobile_client_sessions = mobile_client_sessions @property - def members(self): + def active_web_sessions(self): """ - :rtype: list of [GroupMemberInfo] + List of web sessions made by this team member. + + :rtype: list of [ActiveWebSession] """ - if self._members_present: - return self._members_value + if self._active_web_sessions_present: + return self._active_web_sessions_value else: - raise AttributeError("missing required field 'members'") + return None - @members.setter - def members(self, val): - val = self._members_validator.validate(val) - self._members_value = val - self._members_present = True + @active_web_sessions.setter + def active_web_sessions(self, val): + if val is None: + del self.active_web_sessions + return + val = self._active_web_sessions_validator.validate(val) + self._active_web_sessions_value = val + self._active_web_sessions_present = True - @members.deleter - def members(self): - self._members_value = None - self._members_present = False + @active_web_sessions.deleter + def active_web_sessions(self): + self._active_web_sessions_value = None + self._active_web_sessions_present = False + + @property + def desktop_client_sessions(self): + """ + List of desktop clients used by this team member. + + :rtype: list of [DesktopClientSession] + """ + if self._desktop_client_sessions_present: + return self._desktop_client_sessions_value + else: + return None + + @desktop_client_sessions.setter + def desktop_client_sessions(self, val): + if val is None: + del self.desktop_client_sessions + return + val = self._desktop_client_sessions_validator.validate(val) + self._desktop_client_sessions_value = val + self._desktop_client_sessions_present = True + + @desktop_client_sessions.deleter + def desktop_client_sessions(self): + self._desktop_client_sessions_value = None + self._desktop_client_sessions_present = False + + @property + def mobile_client_sessions(self): + """ + List of mobile client used by this team member. + + :rtype: list of [MobileClientSession] + """ + if self._mobile_client_sessions_present: + return self._mobile_client_sessions_value + else: + return None + + @mobile_client_sessions.setter + def mobile_client_sessions(self, val): + if val is None: + del self.mobile_client_sessions + return + val = self._mobile_client_sessions_validator.validate(val) + self._mobile_client_sessions_value = val + self._mobile_client_sessions_present = True + + @mobile_client_sessions.deleter + def mobile_client_sessions(self): + self._mobile_client_sessions_value = None + self._mobile_client_sessions_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ListMemberDevicesResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ListMemberDevicesResult(active_web_sessions={!r}, desktop_client_sessions={!r}, mobile_client_sessions={!r})'.format( + self._active_web_sessions_value, + self._desktop_client_sessions_value, + self._mobile_client_sessions_value, + ) + +ListMemberDevicesResult_validator = bv.Struct(ListMemberDevicesResult) + +class ListMembersAppsArg(bb.Struct): + """ + Arguments for + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps`. + + :ivar team.ListMembersAppsArg.cursor: At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` + the cursor shouldn't be passed. Then, if the result of the call includes + a cursor, the following requests should include the received cursors in + order to receive the next sub list of the team applications. + """ + + __slots__ = [ + '_cursor_value', + '_cursor_present', + ] + + _has_required_fields = False + + def __init__(self, + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property def cursor(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` to - obtain additional group members. + At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` + the cursor shouldn't be passed. Then, if the result of the call includes + a cursor, the following requests should include the received cursors in + order to receive the next sub list of the team applications. :rtype: str """ if self._cursor_present: return self._cursor_value else: - raise AttributeError("missing required field 'cursor'") + return None @cursor.setter def cursor(self, val): + if val is None: + del self.cursor + return val = self._cursor_validator.validate(val) self._cursor_value = val self._cursor_present = True @@ -6137,256 +9817,380 @@ def cursor(self): self._cursor_value = None self._cursor_present = False - @property - def has_more(self): - """ - Is true if there are additional group members that have not been - returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_groups_members_list_continue` can - retrieve them. - - :rtype: bool - """ - if self._has_more_present: - return self._has_more_value - else: - raise AttributeError("missing required field 'has_more'") - - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True - - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsMembersListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMembersAppsArg, self)._process_custom_annotations(annotation_type, field_path, processor) - def __repr__(self): - return 'GroupsMembersListResult(members={!r}, cursor={!r}, has_more={!r})'.format( - self._members_value, + def __repr__(self): + return 'ListMembersAppsArg(cursor={!r})'.format( self._cursor_value, - self._has_more_value, ) -GroupsMembersListResult_validator = bv.Struct(GroupsMembersListResult) +ListMembersAppsArg_validator = bv.Struct(ListMembersAppsArg) -class GroupsPollError(async_.PollError): +class ListMembersAppsError(bb.Union): """ + Error returned by + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps`. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.GroupsPollError.access_denied: You are not allowed to poll this - job. + :ivar team.ListMembersAppsError.reset: Indicates that the cursor has been + invalidated. Call + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` + again with an empty cursor to obtain a new cursor. """ + _catch_all = 'other' # Attribute is overwritten below the class definition - access_denied = None + reset = None + # Attribute is overwritten below the class definition + other = None - def is_access_denied(self): + def is_reset(self): """ - Check if the union tag is ``access_denied``. + Check if the union tag is ``reset``. :rtype: bool """ - return self._tag == 'access_denied' + return self._tag == 'reset' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsPollError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMembersAppsError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsPollError(%r, %r)' % (self._tag, self._value) + return 'ListMembersAppsError(%r, %r)' % (self._tag, self._value) -GroupsPollError_validator = bv.Union(GroupsPollError) +ListMembersAppsError_validator = bv.Union(ListMembersAppsError) -class GroupsSelector(bb.Union): +class ListMembersAppsResult(bb.Struct): """ - Argument for selecting a list of groups, either by group_ids, or external - group IDs. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Information returned by + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps`. - :ivar list of [str] team.GroupsSelector.group_ids: List of group IDs. - :ivar list of [str] team.GroupsSelector.group_external_ids: List of external - IDs of groups. + :ivar team.ListMembersAppsResult.apps: The linked applications of each + member of the team. + :ivar team.ListMembersAppsResult.has_more: If true, then there are more apps + available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` + to retrieve the rest. + :ivar team.ListMembersAppsResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` + to receive the next sub list of team's applications. """ - _catch_all = None + __slots__ = [ + '_apps_value', + '_apps_present', + '_has_more_value', + '_has_more_present', + '_cursor_value', + '_cursor_present', + ] - @classmethod - def group_ids(cls, val): - """ - Create an instance of this class set to the ``group_ids`` tag with value - ``val``. + _has_required_fields = True - :param list of [str] val: - :rtype: GroupsSelector - """ - return cls('group_ids', val) + def __init__(self, + apps=None, + has_more=None, + cursor=None): + self._apps_value = None + self._apps_present = False + self._has_more_value = None + self._has_more_present = False + self._cursor_value = None + self._cursor_present = False + if apps is not None: + self.apps = apps + if has_more is not None: + self.has_more = has_more + if cursor is not None: + self.cursor = cursor - @classmethod - def group_external_ids(cls, val): + @property + def apps(self): """ - Create an instance of this class set to the ``group_external_ids`` tag - with value ``val``. + The linked applications of each member of the team. - :param list of [str] val: - :rtype: GroupsSelector + :rtype: list of [MemberLinkedApps] """ - return cls('group_external_ids', val) + if self._apps_present: + return self._apps_value + else: + raise AttributeError("missing required field 'apps'") - def is_group_ids(self): - """ - Check if the union tag is ``group_ids``. + @apps.setter + def apps(self, val): + val = self._apps_validator.validate(val) + self._apps_value = val + self._apps_present = True - :rtype: bool - """ - return self._tag == 'group_ids' + @apps.deleter + def apps(self): + self._apps_value = None + self._apps_present = False - def is_group_external_ids(self): + @property + def has_more(self): """ - Check if the union tag is ``group_external_ids``. + If true, then there are more apps available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` + to retrieve the rest. :rtype: bool """ - return self._tag == 'group_external_ids' + if self._has_more_present: + return self._has_more_value + else: + raise AttributeError("missing required field 'has_more'") - def get_group_ids(self): - """ - List of group IDs. + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - Only call this if :meth:`is_group_ids` is true. + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False - :rtype: list of [str] + @property + def cursor(self): """ - if not self.is_group_ids(): - raise AttributeError("tag 'group_ids' not set") - return self._value + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` + to receive the next sub list of team's applications. - def get_group_external_ids(self): + :rtype: str """ - List of external IDs of groups. + if self._cursor_present: + return self._cursor_value + else: + return None - Only call this if :meth:`is_group_external_ids` is true. + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - :rtype: list of [str] - """ - if not self.is_group_external_ids(): - raise AttributeError("tag 'group_external_ids' not set") - return self._value + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupsSelector, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMembersAppsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupsSelector(%r, %r)' % (self._tag, self._value) + return 'ListMembersAppsResult(apps={!r}, has_more={!r}, cursor={!r})'.format( + self._apps_value, + self._has_more_value, + self._cursor_value, + ) -GroupsSelector_validator = bv.Union(GroupsSelector) +ListMembersAppsResult_validator = bv.Struct(ListMembersAppsResult) -class HasTeamFileEventsValue(bb.Union): +class ListMembersDevicesArg(bb.Struct): """ - The value for ``Feature.has_team_file_events``. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar bool team.HasTeamFileEventsValue.enabled: Does this team have file - events. + :ivar team.ListMembersDevicesArg.cursor: At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` the + cursor shouldn't be passed. Then, if the result of the call includes a + cursor, the following requests should include the received cursors in + order to receive the next sub list of team devices. + :ivar team.ListMembersDevicesArg.include_web_sessions: Whether to list web + sessions of the team members. + :ivar team.ListMembersDevicesArg.include_desktop_clients: Whether to list + desktop clients of the team members. + :ivar team.ListMembersDevicesArg.include_mobile_clients: Whether to list + mobile clients of the team members. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_cursor_value', + '_cursor_present', + '_include_web_sessions_value', + '_include_web_sessions_present', + '_include_desktop_clients_value', + '_include_desktop_clients_present', + '_include_mobile_clients_value', + '_include_mobile_clients_present', + ] - @classmethod - def enabled(cls, val): + _has_required_fields = False + + def __init__(self, + cursor=None, + include_web_sessions=None, + include_desktop_clients=None, + include_mobile_clients=None): + self._cursor_value = None + self._cursor_present = False + self._include_web_sessions_value = None + self._include_web_sessions_present = False + self._include_desktop_clients_value = None + self._include_desktop_clients_present = False + self._include_mobile_clients_value = None + self._include_mobile_clients_present = False + if cursor is not None: + self.cursor = cursor + if include_web_sessions is not None: + self.include_web_sessions = include_web_sessions + if include_desktop_clients is not None: + self.include_desktop_clients = include_desktop_clients + if include_mobile_clients is not None: + self.include_mobile_clients = include_mobile_clients + + @property + def cursor(self): """ - Create an instance of this class set to the ``enabled`` tag with value - ``val``. + At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` the + cursor shouldn't be passed. Then, if the result of the call includes a + cursor, the following requests should include the received cursors in + order to receive the next sub list of team devices. - :param bool val: - :rtype: HasTeamFileEventsValue + :rtype: str """ - return cls('enabled', val) + if self._cursor_present: + return self._cursor_value + else: + return None - def is_enabled(self): + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True + + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False + + @property + def include_web_sessions(self): """ - Check if the union tag is ``enabled``. + Whether to list web sessions of the team members. :rtype: bool """ - return self._tag == 'enabled' + if self._include_web_sessions_present: + return self._include_web_sessions_value + else: + return True - def is_other(self): + @include_web_sessions.setter + def include_web_sessions(self, val): + val = self._include_web_sessions_validator.validate(val) + self._include_web_sessions_value = val + self._include_web_sessions_present = True + + @include_web_sessions.deleter + def include_web_sessions(self): + self._include_web_sessions_value = None + self._include_web_sessions_present = False + + @property + def include_desktop_clients(self): """ - Check if the union tag is ``other``. + Whether to list desktop clients of the team members. :rtype: bool """ - return self._tag == 'other' + if self._include_desktop_clients_present: + return self._include_desktop_clients_value + else: + return True - def get_enabled(self): - """ - Does this team have file events. + @include_desktop_clients.setter + def include_desktop_clients(self, val): + val = self._include_desktop_clients_validator.validate(val) + self._include_desktop_clients_value = val + self._include_desktop_clients_present = True - Only call this if :meth:`is_enabled` is true. + @include_desktop_clients.deleter + def include_desktop_clients(self): + self._include_desktop_clients_value = None + self._include_desktop_clients_present = False + + @property + def include_mobile_clients(self): + """ + Whether to list mobile clients of the team members. :rtype: bool """ - if not self.is_enabled(): - raise AttributeError("tag 'enabled' not set") - return self._value + if self._include_mobile_clients_present: + return self._include_mobile_clients_value + else: + return True + + @include_mobile_clients.setter + def include_mobile_clients(self, val): + val = self._include_mobile_clients_validator.validate(val) + self._include_mobile_clients_value = val + self._include_mobile_clients_present = True + + @include_mobile_clients.deleter + def include_mobile_clients(self): + self._include_mobile_clients_value = None + self._include_mobile_clients_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(HasTeamFileEventsValue, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMembersDevicesArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'HasTeamFileEventsValue(%r, %r)' % (self._tag, self._value) + return 'ListMembersDevicesArg(cursor={!r}, include_web_sessions={!r}, include_desktop_clients={!r}, include_mobile_clients={!r})'.format( + self._cursor_value, + self._include_web_sessions_value, + self._include_desktop_clients_value, + self._include_mobile_clients_value, + ) -HasTeamFileEventsValue_validator = bv.Union(HasTeamFileEventsValue) +ListMembersDevicesArg_validator = bv.Struct(ListMembersDevicesArg) -class HasTeamSelectiveSyncValue(bb.Union): +class ListMembersDevicesError(bb.Union): """ - The value for ``Feature.has_team_selective_sync``. - This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar bool team.HasTeamSelectiveSyncValue.has_team_selective_sync: Does this - team have team selective sync enabled. + :ivar team.ListMembersDevicesError.reset: Indicates that the cursor has been + invalidated. Call + :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` again + with an empty cursor to obtain a new cursor. """ _catch_all = 'other' # Attribute is overwritten below the class definition + reset = None + # Attribute is overwritten below the class definition other = None - @classmethod - def has_team_selective_sync(cls, val): - """ - Create an instance of this class set to the ``has_team_selective_sync`` - tag with value ``val``. - - :param bool val: - :rtype: HasTeamSelectiveSyncValue - """ - return cls('has_team_selective_sync', val) - - def is_has_team_selective_sync(self): + def is_reset(self): """ - Check if the union tag is ``has_team_selective_sync``. + Check if the union tag is ``reset``. :rtype: bool """ - return self._tag == 'has_team_selective_sync' + return self._tag == 'reset' def is_other(self): """ @@ -6396,166 +10200,237 @@ def is_other(self): """ return self._tag == 'other' - def get_has_team_selective_sync(self): - """ - Does this team have team selective sync enabled. - - Only call this if :meth:`is_has_team_selective_sync` is true. - - :rtype: bool - """ - if not self.is_has_team_selective_sync(): - raise AttributeError("tag 'has_team_selective_sync' not set") - return self._value - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(HasTeamSelectiveSyncValue, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMembersDevicesError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'HasTeamSelectiveSyncValue(%r, %r)' % (self._tag, self._value) + return 'ListMembersDevicesError(%r, %r)' % (self._tag, self._value) -HasTeamSelectiveSyncValue_validator = bv.Union(HasTeamSelectiveSyncValue) +ListMembersDevicesError_validator = bv.Union(ListMembersDevicesError) -class HasTeamSharedDropboxValue(bb.Union): +class ListMembersDevicesResult(bb.Struct): + """ + :ivar team.ListMembersDevicesResult.devices: The devices of each member of + the team. + :ivar team.ListMembersDevicesResult.has_more: If true, then there are more + devices available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to + retrieve the rest. + :ivar team.ListMembersDevicesResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to + receive the next sub list of team's devices. """ - The value for ``Feature.has_team_shared_dropbox``. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + __slots__ = [ + '_devices_value', + '_devices_present', + '_has_more_value', + '_has_more_present', + '_cursor_value', + '_cursor_present', + ] - :ivar bool team.HasTeamSharedDropboxValue.has_team_shared_dropbox: Does this - team have a shared team root. - """ + _has_required_fields = True - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + def __init__(self, + devices=None, + has_more=None, + cursor=None): + self._devices_value = None + self._devices_present = False + self._has_more_value = None + self._has_more_present = False + self._cursor_value = None + self._cursor_present = False + if devices is not None: + self.devices = devices + if has_more is not None: + self.has_more = has_more + if cursor is not None: + self.cursor = cursor - @classmethod - def has_team_shared_dropbox(cls, val): + @property + def devices(self): """ - Create an instance of this class set to the ``has_team_shared_dropbox`` - tag with value ``val``. + The devices of each member of the team. - :param bool val: - :rtype: HasTeamSharedDropboxValue + :rtype: list of [MemberDevices] """ - return cls('has_team_shared_dropbox', val) + if self._devices_present: + return self._devices_value + else: + raise AttributeError("missing required field 'devices'") - def is_has_team_shared_dropbox(self): + @devices.setter + def devices(self, val): + val = self._devices_validator.validate(val) + self._devices_value = val + self._devices_present = True + + @devices.deleter + def devices(self): + self._devices_value = None + self._devices_present = False + + @property + def has_more(self): """ - Check if the union tag is ``has_team_shared_dropbox``. + If true, then there are more devices available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to + retrieve the rest. :rtype: bool """ - return self._tag == 'has_team_shared_dropbox' + if self._has_more_present: + return self._has_more_value + else: + raise AttributeError("missing required field 'has_more'") - def is_other(self): - """ - Check if the union tag is ``other``. + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - :rtype: bool + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False + + @property + def cursor(self): """ - return self._tag == 'other' + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to + receive the next sub list of team's devices. - def get_has_team_shared_dropbox(self): + :rtype: str """ - Does this team have a shared team root. + if self._cursor_present: + return self._cursor_value + else: + return None - Only call this if :meth:`is_has_team_shared_dropbox` is true. + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - :rtype: bool - """ - if not self.is_has_team_shared_dropbox(): - raise AttributeError("tag 'has_team_shared_dropbox' not set") - return self._value + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(HasTeamSharedDropboxValue, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListMembersDevicesResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'HasTeamSharedDropboxValue(%r, %r)' % (self._tag, self._value) + return 'ListMembersDevicesResult(devices={!r}, has_more={!r}, cursor={!r})'.format( + self._devices_value, + self._has_more_value, + self._cursor_value, + ) -HasTeamSharedDropboxValue_validator = bv.Union(HasTeamSharedDropboxValue) +ListMembersDevicesResult_validator = bv.Struct(ListMembersDevicesResult) -class ListMemberAppsArg(bb.Struct): +class ListTeamAppsArg(bb.Struct): """ - :ivar team.ListMemberAppsArg.team_member_id: The team member id. + Arguments for + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps`. + + :ivar team.ListTeamAppsArg.cursor: At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` + the cursor shouldn't be passed. Then, if the result of the call includes + a cursor, the following requests should include the received cursors in + order to receive the next sub list of the team applications. """ __slots__ = [ - '_team_member_id_value', - '_team_member_id_present', + '_cursor_value', + '_cursor_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - team_member_id=None): - self._team_member_id_value = None - self._team_member_id_present = False - if team_member_id is not None: - self.team_member_id = team_member_id + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def team_member_id(self): + def cursor(self): """ - The team member id. + At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` + the cursor shouldn't be passed. Then, if the result of the call includes + a cursor, the following requests should include the received cursors in + order to receive the next sub list of the team applications. :rtype: str """ - if self._team_member_id_present: - return self._team_member_id_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'team_member_id'") + return None - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMemberAppsArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListTeamAppsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListMemberAppsArg(team_member_id={!r})'.format( - self._team_member_id_value, + return 'ListTeamAppsArg(cursor={!r})'.format( + self._cursor_value, ) -ListMemberAppsArg_validator = bv.Struct(ListMemberAppsArg) +ListTeamAppsArg_validator = bv.Struct(ListTeamAppsArg) -class ListMemberAppsError(bb.Union): +class ListTeamAppsError(bb.Union): """ Error returned by - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_member_linked_apps`. + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps`. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.ListMemberAppsError.member_not_found: Member not found. + :ivar team.ListTeamAppsError.reset: Indicates that the cursor has been + invalidated. Call + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` + again with an empty cursor to obtain a new cursor. """ _catch_all = 'other' # Attribute is overwritten below the class definition - member_not_found = None + reset = None # Attribute is overwritten below the class definition other = None - def is_member_not_found(self): + def is_reset(self): """ - Check if the union tag is ``member_not_found``. + Check if the union tag is ``reset``. :rtype: bool """ - return self._tag == 'member_not_found' + return self._tag == 'reset' def is_other(self): """ @@ -6566,80 +10441,163 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMemberAppsError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListTeamAppsError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListMemberAppsError(%r, %r)' % (self._tag, self._value) + return 'ListTeamAppsError(%r, %r)' % (self._tag, self._value) -ListMemberAppsError_validator = bv.Union(ListMemberAppsError) +ListTeamAppsError_validator = bv.Union(ListTeamAppsError) -class ListMemberAppsResult(bb.Struct): +class ListTeamAppsResult(bb.Struct): """ - :ivar team.ListMemberAppsResult.linked_api_apps: List of third party - applications linked by this team member. + Information returned by + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps`. + + :ivar team.ListTeamAppsResult.apps: The linked applications of each member + of the team. + :ivar team.ListTeamAppsResult.has_more: If true, then there are more apps + available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` + to retrieve the rest. + :ivar team.ListTeamAppsResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` + to receive the next sub list of team's applications. """ __slots__ = [ - '_linked_api_apps_value', - '_linked_api_apps_present', + '_apps_value', + '_apps_present', + '_has_more_value', + '_has_more_present', + '_cursor_value', + '_cursor_present', ] _has_required_fields = True def __init__(self, - linked_api_apps=None): - self._linked_api_apps_value = None - self._linked_api_apps_present = False - if linked_api_apps is not None: - self.linked_api_apps = linked_api_apps + apps=None, + has_more=None, + cursor=None): + self._apps_value = None + self._apps_present = False + self._has_more_value = None + self._has_more_present = False + self._cursor_value = None + self._cursor_present = False + if apps is not None: + self.apps = apps + if has_more is not None: + self.has_more = has_more + if cursor is not None: + self.cursor = cursor @property - def linked_api_apps(self): + def apps(self): """ - List of third party applications linked by this team member. + The linked applications of each member of the team. - :rtype: list of [ApiApp] + :rtype: list of [MemberLinkedApps] """ - if self._linked_api_apps_present: - return self._linked_api_apps_value + if self._apps_present: + return self._apps_value else: - raise AttributeError("missing required field 'linked_api_apps'") + raise AttributeError("missing required field 'apps'") - @linked_api_apps.setter - def linked_api_apps(self, val): - val = self._linked_api_apps_validator.validate(val) - self._linked_api_apps_value = val - self._linked_api_apps_present = True + @apps.setter + def apps(self, val): + val = self._apps_validator.validate(val) + self._apps_value = val + self._apps_present = True - @linked_api_apps.deleter - def linked_api_apps(self): - self._linked_api_apps_value = None - self._linked_api_apps_present = False + @apps.deleter + def apps(self): + self._apps_value = None + self._apps_present = False + + @property + def has_more(self): + """ + If true, then there are more apps available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` + to retrieve the rest. + + :rtype: bool + """ + if self._has_more_present: + return self._has_more_value + else: + raise AttributeError("missing required field 'has_more'") + + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True + + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False + + @property + def cursor(self): + """ + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` + to receive the next sub list of team's applications. + + :rtype: str + """ + if self._cursor_present: + return self._cursor_value + else: + return None + + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True + + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMemberAppsResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListTeamAppsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListMemberAppsResult(linked_api_apps={!r})'.format( - self._linked_api_apps_value, + return 'ListTeamAppsResult(apps={!r}, has_more={!r}, cursor={!r})'.format( + self._apps_value, + self._has_more_value, + self._cursor_value, ) -ListMemberAppsResult_validator = bv.Struct(ListMemberAppsResult) +ListTeamAppsResult_validator = bv.Struct(ListTeamAppsResult) -class ListMemberDevicesArg(bb.Struct): +class ListTeamDevicesArg(bb.Struct): """ - :ivar team.ListMemberDevicesArg.team_member_id: The team's member id. - :ivar team.ListMemberDevicesArg.include_web_sessions: Whether to list web - sessions of the team's member. - :ivar team.ListMemberDevicesArg.include_desktop_clients: Whether to list - linked desktop devices of the team's member. - :ivar team.ListMemberDevicesArg.include_mobile_clients: Whether to list - linked mobile devices of the team's member. + :ivar team.ListTeamDevicesArg.cursor: At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` the + cursor shouldn't be passed. Then, if the result of the call includes a + cursor, the following requests should include the received cursors in + order to receive the next sub list of team devices. + :ivar team.ListTeamDevicesArg.include_web_sessions: Whether to list web + sessions of the team members. + :ivar team.ListTeamDevicesArg.include_desktop_clients: Whether to list + desktop clients of the team members. + :ivar team.ListTeamDevicesArg.include_mobile_clients: Whether to list mobile + clients of the team members. """ __slots__ = [ - '_team_member_id_value', - '_team_member_id_present', + '_cursor_value', + '_cursor_present', '_include_web_sessions_value', '_include_web_sessions_present', '_include_desktop_clients_value', @@ -6648,23 +10606,23 @@ class ListMemberDevicesArg(bb.Struct): '_include_mobile_clients_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - team_member_id=None, + cursor=None, include_web_sessions=None, include_desktop_clients=None, include_mobile_clients=None): - self._team_member_id_value = None - self._team_member_id_present = False + self._cursor_value = None + self._cursor_present = False self._include_web_sessions_value = None self._include_web_sessions_present = False self._include_desktop_clients_value = None self._include_desktop_clients_present = False self._include_mobile_clients_value = None self._include_mobile_clients_present = False - if team_member_id is not None: - self.team_member_id = team_member_id + if cursor is not None: + self.cursor = cursor if include_web_sessions is not None: self.include_web_sessions = include_web_sessions if include_desktop_clients is not None: @@ -6673,32 +10631,39 @@ def __init__(self, self.include_mobile_clients = include_mobile_clients @property - def team_member_id(self): + def cursor(self): """ - The team's member id. + At the first call to the + :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` the + cursor shouldn't be passed. Then, if the result of the call includes a + cursor, the following requests should include the received cursors in + order to receive the next sub list of team devices. :rtype: str """ - if self._team_member_id_present: - return self._team_member_id_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'team_member_id'") + return None - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False @property def include_web_sessions(self): """ - Whether to list web sessions of the team's member. + Whether to list web sessions of the team members. :rtype: bool """ @@ -6721,7 +10686,7 @@ def include_web_sessions(self): @property def include_desktop_clients(self): """ - Whether to list linked desktop devices of the team's member. + Whether to list desktop clients of the team members. :rtype: bool """ @@ -6742,2910 +10707,3078 @@ def include_desktop_clients(self): self._include_desktop_clients_present = False @property - def include_mobile_clients(self): + def include_mobile_clients(self): + """ + Whether to list mobile clients of the team members. + + :rtype: bool + """ + if self._include_mobile_clients_present: + return self._include_mobile_clients_value + else: + return True + + @include_mobile_clients.setter + def include_mobile_clients(self, val): + val = self._include_mobile_clients_validator.validate(val) + self._include_mobile_clients_value = val + self._include_mobile_clients_present = True + + @include_mobile_clients.deleter + def include_mobile_clients(self): + self._include_mobile_clients_value = None + self._include_mobile_clients_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ListTeamDevicesArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ListTeamDevicesArg(cursor={!r}, include_web_sessions={!r}, include_desktop_clients={!r}, include_mobile_clients={!r})'.format( + self._cursor_value, + self._include_web_sessions_value, + self._include_desktop_clients_value, + self._include_mobile_clients_value, + ) + +ListTeamDevicesArg_validator = bv.Struct(ListTeamDevicesArg) + +class ListTeamDevicesError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.ListTeamDevicesError.reset: Indicates that the cursor has been + invalidated. Call + :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` again + with an empty cursor to obtain a new cursor. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + reset = None + # Attribute is overwritten below the class definition + other = None + + def is_reset(self): + """ + Check if the union tag is ``reset``. + + :rtype: bool + """ + return self._tag == 'reset' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ListTeamDevicesError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ListTeamDevicesError(%r, %r)' % (self._tag, self._value) + +ListTeamDevicesError_validator = bv.Union(ListTeamDevicesError) + +class ListTeamDevicesResult(bb.Struct): + """ + :ivar team.ListTeamDevicesResult.devices: The devices of each member of the + team. + :ivar team.ListTeamDevicesResult.has_more: If true, then there are more + devices available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to + retrieve the rest. + :ivar team.ListTeamDevicesResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to + receive the next sub list of team's devices. + """ + + __slots__ = [ + '_devices_value', + '_devices_present', + '_has_more_value', + '_has_more_present', + '_cursor_value', + '_cursor_present', + ] + + _has_required_fields = True + + def __init__(self, + devices=None, + has_more=None, + cursor=None): + self._devices_value = None + self._devices_present = False + self._has_more_value = None + self._has_more_present = False + self._cursor_value = None + self._cursor_present = False + if devices is not None: + self.devices = devices + if has_more is not None: + self.has_more = has_more + if cursor is not None: + self.cursor = cursor + + @property + def devices(self): + """ + The devices of each member of the team. + + :rtype: list of [MemberDevices] + """ + if self._devices_present: + return self._devices_value + else: + raise AttributeError("missing required field 'devices'") + + @devices.setter + def devices(self, val): + val = self._devices_validator.validate(val) + self._devices_value = val + self._devices_present = True + + @devices.deleter + def devices(self): + self._devices_value = None + self._devices_present = False + + @property + def has_more(self): + """ + If true, then there are more devices available. Pass the cursor to + :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to + retrieve the rest. + + :rtype: bool + """ + if self._has_more_present: + return self._has_more_value + else: + raise AttributeError("missing required field 'has_more'") + + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True + + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False + + @property + def cursor(self): """ - Whether to list linked mobile devices of the team's member. + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to + receive the next sub list of team's devices. - :rtype: bool + :rtype: str """ - if self._include_mobile_clients_present: - return self._include_mobile_clients_value + if self._cursor_present: + return self._cursor_value else: - return True + return None - @include_mobile_clients.setter - def include_mobile_clients(self, val): - val = self._include_mobile_clients_validator.validate(val) - self._include_mobile_clients_value = val - self._include_mobile_clients_present = True + @cursor.setter + def cursor(self, val): + if val is None: + del self.cursor + return + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @include_mobile_clients.deleter - def include_mobile_clients(self): - self._include_mobile_clients_value = None - self._include_mobile_clients_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMemberDevicesArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ListTeamDevicesResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListMemberDevicesArg(team_member_id={!r}, include_web_sessions={!r}, include_desktop_clients={!r}, include_mobile_clients={!r})'.format( - self._team_member_id_value, - self._include_web_sessions_value, - self._include_desktop_clients_value, - self._include_mobile_clients_value, + return 'ListTeamDevicesResult(devices={!r}, has_more={!r}, cursor={!r})'.format( + self._devices_value, + self._has_more_value, + self._cursor_value, ) -ListMemberDevicesArg_validator = bv.Struct(ListMemberDevicesArg) +ListTeamDevicesResult_validator = bv.Struct(ListTeamDevicesResult) -class ListMemberDevicesError(bb.Union): +class MemberAccess(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Specify access type a member should have when joined to a group. - :ivar team.ListMemberDevicesError.member_not_found: Member not found. + :ivar team.MemberAccess.user: Identity of a user. + :ivar team.MemberAccess.access_type: Access type. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - member_not_found = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_user_value', + '_user_present', + '_access_type_value', + '_access_type_present', + ] - def is_member_not_found(self): + _has_required_fields = True + + def __init__(self, + user=None, + access_type=None): + self._user_value = None + self._user_present = False + self._access_type_value = None + self._access_type_present = False + if user is not None: + self.user = user + if access_type is not None: + self.access_type = access_type + + @property + def user(self): """ - Check if the union tag is ``member_not_found``. + Identity of a user. - :rtype: bool + :rtype: UserSelectorArg """ - return self._tag == 'member_not_found' + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") - def is_other(self): + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False + + @property + def access_type(self): """ - Check if the union tag is ``other``. + Access type. - :rtype: bool + :rtype: GroupAccessType """ - return self._tag == 'other' + if self._access_type_present: + return self._access_type_value + else: + raise AttributeError("missing required field 'access_type'") + + @access_type.setter + def access_type(self, val): + self._access_type_validator.validate_type_only(val) + self._access_type_value = val + self._access_type_present = True + + @access_type.deleter + def access_type(self): + self._access_type_value = None + self._access_type_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMemberDevicesError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberAccess, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListMemberDevicesError(%r, %r)' % (self._tag, self._value) + return 'MemberAccess(user={!r}, access_type={!r})'.format( + self._user_value, + self._access_type_value, + ) -ListMemberDevicesError_validator = bv.Union(ListMemberDevicesError) +MemberAccess_validator = bv.Struct(MemberAccess) -class ListMemberDevicesResult(bb.Struct): +class MemberAddArg(bb.Struct): """ - :ivar team.ListMemberDevicesResult.active_web_sessions: List of web sessions - made by this team member. - :ivar team.ListMemberDevicesResult.desktop_client_sessions: List of desktop - clients used by this team member. - :ivar team.ListMemberDevicesResult.mobile_client_sessions: List of mobile - client used by this team member. + :ivar team.MemberAddArg.member_given_name: Member's first name. + :ivar team.MemberAddArg.member_surname: Member's last name. + :ivar team.MemberAddArg.member_external_id: External ID for member. + :ivar team.MemberAddArg.member_persistent_id: Persistent ID for member. This + field is only available to teams using persistent ID SAML configuration. + :ivar team.MemberAddArg.send_welcome_email: Whether to send a welcome email + to the member. If send_welcome_email is false, no email invitation will + be sent to the user. This may be useful for apps using single sign-on + (SSO) flows for onboarding that want to handle announcements themselves. + :ivar team.MemberAddArg.is_directory_restricted: Whether a user is directory + restricted. """ __slots__ = [ - '_active_web_sessions_value', - '_active_web_sessions_present', - '_desktop_client_sessions_value', - '_desktop_client_sessions_present', - '_mobile_client_sessions_value', - '_mobile_client_sessions_present', + '_member_email_value', + '_member_email_present', + '_member_given_name_value', + '_member_given_name_present', + '_member_surname_value', + '_member_surname_present', + '_member_external_id_value', + '_member_external_id_present', + '_member_persistent_id_value', + '_member_persistent_id_present', + '_send_welcome_email_value', + '_send_welcome_email_present', + '_role_value', + '_role_present', + '_is_directory_restricted_value', + '_is_directory_restricted_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - active_web_sessions=None, - desktop_client_sessions=None, - mobile_client_sessions=None): - self._active_web_sessions_value = None - self._active_web_sessions_present = False - self._desktop_client_sessions_value = None - self._desktop_client_sessions_present = False - self._mobile_client_sessions_value = None - self._mobile_client_sessions_present = False - if active_web_sessions is not None: - self.active_web_sessions = active_web_sessions - if desktop_client_sessions is not None: - self.desktop_client_sessions = desktop_client_sessions - if mobile_client_sessions is not None: - self.mobile_client_sessions = mobile_client_sessions + member_email=None, + member_given_name=None, + member_surname=None, + member_external_id=None, + member_persistent_id=None, + send_welcome_email=None, + role=None, + is_directory_restricted=None): + self._member_email_value = None + self._member_email_present = False + self._member_given_name_value = None + self._member_given_name_present = False + self._member_surname_value = None + self._member_surname_present = False + self._member_external_id_value = None + self._member_external_id_present = False + self._member_persistent_id_value = None + self._member_persistent_id_present = False + self._send_welcome_email_value = None + self._send_welcome_email_present = False + self._role_value = None + self._role_present = False + self._is_directory_restricted_value = None + self._is_directory_restricted_present = False + if member_email is not None: + self.member_email = member_email + if member_given_name is not None: + self.member_given_name = member_given_name + if member_surname is not None: + self.member_surname = member_surname + if member_external_id is not None: + self.member_external_id = member_external_id + if member_persistent_id is not None: + self.member_persistent_id = member_persistent_id + if send_welcome_email is not None: + self.send_welcome_email = send_welcome_email + if role is not None: + self.role = role + if is_directory_restricted is not None: + self.is_directory_restricted = is_directory_restricted + + @property + def member_email(self): + """ + :rtype: str + """ + if self._member_email_present: + return self._member_email_value + else: + raise AttributeError("missing required field 'member_email'") + + @member_email.setter + def member_email(self, val): + val = self._member_email_validator.validate(val) + self._member_email_value = val + self._member_email_present = True + + @member_email.deleter + def member_email(self): + self._member_email_value = None + self._member_email_present = False @property - def active_web_sessions(self): + def member_given_name(self): """ - List of web sessions made by this team member. + Member's first name. - :rtype: list of [ActiveWebSession] + :rtype: str """ - if self._active_web_sessions_present: - return self._active_web_sessions_value + if self._member_given_name_present: + return self._member_given_name_value else: return None - @active_web_sessions.setter - def active_web_sessions(self, val): + @member_given_name.setter + def member_given_name(self, val): if val is None: - del self.active_web_sessions + del self.member_given_name return - val = self._active_web_sessions_validator.validate(val) - self._active_web_sessions_value = val - self._active_web_sessions_present = True + val = self._member_given_name_validator.validate(val) + self._member_given_name_value = val + self._member_given_name_present = True - @active_web_sessions.deleter - def active_web_sessions(self): - self._active_web_sessions_value = None - self._active_web_sessions_present = False + @member_given_name.deleter + def member_given_name(self): + self._member_given_name_value = None + self._member_given_name_present = False @property - def desktop_client_sessions(self): + def member_surname(self): """ - List of desktop clients used by this team member. + Member's last name. - :rtype: list of [DesktopClientSession] + :rtype: str """ - if self._desktop_client_sessions_present: - return self._desktop_client_sessions_value + if self._member_surname_present: + return self._member_surname_value else: return None - @desktop_client_sessions.setter - def desktop_client_sessions(self, val): + @member_surname.setter + def member_surname(self, val): if val is None: - del self.desktop_client_sessions + del self.member_surname return - val = self._desktop_client_sessions_validator.validate(val) - self._desktop_client_sessions_value = val - self._desktop_client_sessions_present = True + val = self._member_surname_validator.validate(val) + self._member_surname_value = val + self._member_surname_present = True - @desktop_client_sessions.deleter - def desktop_client_sessions(self): - self._desktop_client_sessions_value = None - self._desktop_client_sessions_present = False + @member_surname.deleter + def member_surname(self): + self._member_surname_value = None + self._member_surname_present = False @property - def mobile_client_sessions(self): + def member_external_id(self): """ - List of mobile client used by this team member. + External ID for member. - :rtype: list of [MobileClientSession] + :rtype: str """ - if self._mobile_client_sessions_present: - return self._mobile_client_sessions_value + if self._member_external_id_present: + return self._member_external_id_value else: return None - @mobile_client_sessions.setter - def mobile_client_sessions(self, val): + @member_external_id.setter + def member_external_id(self, val): if val is None: - del self.mobile_client_sessions + del self.member_external_id return - val = self._mobile_client_sessions_validator.validate(val) - self._mobile_client_sessions_value = val - self._mobile_client_sessions_present = True - - @mobile_client_sessions.deleter - def mobile_client_sessions(self): - self._mobile_client_sessions_value = None - self._mobile_client_sessions_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMemberDevicesResult, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ListMemberDevicesResult(active_web_sessions={!r}, desktop_client_sessions={!r}, mobile_client_sessions={!r})'.format( - self._active_web_sessions_value, - self._desktop_client_sessions_value, - self._mobile_client_sessions_value, - ) - -ListMemberDevicesResult_validator = bv.Struct(ListMemberDevicesResult) - -class ListMembersAppsArg(bb.Struct): - """ - Arguments for - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps`. - - :ivar team.ListMembersAppsArg.cursor: At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` - the cursor shouldn't be passed. Then, if the result of the call includes - a cursor, the following requests should include the received cursors in - order to receive the next sub list of the team applications. - """ - - __slots__ = [ - '_cursor_value', - '_cursor_present', - ] - - _has_required_fields = False + val = self._member_external_id_validator.validate(val) + self._member_external_id_value = val + self._member_external_id_present = True - def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + @member_external_id.deleter + def member_external_id(self): + self._member_external_id_value = None + self._member_external_id_present = False @property - def cursor(self): + def member_persistent_id(self): """ - At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` - the cursor shouldn't be passed. Then, if the result of the call includes - a cursor, the following requests should include the received cursors in - order to receive the next sub list of the team applications. + Persistent ID for member. This field is only available to teams using + persistent ID SAML configuration. :rtype: str """ - if self._cursor_present: - return self._cursor_value + if self._member_persistent_id_present: + return self._member_persistent_id_value else: return None - @cursor.setter - def cursor(self, val): + @member_persistent_id.setter + def member_persistent_id(self, val): if val is None: - del self.cursor - return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True - - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMembersAppsArg, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ListMembersAppsArg(cursor={!r})'.format( - self._cursor_value, - ) - -ListMembersAppsArg_validator = bv.Struct(ListMembersAppsArg) - -class ListMembersAppsError(bb.Union): - """ - Error returned by - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps`. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.ListMembersAppsError.reset: Indicates that the cursor has been - invalidated. Call - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` - again with an empty cursor to obtain a new cursor. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - reset = None - # Attribute is overwritten below the class definition - other = None - - def is_reset(self): - """ - Check if the union tag is ``reset``. - - :rtype: bool - """ - return self._tag == 'reset' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMembersAppsError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ListMembersAppsError(%r, %r)' % (self._tag, self._value) - -ListMembersAppsError_validator = bv.Union(ListMembersAppsError) - -class ListMembersAppsResult(bb.Struct): - """ - Information returned by - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps`. - - :ivar team.ListMembersAppsResult.apps: The linked applications of each - member of the team. - :ivar team.ListMembersAppsResult.has_more: If true, then there are more apps - available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` - to retrieve the rest. - :ivar team.ListMembersAppsResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` - to receive the next sub list of team's applications. - """ - - __slots__ = [ - '_apps_value', - '_apps_present', - '_has_more_value', - '_has_more_present', - '_cursor_value', - '_cursor_present', - ] - - _has_required_fields = True - - def __init__(self, - apps=None, - has_more=None, - cursor=None): - self._apps_value = None - self._apps_present = False - self._has_more_value = None - self._has_more_present = False - self._cursor_value = None - self._cursor_present = False - if apps is not None: - self.apps = apps - if has_more is not None: - self.has_more = has_more - if cursor is not None: - self.cursor = cursor + del self.member_persistent_id + return + val = self._member_persistent_id_validator.validate(val) + self._member_persistent_id_value = val + self._member_persistent_id_present = True + + @member_persistent_id.deleter + def member_persistent_id(self): + self._member_persistent_id_value = None + self._member_persistent_id_present = False @property - def apps(self): + def send_welcome_email(self): """ - The linked applications of each member of the team. + Whether to send a welcome email to the member. If send_welcome_email is + false, no email invitation will be sent to the user. This may be useful + for apps using single sign-on (SSO) flows for onboarding that want to + handle announcements themselves. - :rtype: list of [MemberLinkedApps] + :rtype: bool """ - if self._apps_present: - return self._apps_value + if self._send_welcome_email_present: + return self._send_welcome_email_value else: - raise AttributeError("missing required field 'apps'") + return True - @apps.setter - def apps(self, val): - val = self._apps_validator.validate(val) - self._apps_value = val - self._apps_present = True + @send_welcome_email.setter + def send_welcome_email(self, val): + val = self._send_welcome_email_validator.validate(val) + self._send_welcome_email_value = val + self._send_welcome_email_present = True - @apps.deleter - def apps(self): - self._apps_value = None - self._apps_present = False + @send_welcome_email.deleter + def send_welcome_email(self): + self._send_welcome_email_value = None + self._send_welcome_email_present = False @property - def has_more(self): + def role(self): """ - If true, then there are more apps available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` - to retrieve the rest. - - :rtype: bool + :rtype: AdminTier """ - if self._has_more_present: - return self._has_more_value + if self._role_present: + return self._role_value else: - raise AttributeError("missing required field 'has_more'") + return AdminTier.member_only - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + @role.setter + def role(self, val): + self._role_validator.validate_type_only(val) + self._role_value = val + self._role_present = True - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + @role.deleter + def role(self): + self._role_value = None + self._role_present = False @property - def cursor(self): + def is_directory_restricted(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_members_linked_apps` - to receive the next sub list of team's applications. + Whether a user is directory restricted. - :rtype: str + :rtype: bool """ - if self._cursor_present: - return self._cursor_value + if self._is_directory_restricted_present: + return self._is_directory_restricted_value else: return None - @cursor.setter - def cursor(self, val): + @is_directory_restricted.setter + def is_directory_restricted(self, val): if val is None: - del self.cursor + del self.is_directory_restricted return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + val = self._is_directory_restricted_validator.validate(val) + self._is_directory_restricted_value = val + self._is_directory_restricted_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @is_directory_restricted.deleter + def is_directory_restricted(self): + self._is_directory_restricted_value = None + self._is_directory_restricted_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMembersAppsResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberAddArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListMembersAppsResult(apps={!r}, has_more={!r}, cursor={!r})'.format( - self._apps_value, - self._has_more_value, - self._cursor_value, + return 'MemberAddArg(member_email={!r}, member_given_name={!r}, member_surname={!r}, member_external_id={!r}, member_persistent_id={!r}, send_welcome_email={!r}, role={!r}, is_directory_restricted={!r})'.format( + self._member_email_value, + self._member_given_name_value, + self._member_surname_value, + self._member_external_id_value, + self._member_persistent_id_value, + self._send_welcome_email_value, + self._role_value, + self._is_directory_restricted_value, ) -ListMembersAppsResult_validator = bv.Struct(ListMembersAppsResult) +MemberAddArg_validator = bv.Struct(MemberAddArg) -class ListMembersDevicesArg(bb.Struct): +class MemberAddResult(bb.Union): """ - :ivar team.ListMembersDevicesArg.cursor: At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` the - cursor shouldn't be passed. Then, if the result of the call includes a - cursor, the following requests should include the received cursors in - order to receive the next sub list of team devices. - :ivar team.ListMembersDevicesArg.include_web_sessions: Whether to list web - sessions of the team members. - :ivar team.ListMembersDevicesArg.include_desktop_clients: Whether to list - desktop clients of the team members. - :ivar team.ListMembersDevicesArg.include_mobile_clients: Whether to list - mobile clients of the team members. + Describes the result of attempting to add a single user to the team. + 'success' is the only value indicating that a user was indeed added to the + team - the other values explain the type of failure that occurred, and + include the email of the user for which the operation has failed. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar TeamMemberInfo MemberAddResult.success: Describes a user that was + successfully added to the team. + :ivar str team.MemberAddResult.team_license_limit: Team is already full. The + organization has no available licenses. + :ivar str team.MemberAddResult.free_team_member_limit_reached: Team is + already full. The free team member limit has been reached. + :ivar str team.MemberAddResult.user_already_on_team: User is already on this + team. The provided email address is associated with a user who is + already a member of (including in recoverable state) or invited to the + team. + :ivar str team.MemberAddResult.user_on_another_team: User is already on + another team. The provided email address is associated with a user that + is already a member or invited to another team. + :ivar str team.MemberAddResult.user_already_paired: User is already paired. + :ivar str team.MemberAddResult.user_migration_failed: User migration has + failed. + :ivar str team.MemberAddResult.duplicate_external_member_id: A user with the + given external member ID already exists on the team (including in + recoverable state). + :ivar str team.MemberAddResult.duplicate_member_persistent_id: A user with + the given persistent ID already exists on the team (including in + recoverable state). + :ivar str team.MemberAddResult.persistent_id_disabled: Persistent ID is only + available to teams with persistent ID SAML configuration. Please contact + Dropbox for more information. + :ivar str team.MemberAddResult.user_creation_failed: User creation has + failed. """ - __slots__ = [ - '_cursor_value', - '_cursor_present', - '_include_web_sessions_value', - '_include_web_sessions_present', - '_include_desktop_clients_value', - '_include_desktop_clients_present', - '_include_mobile_clients_value', - '_include_mobile_clients_present', - ] + _catch_all = None - _has_required_fields = False + @classmethod + def success(cls, val): + """ + Create an instance of this class set to the ``success`` tag with value + ``val``. - def __init__(self, - cursor=None, - include_web_sessions=None, - include_desktop_clients=None, - include_mobile_clients=None): - self._cursor_value = None - self._cursor_present = False - self._include_web_sessions_value = None - self._include_web_sessions_present = False - self._include_desktop_clients_value = None - self._include_desktop_clients_present = False - self._include_mobile_clients_value = None - self._include_mobile_clients_present = False - if cursor is not None: - self.cursor = cursor - if include_web_sessions is not None: - self.include_web_sessions = include_web_sessions - if include_desktop_clients is not None: - self.include_desktop_clients = include_desktop_clients - if include_mobile_clients is not None: - self.include_mobile_clients = include_mobile_clients + :param TeamMemberInfo val: + :rtype: MemberAddResult + """ + return cls('success', val) - @property - def cursor(self): + @classmethod + def team_license_limit(cls, val): """ - At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` the - cursor shouldn't be passed. Then, if the result of the call includes a - cursor, the following requests should include the received cursors in - order to receive the next sub list of team devices. + Create an instance of this class set to the ``team_license_limit`` tag + with value ``val``. - :rtype: str + :param str val: + :rtype: MemberAddResult """ - if self._cursor_present: - return self._cursor_value - else: - return None + return cls('team_license_limit', val) - @cursor.setter - def cursor(self, val): - if val is None: - del self.cursor - return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @classmethod + def free_team_member_limit_reached(cls, val): + """ + Create an instance of this class set to the + ``free_team_member_limit_reached`` tag with value ``val``. + + :param str val: + :rtype: MemberAddResult + """ + return cls('free_team_member_limit_reached', val) + + @classmethod + def user_already_on_team(cls, val): + """ + Create an instance of this class set to the ``user_already_on_team`` tag + with value ``val``. - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + :param str val: + :rtype: MemberAddResult + """ + return cls('user_already_on_team', val) - @property - def include_web_sessions(self): + @classmethod + def user_on_another_team(cls, val): """ - Whether to list web sessions of the team members. + Create an instance of this class set to the ``user_on_another_team`` tag + with value ``val``. - :rtype: bool + :param str val: + :rtype: MemberAddResult """ - if self._include_web_sessions_present: - return self._include_web_sessions_value - else: - return True + return cls('user_on_another_team', val) - @include_web_sessions.setter - def include_web_sessions(self, val): - val = self._include_web_sessions_validator.validate(val) - self._include_web_sessions_value = val - self._include_web_sessions_present = True + @classmethod + def user_already_paired(cls, val): + """ + Create an instance of this class set to the ``user_already_paired`` tag + with value ``val``. - @include_web_sessions.deleter - def include_web_sessions(self): - self._include_web_sessions_value = None - self._include_web_sessions_present = False + :param str val: + :rtype: MemberAddResult + """ + return cls('user_already_paired', val) - @property - def include_desktop_clients(self): + @classmethod + def user_migration_failed(cls, val): """ - Whether to list desktop clients of the team members. + Create an instance of this class set to the ``user_migration_failed`` + tag with value ``val``. - :rtype: bool + :param str val: + :rtype: MemberAddResult """ - if self._include_desktop_clients_present: - return self._include_desktop_clients_value - else: - return True + return cls('user_migration_failed', val) - @include_desktop_clients.setter - def include_desktop_clients(self, val): - val = self._include_desktop_clients_validator.validate(val) - self._include_desktop_clients_value = val - self._include_desktop_clients_present = True + @classmethod + def duplicate_external_member_id(cls, val): + """ + Create an instance of this class set to the + ``duplicate_external_member_id`` tag with value ``val``. - @include_desktop_clients.deleter - def include_desktop_clients(self): - self._include_desktop_clients_value = None - self._include_desktop_clients_present = False + :param str val: + :rtype: MemberAddResult + """ + return cls('duplicate_external_member_id', val) - @property - def include_mobile_clients(self): + @classmethod + def duplicate_member_persistent_id(cls, val): """ - Whether to list mobile clients of the team members. + Create an instance of this class set to the + ``duplicate_member_persistent_id`` tag with value ``val``. - :rtype: bool + :param str val: + :rtype: MemberAddResult """ - if self._include_mobile_clients_present: - return self._include_mobile_clients_value - else: - return True + return cls('duplicate_member_persistent_id', val) - @include_mobile_clients.setter - def include_mobile_clients(self, val): - val = self._include_mobile_clients_validator.validate(val) - self._include_mobile_clients_value = val - self._include_mobile_clients_present = True + @classmethod + def persistent_id_disabled(cls, val): + """ + Create an instance of this class set to the ``persistent_id_disabled`` + tag with value ``val``. - @include_mobile_clients.deleter - def include_mobile_clients(self): - self._include_mobile_clients_value = None - self._include_mobile_clients_present = False + :param str val: + :rtype: MemberAddResult + """ + return cls('persistent_id_disabled', val) - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMembersDevicesArg, self)._process_custom_annotations(annotation_type, field_path, processor) + @classmethod + def user_creation_failed(cls, val): + """ + Create an instance of this class set to the ``user_creation_failed`` tag + with value ``val``. - def __repr__(self): - return 'ListMembersDevicesArg(cursor={!r}, include_web_sessions={!r}, include_desktop_clients={!r}, include_mobile_clients={!r})'.format( - self._cursor_value, - self._include_web_sessions_value, - self._include_desktop_clients_value, - self._include_mobile_clients_value, - ) + :param str val: + :rtype: MemberAddResult + """ + return cls('user_creation_failed', val) -ListMembersDevicesArg_validator = bv.Struct(ListMembersDevicesArg) + def is_success(self): + """ + Check if the union tag is ``success``. -class ListMembersDevicesError(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :rtype: bool + """ + return self._tag == 'success' - :ivar team.ListMembersDevicesError.reset: Indicates that the cursor has been - invalidated. Call - :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` again - with an empty cursor to obtain a new cursor. - """ + def is_team_license_limit(self): + """ + Check if the union tag is ``team_license_limit``. - _catch_all = 'other' - # Attribute is overwritten below the class definition - reset = None - # Attribute is overwritten below the class definition - other = None + :rtype: bool + """ + return self._tag == 'team_license_limit' - def is_reset(self): + def is_free_team_member_limit_reached(self): """ - Check if the union tag is ``reset``. + Check if the union tag is ``free_team_member_limit_reached``. :rtype: bool """ - return self._tag == 'reset' + return self._tag == 'free_team_member_limit_reached' - def is_other(self): + def is_user_already_on_team(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``user_already_on_team``. :rtype: bool """ - return self._tag == 'other' + return self._tag == 'user_already_on_team' - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMembersDevicesError, self)._process_custom_annotations(annotation_type, field_path, processor) + def is_user_on_another_team(self): + """ + Check if the union tag is ``user_on_another_team``. - def __repr__(self): - return 'ListMembersDevicesError(%r, %r)' % (self._tag, self._value) + :rtype: bool + """ + return self._tag == 'user_on_another_team' -ListMembersDevicesError_validator = bv.Union(ListMembersDevicesError) + def is_user_already_paired(self): + """ + Check if the union tag is ``user_already_paired``. -class ListMembersDevicesResult(bb.Struct): - """ - :ivar team.ListMembersDevicesResult.devices: The devices of each member of - the team. - :ivar team.ListMembersDevicesResult.has_more: If true, then there are more - devices available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to - retrieve the rest. - :ivar team.ListMembersDevicesResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to - receive the next sub list of team's devices. - """ + :rtype: bool + """ + return self._tag == 'user_already_paired' - __slots__ = [ - '_devices_value', - '_devices_present', - '_has_more_value', - '_has_more_present', - '_cursor_value', - '_cursor_present', - ] + def is_user_migration_failed(self): + """ + Check if the union tag is ``user_migration_failed``. - _has_required_fields = True + :rtype: bool + """ + return self._tag == 'user_migration_failed' - def __init__(self, - devices=None, - has_more=None, - cursor=None): - self._devices_value = None - self._devices_present = False - self._has_more_value = None - self._has_more_present = False - self._cursor_value = None - self._cursor_present = False - if devices is not None: - self.devices = devices - if has_more is not None: - self.has_more = has_more - if cursor is not None: - self.cursor = cursor + def is_duplicate_external_member_id(self): + """ + Check if the union tag is ``duplicate_external_member_id``. - @property - def devices(self): + :rtype: bool """ - The devices of each member of the team. + return self._tag == 'duplicate_external_member_id' - :rtype: list of [MemberDevices] + def is_duplicate_member_persistent_id(self): """ - if self._devices_present: - return self._devices_value - else: - raise AttributeError("missing required field 'devices'") + Check if the union tag is ``duplicate_member_persistent_id``. - @devices.setter - def devices(self, val): - val = self._devices_validator.validate(val) - self._devices_value = val - self._devices_present = True + :rtype: bool + """ + return self._tag == 'duplicate_member_persistent_id' - @devices.deleter - def devices(self): - self._devices_value = None - self._devices_present = False + def is_persistent_id_disabled(self): + """ + Check if the union tag is ``persistent_id_disabled``. - @property - def has_more(self): + :rtype: bool """ - If true, then there are more devices available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to - retrieve the rest. + return self._tag == 'persistent_id_disabled' + + def is_user_creation_failed(self): + """ + Check if the union tag is ``user_creation_failed``. :rtype: bool """ - if self._has_more_present: - return self._has_more_value - else: - raise AttributeError("missing required field 'has_more'") + return self._tag == 'user_creation_failed' - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + def get_success(self): + """ + Describes a user that was successfully added to the team. - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + Only call this if :meth:`is_success` is true. - @property - def cursor(self): + :rtype: TeamMemberInfo """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_devices_list_members_devices` to - receive the next sub list of team's devices. + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value - :rtype: str + def get_team_license_limit(self): """ - if self._cursor_present: - return self._cursor_value - else: - return None + Team is already full. The organization has no available licenses. - @cursor.setter - def cursor(self, val): - if val is None: - del self.cursor - return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + Only call this if :meth:`is_team_license_limit` is true. - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + :rtype: str + """ + if not self.is_team_license_limit(): + raise AttributeError("tag 'team_license_limit' not set") + return self._value - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListMembersDevicesResult, self)._process_custom_annotations(annotation_type, field_path, processor) + def get_free_team_member_limit_reached(self): + """ + Team is already full. The free team member limit has been reached. - def __repr__(self): - return 'ListMembersDevicesResult(devices={!r}, has_more={!r}, cursor={!r})'.format( - self._devices_value, - self._has_more_value, - self._cursor_value, - ) + Only call this if :meth:`is_free_team_member_limit_reached` is true. -ListMembersDevicesResult_validator = bv.Struct(ListMembersDevicesResult) + :rtype: str + """ + if not self.is_free_team_member_limit_reached(): + raise AttributeError("tag 'free_team_member_limit_reached' not set") + return self._value -class ListTeamAppsArg(bb.Struct): - """ - Arguments for - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps`. + def get_user_already_on_team(self): + """ + User is already on this team. The provided email address is associated + with a user who is already a member of (including in recoverable state) + or invited to the team. - :ivar team.ListTeamAppsArg.cursor: At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` - the cursor shouldn't be passed. Then, if the result of the call includes - a cursor, the following requests should include the received cursors in - order to receive the next sub list of the team applications. - """ + Only call this if :meth:`is_user_already_on_team` is true. - __slots__ = [ - '_cursor_value', - '_cursor_present', - ] + :rtype: str + """ + if not self.is_user_already_on_team(): + raise AttributeError("tag 'user_already_on_team' not set") + return self._value - _has_required_fields = False + def get_user_on_another_team(self): + """ + User is already on another team. The provided email address is + associated with a user that is already a member or invited to another + team. - def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + Only call this if :meth:`is_user_on_another_team` is true. - @property - def cursor(self): + :rtype: str """ - At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` - the cursor shouldn't be passed. Then, if the result of the call includes - a cursor, the following requests should include the received cursors in - order to receive the next sub list of the team applications. + if not self.is_user_on_another_team(): + raise AttributeError("tag 'user_on_another_team' not set") + return self._value + + def get_user_already_paired(self): + """ + User is already paired. + + Only call this if :meth:`is_user_already_paired` is true. :rtype: str """ - if self._cursor_present: - return self._cursor_value - else: - return None + if not self.is_user_already_paired(): + raise AttributeError("tag 'user_already_paired' not set") + return self._value - @cursor.setter - def cursor(self, val): - if val is None: - del self.cursor - return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + def get_user_migration_failed(self): + """ + User migration has failed. - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + Only call this if :meth:`is_user_migration_failed` is true. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListTeamAppsArg, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: str + """ + if not self.is_user_migration_failed(): + raise AttributeError("tag 'user_migration_failed' not set") + return self._value - def __repr__(self): - return 'ListTeamAppsArg(cursor={!r})'.format( - self._cursor_value, - ) + def get_duplicate_external_member_id(self): + """ + A user with the given external member ID already exists on the team + (including in recoverable state). -ListTeamAppsArg_validator = bv.Struct(ListTeamAppsArg) + Only call this if :meth:`is_duplicate_external_member_id` is true. -class ListTeamAppsError(bb.Union): - """ - Error returned by - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps`. + :rtype: str + """ + if not self.is_duplicate_external_member_id(): + raise AttributeError("tag 'duplicate_external_member_id' not set") + return self._value - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + def get_duplicate_member_persistent_id(self): + """ + A user with the given persistent ID already exists on the team + (including in recoverable state). - :ivar team.ListTeamAppsError.reset: Indicates that the cursor has been - invalidated. Call - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` - again with an empty cursor to obtain a new cursor. - """ + Only call this if :meth:`is_duplicate_member_persistent_id` is true. - _catch_all = 'other' - # Attribute is overwritten below the class definition - reset = None - # Attribute is overwritten below the class definition - other = None + :rtype: str + """ + if not self.is_duplicate_member_persistent_id(): + raise AttributeError("tag 'duplicate_member_persistent_id' not set") + return self._value - def is_reset(self): + def get_persistent_id_disabled(self): """ - Check if the union tag is ``reset``. + Persistent ID is only available to teams with persistent ID SAML + configuration. Please contact Dropbox for more information. - :rtype: bool + Only call this if :meth:`is_persistent_id_disabled` is true. + + :rtype: str """ - return self._tag == 'reset' + if not self.is_persistent_id_disabled(): + raise AttributeError("tag 'persistent_id_disabled' not set") + return self._value - def is_other(self): + def get_user_creation_failed(self): """ - Check if the union tag is ``other``. + User creation has failed. - :rtype: bool + Only call this if :meth:`is_user_creation_failed` is true. + + :rtype: str """ - return self._tag == 'other' + if not self.is_user_creation_failed(): + raise AttributeError("tag 'user_creation_failed' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListTeamAppsError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberAddResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListTeamAppsError(%r, %r)' % (self._tag, self._value) + return 'MemberAddResult(%r, %r)' % (self._tag, self._value) -ListTeamAppsError_validator = bv.Union(ListTeamAppsError) +MemberAddResult_validator = bv.Union(MemberAddResult) -class ListTeamAppsResult(bb.Struct): +class MemberDevices(bb.Struct): """ - Information returned by - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps`. + Information on devices of a team's member. - :ivar team.ListTeamAppsResult.apps: The linked applications of each member - of the team. - :ivar team.ListTeamAppsResult.has_more: If true, then there are more apps - available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` - to retrieve the rest. - :ivar team.ListTeamAppsResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` - to receive the next sub list of team's applications. + :ivar team.MemberDevices.team_member_id: The member unique Id. + :ivar team.MemberDevices.web_sessions: List of web sessions made by this + team member. + :ivar team.MemberDevices.desktop_clients: List of desktop clients by this + team member. + :ivar team.MemberDevices.mobile_clients: List of mobile clients by this team + member. """ __slots__ = [ - '_apps_value', - '_apps_present', - '_has_more_value', - '_has_more_present', - '_cursor_value', - '_cursor_present', + '_team_member_id_value', + '_team_member_id_present', + '_web_sessions_value', + '_web_sessions_present', + '_desktop_clients_value', + '_desktop_clients_present', + '_mobile_clients_value', + '_mobile_clients_present', ] _has_required_fields = True def __init__(self, - apps=None, - has_more=None, - cursor=None): - self._apps_value = None - self._apps_present = False - self._has_more_value = None - self._has_more_present = False - self._cursor_value = None - self._cursor_present = False - if apps is not None: - self.apps = apps - if has_more is not None: - self.has_more = has_more - if cursor is not None: - self.cursor = cursor + team_member_id=None, + web_sessions=None, + desktop_clients=None, + mobile_clients=None): + self._team_member_id_value = None + self._team_member_id_present = False + self._web_sessions_value = None + self._web_sessions_present = False + self._desktop_clients_value = None + self._desktop_clients_present = False + self._mobile_clients_value = None + self._mobile_clients_present = False + if team_member_id is not None: + self.team_member_id = team_member_id + if web_sessions is not None: + self.web_sessions = web_sessions + if desktop_clients is not None: + self.desktop_clients = desktop_clients + if mobile_clients is not None: + self.mobile_clients = mobile_clients @property - def apps(self): + def team_member_id(self): """ - The linked applications of each member of the team. + The member unique Id. - :rtype: list of [MemberLinkedApps] + :rtype: str """ - if self._apps_present: - return self._apps_value + if self._team_member_id_present: + return self._team_member_id_value else: - raise AttributeError("missing required field 'apps'") + raise AttributeError("missing required field 'team_member_id'") - @apps.setter - def apps(self, val): - val = self._apps_validator.validate(val) - self._apps_value = val - self._apps_present = True + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - @apps.deleter - def apps(self): - self._apps_value = None - self._apps_present = False + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False @property - def has_more(self): + def web_sessions(self): """ - If true, then there are more apps available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` - to retrieve the rest. + List of web sessions made by this team member. - :rtype: bool + :rtype: list of [ActiveWebSession] """ - if self._has_more_present: - return self._has_more_value + if self._web_sessions_present: + return self._web_sessions_value else: - raise AttributeError("missing required field 'has_more'") + return None - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + @web_sessions.setter + def web_sessions(self, val): + if val is None: + del self.web_sessions + return + val = self._web_sessions_validator.validate(val) + self._web_sessions_value = val + self._web_sessions_present = True - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + @web_sessions.deleter + def web_sessions(self): + self._web_sessions_value = None + self._web_sessions_present = False @property - def cursor(self): + def desktop_clients(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_list_team_linked_apps` - to receive the next sub list of team's applications. + List of desktop clients by this team member. - :rtype: str + :rtype: list of [DesktopClientSession] """ - if self._cursor_present: - return self._cursor_value + if self._desktop_clients_present: + return self._desktop_clients_value else: return None - @cursor.setter - def cursor(self, val): + @desktop_clients.setter + def desktop_clients(self, val): if val is None: - del self.cursor + del self.desktop_clients return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True - - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListTeamAppsResult, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ListTeamAppsResult(apps={!r}, has_more={!r}, cursor={!r})'.format( - self._apps_value, - self._has_more_value, - self._cursor_value, - ) - -ListTeamAppsResult_validator = bv.Struct(ListTeamAppsResult) - -class ListTeamDevicesArg(bb.Struct): - """ - :ivar team.ListTeamDevicesArg.cursor: At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` the - cursor shouldn't be passed. Then, if the result of the call includes a - cursor, the following requests should include the received cursors in - order to receive the next sub list of team devices. - :ivar team.ListTeamDevicesArg.include_web_sessions: Whether to list web - sessions of the team members. - :ivar team.ListTeamDevicesArg.include_desktop_clients: Whether to list - desktop clients of the team members. - :ivar team.ListTeamDevicesArg.include_mobile_clients: Whether to list mobile - clients of the team members. - """ - - __slots__ = [ - '_cursor_value', - '_cursor_present', - '_include_web_sessions_value', - '_include_web_sessions_present', - '_include_desktop_clients_value', - '_include_desktop_clients_present', - '_include_mobile_clients_value', - '_include_mobile_clients_present', - ] - - _has_required_fields = False + val = self._desktop_clients_validator.validate(val) + self._desktop_clients_value = val + self._desktop_clients_present = True - def __init__(self, - cursor=None, - include_web_sessions=None, - include_desktop_clients=None, - include_mobile_clients=None): - self._cursor_value = None - self._cursor_present = False - self._include_web_sessions_value = None - self._include_web_sessions_present = False - self._include_desktop_clients_value = None - self._include_desktop_clients_present = False - self._include_mobile_clients_value = None - self._include_mobile_clients_present = False - if cursor is not None: - self.cursor = cursor - if include_web_sessions is not None: - self.include_web_sessions = include_web_sessions - if include_desktop_clients is not None: - self.include_desktop_clients = include_desktop_clients - if include_mobile_clients is not None: - self.include_mobile_clients = include_mobile_clients + @desktop_clients.deleter + def desktop_clients(self): + self._desktop_clients_value = None + self._desktop_clients_present = False @property - def cursor(self): + def mobile_clients(self): """ - At the first call to the - :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` the - cursor shouldn't be passed. Then, if the result of the call includes a - cursor, the following requests should include the received cursors in - order to receive the next sub list of team devices. + List of mobile clients by this team member. - :rtype: str + :rtype: list of [MobileClientSession] """ - if self._cursor_present: - return self._cursor_value + if self._mobile_clients_present: + return self._mobile_clients_value else: return None - @cursor.setter - def cursor(self, val): + @mobile_clients.setter + def mobile_clients(self, val): if val is None: - del self.cursor + del self.mobile_clients return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + val = self._mobile_clients_validator.validate(val) + self._mobile_clients_value = val + self._mobile_clients_present = True + + @mobile_clients.deleter + def mobile_clients(self): + self._mobile_clients_value = None + self._mobile_clients_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberDevices, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberDevices(team_member_id={!r}, web_sessions={!r}, desktop_clients={!r}, mobile_clients={!r})'.format( + self._team_member_id_value, + self._web_sessions_value, + self._desktop_clients_value, + self._mobile_clients_value, + ) + +MemberDevices_validator = bv.Struct(MemberDevices) - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False +class MemberLinkedApps(bb.Struct): + """ + Information on linked applications of a team member. - @property - def include_web_sessions(self): - """ - Whether to list web sessions of the team members. + :ivar team.MemberLinkedApps.team_member_id: The member unique Id. + :ivar team.MemberLinkedApps.linked_api_apps: List of third party + applications linked by this team member. + """ - :rtype: bool - """ - if self._include_web_sessions_present: - return self._include_web_sessions_value - else: - return True + __slots__ = [ + '_team_member_id_value', + '_team_member_id_present', + '_linked_api_apps_value', + '_linked_api_apps_present', + ] - @include_web_sessions.setter - def include_web_sessions(self, val): - val = self._include_web_sessions_validator.validate(val) - self._include_web_sessions_value = val - self._include_web_sessions_present = True + _has_required_fields = True - @include_web_sessions.deleter - def include_web_sessions(self): - self._include_web_sessions_value = None - self._include_web_sessions_present = False + def __init__(self, + team_member_id=None, + linked_api_apps=None): + self._team_member_id_value = None + self._team_member_id_present = False + self._linked_api_apps_value = None + self._linked_api_apps_present = False + if team_member_id is not None: + self.team_member_id = team_member_id + if linked_api_apps is not None: + self.linked_api_apps = linked_api_apps @property - def include_desktop_clients(self): + def team_member_id(self): """ - Whether to list desktop clients of the team members. + The member unique Id. - :rtype: bool + :rtype: str """ - if self._include_desktop_clients_present: - return self._include_desktop_clients_value + if self._team_member_id_present: + return self._team_member_id_value else: - return True + raise AttributeError("missing required field 'team_member_id'") - @include_desktop_clients.setter - def include_desktop_clients(self, val): - val = self._include_desktop_clients_validator.validate(val) - self._include_desktop_clients_value = val - self._include_desktop_clients_present = True + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - @include_desktop_clients.deleter - def include_desktop_clients(self): - self._include_desktop_clients_value = None - self._include_desktop_clients_present = False + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False @property - def include_mobile_clients(self): + def linked_api_apps(self): """ - Whether to list mobile clients of the team members. + List of third party applications linked by this team member. - :rtype: bool + :rtype: list of [ApiApp] """ - if self._include_mobile_clients_present: - return self._include_mobile_clients_value + if self._linked_api_apps_present: + return self._linked_api_apps_value else: - return True + raise AttributeError("missing required field 'linked_api_apps'") - @include_mobile_clients.setter - def include_mobile_clients(self, val): - val = self._include_mobile_clients_validator.validate(val) - self._include_mobile_clients_value = val - self._include_mobile_clients_present = True + @linked_api_apps.setter + def linked_api_apps(self, val): + val = self._linked_api_apps_validator.validate(val) + self._linked_api_apps_value = val + self._linked_api_apps_present = True - @include_mobile_clients.deleter - def include_mobile_clients(self): - self._include_mobile_clients_value = None - self._include_mobile_clients_present = False + @linked_api_apps.deleter + def linked_api_apps(self): + self._linked_api_apps_value = None + self._linked_api_apps_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListTeamDevicesArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberLinkedApps, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ListTeamDevicesArg(cursor={!r}, include_web_sessions={!r}, include_desktop_clients={!r}, include_mobile_clients={!r})'.format( - self._cursor_value, - self._include_web_sessions_value, - self._include_desktop_clients_value, - self._include_mobile_clients_value, + return 'MemberLinkedApps(team_member_id={!r}, linked_api_apps={!r})'.format( + self._team_member_id_value, + self._linked_api_apps_value, ) -ListTeamDevicesArg_validator = bv.Struct(ListTeamDevicesArg) +MemberLinkedApps_validator = bv.Struct(MemberLinkedApps) -class ListTeamDevicesError(bb.Union): +class MemberProfile(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Basic member profile. - :ivar team.ListTeamDevicesError.reset: Indicates that the cursor has been - invalidated. Call - :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` again - with an empty cursor to obtain a new cursor. + :ivar team.MemberProfile.team_member_id: ID of user as a member of a team. + :ivar team.MemberProfile.external_id: External ID that a team can attach to + the user. An application using the API may find it easier to use their + own IDs instead of Dropbox IDs like account_id or team_member_id. + :ivar team.MemberProfile.account_id: A user's account identifier. + :ivar team.MemberProfile.email: Email address of user. + :ivar team.MemberProfile.email_verified: Is true if the user's email is + verified to be owned by the user. + :ivar team.MemberProfile.secondary_emails: Secondary emails of a user. + :ivar team.MemberProfile.status: The user's status as a member of a specific + team. + :ivar team.MemberProfile.name: Representations for a person's name. + :ivar team.MemberProfile.membership_type: The user's membership type: full + (normal team member) vs limited (does not use a license; no access to + the team's shared quota). + :ivar team.MemberProfile.invited_on: The date and time the user was invited + to the team (contains value only when the member's status matches + ``TeamMemberStatus.invited``). + :ivar team.MemberProfile.joined_on: The date and time the user joined as a + member of a specific team. + :ivar team.MemberProfile.suspended_on: The date and time the user was + suspended from the team (contains value only when the member's status + matches ``TeamMemberStatus.suspended``). + :ivar team.MemberProfile.persistent_id: Persistent ID that a team can attach + to the user. The persistent ID is unique ID to be used for SAML + authentication. + :ivar team.MemberProfile.is_directory_restricted: Whether the user is a + directory restricted user. + :ivar team.MemberProfile.profile_photo_url: URL for the photo representing + the user, if one is set. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - reset = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_team_member_id_value', + '_team_member_id_present', + '_external_id_value', + '_external_id_present', + '_account_id_value', + '_account_id_present', + '_email_value', + '_email_present', + '_email_verified_value', + '_email_verified_present', + '_secondary_emails_value', + '_secondary_emails_present', + '_status_value', + '_status_present', + '_name_value', + '_name_present', + '_membership_type_value', + '_membership_type_present', + '_invited_on_value', + '_invited_on_present', + '_joined_on_value', + '_joined_on_present', + '_suspended_on_value', + '_suspended_on_present', + '_persistent_id_value', + '_persistent_id_present', + '_is_directory_restricted_value', + '_is_directory_restricted_present', + '_profile_photo_url_value', + '_profile_photo_url_present', + ] + + _has_required_fields = True + + def __init__(self, + team_member_id=None, + email=None, + email_verified=None, + status=None, + name=None, + membership_type=None, + external_id=None, + account_id=None, + secondary_emails=None, + invited_on=None, + joined_on=None, + suspended_on=None, + persistent_id=None, + is_directory_restricted=None, + profile_photo_url=None): + self._team_member_id_value = None + self._team_member_id_present = False + self._external_id_value = None + self._external_id_present = False + self._account_id_value = None + self._account_id_present = False + self._email_value = None + self._email_present = False + self._email_verified_value = None + self._email_verified_present = False + self._secondary_emails_value = None + self._secondary_emails_present = False + self._status_value = None + self._status_present = False + self._name_value = None + self._name_present = False + self._membership_type_value = None + self._membership_type_present = False + self._invited_on_value = None + self._invited_on_present = False + self._joined_on_value = None + self._joined_on_present = False + self._suspended_on_value = None + self._suspended_on_present = False + self._persistent_id_value = None + self._persistent_id_present = False + self._is_directory_restricted_value = None + self._is_directory_restricted_present = False + self._profile_photo_url_value = None + self._profile_photo_url_present = False + if team_member_id is not None: + self.team_member_id = team_member_id + if external_id is not None: + self.external_id = external_id + if account_id is not None: + self.account_id = account_id + if email is not None: + self.email = email + if email_verified is not None: + self.email_verified = email_verified + if secondary_emails is not None: + self.secondary_emails = secondary_emails + if status is not None: + self.status = status + if name is not None: + self.name = name + if membership_type is not None: + self.membership_type = membership_type + if invited_on is not None: + self.invited_on = invited_on + if joined_on is not None: + self.joined_on = joined_on + if suspended_on is not None: + self.suspended_on = suspended_on + if persistent_id is not None: + self.persistent_id = persistent_id + if is_directory_restricted is not None: + self.is_directory_restricted = is_directory_restricted + if profile_photo_url is not None: + self.profile_photo_url = profile_photo_url - def is_reset(self): + @property + def team_member_id(self): """ - Check if the union tag is ``reset``. + ID of user as a member of a team. - :rtype: bool + :rtype: str """ - return self._tag == 'reset' + if self._team_member_id_present: + return self._team_member_id_value + else: + raise AttributeError("missing required field 'team_member_id'") - def is_other(self): - """ - Check if the union tag is ``other``. + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - :rtype: bool + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False + + @property + def external_id(self): """ - return self._tag == 'other' + External ID that a team can attach to the user. An application using the + API may find it easier to use their own IDs instead of Dropbox IDs like + account_id or team_member_id. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListTeamDevicesError, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: str + """ + if self._external_id_present: + return self._external_id_value + else: + return None - def __repr__(self): - return 'ListTeamDevicesError(%r, %r)' % (self._tag, self._value) + @external_id.setter + def external_id(self, val): + if val is None: + del self.external_id + return + val = self._external_id_validator.validate(val) + self._external_id_value = val + self._external_id_present = True -ListTeamDevicesError_validator = bv.Union(ListTeamDevicesError) + @external_id.deleter + def external_id(self): + self._external_id_value = None + self._external_id_present = False -class ListTeamDevicesResult(bb.Struct): - """ - :ivar team.ListTeamDevicesResult.devices: The devices of each member of the - team. - :ivar team.ListTeamDevicesResult.has_more: If true, then there are more - devices available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to - retrieve the rest. - :ivar team.ListTeamDevicesResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to - receive the next sub list of team's devices. - """ + @property + def account_id(self): + """ + A user's account identifier. - __slots__ = [ - '_devices_value', - '_devices_present', - '_has_more_value', - '_has_more_present', - '_cursor_value', - '_cursor_present', - ] + :rtype: str + """ + if self._account_id_present: + return self._account_id_value + else: + return None - _has_required_fields = True + @account_id.setter + def account_id(self, val): + if val is None: + del self.account_id + return + val = self._account_id_validator.validate(val) + self._account_id_value = val + self._account_id_present = True - def __init__(self, - devices=None, - has_more=None, - cursor=None): - self._devices_value = None - self._devices_present = False - self._has_more_value = None - self._has_more_present = False - self._cursor_value = None - self._cursor_present = False - if devices is not None: - self.devices = devices - if has_more is not None: - self.has_more = has_more - if cursor is not None: - self.cursor = cursor + @account_id.deleter + def account_id(self): + self._account_id_value = None + self._account_id_present = False @property - def devices(self): + def email(self): """ - The devices of each member of the team. + Email address of user. - :rtype: list of [MemberDevices] + :rtype: str """ - if self._devices_present: - return self._devices_value + if self._email_present: + return self._email_value else: - raise AttributeError("missing required field 'devices'") + raise AttributeError("missing required field 'email'") - @devices.setter - def devices(self, val): - val = self._devices_validator.validate(val) - self._devices_value = val - self._devices_present = True + @email.setter + def email(self, val): + val = self._email_validator.validate(val) + self._email_value = val + self._email_present = True - @devices.deleter - def devices(self): - self._devices_value = None - self._devices_present = False + @email.deleter + def email(self): + self._email_value = None + self._email_present = False @property - def has_more(self): + def email_verified(self): """ - If true, then there are more devices available. Pass the cursor to - :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to - retrieve the rest. + Is true if the user's email is verified to be owned by the user. :rtype: bool """ - if self._has_more_present: - return self._has_more_value + if self._email_verified_present: + return self._email_verified_value else: - raise AttributeError("missing required field 'has_more'") + raise AttributeError("missing required field 'email_verified'") - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + @email_verified.setter + def email_verified(self, val): + val = self._email_verified_validator.validate(val) + self._email_verified_value = val + self._email_verified_present = True - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + @email_verified.deleter + def email_verified(self): + self._email_verified_value = None + self._email_verified_present = False @property - def cursor(self): + def secondary_emails(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_devices_list_team_devices` to - receive the next sub list of team's devices. + Secondary emails of a user. - :rtype: str + :rtype: list of [secondary_emails.SecondaryEmail] """ - if self._cursor_present: - return self._cursor_value + if self._secondary_emails_present: + return self._secondary_emails_value else: return None - @cursor.setter - def cursor(self, val): + @secondary_emails.setter + def secondary_emails(self, val): if val is None: - del self.cursor + del self.secondary_emails return - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True - - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ListTeamDevicesResult, self)._process_custom_annotations(annotation_type, field_path, processor) + val = self._secondary_emails_validator.validate(val) + self._secondary_emails_value = val + self._secondary_emails_present = True - def __repr__(self): - return 'ListTeamDevicesResult(devices={!r}, has_more={!r}, cursor={!r})'.format( - self._devices_value, - self._has_more_value, - self._cursor_value, - ) + @secondary_emails.deleter + def secondary_emails(self): + self._secondary_emails_value = None + self._secondary_emails_present = False -ListTeamDevicesResult_validator = bv.Struct(ListTeamDevicesResult) + @property + def status(self): + """ + The user's status as a member of a specific team. -class MemberAccess(bb.Struct): - """ - Specify access type a member should have when joined to a group. + :rtype: TeamMemberStatus + """ + if self._status_present: + return self._status_value + else: + raise AttributeError("missing required field 'status'") - :ivar team.MemberAccess.user: Identity of a user. - :ivar team.MemberAccess.access_type: Access type. - """ + @status.setter + def status(self, val): + self._status_validator.validate_type_only(val) + self._status_value = val + self._status_present = True - __slots__ = [ - '_user_value', - '_user_present', - '_access_type_value', - '_access_type_present', - ] + @status.deleter + def status(self): + self._status_value = None + self._status_present = False - _has_required_fields = True + @property + def name(self): + """ + Representations for a person's name. - def __init__(self, - user=None, - access_type=None): - self._user_value = None - self._user_present = False - self._access_type_value = None - self._access_type_present = False - if user is not None: - self.user = user - if access_type is not None: - self.access_type = access_type + :rtype: users.Name + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") + + @name.setter + def name(self, val): + self._name_validator.validate_type_only(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False @property - def user(self): + def membership_type(self): """ - Identity of a user. + The user's membership type: full (normal team member) vs limited (does + not use a license; no access to the team's shared quota). - :rtype: UserSelectorArg + :rtype: TeamMembershipType """ - if self._user_present: - return self._user_value + if self._membership_type_present: + return self._membership_type_value else: - raise AttributeError("missing required field 'user'") + raise AttributeError("missing required field 'membership_type'") - @user.setter - def user(self, val): - self._user_validator.validate_type_only(val) - self._user_value = val - self._user_present = True + @membership_type.setter + def membership_type(self, val): + self._membership_type_validator.validate_type_only(val) + self._membership_type_value = val + self._membership_type_present = True - @user.deleter - def user(self): - self._user_value = None - self._user_present = False + @membership_type.deleter + def membership_type(self): + self._membership_type_value = None + self._membership_type_present = False @property - def access_type(self): + def invited_on(self): """ - Access type. + The date and time the user was invited to the team (contains value only + when the member's status matches ``TeamMemberStatus.invited``). - :rtype: GroupAccessType + :rtype: datetime.datetime """ - if self._access_type_present: - return self._access_type_value + if self._invited_on_present: + return self._invited_on_value else: - raise AttributeError("missing required field 'access_type'") - - @access_type.setter - def access_type(self, val): - self._access_type_validator.validate_type_only(val) - self._access_type_value = val - self._access_type_present = True - - @access_type.deleter - def access_type(self): - self._access_type_value = None - self._access_type_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberAccess, self)._process_custom_annotations(annotation_type, field_path, processor) + return None - def __repr__(self): - return 'MemberAccess(user={!r}, access_type={!r})'.format( - self._user_value, - self._access_type_value, - ) + @invited_on.setter + def invited_on(self, val): + if val is None: + del self.invited_on + return + val = self._invited_on_validator.validate(val) + self._invited_on_value = val + self._invited_on_present = True -MemberAccess_validator = bv.Struct(MemberAccess) + @invited_on.deleter + def invited_on(self): + self._invited_on_value = None + self._invited_on_present = False -class MemberAddArg(bb.Struct): - """ - :ivar team.MemberAddArg.member_given_name: Member's first name. - :ivar team.MemberAddArg.member_surname: Member's last name. - :ivar team.MemberAddArg.member_external_id: External ID for member. - :ivar team.MemberAddArg.member_persistent_id: Persistent ID for member. This - field is only available to teams using persistent ID SAML configuration. - :ivar team.MemberAddArg.send_welcome_email: Whether to send a welcome email - to the member. If send_welcome_email is false, no email invitation will - be sent to the user. This may be useful for apps using single sign-on - (SSO) flows for onboarding that want to handle announcements themselves. - :ivar team.MemberAddArg.is_directory_restricted: Whether a user is directory - restricted. - """ + @property + def joined_on(self): + """ + The date and time the user joined as a member of a specific team. - __slots__ = [ - '_member_email_value', - '_member_email_present', - '_member_given_name_value', - '_member_given_name_present', - '_member_surname_value', - '_member_surname_present', - '_member_external_id_value', - '_member_external_id_present', - '_member_persistent_id_value', - '_member_persistent_id_present', - '_send_welcome_email_value', - '_send_welcome_email_present', - '_role_value', - '_role_present', - '_is_directory_restricted_value', - '_is_directory_restricted_present', - ] + :rtype: datetime.datetime + """ + if self._joined_on_present: + return self._joined_on_value + else: + return None - _has_required_fields = True + @joined_on.setter + def joined_on(self, val): + if val is None: + del self.joined_on + return + val = self._joined_on_validator.validate(val) + self._joined_on_value = val + self._joined_on_present = True - def __init__(self, - member_email=None, - member_given_name=None, - member_surname=None, - member_external_id=None, - member_persistent_id=None, - send_welcome_email=None, - role=None, - is_directory_restricted=None): - self._member_email_value = None - self._member_email_present = False - self._member_given_name_value = None - self._member_given_name_present = False - self._member_surname_value = None - self._member_surname_present = False - self._member_external_id_value = None - self._member_external_id_present = False - self._member_persistent_id_value = None - self._member_persistent_id_present = False - self._send_welcome_email_value = None - self._send_welcome_email_present = False - self._role_value = None - self._role_present = False - self._is_directory_restricted_value = None - self._is_directory_restricted_present = False - if member_email is not None: - self.member_email = member_email - if member_given_name is not None: - self.member_given_name = member_given_name - if member_surname is not None: - self.member_surname = member_surname - if member_external_id is not None: - self.member_external_id = member_external_id - if member_persistent_id is not None: - self.member_persistent_id = member_persistent_id - if send_welcome_email is not None: - self.send_welcome_email = send_welcome_email - if role is not None: - self.role = role - if is_directory_restricted is not None: - self.is_directory_restricted = is_directory_restricted + @joined_on.deleter + def joined_on(self): + self._joined_on_value = None + self._joined_on_present = False @property - def member_email(self): + def suspended_on(self): """ - :rtype: str + The date and time the user was suspended from the team (contains value + only when the member's status matches ``TeamMemberStatus.suspended``). + + :rtype: datetime.datetime """ - if self._member_email_present: - return self._member_email_value + if self._suspended_on_present: + return self._suspended_on_value else: - raise AttributeError("missing required field 'member_email'") + return None - @member_email.setter - def member_email(self, val): - val = self._member_email_validator.validate(val) - self._member_email_value = val - self._member_email_present = True + @suspended_on.setter + def suspended_on(self, val): + if val is None: + del self.suspended_on + return + val = self._suspended_on_validator.validate(val) + self._suspended_on_value = val + self._suspended_on_present = True - @member_email.deleter - def member_email(self): - self._member_email_value = None - self._member_email_present = False + @suspended_on.deleter + def suspended_on(self): + self._suspended_on_value = None + self._suspended_on_present = False @property - def member_given_name(self): + def persistent_id(self): """ - Member's first name. + Persistent ID that a team can attach to the user. The persistent ID is + unique ID to be used for SAML authentication. :rtype: str """ - if self._member_given_name_present: - return self._member_given_name_value + if self._persistent_id_present: + return self._persistent_id_value else: return None - @member_given_name.setter - def member_given_name(self, val): + @persistent_id.setter + def persistent_id(self, val): if val is None: - del self.member_given_name + del self.persistent_id return - val = self._member_given_name_validator.validate(val) - self._member_given_name_value = val - self._member_given_name_present = True + val = self._persistent_id_validator.validate(val) + self._persistent_id_value = val + self._persistent_id_present = True - @member_given_name.deleter - def member_given_name(self): - self._member_given_name_value = None - self._member_given_name_present = False + @persistent_id.deleter + def persistent_id(self): + self._persistent_id_value = None + self._persistent_id_present = False @property - def member_surname(self): + def is_directory_restricted(self): """ - Member's last name. + Whether the user is a directory restricted user. - :rtype: str + :rtype: bool """ - if self._member_surname_present: - return self._member_surname_value + if self._is_directory_restricted_present: + return self._is_directory_restricted_value else: return None - @member_surname.setter - def member_surname(self, val): + @is_directory_restricted.setter + def is_directory_restricted(self, val): if val is None: - del self.member_surname + del self.is_directory_restricted return - val = self._member_surname_validator.validate(val) - self._member_surname_value = val - self._member_surname_present = True + val = self._is_directory_restricted_validator.validate(val) + self._is_directory_restricted_value = val + self._is_directory_restricted_present = True - @member_surname.deleter - def member_surname(self): - self._member_surname_value = None - self._member_surname_present = False + @is_directory_restricted.deleter + def is_directory_restricted(self): + self._is_directory_restricted_value = None + self._is_directory_restricted_present = False @property - def member_external_id(self): + def profile_photo_url(self): """ - External ID for member. + URL for the photo representing the user, if one is set. :rtype: str """ - if self._member_external_id_present: - return self._member_external_id_value + if self._profile_photo_url_present: + return self._profile_photo_url_value else: return None - @member_external_id.setter - def member_external_id(self, val): + @profile_photo_url.setter + def profile_photo_url(self, val): if val is None: - del self.member_external_id + del self.profile_photo_url return - val = self._member_external_id_validator.validate(val) - self._member_external_id_value = val - self._member_external_id_present = True + val = self._profile_photo_url_validator.validate(val) + self._profile_photo_url_value = val + self._profile_photo_url_present = True - @member_external_id.deleter - def member_external_id(self): - self._member_external_id_value = None - self._member_external_id_present = False + @profile_photo_url.deleter + def profile_photo_url(self): + self._profile_photo_url_value = None + self._profile_photo_url_present = False - @property - def member_persistent_id(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberProfile, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberProfile(team_member_id={!r}, email={!r}, email_verified={!r}, status={!r}, name={!r}, membership_type={!r}, external_id={!r}, account_id={!r}, secondary_emails={!r}, invited_on={!r}, joined_on={!r}, suspended_on={!r}, persistent_id={!r}, is_directory_restricted={!r}, profile_photo_url={!r})'.format( + self._team_member_id_value, + self._email_value, + self._email_verified_value, + self._status_value, + self._name_value, + self._membership_type_value, + self._external_id_value, + self._account_id_value, + self._secondary_emails_value, + self._invited_on_value, + self._joined_on_value, + self._suspended_on_value, + self._persistent_id_value, + self._is_directory_restricted_value, + self._profile_photo_url_value, + ) + +MemberProfile_validator = bv.Struct(MemberProfile) + +class UserSelectorError(bb.Union): + """ + Error that can be returned whenever a struct derived from + :class:`UserSelectorArg` is used. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.UserSelectorError.user_not_found: No matching user found. The + provided team_member_id, email, or external_id does not exist on this + team. + """ + + _catch_all = None + # Attribute is overwritten below the class definition + user_not_found = None + + def is_user_not_found(self): """ - Persistent ID for member. This field is only available to teams using - persistent ID SAML configuration. + Check if the union tag is ``user_not_found``. - :rtype: str + :rtype: bool """ - if self._member_persistent_id_present: - return self._member_persistent_id_value - else: - return None + return self._tag == 'user_not_found' - @member_persistent_id.setter - def member_persistent_id(self, val): - if val is None: - del self.member_persistent_id - return - val = self._member_persistent_id_validator.validate(val) - self._member_persistent_id_value = val - self._member_persistent_id_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) - @member_persistent_id.deleter - def member_persistent_id(self): - self._member_persistent_id_value = None - self._member_persistent_id_present = False + def __repr__(self): + return 'UserSelectorError(%r, %r)' % (self._tag, self._value) - @property - def send_welcome_email(self): +UserSelectorError_validator = bv.Union(UserSelectorError) + +class MemberSelectorError(UserSelectorError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.MemberSelectorError.user_not_in_team: The user is not a member of + the team. + """ + + # Attribute is overwritten below the class definition + user_not_in_team = None + + def is_user_not_in_team(self): """ - Whether to send a welcome email to the member. If send_welcome_email is - false, no email invitation will be sent to the user. This may be useful - for apps using single sign-on (SSO) flows for onboarding that want to - handle announcements themselves. + Check if the union tag is ``user_not_in_team``. :rtype: bool """ - if self._send_welcome_email_present: - return self._send_welcome_email_value - else: - return True + return self._tag == 'user_not_in_team' - @send_welcome_email.setter - def send_welcome_email(self, val): - val = self._send_welcome_email_validator.validate(val) - self._send_welcome_email_value = val - self._send_welcome_email_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) - @send_welcome_email.deleter - def send_welcome_email(self): - self._send_welcome_email_value = None - self._send_welcome_email_present = False + def __repr__(self): + return 'MemberSelectorError(%r, %r)' % (self._tag, self._value) + +MemberSelectorError_validator = bv.Union(MemberSelectorError) + +class MembersAddArg(bb.Struct): + """ + :ivar team.MembersAddArg.new_members: Details of new members to be added to + the team. + :ivar team.MembersAddArg.force_async: Whether to force the add to happen + asynchronously. + """ + + __slots__ = [ + '_new_members_value', + '_new_members_present', + '_force_async_value', + '_force_async_present', + ] + + _has_required_fields = True + + def __init__(self, + new_members=None, + force_async=None): + self._new_members_value = None + self._new_members_present = False + self._force_async_value = None + self._force_async_present = False + if new_members is not None: + self.new_members = new_members + if force_async is not None: + self.force_async = force_async @property - def role(self): + def new_members(self): """ - :rtype: AdminTier + Details of new members to be added to the team. + + :rtype: list of [MemberAddArg] """ - if self._role_present: - return self._role_value + if self._new_members_present: + return self._new_members_value else: - return AdminTier.member_only + raise AttributeError("missing required field 'new_members'") - @role.setter - def role(self, val): - self._role_validator.validate_type_only(val) - self._role_value = val - self._role_present = True + @new_members.setter + def new_members(self, val): + val = self._new_members_validator.validate(val) + self._new_members_value = val + self._new_members_present = True - @role.deleter - def role(self): - self._role_value = None - self._role_present = False + @new_members.deleter + def new_members(self): + self._new_members_value = None + self._new_members_present = False @property - def is_directory_restricted(self): + def force_async(self): """ - Whether a user is directory restricted. + Whether to force the add to happen asynchronously. :rtype: bool """ - if self._is_directory_restricted_present: - return self._is_directory_restricted_value + if self._force_async_present: + return self._force_async_value else: - return None + return False - @is_directory_restricted.setter - def is_directory_restricted(self, val): - if val is None: - del self.is_directory_restricted - return - val = self._is_directory_restricted_validator.validate(val) - self._is_directory_restricted_value = val - self._is_directory_restricted_present = True + @force_async.setter + def force_async(self, val): + val = self._force_async_validator.validate(val) + self._force_async_value = val + self._force_async_present = True - @is_directory_restricted.deleter - def is_directory_restricted(self): - self._is_directory_restricted_value = None - self._is_directory_restricted_present = False + @force_async.deleter + def force_async(self): + self._force_async_value = None + self._force_async_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberAddArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersAddArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberAddArg(member_email={!r}, member_given_name={!r}, member_surname={!r}, member_external_id={!r}, member_persistent_id={!r}, send_welcome_email={!r}, role={!r}, is_directory_restricted={!r})'.format( - self._member_email_value, - self._member_given_name_value, - self._member_surname_value, - self._member_external_id_value, - self._member_persistent_id_value, - self._send_welcome_email_value, - self._role_value, - self._is_directory_restricted_value, + return 'MembersAddArg(new_members={!r}, force_async={!r})'.format( + self._new_members_value, + self._force_async_value, ) -MemberAddArg_validator = bv.Struct(MemberAddArg) - -class MemberAddResult(bb.Union): - """ - Describes the result of attempting to add a single user to the team. - 'success' is the only value indicating that a user was indeed added to the - team - the other values explain the type of failure that occurred, and - include the email of the user for which the operation has failed. - +MembersAddArg_validator = bv.Struct(MembersAddArg) + +class MembersAddJobStatus(async_.PollResultBase): + """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar TeamMemberInfo MemberAddResult.success: Describes a user that was - successfully added to the team. - :ivar str team.MemberAddResult.team_license_limit: Team is already full. The - organization has no available licenses. - :ivar str team.MemberAddResult.free_team_member_limit_reached: Team is - already full. The free team member limit has been reached. - :ivar str team.MemberAddResult.user_already_on_team: User is already on this - team. The provided email address is associated with a user who is - already a member of (including in recoverable state) or invited to the - team. - :ivar str team.MemberAddResult.user_on_another_team: User is already on - another team. The provided email address is associated with a user that - is already a member or invited to another team. - :ivar str team.MemberAddResult.user_already_paired: User is already paired. - :ivar str team.MemberAddResult.user_migration_failed: User migration has - failed. - :ivar str team.MemberAddResult.duplicate_external_member_id: A user with the - given external member ID already exists on the team (including in - recoverable state). - :ivar str team.MemberAddResult.duplicate_member_persistent_id: A user with - the given persistent ID already exists on the team (including in - recoverable state). - :ivar str team.MemberAddResult.persistent_id_disabled: Persistent ID is only - available to teams with persistent ID SAML configuration. Please contact - Dropbox for more information. - :ivar str team.MemberAddResult.user_creation_failed: User creation has - failed. + :ivar list of [MemberAddResult] team.MembersAddJobStatus.complete: The + asynchronous job has finished. For each member that was specified in the + parameter :type:`MembersAddArg` that was provided to + :route:`members/add`, a corresponding item is returned in this list. + :ivar str team.MembersAddJobStatus.failed: The asynchronous job returned an + error. The string contains an error message. """ - _catch_all = None - @classmethod - def success(cls, val): + def complete(cls, val): """ - Create an instance of this class set to the ``success`` tag with value + Create an instance of this class set to the ``complete`` tag with value ``val``. - :param TeamMemberInfo val: - :rtype: MemberAddResult + :param list of [MemberAddResult] val: + :rtype: MembersAddJobStatus """ - return cls('success', val) + return cls('complete', val) @classmethod - def team_license_limit(cls, val): + def failed(cls, val): """ - Create an instance of this class set to the ``team_license_limit`` tag - with value ``val``. + Create an instance of this class set to the ``failed`` tag with value + ``val``. :param str val: - :rtype: MemberAddResult + :rtype: MembersAddJobStatus """ - return cls('team_license_limit', val) + return cls('failed', val) - @classmethod - def free_team_member_limit_reached(cls, val): + def is_complete(self): """ - Create an instance of this class set to the - ``free_team_member_limit_reached`` tag with value ``val``. + Check if the union tag is ``complete``. - :param str val: - :rtype: MemberAddResult + :rtype: bool """ - return cls('free_team_member_limit_reached', val) + return self._tag == 'complete' - @classmethod - def user_already_on_team(cls, val): + def is_failed(self): """ - Create an instance of this class set to the ``user_already_on_team`` tag - with value ``val``. + Check if the union tag is ``failed``. - :param str val: - :rtype: MemberAddResult + :rtype: bool """ - return cls('user_already_on_team', val) + return self._tag == 'failed' - @classmethod - def user_on_another_team(cls, val): + def get_complete(self): """ - Create an instance of this class set to the ``user_on_another_team`` tag - with value ``val``. + The asynchronous job has finished. For each member that was specified in + the parameter :class:`MembersAddArg` that was provided to + :meth:`dropbox.dropbox.Dropbox.team_members_add`, a corresponding item + is returned in this list. - :param str val: - :rtype: MemberAddResult - """ - return cls('user_on_another_team', val) + Only call this if :meth:`is_complete` is true. - @classmethod - def user_already_paired(cls, val): + :rtype: list of [MemberAddResult] """ - Create an instance of this class set to the ``user_already_paired`` tag - with value ``val``. + if not self.is_complete(): + raise AttributeError("tag 'complete' not set") + return self._value - :param str val: - :rtype: MemberAddResult + def get_failed(self): """ - return cls('user_already_paired', val) + The asynchronous job returned an error. The string contains an error + message. - @classmethod - def user_migration_failed(cls, val): - """ - Create an instance of this class set to the ``user_migration_failed`` - tag with value ``val``. + Only call this if :meth:`is_failed` is true. - :param str val: - :rtype: MemberAddResult + :rtype: str """ - return cls('user_migration_failed', val) + if not self.is_failed(): + raise AttributeError("tag 'failed' not set") + return self._value - @classmethod - def duplicate_external_member_id(cls, val): - """ - Create an instance of this class set to the - ``duplicate_external_member_id`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersAddJobStatus, self)._process_custom_annotations(annotation_type, field_path, processor) - :param str val: - :rtype: MemberAddResult - """ - return cls('duplicate_external_member_id', val) + def __repr__(self): + return 'MembersAddJobStatus(%r, %r)' % (self._tag, self._value) + +MembersAddJobStatus_validator = bv.Union(MembersAddJobStatus) + +class MembersAddLaunch(async_.LaunchResultBase): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ @classmethod - def duplicate_member_persistent_id(cls, val): + def complete(cls, val): """ - Create an instance of this class set to the - ``duplicate_member_persistent_id`` tag with value ``val``. + Create an instance of this class set to the ``complete`` tag with value + ``val``. - :param str val: - :rtype: MemberAddResult + :param list of [MemberAddResult] val: + :rtype: MembersAddLaunch """ - return cls('duplicate_member_persistent_id', val) + return cls('complete', val) - @classmethod - def persistent_id_disabled(cls, val): + def is_complete(self): """ - Create an instance of this class set to the ``persistent_id_disabled`` - tag with value ``val``. + Check if the union tag is ``complete``. - :param str val: - :rtype: MemberAddResult + :rtype: bool """ - return cls('persistent_id_disabled', val) + return self._tag == 'complete' - @classmethod - def user_creation_failed(cls, val): + def get_complete(self): """ - Create an instance of this class set to the ``user_creation_failed`` tag - with value ``val``. + Only call this if :meth:`is_complete` is true. - :param str val: - :rtype: MemberAddResult + :rtype: list of [MemberAddResult] """ - return cls('user_creation_failed', val) + if not self.is_complete(): + raise AttributeError("tag 'complete' not set") + return self._value - def is_success(self): - """ - Check if the union tag is ``success``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersAddLaunch, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool + def __repr__(self): + return 'MembersAddLaunch(%r, %r)' % (self._tag, self._value) + +MembersAddLaunch_validator = bv.Union(MembersAddLaunch) + +class MembersDeactivateBaseArg(bb.Struct): + """ + Exactly one of team_member_id, email, or external_id must be provided to + identify the user account. + + :ivar team.MembersDeactivateBaseArg.user: Identity of user to + remove/suspend/have their files moved. + """ + + __slots__ = [ + '_user_value', + '_user_present', + ] + + _has_required_fields = True + + def __init__(self, + user=None): + self._user_value = None + self._user_present = False + if user is not None: + self.user = user + + @property + def user(self): """ - return self._tag == 'success' + Identity of user to remove/suspend/have their files moved. - def is_team_license_limit(self): + :rtype: UserSelectorArg """ - Check if the union tag is ``team_license_limit``. + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") + + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersDeactivateBaseArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MembersDeactivateBaseArg(user={!r})'.format( + self._user_value, + ) + +MembersDeactivateBaseArg_validator = bv.Struct(MembersDeactivateBaseArg) + +class MembersDataTransferArg(MembersDeactivateBaseArg): + """ + :ivar team.MembersDataTransferArg.transfer_dest_id: Files from the deleted + member account will be transferred to this user. + :ivar team.MembersDataTransferArg.transfer_admin_id: Errors during the + transfer process will be sent via email to this user. + """ + + __slots__ = [ + '_transfer_dest_id_value', + '_transfer_dest_id_present', + '_transfer_admin_id_value', + '_transfer_admin_id_present', + ] - :rtype: bool - """ - return self._tag == 'team_license_limit' + _has_required_fields = True - def is_free_team_member_limit_reached(self): - """ - Check if the union tag is ``free_team_member_limit_reached``. + def __init__(self, + user=None, + transfer_dest_id=None, + transfer_admin_id=None): + super(MembersDataTransferArg, self).__init__(user) + self._transfer_dest_id_value = None + self._transfer_dest_id_present = False + self._transfer_admin_id_value = None + self._transfer_admin_id_present = False + if transfer_dest_id is not None: + self.transfer_dest_id = transfer_dest_id + if transfer_admin_id is not None: + self.transfer_admin_id = transfer_admin_id - :rtype: bool + @property + def transfer_dest_id(self): """ - return self._tag == 'free_team_member_limit_reached' + Files from the deleted member account will be transferred to this user. - def is_user_already_on_team(self): + :rtype: UserSelectorArg """ - Check if the union tag is ``user_already_on_team``. + if self._transfer_dest_id_present: + return self._transfer_dest_id_value + else: + raise AttributeError("missing required field 'transfer_dest_id'") - :rtype: bool - """ - return self._tag == 'user_already_on_team' + @transfer_dest_id.setter + def transfer_dest_id(self, val): + self._transfer_dest_id_validator.validate_type_only(val) + self._transfer_dest_id_value = val + self._transfer_dest_id_present = True - def is_user_on_another_team(self): - """ - Check if the union tag is ``user_on_another_team``. + @transfer_dest_id.deleter + def transfer_dest_id(self): + self._transfer_dest_id_value = None + self._transfer_dest_id_present = False - :rtype: bool + @property + def transfer_admin_id(self): """ - return self._tag == 'user_on_another_team' + Errors during the transfer process will be sent via email to this user. - def is_user_already_paired(self): + :rtype: UserSelectorArg """ - Check if the union tag is ``user_already_paired``. + if self._transfer_admin_id_present: + return self._transfer_admin_id_value + else: + raise AttributeError("missing required field 'transfer_admin_id'") - :rtype: bool - """ - return self._tag == 'user_already_paired' + @transfer_admin_id.setter + def transfer_admin_id(self, val): + self._transfer_admin_id_validator.validate_type_only(val) + self._transfer_admin_id_value = val + self._transfer_admin_id_present = True - def is_user_migration_failed(self): - """ - Check if the union tag is ``user_migration_failed``. + @transfer_admin_id.deleter + def transfer_admin_id(self): + self._transfer_admin_id_value = None + self._transfer_admin_id_present = False - :rtype: bool - """ - return self._tag == 'user_migration_failed' + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersDataTransferArg, self)._process_custom_annotations(annotation_type, field_path, processor) - def is_duplicate_external_member_id(self): - """ - Check if the union tag is ``duplicate_external_member_id``. + def __repr__(self): + return 'MembersDataTransferArg(user={!r}, transfer_dest_id={!r}, transfer_admin_id={!r})'.format( + self._user_value, + self._transfer_dest_id_value, + self._transfer_admin_id_value, + ) - :rtype: bool - """ - return self._tag == 'duplicate_external_member_id' +MembersDataTransferArg_validator = bv.Struct(MembersDataTransferArg) - def is_duplicate_member_persistent_id(self): - """ - Check if the union tag is ``duplicate_member_persistent_id``. +class MembersDeactivateArg(MembersDeactivateBaseArg): + """ + :ivar team.MembersDeactivateArg.wipe_data: If provided, controls if the + user's data will be deleted on their linked devices. + """ - :rtype: bool - """ - return self._tag == 'duplicate_member_persistent_id' + __slots__ = [ + '_wipe_data_value', + '_wipe_data_present', + ] - def is_persistent_id_disabled(self): - """ - Check if the union tag is ``persistent_id_disabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'persistent_id_disabled' + def __init__(self, + user=None, + wipe_data=None): + super(MembersDeactivateArg, self).__init__(user) + self._wipe_data_value = None + self._wipe_data_present = False + if wipe_data is not None: + self.wipe_data = wipe_data - def is_user_creation_failed(self): + @property + def wipe_data(self): """ - Check if the union tag is ``user_creation_failed``. + If provided, controls if the user's data will be deleted on their linked + devices. :rtype: bool """ - return self._tag == 'user_creation_failed' + if self._wipe_data_present: + return self._wipe_data_value + else: + return True - def get_success(self): - """ - Describes a user that was successfully added to the team. + @wipe_data.setter + def wipe_data(self, val): + val = self._wipe_data_validator.validate(val) + self._wipe_data_value = val + self._wipe_data_present = True - Only call this if :meth:`is_success` is true. + @wipe_data.deleter + def wipe_data(self): + self._wipe_data_value = None + self._wipe_data_present = False - :rtype: TeamMemberInfo - """ - if not self.is_success(): - raise AttributeError("tag 'success' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersDeactivateArg, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_team_license_limit(self): - """ - Team is already full. The organization has no available licenses. + def __repr__(self): + return 'MembersDeactivateArg(user={!r}, wipe_data={!r})'.format( + self._user_value, + self._wipe_data_value, + ) - Only call this if :meth:`is_team_license_limit` is true. +MembersDeactivateArg_validator = bv.Struct(MembersDeactivateArg) - :rtype: str - """ - if not self.is_team_license_limit(): - raise AttributeError("tag 'team_license_limit' not set") - return self._value +class MembersDeactivateError(UserSelectorError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - def get_free_team_member_limit_reached(self): - """ - Team is already full. The free team member limit has been reached. + :ivar team.MembersDeactivateError.user_not_in_team: The user is not a member + of the team. + """ - Only call this if :meth:`is_free_team_member_limit_reached` is true. + _catch_all = 'other' + # Attribute is overwritten below the class definition + user_not_in_team = None + # Attribute is overwritten below the class definition + other = None - :rtype: str + def is_user_not_in_team(self): """ - if not self.is_free_team_member_limit_reached(): - raise AttributeError("tag 'free_team_member_limit_reached' not set") - return self._value + Check if the union tag is ``user_not_in_team``. - def get_user_already_on_team(self): + :rtype: bool """ - User is already on this team. The provided email address is associated - with a user who is already a member of (including in recoverable state) - or invited to the team. - - Only call this if :meth:`is_user_already_on_team` is true. + return self._tag == 'user_not_in_team' - :rtype: str + def is_other(self): """ - if not self.is_user_already_on_team(): - raise AttributeError("tag 'user_already_on_team' not set") - return self._value + Check if the union tag is ``other``. - def get_user_on_another_team(self): + :rtype: bool """ - User is already on another team. The provided email address is - associated with a user that is already a member or invited to another - team. + return self._tag == 'other' - Only call this if :meth:`is_user_on_another_team` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersDeactivateError, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: str - """ - if not self.is_user_on_another_team(): - raise AttributeError("tag 'user_on_another_team' not set") - return self._value + def __repr__(self): + return 'MembersDeactivateError(%r, %r)' % (self._tag, self._value) - def get_user_already_paired(self): - """ - User is already paired. +MembersDeactivateError_validator = bv.Union(MembersDeactivateError) - Only call this if :meth:`is_user_already_paired` is true. +class MembersDeleteProfilePhotoArg(bb.Struct): + """ + :ivar team.MembersDeleteProfilePhotoArg.user: Identity of the user whose + profile photo will be deleted. + """ - :rtype: str - """ - if not self.is_user_already_paired(): - raise AttributeError("tag 'user_already_paired' not set") - return self._value + __slots__ = [ + '_user_value', + '_user_present', + ] - def get_user_migration_failed(self): - """ - User migration has failed. + _has_required_fields = True - Only call this if :meth:`is_user_migration_failed` is true. + def __init__(self, + user=None): + self._user_value = None + self._user_present = False + if user is not None: + self.user = user - :rtype: str + @property + def user(self): """ - if not self.is_user_migration_failed(): - raise AttributeError("tag 'user_migration_failed' not set") - return self._value + Identity of the user whose profile photo will be deleted. - def get_duplicate_external_member_id(self): + :rtype: UserSelectorArg """ - A user with the given external member ID already exists on the team - (including in recoverable state). + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") - Only call this if :meth:`is_duplicate_external_member_id` is true. + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True - :rtype: str - """ - if not self.is_duplicate_external_member_id(): - raise AttributeError("tag 'duplicate_external_member_id' not set") - return self._value + @user.deleter + def user(self): + self._user_value = None + self._user_present = False - def get_duplicate_member_persistent_id(self): - """ - A user with the given persistent ID already exists on the team - (including in recoverable state). + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersDeleteProfilePhotoArg, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_duplicate_member_persistent_id` is true. + def __repr__(self): + return 'MembersDeleteProfilePhotoArg(user={!r})'.format( + self._user_value, + ) - :rtype: str - """ - if not self.is_duplicate_member_persistent_id(): - raise AttributeError("tag 'duplicate_member_persistent_id' not set") - return self._value +MembersDeleteProfilePhotoArg_validator = bv.Struct(MembersDeleteProfilePhotoArg) - def get_persistent_id_disabled(self): - """ - Persistent ID is only available to teams with persistent ID SAML - configuration. Please contact Dropbox for more information. +class MembersDeleteProfilePhotoError(MemberSelectorError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - Only call this if :meth:`is_persistent_id_disabled` is true. + :ivar team.MembersDeleteProfilePhotoError.set_profile_disallowed: Modifying + deleted users is not allowed. + """ - :rtype: str + _catch_all = 'other' + # Attribute is overwritten below the class definition + set_profile_disallowed = None + # Attribute is overwritten below the class definition + other = None + + def is_set_profile_disallowed(self): """ - if not self.is_persistent_id_disabled(): - raise AttributeError("tag 'persistent_id_disabled' not set") - return self._value + Check if the union tag is ``set_profile_disallowed``. - def get_user_creation_failed(self): + :rtype: bool """ - User creation has failed. + return self._tag == 'set_profile_disallowed' - Only call this if :meth:`is_user_creation_failed` is true. + def is_other(self): + """ + Check if the union tag is ``other``. - :rtype: str + :rtype: bool """ - if not self.is_user_creation_failed(): - raise AttributeError("tag 'user_creation_failed' not set") - return self._value + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberAddResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersDeleteProfilePhotoError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberAddResult(%r, %r)' % (self._tag, self._value) + return 'MembersDeleteProfilePhotoError(%r, %r)' % (self._tag, self._value) -MemberAddResult_validator = bv.Union(MemberAddResult) +MembersDeleteProfilePhotoError_validator = bv.Union(MembersDeleteProfilePhotoError) -class MemberDevices(bb.Struct): +class MembersGetInfoArgs(bb.Struct): """ - Information on devices of a team's member. - - :ivar team.MemberDevices.team_member_id: The member unique Id. - :ivar team.MemberDevices.web_sessions: List of web sessions made by this - team member. - :ivar team.MemberDevices.desktop_clients: List of desktop clients by this - team member. - :ivar team.MemberDevices.mobile_clients: List of mobile clients by this team - member. + :ivar team.MembersGetInfoArgs.members: List of team members. """ __slots__ = [ - '_team_member_id_value', - '_team_member_id_present', - '_web_sessions_value', - '_web_sessions_present', - '_desktop_clients_value', - '_desktop_clients_present', - '_mobile_clients_value', - '_mobile_clients_present', + '_members_value', + '_members_present', ] _has_required_fields = True def __init__(self, - team_member_id=None, - web_sessions=None, - desktop_clients=None, - mobile_clients=None): - self._team_member_id_value = None - self._team_member_id_present = False - self._web_sessions_value = None - self._web_sessions_present = False - self._desktop_clients_value = None - self._desktop_clients_present = False - self._mobile_clients_value = None - self._mobile_clients_present = False - if team_member_id is not None: - self.team_member_id = team_member_id - if web_sessions is not None: - self.web_sessions = web_sessions - if desktop_clients is not None: - self.desktop_clients = desktop_clients - if mobile_clients is not None: - self.mobile_clients = mobile_clients + members=None): + self._members_value = None + self._members_present = False + if members is not None: + self.members = members @property - def team_member_id(self): + def members(self): """ - The member unique Id. + List of team members. - :rtype: str + :rtype: list of [UserSelectorArg] """ - if self._team_member_id_present: - return self._team_member_id_value + if self._members_present: + return self._members_value else: - raise AttributeError("missing required field 'team_member_id'") - - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True - - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False - - @property - def web_sessions(self): - """ - List of web sessions made by this team member. + raise AttributeError("missing required field 'members'") - :rtype: list of [ActiveWebSession] - """ - if self._web_sessions_present: - return self._web_sessions_value - else: - return None + @members.setter + def members(self, val): + val = self._members_validator.validate(val) + self._members_value = val + self._members_present = True - @web_sessions.setter - def web_sessions(self, val): - if val is None: - del self.web_sessions - return - val = self._web_sessions_validator.validate(val) - self._web_sessions_value = val - self._web_sessions_present = True + @members.deleter + def members(self): + self._members_value = None + self._members_present = False - @web_sessions.deleter - def web_sessions(self): - self._web_sessions_value = None - self._web_sessions_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersGetInfoArgs, self)._process_custom_annotations(annotation_type, field_path, processor) - @property - def desktop_clients(self): - """ - List of desktop clients by this team member. + def __repr__(self): + return 'MembersGetInfoArgs(members={!r})'.format( + self._members_value, + ) - :rtype: list of [DesktopClientSession] - """ - if self._desktop_clients_present: - return self._desktop_clients_value - else: - return None +MembersGetInfoArgs_validator = bv.Struct(MembersGetInfoArgs) - @desktop_clients.setter - def desktop_clients(self, val): - if val is None: - del self.desktop_clients - return - val = self._desktop_clients_validator.validate(val) - self._desktop_clients_value = val - self._desktop_clients_present = True +class MembersGetInfoError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - @desktop_clients.deleter - def desktop_clients(self): - self._desktop_clients_value = None - self._desktop_clients_present = False + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None - @property - def mobile_clients(self): + def is_other(self): """ - List of mobile clients by this team member. + Check if the union tag is ``other``. - :rtype: list of [MobileClientSession] + :rtype: bool """ - if self._mobile_clients_present: - return self._mobile_clients_value - else: - return None - - @mobile_clients.setter - def mobile_clients(self, val): - if val is None: - del self.mobile_clients - return - val = self._mobile_clients_validator.validate(val) - self._mobile_clients_value = val - self._mobile_clients_present = True - - @mobile_clients.deleter - def mobile_clients(self): - self._mobile_clients_value = None - self._mobile_clients_present = False + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberDevices, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersGetInfoError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberDevices(team_member_id={!r}, web_sessions={!r}, desktop_clients={!r}, mobile_clients={!r})'.format( - self._team_member_id_value, - self._web_sessions_value, - self._desktop_clients_value, - self._mobile_clients_value, - ) + return 'MembersGetInfoError(%r, %r)' % (self._tag, self._value) -MemberDevices_validator = bv.Struct(MemberDevices) +MembersGetInfoError_validator = bv.Union(MembersGetInfoError) -class MemberLinkedApps(bb.Struct): +class MembersGetInfoItem(bb.Union): """ - Information on linked applications of a team member. + Describes a result obtained for a single user whose id was specified in the + parameter of :meth:`dropbox.dropbox.Dropbox.team_members_get_info`. - :ivar team.MemberLinkedApps.team_member_id: The member unique Id. - :ivar team.MemberLinkedApps.linked_api_apps: List of third party - applications linked by this team member. - """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - __slots__ = [ - '_team_member_id_value', - '_team_member_id_present', - '_linked_api_apps_value', - '_linked_api_apps_present', - ] + :ivar str team.MembersGetInfoItem.id_not_found: An ID that was provided as a + parameter to :route:`members/get_info`, and did not match a + corresponding user. This might be a team_member_id, an email, or an + external ID, depending on how the method was called. + :ivar TeamMemberInfo MembersGetInfoItem.member_info: Info about a team + member. + """ - _has_required_fields = True + _catch_all = None - def __init__(self, - team_member_id=None, - linked_api_apps=None): - self._team_member_id_value = None - self._team_member_id_present = False - self._linked_api_apps_value = None - self._linked_api_apps_present = False - if team_member_id is not None: - self.team_member_id = team_member_id - if linked_api_apps is not None: - self.linked_api_apps = linked_api_apps + @classmethod + def id_not_found(cls, val): + """ + Create an instance of this class set to the ``id_not_found`` tag with + value ``val``. - @property - def team_member_id(self): + :param str val: + :rtype: MembersGetInfoItem """ - The member unique Id. + return cls('id_not_found', val) - :rtype: str + @classmethod + def member_info(cls, val): """ - if self._team_member_id_present: - return self._team_member_id_value - else: - raise AttributeError("missing required field 'team_member_id'") + Create an instance of this class set to the ``member_info`` tag with + value ``val``. - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True + :param TeamMemberInfo val: + :rtype: MembersGetInfoItem + """ + return cls('member_info', val) - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False + def is_id_not_found(self): + """ + Check if the union tag is ``id_not_found``. - @property - def linked_api_apps(self): + :rtype: bool """ - List of third party applications linked by this team member. + return self._tag == 'id_not_found' - :rtype: list of [ApiApp] + def is_member_info(self): """ - if self._linked_api_apps_present: - return self._linked_api_apps_value - else: - raise AttributeError("missing required field 'linked_api_apps'") + Check if the union tag is ``member_info``. - @linked_api_apps.setter - def linked_api_apps(self, val): - val = self._linked_api_apps_validator.validate(val) - self._linked_api_apps_value = val - self._linked_api_apps_present = True + :rtype: bool + """ + return self._tag == 'member_info' - @linked_api_apps.deleter - def linked_api_apps(self): - self._linked_api_apps_value = None - self._linked_api_apps_present = False + def get_id_not_found(self): + """ + An ID that was provided as a parameter to + :meth:`dropbox.dropbox.Dropbox.team_members_get_info`, and did not match + a corresponding user. This might be a team_member_id, an email, or an + external ID, depending on how the method was called. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberLinkedApps, self)._process_custom_annotations(annotation_type, field_path, processor) + Only call this if :meth:`is_id_not_found` is true. - def __repr__(self): - return 'MemberLinkedApps(team_member_id={!r}, linked_api_apps={!r})'.format( - self._team_member_id_value, - self._linked_api_apps_value, - ) + :rtype: str + """ + if not self.is_id_not_found(): + raise AttributeError("tag 'id_not_found' not set") + return self._value -MemberLinkedApps_validator = bv.Struct(MemberLinkedApps) + def get_member_info(self): + """ + Info about a team member. -class MemberProfile(bb.Struct): - """ - Basic member profile. + Only call this if :meth:`is_member_info` is true. - :ivar team.MemberProfile.team_member_id: ID of user as a member of a team. - :ivar team.MemberProfile.external_id: External ID that a team can attach to - the user. An application using the API may find it easier to use their - own IDs instead of Dropbox IDs like account_id or team_member_id. - :ivar team.MemberProfile.account_id: A user's account identifier. - :ivar team.MemberProfile.email: Email address of user. - :ivar team.MemberProfile.email_verified: Is true if the user's email is - verified to be owned by the user. - :ivar team.MemberProfile.status: The user's status as a member of a specific - team. - :ivar team.MemberProfile.name: Representations for a person's name. - :ivar team.MemberProfile.membership_type: The user's membership type: full - (normal team member) vs limited (does not use a license; no access to - the team's shared quota). - :ivar team.MemberProfile.joined_on: The date and time the user joined as a - member of a specific team. - :ivar team.MemberProfile.suspended_on: The date and time the user was - suspended from the team (contains value only when the member's status - matches ``TeamMemberStatus.suspended``. - :ivar team.MemberProfile.persistent_id: Persistent ID that a team can attach - to the user. The persistent ID is unique ID to be used for SAML - authentication. - :ivar team.MemberProfile.is_directory_restricted: Whether the user is a - directory restricted user. - :ivar team.MemberProfile.profile_photo_url: URL for the photo representing - the user, if one is set. - """ + :rtype: TeamMemberInfo + """ + if not self.is_member_info(): + raise AttributeError("tag 'member_info' not set") + return self._value - __slots__ = [ - '_team_member_id_value', - '_team_member_id_present', - '_external_id_value', - '_external_id_present', - '_account_id_value', - '_account_id_present', - '_email_value', - '_email_present', - '_email_verified_value', - '_email_verified_present', - '_status_value', - '_status_present', - '_name_value', - '_name_present', - '_membership_type_value', - '_membership_type_present', - '_joined_on_value', - '_joined_on_present', - '_suspended_on_value', - '_suspended_on_present', - '_persistent_id_value', - '_persistent_id_present', - '_is_directory_restricted_value', - '_is_directory_restricted_present', - '_profile_photo_url_value', - '_profile_photo_url_present', - ] + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersGetInfoItem, self)._process_custom_annotations(annotation_type, field_path, processor) - _has_required_fields = True + def __repr__(self): + return 'MembersGetInfoItem(%r, %r)' % (self._tag, self._value) - def __init__(self, - team_member_id=None, - email=None, - email_verified=None, - status=None, - name=None, - membership_type=None, - external_id=None, - account_id=None, - joined_on=None, - suspended_on=None, - persistent_id=None, - is_directory_restricted=None, - profile_photo_url=None): - self._team_member_id_value = None - self._team_member_id_present = False - self._external_id_value = None - self._external_id_present = False - self._account_id_value = None - self._account_id_present = False - self._email_value = None - self._email_present = False - self._email_verified_value = None - self._email_verified_present = False - self._status_value = None - self._status_present = False - self._name_value = None - self._name_present = False - self._membership_type_value = None - self._membership_type_present = False - self._joined_on_value = None - self._joined_on_present = False - self._suspended_on_value = None - self._suspended_on_present = False - self._persistent_id_value = None - self._persistent_id_present = False - self._is_directory_restricted_value = None - self._is_directory_restricted_present = False - self._profile_photo_url_value = None - self._profile_photo_url_present = False - if team_member_id is not None: - self.team_member_id = team_member_id - if external_id is not None: - self.external_id = external_id - if account_id is not None: - self.account_id = account_id - if email is not None: - self.email = email - if email_verified is not None: - self.email_verified = email_verified - if status is not None: - self.status = status - if name is not None: - self.name = name - if membership_type is not None: - self.membership_type = membership_type - if joined_on is not None: - self.joined_on = joined_on - if suspended_on is not None: - self.suspended_on = suspended_on - if persistent_id is not None: - self.persistent_id = persistent_id - if is_directory_restricted is not None: - self.is_directory_restricted = is_directory_restricted - if profile_photo_url is not None: - self.profile_photo_url = profile_photo_url +MembersGetInfoItem_validator = bv.Union(MembersGetInfoItem) - @property - def team_member_id(self): - """ - ID of user as a member of a team. +class MembersInfo(bb.Struct): + """ + :ivar team.MembersInfo.team_member_ids: Team member IDs of the users under + this hold. + :ivar team.MembersInfo.permanently_deleted_users: The number of permanently + deleted users that were under this hold. + """ - :rtype: str - """ - if self._team_member_id_present: - return self._team_member_id_value - else: - raise AttributeError("missing required field 'team_member_id'") + __slots__ = [ + '_team_member_ids_value', + '_team_member_ids_present', + '_permanently_deleted_users_value', + '_permanently_deleted_users_present', + ] - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True + _has_required_fields = True - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False + def __init__(self, + team_member_ids=None, + permanently_deleted_users=None): + self._team_member_ids_value = None + self._team_member_ids_present = False + self._permanently_deleted_users_value = None + self._permanently_deleted_users_present = False + if team_member_ids is not None: + self.team_member_ids = team_member_ids + if permanently_deleted_users is not None: + self.permanently_deleted_users = permanently_deleted_users @property - def external_id(self): + def team_member_ids(self): """ - External ID that a team can attach to the user. An application using the - API may find it easier to use their own IDs instead of Dropbox IDs like - account_id or team_member_id. + Team member IDs of the users under this hold. - :rtype: str + :rtype: list of [str] """ - if self._external_id_present: - return self._external_id_value + if self._team_member_ids_present: + return self._team_member_ids_value else: - return None + raise AttributeError("missing required field 'team_member_ids'") - @external_id.setter - def external_id(self, val): - if val is None: - del self.external_id - return - val = self._external_id_validator.validate(val) - self._external_id_value = val - self._external_id_present = True + @team_member_ids.setter + def team_member_ids(self, val): + val = self._team_member_ids_validator.validate(val) + self._team_member_ids_value = val + self._team_member_ids_present = True - @external_id.deleter - def external_id(self): - self._external_id_value = None - self._external_id_present = False + @team_member_ids.deleter + def team_member_ids(self): + self._team_member_ids_value = None + self._team_member_ids_present = False @property - def account_id(self): + def permanently_deleted_users(self): """ - A user's account identifier. + The number of permanently deleted users that were under this hold. - :rtype: str + :rtype: int """ - if self._account_id_present: - return self._account_id_value + if self._permanently_deleted_users_present: + return self._permanently_deleted_users_value else: - return None + raise AttributeError("missing required field 'permanently_deleted_users'") - @account_id.setter - def account_id(self, val): - if val is None: - del self.account_id - return - val = self._account_id_validator.validate(val) - self._account_id_value = val - self._account_id_present = True + @permanently_deleted_users.setter + def permanently_deleted_users(self, val): + val = self._permanently_deleted_users_validator.validate(val) + self._permanently_deleted_users_value = val + self._permanently_deleted_users_present = True - @account_id.deleter - def account_id(self): - self._account_id_value = None - self._account_id_present = False + @permanently_deleted_users.deleter + def permanently_deleted_users(self): + self._permanently_deleted_users_value = None + self._permanently_deleted_users_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MembersInfo(team_member_ids={!r}, permanently_deleted_users={!r})'.format( + self._team_member_ids_value, + self._permanently_deleted_users_value, + ) + +MembersInfo_validator = bv.Struct(MembersInfo) + +class MembersListArg(bb.Struct): + """ + :ivar team.MembersListArg.limit: Number of results to return per call. + :ivar team.MembersListArg.include_removed: Whether to return removed + members. + """ + + __slots__ = [ + '_limit_value', + '_limit_present', + '_include_removed_value', + '_include_removed_present', + ] + + _has_required_fields = False + + def __init__(self, + limit=None, + include_removed=None): + self._limit_value = None + self._limit_present = False + self._include_removed_value = None + self._include_removed_present = False + if limit is not None: + self.limit = limit + if include_removed is not None: + self.include_removed = include_removed @property - def email(self): + def limit(self): """ - Email address of user. + Number of results to return per call. - :rtype: str + :rtype: int """ - if self._email_present: - return self._email_value + if self._limit_present: + return self._limit_value else: - raise AttributeError("missing required field 'email'") + return 1000 - @email.setter - def email(self, val): - val = self._email_validator.validate(val) - self._email_value = val - self._email_present = True + @limit.setter + def limit(self, val): + val = self._limit_validator.validate(val) + self._limit_value = val + self._limit_present = True - @email.deleter - def email(self): - self._email_value = None - self._email_present = False + @limit.deleter + def limit(self): + self._limit_value = None + self._limit_present = False @property - def email_verified(self): + def include_removed(self): """ - Is true if the user's email is verified to be owned by the user. + Whether to return removed members. :rtype: bool """ - if self._email_verified_present: - return self._email_verified_value + if self._include_removed_present: + return self._include_removed_value else: - raise AttributeError("missing required field 'email_verified'") + return False - @email_verified.setter - def email_verified(self, val): - val = self._email_verified_validator.validate(val) - self._email_verified_value = val - self._email_verified_present = True + @include_removed.setter + def include_removed(self, val): + val = self._include_removed_validator.validate(val) + self._include_removed_value = val + self._include_removed_present = True - @email_verified.deleter - def email_verified(self): - self._email_verified_value = None - self._email_verified_present = False + @include_removed.deleter + def include_removed(self): + self._include_removed_value = None + self._include_removed_present = False - @property - def status(self): - """ - The user's status as a member of a specific team. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersListArg, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: TeamMemberStatus - """ - if self._status_present: - return self._status_value - else: - raise AttributeError("missing required field 'status'") + def __repr__(self): + return 'MembersListArg(limit={!r}, include_removed={!r})'.format( + self._limit_value, + self._include_removed_value, + ) - @status.setter - def status(self, val): - self._status_validator.validate_type_only(val) - self._status_value = val - self._status_present = True +MembersListArg_validator = bv.Struct(MembersListArg) - @status.deleter - def status(self): - self._status_value = None - self._status_present = False +class MembersListContinueArg(bb.Struct): + """ + :ivar team.MembersListContinueArg.cursor: Indicates from what point to get + the next set of members. + """ + + __slots__ = [ + '_cursor_value', + '_cursor_present', + ] + + _has_required_fields = True + + def __init__(self, + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def name(self): + def cursor(self): """ - Representations for a person's name. + Indicates from what point to get the next set of members. - :rtype: users.Name + :rtype: str """ - if self._name_present: - return self._name_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'name'") + raise AttributeError("missing required field 'cursor'") - @name.setter - def name(self, val): - self._name_validator.validate_type_only(val) - self._name_value = val - self._name_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True + + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MembersListContinueArg(cursor={!r})'.format( + self._cursor_value, + ) + +MembersListContinueArg_validator = bv.Struct(MembersListContinueArg) + +class MembersListContinueError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.MembersListContinueError.invalid_cursor: The cursor is invalid. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_cursor = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_cursor(self): + """ + Check if the union tag is ``invalid_cursor``. - @name.deleter - def name(self): - self._name_value = None - self._name_present = False + :rtype: bool + """ + return self._tag == 'invalid_cursor' - @property - def membership_type(self): + def is_other(self): """ - The user's membership type: full (normal team member) vs limited (does - not use a license; no access to the team's shared quota). + Check if the union tag is ``other``. - :rtype: TeamMembershipType + :rtype: bool """ - if self._membership_type_present: - return self._membership_type_value - else: - raise AttributeError("missing required field 'membership_type'") + return self._tag == 'other' - @membership_type.setter - def membership_type(self, val): - self._membership_type_validator.validate_type_only(val) - self._membership_type_value = val - self._membership_type_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) - @membership_type.deleter - def membership_type(self): - self._membership_type_value = None - self._membership_type_present = False + def __repr__(self): + return 'MembersListContinueError(%r, %r)' % (self._tag, self._value) - @property - def joined_on(self): +MembersListContinueError_validator = bv.Union(MembersListContinueError) + +class MembersListError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + def is_other(self): """ - The date and time the user joined as a member of a specific team. + Check if the union tag is ``other``. - :rtype: datetime.datetime + :rtype: bool """ - if self._joined_on_present: - return self._joined_on_value - else: - return None + return self._tag == 'other' - @joined_on.setter - def joined_on(self, val): - if val is None: - del self.joined_on - return - val = self._joined_on_validator.validate(val) - self._joined_on_value = val - self._joined_on_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersListError, self)._process_custom_annotations(annotation_type, field_path, processor) - @joined_on.deleter - def joined_on(self): - self._joined_on_value = None - self._joined_on_present = False + def __repr__(self): + return 'MembersListError(%r, %r)' % (self._tag, self._value) - @property - def suspended_on(self): - """ - The date and time the user was suspended from the team (contains value - only when the member's status matches ``TeamMemberStatus.suspended``. +MembersListError_validator = bv.Union(MembersListError) - :rtype: datetime.datetime - """ - if self._suspended_on_present: - return self._suspended_on_value - else: - return None +class MembersListResult(bb.Struct): + """ + :ivar team.MembersListResult.members: List of team members. + :ivar team.MembersListResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` to obtain the + additional members. + :ivar team.MembersListResult.has_more: Is true if there are additional team + members that have not been returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` can retrieve + them. + """ - @suspended_on.setter - def suspended_on(self, val): - if val is None: - del self.suspended_on - return - val = self._suspended_on_validator.validate(val) - self._suspended_on_value = val - self._suspended_on_present = True + __slots__ = [ + '_members_value', + '_members_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', + ] - @suspended_on.deleter - def suspended_on(self): - self._suspended_on_value = None - self._suspended_on_present = False + _has_required_fields = True + + def __init__(self, + members=None, + cursor=None, + has_more=None): + self._members_value = None + self._members_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if members is not None: + self.members = members + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more @property - def persistent_id(self): + def members(self): """ - Persistent ID that a team can attach to the user. The persistent ID is - unique ID to be used for SAML authentication. + List of team members. - :rtype: str + :rtype: list of [TeamMemberInfo] """ - if self._persistent_id_present: - return self._persistent_id_value + if self._members_present: + return self._members_value else: - return None + raise AttributeError("missing required field 'members'") - @persistent_id.setter - def persistent_id(self, val): - if val is None: - del self.persistent_id - return - val = self._persistent_id_validator.validate(val) - self._persistent_id_value = val - self._persistent_id_present = True + @members.setter + def members(self, val): + val = self._members_validator.validate(val) + self._members_value = val + self._members_present = True - @persistent_id.deleter - def persistent_id(self): - self._persistent_id_value = None - self._persistent_id_present = False + @members.deleter + def members(self): + self._members_value = None + self._members_present = False @property - def is_directory_restricted(self): + def cursor(self): """ - Whether the user is a directory restricted user. + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` to obtain the + additional members. - :rtype: bool + :rtype: str """ - if self._is_directory_restricted_present: - return self._is_directory_restricted_value + if self._cursor_present: + return self._cursor_value else: - return None + raise AttributeError("missing required field 'cursor'") - @is_directory_restricted.setter - def is_directory_restricted(self, val): - if val is None: - del self.is_directory_restricted - return - val = self._is_directory_restricted_validator.validate(val) - self._is_directory_restricted_value = val - self._is_directory_restricted_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @is_directory_restricted.deleter - def is_directory_restricted(self): - self._is_directory_restricted_value = None - self._is_directory_restricted_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False @property - def profile_photo_url(self): + def has_more(self): """ - URL for the photo representing the user, if one is set. + Is true if there are additional team members that have not been returned + yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` can retrieve + them. - :rtype: str + :rtype: bool """ - if self._profile_photo_url_present: - return self._profile_photo_url_value + if self._has_more_present: + return self._has_more_value else: - return None - - @profile_photo_url.setter - def profile_photo_url(self, val): - if val is None: - del self.profile_photo_url - return - val = self._profile_photo_url_validator.validate(val) - self._profile_photo_url_value = val - self._profile_photo_url_present = True - - @profile_photo_url.deleter - def profile_photo_url(self): - self._profile_photo_url_value = None - self._profile_photo_url_present = False + raise AttributeError("missing required field 'has_more'") - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberProfile, self)._process_custom_annotations(annotation_type, field_path, processor) + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - def __repr__(self): - return 'MemberProfile(team_member_id={!r}, email={!r}, email_verified={!r}, status={!r}, name={!r}, membership_type={!r}, external_id={!r}, account_id={!r}, joined_on={!r}, suspended_on={!r}, persistent_id={!r}, is_directory_restricted={!r}, profile_photo_url={!r})'.format( - self._team_member_id_value, - self._email_value, - self._email_verified_value, - self._status_value, - self._name_value, - self._membership_type_value, - self._external_id_value, - self._account_id_value, - self._joined_on_value, - self._suspended_on_value, - self._persistent_id_value, - self._is_directory_restricted_value, - self._profile_photo_url_value, + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MembersListResult(members={!r}, cursor={!r}, has_more={!r})'.format( + self._members_value, + self._cursor_value, + self._has_more_value, ) -MemberProfile_validator = bv.Struct(MemberProfile) +MembersListResult_validator = bv.Struct(MembersListResult) -class UserSelectorError(bb.Union): +class MembersRecoverArg(bb.Struct): """ - Error that can be returned whenever a struct derived from - :class:`UserSelectorArg` is used. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Exactly one of team_member_id, email, or external_id must be provided to + identify the user account. - :ivar team.UserSelectorError.user_not_found: No matching user found. The - provided team_member_id, email, or external_id does not exist on this - team. + :ivar team.MembersRecoverArg.user: Identity of user to recover. """ - _catch_all = None - # Attribute is overwritten below the class definition - user_not_found = None + __slots__ = [ + '_user_value', + '_user_present', + ] - def is_user_not_found(self): + _has_required_fields = True + + def __init__(self, + user=None): + self._user_value = None + self._user_present = False + if user is not None: + self.user = user + + @property + def user(self): """ - Check if the union tag is ``user_not_found``. + Identity of user to recover. - :rtype: bool + :rtype: UserSelectorArg """ - return self._tag == 'user_not_found' + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") + + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(UserSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersRecoverArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'UserSelectorError(%r, %r)' % (self._tag, self._value) + return 'MembersRecoverArg(user={!r})'.format( + self._user_value, + ) -UserSelectorError_validator = bv.Union(UserSelectorError) +MembersRecoverArg_validator = bv.Struct(MembersRecoverArg) -class MemberSelectorError(UserSelectorError): +class MembersRecoverError(UserSelectorError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.MemberSelectorError.user_not_in_team: The user is not a member of + :ivar team.MembersRecoverError.user_unrecoverable: The user is not + recoverable. + :ivar team.MembersRecoverError.user_not_in_team: The user is not a member of the team. + :ivar team.MembersRecoverError.team_license_limit: Team is full. The + organization has no available licenses. """ + _catch_all = 'other' + # Attribute is overwritten below the class definition + user_unrecoverable = None # Attribute is overwritten below the class definition user_not_in_team = None + # Attribute is overwritten below the class definition + team_license_limit = None + # Attribute is overwritten below the class definition + other = None + + def is_user_unrecoverable(self): + """ + Check if the union tag is ``user_unrecoverable``. + + :rtype: bool + """ + return self._tag == 'user_unrecoverable' def is_user_not_in_team(self): """ @@ -9655,458 +13788,510 @@ def is_user_not_in_team(self): """ return self._tag == 'user_not_in_team' + def is_team_license_limit(self): + """ + Check if the union tag is ``team_license_limit``. + + :rtype: bool + """ + return self._tag == 'team_license_limit' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSelectorError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersRecoverError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSelectorError(%r, %r)' % (self._tag, self._value) + return 'MembersRecoverError(%r, %r)' % (self._tag, self._value) -MemberSelectorError_validator = bv.Union(MemberSelectorError) +MembersRecoverError_validator = bv.Union(MembersRecoverError) -class MembersAddArg(bb.Struct): +class MembersRemoveArg(MembersDeactivateArg): """ - :ivar team.MembersAddArg.new_members: Details of new members to be added to - the team. - :ivar team.MembersAddArg.force_async: Whether to force the add to happen - asynchronously. + :ivar team.MembersRemoveArg.transfer_dest_id: If provided, files from the + deleted member account will be transferred to this user. + :ivar team.MembersRemoveArg.transfer_admin_id: If provided, errors during + the transfer process will be sent via email to this user. If the + transfer_dest_id argument was provided, then this argument must be + provided as well. + :ivar team.MembersRemoveArg.keep_account: Downgrade the member to a Basic + account. The user will retain the email address associated with their + Dropbox account and data in their account that is not restricted to + team members. In order to keep the account the argument ``wipe_data`` + should be set to ``False``. + :ivar team.MembersRemoveArg.retain_team_shares: If provided, allows removed + users to keep access to Dropbox folders (not Dropbox Paper folders) + already explicitly shared with them (not via a group) when they are + downgraded to a Basic account. Users will not retain access to folders + that do not allow external sharing. In order to keep the sharing + relationships, the arguments ``wipe_data`` should be set to ``False`` + and ``keep_account`` should be set to ``True``. """ __slots__ = [ - '_new_members_value', - '_new_members_present', - '_force_async_value', - '_force_async_present', + '_transfer_dest_id_value', + '_transfer_dest_id_present', + '_transfer_admin_id_value', + '_transfer_admin_id_present', + '_keep_account_value', + '_keep_account_present', + '_retain_team_shares_value', + '_retain_team_shares_present', ] _has_required_fields = True def __init__(self, - new_members=None, - force_async=None): - self._new_members_value = None - self._new_members_present = False - self._force_async_value = None - self._force_async_present = False - if new_members is not None: - self.new_members = new_members - if force_async is not None: - self.force_async = force_async + user=None, + wipe_data=None, + transfer_dest_id=None, + transfer_admin_id=None, + keep_account=None, + retain_team_shares=None): + super(MembersRemoveArg, self).__init__(user, + wipe_data) + self._transfer_dest_id_value = None + self._transfer_dest_id_present = False + self._transfer_admin_id_value = None + self._transfer_admin_id_present = False + self._keep_account_value = None + self._keep_account_present = False + self._retain_team_shares_value = None + self._retain_team_shares_present = False + if transfer_dest_id is not None: + self.transfer_dest_id = transfer_dest_id + if transfer_admin_id is not None: + self.transfer_admin_id = transfer_admin_id + if keep_account is not None: + self.keep_account = keep_account + if retain_team_shares is not None: + self.retain_team_shares = retain_team_shares @property - def new_members(self): + def transfer_dest_id(self): """ - Details of new members to be added to the team. + If provided, files from the deleted member account will be transferred + to this user. - :rtype: list of [MemberAddArg] + :rtype: UserSelectorArg """ - if self._new_members_present: - return self._new_members_value + if self._transfer_dest_id_present: + return self._transfer_dest_id_value else: - raise AttributeError("missing required field 'new_members'") + return None - @new_members.setter - def new_members(self, val): - val = self._new_members_validator.validate(val) - self._new_members_value = val - self._new_members_present = True + @transfer_dest_id.setter + def transfer_dest_id(self, val): + if val is None: + del self.transfer_dest_id + return + self._transfer_dest_id_validator.validate_type_only(val) + self._transfer_dest_id_value = val + self._transfer_dest_id_present = True - @new_members.deleter - def new_members(self): - self._new_members_value = None - self._new_members_present = False + @transfer_dest_id.deleter + def transfer_dest_id(self): + self._transfer_dest_id_value = None + self._transfer_dest_id_present = False + + @property + def transfer_admin_id(self): + """ + If provided, errors during the transfer process will be sent via email + to this user. If the transfer_dest_id argument was provided, then this + argument must be provided as well. + + :rtype: UserSelectorArg + """ + if self._transfer_admin_id_present: + return self._transfer_admin_id_value + else: + return None + + @transfer_admin_id.setter + def transfer_admin_id(self, val): + if val is None: + del self.transfer_admin_id + return + self._transfer_admin_id_validator.validate_type_only(val) + self._transfer_admin_id_value = val + self._transfer_admin_id_present = True + + @transfer_admin_id.deleter + def transfer_admin_id(self): + self._transfer_admin_id_value = None + self._transfer_admin_id_present = False + + @property + def keep_account(self): + """ + Downgrade the member to a Basic account. The user will retain the email + address associated with their Dropbox account and data in their account + that is not restricted to team members. In order to keep the account the + argument ``wipe_data`` should be set to ``False``. + + :rtype: bool + """ + if self._keep_account_present: + return self._keep_account_value + else: + return False + + @keep_account.setter + def keep_account(self, val): + val = self._keep_account_validator.validate(val) + self._keep_account_value = val + self._keep_account_present = True + + @keep_account.deleter + def keep_account(self): + self._keep_account_value = None + self._keep_account_present = False @property - def force_async(self): + def retain_team_shares(self): """ - Whether to force the add to happen asynchronously. + If provided, allows removed users to keep access to Dropbox folders (not + Dropbox Paper folders) already explicitly shared with them (not via a + group) when they are downgraded to a Basic account. Users will not + retain access to folders that do not allow external sharing. In order to + keep the sharing relationships, the arguments ``wipe_data`` should be + set to ``False`` and ``keep_account`` should be set to ``True``. :rtype: bool """ - if self._force_async_present: - return self._force_async_value + if self._retain_team_shares_present: + return self._retain_team_shares_value else: return False - @force_async.setter - def force_async(self, val): - val = self._force_async_validator.validate(val) - self._force_async_value = val - self._force_async_present = True + @retain_team_shares.setter + def retain_team_shares(self, val): + val = self._retain_team_shares_validator.validate(val) + self._retain_team_shares_value = val + self._retain_team_shares_present = True - @force_async.deleter - def force_async(self): - self._force_async_value = None - self._force_async_present = False + @retain_team_shares.deleter + def retain_team_shares(self): + self._retain_team_shares_value = None + self._retain_team_shares_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersAddArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersRemoveArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersAddArg(new_members={!r}, force_async={!r})'.format( - self._new_members_value, - self._force_async_value, + return 'MembersRemoveArg(user={!r}, wipe_data={!r}, transfer_dest_id={!r}, transfer_admin_id={!r}, keep_account={!r}, retain_team_shares={!r})'.format( + self._user_value, + self._wipe_data_value, + self._transfer_dest_id_value, + self._transfer_admin_id_value, + self._keep_account_value, + self._retain_team_shares_value, ) -MembersAddArg_validator = bv.Struct(MembersAddArg) +MembersRemoveArg_validator = bv.Struct(MembersRemoveArg) -class MembersAddJobStatus(async_.PollResultBase): +class MembersTransferFilesError(MembersDeactivateError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar list of [MemberAddResult] team.MembersAddJobStatus.complete: The - asynchronous job has finished. For each member that was specified in the - parameter :type:`MembersAddArg` that was provided to - :route:`members/add`, a corresponding item is returned in this list. - :ivar str team.MembersAddJobStatus.failed: The asynchronous job returned an - error. The string contains an error message. + :ivar + team.MembersTransferFilesError.removed_and_transfer_dest_should_differ: + Expected removed user and transfer_dest user to be different. + :ivar + team.MembersTransferFilesError.removed_and_transfer_admin_should_differ: + Expected removed user and transfer_admin user to be different. + :ivar team.MembersTransferFilesError.transfer_dest_user_not_found: No + matching user found for the argument transfer_dest_id. + :ivar team.MembersTransferFilesError.transfer_dest_user_not_in_team: The + provided transfer_dest_id does not exist on this team. + :ivar team.MembersTransferFilesError.transfer_admin_user_not_in_team: The + provided transfer_admin_id does not exist on this team. + :ivar team.MembersTransferFilesError.transfer_admin_user_not_found: No + matching user found for the argument transfer_admin_id. + :ivar team.MembersTransferFilesError.unspecified_transfer_admin_id: The + transfer_admin_id argument must be provided when file transfer is + requested. + :ivar team.MembersTransferFilesError.transfer_admin_is_not_admin: Specified + transfer_admin user is not a team admin. + :ivar team.MembersTransferFilesError.recipient_not_verified: The recipient + user's email is not verified. """ - @classmethod - def complete(cls, val): - """ - Create an instance of this class set to the ``complete`` tag with value - ``val``. - - :param list of [MemberAddResult] val: - :rtype: MembersAddJobStatus - """ - return cls('complete', val) + # Attribute is overwritten below the class definition + removed_and_transfer_dest_should_differ = None + # Attribute is overwritten below the class definition + removed_and_transfer_admin_should_differ = None + # Attribute is overwritten below the class definition + transfer_dest_user_not_found = None + # Attribute is overwritten below the class definition + transfer_dest_user_not_in_team = None + # Attribute is overwritten below the class definition + transfer_admin_user_not_in_team = None + # Attribute is overwritten below the class definition + transfer_admin_user_not_found = None + # Attribute is overwritten below the class definition + unspecified_transfer_admin_id = None + # Attribute is overwritten below the class definition + transfer_admin_is_not_admin = None + # Attribute is overwritten below the class definition + recipient_not_verified = None - @classmethod - def failed(cls, val): + def is_removed_and_transfer_dest_should_differ(self): """ - Create an instance of this class set to the ``failed`` tag with value - ``val``. + Check if the union tag is ``removed_and_transfer_dest_should_differ``. - :param str val: - :rtype: MembersAddJobStatus + :rtype: bool """ - return cls('failed', val) + return self._tag == 'removed_and_transfer_dest_should_differ' - def is_complete(self): + def is_removed_and_transfer_admin_should_differ(self): """ - Check if the union tag is ``complete``. + Check if the union tag is ``removed_and_transfer_admin_should_differ``. :rtype: bool """ - return self._tag == 'complete' + return self._tag == 'removed_and_transfer_admin_should_differ' - def is_failed(self): + def is_transfer_dest_user_not_found(self): """ - Check if the union tag is ``failed``. + Check if the union tag is ``transfer_dest_user_not_found``. :rtype: bool """ - return self._tag == 'failed' + return self._tag == 'transfer_dest_user_not_found' - def get_complete(self): + def is_transfer_dest_user_not_in_team(self): """ - The asynchronous job has finished. For each member that was specified in - the parameter :class:`MembersAddArg` that was provided to - :meth:`dropbox.dropbox.Dropbox.team_members_add`, a corresponding item - is returned in this list. - - Only call this if :meth:`is_complete` is true. + Check if the union tag is ``transfer_dest_user_not_in_team``. - :rtype: list of [MemberAddResult] + :rtype: bool """ - if not self.is_complete(): - raise AttributeError("tag 'complete' not set") - return self._value + return self._tag == 'transfer_dest_user_not_in_team' - def get_failed(self): + def is_transfer_admin_user_not_in_team(self): """ - The asynchronous job returned an error. The string contains an error - message. - - Only call this if :meth:`is_failed` is true. + Check if the union tag is ``transfer_admin_user_not_in_team``. - :rtype: str + :rtype: bool """ - if not self.is_failed(): - raise AttributeError("tag 'failed' not set") - return self._value - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersAddJobStatus, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersAddJobStatus(%r, %r)' % (self._tag, self._value) - -MembersAddJobStatus_validator = bv.Union(MembersAddJobStatus) - -class MembersAddLaunch(async_.LaunchResultBase): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + return self._tag == 'transfer_admin_user_not_in_team' - @classmethod - def complete(cls, val): + def is_transfer_admin_user_not_found(self): """ - Create an instance of this class set to the ``complete`` tag with value - ``val``. + Check if the union tag is ``transfer_admin_user_not_found``. - :param list of [MemberAddResult] val: - :rtype: MembersAddLaunch + :rtype: bool """ - return cls('complete', val) + return self._tag == 'transfer_admin_user_not_found' - def is_complete(self): + def is_unspecified_transfer_admin_id(self): """ - Check if the union tag is ``complete``. + Check if the union tag is ``unspecified_transfer_admin_id``. :rtype: bool """ - return self._tag == 'complete' + return self._tag == 'unspecified_transfer_admin_id' - def get_complete(self): + def is_transfer_admin_is_not_admin(self): """ - Only call this if :meth:`is_complete` is true. + Check if the union tag is ``transfer_admin_is_not_admin``. - :rtype: list of [MemberAddResult] + :rtype: bool """ - if not self.is_complete(): - raise AttributeError("tag 'complete' not set") - return self._value - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersAddLaunch, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersAddLaunch(%r, %r)' % (self._tag, self._value) - -MembersAddLaunch_validator = bv.Union(MembersAddLaunch) - -class MembersDeactivateBaseArg(bb.Struct): - """ - Exactly one of team_member_id, email, or external_id must be provided to - identify the user account. - - :ivar team.MembersDeactivateBaseArg.user: Identity of user to - remove/suspend/have their files moved. - """ - - __slots__ = [ - '_user_value', - '_user_present', - ] - - _has_required_fields = True - - def __init__(self, - user=None): - self._user_value = None - self._user_present = False - if user is not None: - self.user = user + return self._tag == 'transfer_admin_is_not_admin' - @property - def user(self): + def is_recipient_not_verified(self): """ - Identity of user to remove/suspend/have their files moved. + Check if the union tag is ``recipient_not_verified``. - :rtype: UserSelectorArg + :rtype: bool """ - if self._user_present: - return self._user_value - else: - raise AttributeError("missing required field 'user'") - - @user.setter - def user(self, val): - self._user_validator.validate_type_only(val) - self._user_value = val - self._user_present = True - - @user.deleter - def user(self): - self._user_value = None - self._user_present = False + return self._tag == 'recipient_not_verified' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersDeactivateBaseArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersTransferFilesError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersDeactivateBaseArg(user={!r})'.format( - self._user_value, - ) + return 'MembersTransferFilesError(%r, %r)' % (self._tag, self._value) -MembersDeactivateBaseArg_validator = bv.Struct(MembersDeactivateBaseArg) +MembersTransferFilesError_validator = bv.Union(MembersTransferFilesError) -class MembersDataTransferArg(MembersDeactivateBaseArg): +class MembersRemoveError(MembersTransferFilesError): """ - :ivar team.MembersDataTransferArg.transfer_dest_id: Files from the deleted - member account will be transferred to this user. - :ivar team.MembersDataTransferArg.transfer_admin_id: Errors during the - transfer process will be sent via email to this user. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.MembersRemoveError.remove_last_admin: The user is the last admin + of the team, so it cannot be removed from it. + :ivar team.MembersRemoveError.cannot_keep_account_and_transfer: Cannot keep + account and transfer the data to another user at the same time. + :ivar team.MembersRemoveError.cannot_keep_account_and_delete_data: Cannot + keep account and delete the data at the same time. To keep the account + the argument wipe_data should be set to ``False``. + :ivar team.MembersRemoveError.email_address_too_long_to_be_disabled: The + email address of the user is too long to be disabled. + :ivar team.MembersRemoveError.cannot_keep_invited_user_account: Cannot keep + account of an invited user. + :ivar team.MembersRemoveError.cannot_retain_shares_when_data_wiped: Cannot + retain team shares when the user's data is marked for deletion on their + linked devices. The argument wipe_data should be set to ``False``. + :ivar team.MembersRemoveError.cannot_retain_shares_when_no_account_kept: The + user's account must be kept in order to retain team shares. The argument + keep_account should be set to ``True``. + :ivar + team.MembersRemoveError.cannot_retain_shares_when_team_external_sharing_off: + Externally sharing files, folders, and links must be enabled in team + settings in order to retain team shares for the user. + :ivar team.MembersRemoveError.cannot_keep_account: Only a team admin, can + convert this account to a Basic account. + :ivar team.MembersRemoveError.cannot_keep_account_under_legal_hold: This + user content is currently being held. To convert this member's account + to a Basic account, you'll first need to remove them from the hold. + :ivar team.MembersRemoveError.cannot_keep_account_required_to_sign_tos: To + convert this member to a Basic account, they'll first need to sign in to + Dropbox and agree to the terms of service. """ - __slots__ = [ - '_transfer_dest_id_value', - '_transfer_dest_id_present', - '_transfer_admin_id_value', - '_transfer_admin_id_present', - ] + # Attribute is overwritten below the class definition + remove_last_admin = None + # Attribute is overwritten below the class definition + cannot_keep_account_and_transfer = None + # Attribute is overwritten below the class definition + cannot_keep_account_and_delete_data = None + # Attribute is overwritten below the class definition + email_address_too_long_to_be_disabled = None + # Attribute is overwritten below the class definition + cannot_keep_invited_user_account = None + # Attribute is overwritten below the class definition + cannot_retain_shares_when_data_wiped = None + # Attribute is overwritten below the class definition + cannot_retain_shares_when_no_account_kept = None + # Attribute is overwritten below the class definition + cannot_retain_shares_when_team_external_sharing_off = None + # Attribute is overwritten below the class definition + cannot_keep_account = None + # Attribute is overwritten below the class definition + cannot_keep_account_under_legal_hold = None + # Attribute is overwritten below the class definition + cannot_keep_account_required_to_sign_tos = None - _has_required_fields = True + def is_remove_last_admin(self): + """ + Check if the union tag is ``remove_last_admin``. - def __init__(self, - user=None, - transfer_dest_id=None, - transfer_admin_id=None): - super(MembersDataTransferArg, self).__init__(user) - self._transfer_dest_id_value = None - self._transfer_dest_id_present = False - self._transfer_admin_id_value = None - self._transfer_admin_id_present = False - if transfer_dest_id is not None: - self.transfer_dest_id = transfer_dest_id - if transfer_admin_id is not None: - self.transfer_admin_id = transfer_admin_id + :rtype: bool + """ + return self._tag == 'remove_last_admin' - @property - def transfer_dest_id(self): + def is_cannot_keep_account_and_transfer(self): """ - Files from the deleted member account will be transferred to this user. + Check if the union tag is ``cannot_keep_account_and_transfer``. - :rtype: UserSelectorArg + :rtype: bool """ - if self._transfer_dest_id_present: - return self._transfer_dest_id_value - else: - raise AttributeError("missing required field 'transfer_dest_id'") + return self._tag == 'cannot_keep_account_and_transfer' - @transfer_dest_id.setter - def transfer_dest_id(self, val): - self._transfer_dest_id_validator.validate_type_only(val) - self._transfer_dest_id_value = val - self._transfer_dest_id_present = True + def is_cannot_keep_account_and_delete_data(self): + """ + Check if the union tag is ``cannot_keep_account_and_delete_data``. - @transfer_dest_id.deleter - def transfer_dest_id(self): - self._transfer_dest_id_value = None - self._transfer_dest_id_present = False + :rtype: bool + """ + return self._tag == 'cannot_keep_account_and_delete_data' - @property - def transfer_admin_id(self): + def is_email_address_too_long_to_be_disabled(self): """ - Errors during the transfer process will be sent via email to this user. + Check if the union tag is ``email_address_too_long_to_be_disabled``. - :rtype: UserSelectorArg + :rtype: bool """ - if self._transfer_admin_id_present: - return self._transfer_admin_id_value - else: - raise AttributeError("missing required field 'transfer_admin_id'") + return self._tag == 'email_address_too_long_to_be_disabled' - @transfer_admin_id.setter - def transfer_admin_id(self, val): - self._transfer_admin_id_validator.validate_type_only(val) - self._transfer_admin_id_value = val - self._transfer_admin_id_present = True + def is_cannot_keep_invited_user_account(self): + """ + Check if the union tag is ``cannot_keep_invited_user_account``. - @transfer_admin_id.deleter - def transfer_admin_id(self): - self._transfer_admin_id_value = None - self._transfer_admin_id_present = False + :rtype: bool + """ + return self._tag == 'cannot_keep_invited_user_account' - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersDataTransferArg, self)._process_custom_annotations(annotation_type, field_path, processor) + def is_cannot_retain_shares_when_data_wiped(self): + """ + Check if the union tag is ``cannot_retain_shares_when_data_wiped``. - def __repr__(self): - return 'MembersDataTransferArg(user={!r}, transfer_dest_id={!r}, transfer_admin_id={!r})'.format( - self._user_value, - self._transfer_dest_id_value, - self._transfer_admin_id_value, - ) + :rtype: bool + """ + return self._tag == 'cannot_retain_shares_when_data_wiped' -MembersDataTransferArg_validator = bv.Struct(MembersDataTransferArg) + def is_cannot_retain_shares_when_no_account_kept(self): + """ + Check if the union tag is ``cannot_retain_shares_when_no_account_kept``. -class MembersDeactivateArg(MembersDeactivateBaseArg): - """ - :ivar team.MembersDeactivateArg.wipe_data: If provided, controls if the - user's data will be deleted on their linked devices. - """ + :rtype: bool + """ + return self._tag == 'cannot_retain_shares_when_no_account_kept' - __slots__ = [ - '_wipe_data_value', - '_wipe_data_present', - ] + def is_cannot_retain_shares_when_team_external_sharing_off(self): + """ + Check if the union tag is ``cannot_retain_shares_when_team_external_sharing_off``. - _has_required_fields = True + :rtype: bool + """ + return self._tag == 'cannot_retain_shares_when_team_external_sharing_off' - def __init__(self, - user=None, - wipe_data=None): - super(MembersDeactivateArg, self).__init__(user) - self._wipe_data_value = None - self._wipe_data_present = False - if wipe_data is not None: - self.wipe_data = wipe_data + def is_cannot_keep_account(self): + """ + Check if the union tag is ``cannot_keep_account``. - @property - def wipe_data(self): + :rtype: bool """ - If provided, controls if the user's data will be deleted on their linked - devices. + return self._tag == 'cannot_keep_account' + + def is_cannot_keep_account_under_legal_hold(self): + """ + Check if the union tag is ``cannot_keep_account_under_legal_hold``. :rtype: bool """ - if self._wipe_data_present: - return self._wipe_data_value - else: - return True + return self._tag == 'cannot_keep_account_under_legal_hold' - @wipe_data.setter - def wipe_data(self, val): - val = self._wipe_data_validator.validate(val) - self._wipe_data_value = val - self._wipe_data_present = True + def is_cannot_keep_account_required_to_sign_tos(self): + """ + Check if the union tag is ``cannot_keep_account_required_to_sign_tos``. - @wipe_data.deleter - def wipe_data(self): - self._wipe_data_value = None - self._wipe_data_present = False + :rtype: bool + """ + return self._tag == 'cannot_keep_account_required_to_sign_tos' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersDeactivateArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersRemoveError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersDeactivateArg(user={!r}, wipe_data={!r})'.format( - self._user_value, - self._wipe_data_value, - ) + return 'MembersRemoveError(%r, %r)' % (self._tag, self._value) -MembersDeactivateArg_validator = bv.Struct(MembersDeactivateArg) +MembersRemoveError_validator = bv.Union(MembersRemoveError) -class MembersDeactivateError(UserSelectorError): +class MembersSendWelcomeError(MemberSelectorError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - - :ivar team.MembersDeactivateError.user_not_in_team: The user is not a member - of the team. """ _catch_all = 'other' # Attribute is overwritten below the class definition - user_not_in_team = None - # Attribute is overwritten below the class definition other = None - def is_user_not_in_team(self): - """ - Check if the union tag is ``user_not_in_team``. - - :rtype: bool - """ - return self._tag == 'user_not_in_team' - def is_other(self): """ Check if the union tag is ``other``. @@ -10116,616 +14301,652 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersDeactivateError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSendWelcomeError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersDeactivateError(%r, %r)' % (self._tag, self._value) + return 'MembersSendWelcomeError(%r, %r)' % (self._tag, self._value) -MembersDeactivateError_validator = bv.Union(MembersDeactivateError) +MembersSendWelcomeError_validator = bv.Union(MembersSendWelcomeError) -class MembersGetInfoArgs(bb.Struct): +class MembersSetPermissionsArg(bb.Struct): """ - :ivar team.MembersGetInfoArgs.members: List of team members. + Exactly one of team_member_id, email, or external_id must be provided to + identify the user account. + + :ivar team.MembersSetPermissionsArg.user: Identity of user whose role will + be set. + :ivar team.MembersSetPermissionsArg.new_role: The new role of the member. """ __slots__ = [ - '_members_value', - '_members_present', + '_user_value', + '_user_present', + '_new_role_value', + '_new_role_present', ] _has_required_fields = True def __init__(self, - members=None): - self._members_value = None - self._members_present = False - if members is not None: - self.members = members + user=None, + new_role=None): + self._user_value = None + self._user_present = False + self._new_role_value = None + self._new_role_present = False + if user is not None: + self.user = user + if new_role is not None: + self.new_role = new_role @property - def members(self): + def user(self): """ - List of team members. + Identity of user whose role will be set. - :rtype: list of [UserSelectorArg] + :rtype: UserSelectorArg """ - if self._members_present: - return self._members_value + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") + + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False + + @property + def new_role(self): + """ + The new role of the member. + + :rtype: AdminTier + """ + if self._new_role_present: + return self._new_role_value else: - raise AttributeError("missing required field 'members'") + raise AttributeError("missing required field 'new_role'") - @members.setter - def members(self, val): - val = self._members_validator.validate(val) - self._members_value = val - self._members_present = True + @new_role.setter + def new_role(self, val): + self._new_role_validator.validate_type_only(val) + self._new_role_value = val + self._new_role_present = True - @members.deleter - def members(self): - self._members_value = None - self._members_present = False + @new_role.deleter + def new_role(self): + self._new_role_value = None + self._new_role_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersGetInfoArgs, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSetPermissionsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersGetInfoArgs(members={!r})'.format( - self._members_value, + return 'MembersSetPermissionsArg(user={!r}, new_role={!r})'.format( + self._user_value, + self._new_role_value, ) -MembersGetInfoArgs_validator = bv.Struct(MembersGetInfoArgs) +MembersSetPermissionsArg_validator = bv.Struct(MembersSetPermissionsArg) -class MembersGetInfoError(bb.Union): +class MembersSetPermissionsError(UserSelectorError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. + + :ivar team.MembersSetPermissionsError.last_admin: Cannot remove the admin + setting of the last admin. + :ivar team.MembersSetPermissionsError.user_not_in_team: The user is not a + member of the team. + :ivar team.MembersSetPermissionsError.cannot_set_permissions: Cannot + remove/grant permissions. + :ivar team.MembersSetPermissionsError.team_license_limit: Team is full. The + organization has no available licenses. """ _catch_all = 'other' # Attribute is overwritten below the class definition + last_admin = None + # Attribute is overwritten below the class definition + user_not_in_team = None + # Attribute is overwritten below the class definition + cannot_set_permissions = None + # Attribute is overwritten below the class definition + team_license_limit = None + # Attribute is overwritten below the class definition other = None - def is_other(self): + def is_last_admin(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``last_admin``. :rtype: bool """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersGetInfoError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersGetInfoError(%r, %r)' % (self._tag, self._value) - -MembersGetInfoError_validator = bv.Union(MembersGetInfoError) - -class MembersGetInfoItem(bb.Union): - """ - Describes a result obtained for a single user whose id was specified in the - parameter of :meth:`dropbox.dropbox.Dropbox.team_members_get_info`. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar str team.MembersGetInfoItem.id_not_found: An ID that was provided as a - parameter to :route:`members/get_info`, and did not match a - corresponding user. This might be a team_member_id, an email, or an - external ID, depending on how the method was called. - :ivar TeamMemberInfo MembersGetInfoItem.member_info: Info about a team - member. - """ - - _catch_all = None - - @classmethod - def id_not_found(cls, val): - """ - Create an instance of this class set to the ``id_not_found`` tag with - value ``val``. - - :param str val: - :rtype: MembersGetInfoItem - """ - return cls('id_not_found', val) - - @classmethod - def member_info(cls, val): - """ - Create an instance of this class set to the ``member_info`` tag with - value ``val``. - - :param TeamMemberInfo val: - :rtype: MembersGetInfoItem - """ - return cls('member_info', val) + return self._tag == 'last_admin' - def is_id_not_found(self): + def is_user_not_in_team(self): """ - Check if the union tag is ``id_not_found``. + Check if the union tag is ``user_not_in_team``. :rtype: bool """ - return self._tag == 'id_not_found' + return self._tag == 'user_not_in_team' - def is_member_info(self): + def is_cannot_set_permissions(self): """ - Check if the union tag is ``member_info``. + Check if the union tag is ``cannot_set_permissions``. :rtype: bool """ - return self._tag == 'member_info' + return self._tag == 'cannot_set_permissions' - def get_id_not_found(self): + def is_team_license_limit(self): """ - An ID that was provided as a parameter to - :meth:`dropbox.dropbox.Dropbox.team_members_get_info`, and did not match - a corresponding user. This might be a team_member_id, an email, or an - external ID, depending on how the method was called. - - Only call this if :meth:`is_id_not_found` is true. + Check if the union tag is ``team_license_limit``. - :rtype: str + :rtype: bool """ - if not self.is_id_not_found(): - raise AttributeError("tag 'id_not_found' not set") - return self._value + return self._tag == 'team_license_limit' - def get_member_info(self): + def is_other(self): """ - Info about a team member. - - Only call this if :meth:`is_member_info` is true. + Check if the union tag is ``other``. - :rtype: TeamMemberInfo + :rtype: bool """ - if not self.is_member_info(): - raise AttributeError("tag 'member_info' not set") - return self._value + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersGetInfoItem, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSetPermissionsError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersGetInfoItem(%r, %r)' % (self._tag, self._value) + return 'MembersSetPermissionsError(%r, %r)' % (self._tag, self._value) -MembersGetInfoItem_validator = bv.Union(MembersGetInfoItem) +MembersSetPermissionsError_validator = bv.Union(MembersSetPermissionsError) -class MembersListArg(bb.Struct): +class MembersSetPermissionsResult(bb.Struct): """ - :ivar team.MembersListArg.limit: Number of results to return per call. - :ivar team.MembersListArg.include_removed: Whether to return removed - members. + :ivar team.MembersSetPermissionsResult.team_member_id: The member ID of the + user to which the change was applied. + :ivar team.MembersSetPermissionsResult.role: The role after the change. """ __slots__ = [ - '_limit_value', - '_limit_present', - '_include_removed_value', - '_include_removed_present', + '_team_member_id_value', + '_team_member_id_present', + '_role_value', + '_role_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - limit=None, - include_removed=None): - self._limit_value = None - self._limit_present = False - self._include_removed_value = None - self._include_removed_present = False - if limit is not None: - self.limit = limit - if include_removed is not None: - self.include_removed = include_removed - - @property - def limit(self): - """ - Number of results to return per call. - - :rtype: int - """ - if self._limit_present: - return self._limit_value - else: - return 1000 - - @limit.setter - def limit(self, val): - val = self._limit_validator.validate(val) - self._limit_value = val - self._limit_present = True - - @limit.deleter - def limit(self): - self._limit_value = None - self._limit_present = False + team_member_id=None, + role=None): + self._team_member_id_value = None + self._team_member_id_present = False + self._role_value = None + self._role_present = False + if team_member_id is not None: + self.team_member_id = team_member_id + if role is not None: + self.role = role @property - def include_removed(self): + def team_member_id(self): """ - Whether to return removed members. + The member ID of the user to which the change was applied. - :rtype: bool + :rtype: str """ - if self._include_removed_present: - return self._include_removed_value + if self._team_member_id_present: + return self._team_member_id_value else: - return False - - @include_removed.setter - def include_removed(self, val): - val = self._include_removed_validator.validate(val) - self._include_removed_value = val - self._include_removed_present = True - - @include_removed.deleter - def include_removed(self): - self._include_removed_value = None - self._include_removed_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersListArg, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersListArg(limit={!r}, include_removed={!r})'.format( - self._limit_value, - self._include_removed_value, - ) - -MembersListArg_validator = bv.Struct(MembersListArg) - -class MembersListContinueArg(bb.Struct): - """ - :ivar team.MembersListContinueArg.cursor: Indicates from what point to get - the next set of members. - """ - - __slots__ = [ - '_cursor_value', - '_cursor_present', - ] + raise AttributeError("missing required field 'team_member_id'") - _has_required_fields = True + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False @property - def cursor(self): + def role(self): """ - Indicates from what point to get the next set of members. + The role after the change. - :rtype: str + :rtype: AdminTier """ - if self._cursor_present: - return self._cursor_value + if self._role_present: + return self._role_value else: - raise AttributeError("missing required field 'cursor'") + raise AttributeError("missing required field 'role'") - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @role.setter + def role(self, val): + self._role_validator.validate_type_only(val) + self._role_value = val + self._role_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @role.deleter + def role(self): + self._role_value = None + self._role_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSetPermissionsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersListContinueArg(cursor={!r})'.format( - self._cursor_value, + return 'MembersSetPermissionsResult(team_member_id={!r}, role={!r})'.format( + self._team_member_id_value, + self._role_value, ) -MembersListContinueArg_validator = bv.Struct(MembersListContinueArg) +MembersSetPermissionsResult_validator = bv.Struct(MembersSetPermissionsResult) -class MembersListContinueError(bb.Union): +class MembersSetProfileArg(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Exactly one of team_member_id, email, or external_id must be provided to + identify the user account. At least one of new_email, new_external_id, + new_given_name, and/or new_surname must be provided. - :ivar team.MembersListContinueError.invalid_cursor: The cursor is invalid. + :ivar team.MembersSetProfileArg.user: Identity of user whose profile will be + set. + :ivar team.MembersSetProfileArg.new_email: New email for member. + :ivar team.MembersSetProfileArg.new_external_id: New external ID for member. + :ivar team.MembersSetProfileArg.new_given_name: New given name for member. + :ivar team.MembersSetProfileArg.new_surname: New surname for member. + :ivar team.MembersSetProfileArg.new_persistent_id: New persistent ID. This + field only available to teams using persistent ID SAML configuration. + :ivar team.MembersSetProfileArg.new_is_directory_restricted: New value for + whether the user is a directory restricted user. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - invalid_cursor = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_user_value', + '_user_present', + '_new_email_value', + '_new_email_present', + '_new_external_id_value', + '_new_external_id_present', + '_new_given_name_value', + '_new_given_name_present', + '_new_surname_value', + '_new_surname_present', + '_new_persistent_id_value', + '_new_persistent_id_present', + '_new_is_directory_restricted_value', + '_new_is_directory_restricted_present', + ] - def is_invalid_cursor(self): - """ - Check if the union tag is ``invalid_cursor``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'invalid_cursor' + def __init__(self, + user=None, + new_email=None, + new_external_id=None, + new_given_name=None, + new_surname=None, + new_persistent_id=None, + new_is_directory_restricted=None): + self._user_value = None + self._user_present = False + self._new_email_value = None + self._new_email_present = False + self._new_external_id_value = None + self._new_external_id_present = False + self._new_given_name_value = None + self._new_given_name_present = False + self._new_surname_value = None + self._new_surname_present = False + self._new_persistent_id_value = None + self._new_persistent_id_present = False + self._new_is_directory_restricted_value = None + self._new_is_directory_restricted_present = False + if user is not None: + self.user = user + if new_email is not None: + self.new_email = new_email + if new_external_id is not None: + self.new_external_id = new_external_id + if new_given_name is not None: + self.new_given_name = new_given_name + if new_surname is not None: + self.new_surname = new_surname + if new_persistent_id is not None: + self.new_persistent_id = new_persistent_id + if new_is_directory_restricted is not None: + self.new_is_directory_restricted = new_is_directory_restricted - def is_other(self): + @property + def user(self): """ - Check if the union tag is ``other``. + Identity of user whose profile will be set. - :rtype: bool + :rtype: UserSelectorArg """ - return self._tag == 'other' + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True - def __repr__(self): - return 'MembersListContinueError(%r, %r)' % (self._tag, self._value) + @user.deleter + def user(self): + self._user_value = None + self._user_present = False -MembersListContinueError_validator = bv.Union(MembersListContinueError) + @property + def new_email(self): + """ + New email for member. -class MembersListError(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + :rtype: str + """ + if self._new_email_present: + return self._new_email_value + else: + return None - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + @new_email.setter + def new_email(self, val): + if val is None: + del self.new_email + return + val = self._new_email_validator.validate(val) + self._new_email_value = val + self._new_email_present = True - def is_other(self): - """ - Check if the union tag is ``other``. + @new_email.deleter + def new_email(self): + self._new_email_value = None + self._new_email_present = False - :rtype: bool + @property + def new_external_id(self): """ - return self._tag == 'other' + New external ID for member. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersListError, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: str + """ + if self._new_external_id_present: + return self._new_external_id_value + else: + return None - def __repr__(self): - return 'MembersListError(%r, %r)' % (self._tag, self._value) + @new_external_id.setter + def new_external_id(self, val): + if val is None: + del self.new_external_id + return + val = self._new_external_id_validator.validate(val) + self._new_external_id_value = val + self._new_external_id_present = True -MembersListError_validator = bv.Union(MembersListError) + @new_external_id.deleter + def new_external_id(self): + self._new_external_id_value = None + self._new_external_id_present = False -class MembersListResult(bb.Struct): - """ - :ivar team.MembersListResult.members: List of team members. - :ivar team.MembersListResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` to obtain the - additional members. - :ivar team.MembersListResult.has_more: Is true if there are additional team - members that have not been returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` can retrieve - them. - """ + @property + def new_given_name(self): + """ + New given name for member. - __slots__ = [ - '_members_value', - '_members_present', - '_cursor_value', - '_cursor_present', - '_has_more_value', - '_has_more_present', - ] + :rtype: str + """ + if self._new_given_name_present: + return self._new_given_name_value + else: + return None - _has_required_fields = True + @new_given_name.setter + def new_given_name(self, val): + if val is None: + del self.new_given_name + return + val = self._new_given_name_validator.validate(val) + self._new_given_name_value = val + self._new_given_name_present = True - def __init__(self, - members=None, - cursor=None, - has_more=None): - self._members_value = None - self._members_present = False - self._cursor_value = None - self._cursor_present = False - self._has_more_value = None - self._has_more_present = False - if members is not None: - self.members = members - if cursor is not None: - self.cursor = cursor - if has_more is not None: - self.has_more = has_more + @new_given_name.deleter + def new_given_name(self): + self._new_given_name_value = None + self._new_given_name_present = False @property - def members(self): + def new_surname(self): """ - List of team members. + New surname for member. - :rtype: list of [TeamMemberInfo] + :rtype: str """ - if self._members_present: - return self._members_value + if self._new_surname_present: + return self._new_surname_value else: - raise AttributeError("missing required field 'members'") + return None - @members.setter - def members(self, val): - val = self._members_validator.validate(val) - self._members_value = val - self._members_present = True + @new_surname.setter + def new_surname(self, val): + if val is None: + del self.new_surname + return + val = self._new_surname_validator.validate(val) + self._new_surname_value = val + self._new_surname_present = True - @members.deleter - def members(self): - self._members_value = None - self._members_present = False + @new_surname.deleter + def new_surname(self): + self._new_surname_value = None + self._new_surname_present = False @property - def cursor(self): + def new_persistent_id(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` to obtain the - additional members. + New persistent ID. This field only available to teams using persistent + ID SAML configuration. :rtype: str """ - if self._cursor_present: - return self._cursor_value + if self._new_persistent_id_present: + return self._new_persistent_id_value else: - raise AttributeError("missing required field 'cursor'") + return None - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @new_persistent_id.setter + def new_persistent_id(self, val): + if val is None: + del self.new_persistent_id + return + val = self._new_persistent_id_validator.validate(val) + self._new_persistent_id_value = val + self._new_persistent_id_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @new_persistent_id.deleter + def new_persistent_id(self): + self._new_persistent_id_value = None + self._new_persistent_id_present = False @property - def has_more(self): + def new_is_directory_restricted(self): """ - Is true if there are additional team members that have not been returned - yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_members_list_continue` can retrieve - them. + New value for whether the user is a directory restricted user. :rtype: bool """ - if self._has_more_present: - return self._has_more_value + if self._new_is_directory_restricted_present: + return self._new_is_directory_restricted_value else: - raise AttributeError("missing required field 'has_more'") + return None - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + @new_is_directory_restricted.setter + def new_is_directory_restricted(self, val): + if val is None: + del self.new_is_directory_restricted + return + val = self._new_is_directory_restricted_validator.validate(val) + self._new_is_directory_restricted_value = val + self._new_is_directory_restricted_present = True - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + @new_is_directory_restricted.deleter + def new_is_directory_restricted(self): + self._new_is_directory_restricted_value = None + self._new_is_directory_restricted_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSetProfileArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersListResult(members={!r}, cursor={!r}, has_more={!r})'.format( - self._members_value, - self._cursor_value, - self._has_more_value, + return 'MembersSetProfileArg(user={!r}, new_email={!r}, new_external_id={!r}, new_given_name={!r}, new_surname={!r}, new_persistent_id={!r}, new_is_directory_restricted={!r})'.format( + self._user_value, + self._new_email_value, + self._new_external_id_value, + self._new_given_name_value, + self._new_surname_value, + self._new_persistent_id_value, + self._new_is_directory_restricted_value, ) -MembersListResult_validator = bv.Struct(MembersListResult) +MembersSetProfileArg_validator = bv.Struct(MembersSetProfileArg) -class MembersRecoverArg(bb.Struct): +class MembersSetProfileError(MemberSelectorError): """ - Exactly one of team_member_id, email, or external_id must be provided to - identify the user account. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - :ivar team.MembersRecoverArg.user: Identity of user to recover. + :ivar team.MembersSetProfileError.external_id_and_new_external_id_unsafe: It + is unsafe to use both external_id and new_external_id. + :ivar team.MembersSetProfileError.no_new_data_specified: None of new_email, + new_given_name, new_surname, or new_external_id are specified. + :ivar team.MembersSetProfileError.email_reserved_for_other_user: Email is + already reserved for another user. + :ivar team.MembersSetProfileError.external_id_used_by_other_user: The + external ID is already in use by another team member. + :ivar team.MembersSetProfileError.set_profile_disallowed: Modifying deleted + users is not allowed. + :ivar team.MembersSetProfileError.param_cannot_be_empty: Parameter new_email + cannot be empty. + :ivar team.MembersSetProfileError.persistent_id_disabled: Persistent ID is + only available to teams with persistent ID SAML configuration. Please + contact Dropbox for more information. + :ivar team.MembersSetProfileError.persistent_id_used_by_other_user: The + persistent ID is already in use by another team member. + :ivar team.MembersSetProfileError.directory_restricted_off: Directory + Restrictions option is not available. """ - __slots__ = [ - '_user_value', - '_user_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + external_id_and_new_external_id_unsafe = None + # Attribute is overwritten below the class definition + no_new_data_specified = None + # Attribute is overwritten below the class definition + email_reserved_for_other_user = None + # Attribute is overwritten below the class definition + external_id_used_by_other_user = None + # Attribute is overwritten below the class definition + set_profile_disallowed = None + # Attribute is overwritten below the class definition + param_cannot_be_empty = None + # Attribute is overwritten below the class definition + persistent_id_disabled = None + # Attribute is overwritten below the class definition + persistent_id_used_by_other_user = None + # Attribute is overwritten below the class definition + directory_restricted_off = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_external_id_and_new_external_id_unsafe(self): + """ + Check if the union tag is ``external_id_and_new_external_id_unsafe``. - def __init__(self, - user=None): - self._user_value = None - self._user_present = False - if user is not None: - self.user = user + :rtype: bool + """ + return self._tag == 'external_id_and_new_external_id_unsafe' - @property - def user(self): + def is_no_new_data_specified(self): """ - Identity of user to recover. + Check if the union tag is ``no_new_data_specified``. - :rtype: UserSelectorArg + :rtype: bool """ - if self._user_present: - return self._user_value - else: - raise AttributeError("missing required field 'user'") + return self._tag == 'no_new_data_specified' - @user.setter - def user(self, val): - self._user_validator.validate_type_only(val) - self._user_value = val - self._user_present = True + def is_email_reserved_for_other_user(self): + """ + Check if the union tag is ``email_reserved_for_other_user``. - @user.deleter - def user(self): - self._user_value = None - self._user_present = False + :rtype: bool + """ + return self._tag == 'email_reserved_for_other_user' - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersRecoverArg, self)._process_custom_annotations(annotation_type, field_path, processor) + def is_external_id_used_by_other_user(self): + """ + Check if the union tag is ``external_id_used_by_other_user``. - def __repr__(self): - return 'MembersRecoverArg(user={!r})'.format( - self._user_value, - ) + :rtype: bool + """ + return self._tag == 'external_id_used_by_other_user' -MembersRecoverArg_validator = bv.Struct(MembersRecoverArg) + def is_set_profile_disallowed(self): + """ + Check if the union tag is ``set_profile_disallowed``. -class MembersRecoverError(UserSelectorError): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :rtype: bool + """ + return self._tag == 'set_profile_disallowed' - :ivar team.MembersRecoverError.user_unrecoverable: The user is not - recoverable. - :ivar team.MembersRecoverError.user_not_in_team: The user is not a member of - the team. - :ivar team.MembersRecoverError.team_license_limit: Team is full. The - organization has no available licenses. - """ + def is_param_cannot_be_empty(self): + """ + Check if the union tag is ``param_cannot_be_empty``. - _catch_all = 'other' - # Attribute is overwritten below the class definition - user_unrecoverable = None - # Attribute is overwritten below the class definition - user_not_in_team = None - # Attribute is overwritten below the class definition - team_license_limit = None - # Attribute is overwritten below the class definition - other = None + :rtype: bool + """ + return self._tag == 'param_cannot_be_empty' - def is_user_unrecoverable(self): + def is_persistent_id_disabled(self): """ - Check if the union tag is ``user_unrecoverable``. + Check if the union tag is ``persistent_id_disabled``. :rtype: bool """ - return self._tag == 'user_unrecoverable' + return self._tag == 'persistent_id_disabled' - def is_user_not_in_team(self): + def is_persistent_id_used_by_other_user(self): """ - Check if the union tag is ``user_not_in_team``. + Check if the union tag is ``persistent_id_used_by_other_user``. :rtype: bool """ - return self._tag == 'user_not_in_team' + return self._tag == 'persistent_id_used_by_other_user' - def is_team_license_limit(self): + def is_directory_restricted_off(self): """ - Check if the union tag is ``team_license_limit``. + Check if the union tag is ``directory_restricted_off``. :rtype: bool """ - return self._tag == 'team_license_limit' + return self._tag == 'directory_restricted_off' def is_other(self): """ @@ -10736,423 +14957,316 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersRecoverError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSetProfileError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersRecoverError(%r, %r)' % (self._tag, self._value) + return 'MembersSetProfileError(%r, %r)' % (self._tag, self._value) -MembersRecoverError_validator = bv.Union(MembersRecoverError) +MembersSetProfileError_validator = bv.Union(MembersSetProfileError) -class MembersRemoveArg(MembersDeactivateArg): +class MembersSetProfilePhotoArg(bb.Struct): """ - :ivar team.MembersRemoveArg.transfer_dest_id: If provided, files from the - deleted member account will be transferred to this user. - :ivar team.MembersRemoveArg.transfer_admin_id: If provided, errors during - the transfer process will be sent via email to this user. If the - transfer_dest_id argument was provided, then this argument must be - provided as well. - :ivar team.MembersRemoveArg.keep_account: Downgrade the member to a Basic - account. The user will retain the email address associated with their - Dropbox account and data in their account that is not restricted to - team members. In order to keep the account the argument wipe_data should - be set to False. + :ivar team.MembersSetProfilePhotoArg.user: Identity of the user whose + profile photo will be set. + :ivar team.MembersSetProfilePhotoArg.photo: Image to set as the member's new + profile photo. """ __slots__ = [ - '_transfer_dest_id_value', - '_transfer_dest_id_present', - '_transfer_admin_id_value', - '_transfer_admin_id_present', - '_keep_account_value', - '_keep_account_present', + '_user_value', + '_user_present', + '_photo_value', + '_photo_present', ] _has_required_fields = True def __init__(self, user=None, - wipe_data=None, - transfer_dest_id=None, - transfer_admin_id=None, - keep_account=None): - super(MembersRemoveArg, self).__init__(user, - wipe_data) - self._transfer_dest_id_value = None - self._transfer_dest_id_present = False - self._transfer_admin_id_value = None - self._transfer_admin_id_present = False - self._keep_account_value = None - self._keep_account_present = False - if transfer_dest_id is not None: - self.transfer_dest_id = transfer_dest_id - if transfer_admin_id is not None: - self.transfer_admin_id = transfer_admin_id - if keep_account is not None: - self.keep_account = keep_account - - @property - def transfer_dest_id(self): - """ - If provided, files from the deleted member account will be transferred - to this user. - - :rtype: UserSelectorArg - """ - if self._transfer_dest_id_present: - return self._transfer_dest_id_value - else: - return None - - @transfer_dest_id.setter - def transfer_dest_id(self, val): - if val is None: - del self.transfer_dest_id - return - self._transfer_dest_id_validator.validate_type_only(val) - self._transfer_dest_id_value = val - self._transfer_dest_id_present = True - - @transfer_dest_id.deleter - def transfer_dest_id(self): - self._transfer_dest_id_value = None - self._transfer_dest_id_present = False + photo=None): + self._user_value = None + self._user_present = False + self._photo_value = None + self._photo_present = False + if user is not None: + self.user = user + if photo is not None: + self.photo = photo @property - def transfer_admin_id(self): + def user(self): """ - If provided, errors during the transfer process will be sent via email - to this user. If the transfer_dest_id argument was provided, then this - argument must be provided as well. + Identity of the user whose profile photo will be set. :rtype: UserSelectorArg """ - if self._transfer_admin_id_present: - return self._transfer_admin_id_value + if self._user_present: + return self._user_value else: - return None + raise AttributeError("missing required field 'user'") - @transfer_admin_id.setter - def transfer_admin_id(self, val): - if val is None: - del self.transfer_admin_id - return - self._transfer_admin_id_validator.validate_type_only(val) - self._transfer_admin_id_value = val - self._transfer_admin_id_present = True + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True - @transfer_admin_id.deleter - def transfer_admin_id(self): - self._transfer_admin_id_value = None - self._transfer_admin_id_present = False + @user.deleter + def user(self): + self._user_value = None + self._user_present = False @property - def keep_account(self): + def photo(self): """ - Downgrade the member to a Basic account. The user will retain the email - address associated with their Dropbox account and data in their account - that is not restricted to team members. In order to keep the account the - argument wipe_data should be set to False. + Image to set as the member's new profile photo. - :rtype: bool + :rtype: account.PhotoSourceArg """ - if self._keep_account_present: - return self._keep_account_value + if self._photo_present: + return self._photo_value else: - return False + raise AttributeError("missing required field 'photo'") - @keep_account.setter - def keep_account(self, val): - val = self._keep_account_validator.validate(val) - self._keep_account_value = val - self._keep_account_present = True + @photo.setter + def photo(self, val): + self._photo_validator.validate_type_only(val) + self._photo_value = val + self._photo_present = True - @keep_account.deleter - def keep_account(self): - self._keep_account_value = None - self._keep_account_present = False + @photo.deleter + def photo(self): + self._photo_value = None + self._photo_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersRemoveArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSetProfilePhotoArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersRemoveArg(user={!r}, wipe_data={!r}, transfer_dest_id={!r}, transfer_admin_id={!r}, keep_account={!r})'.format( + return 'MembersSetProfilePhotoArg(user={!r}, photo={!r})'.format( self._user_value, - self._wipe_data_value, - self._transfer_dest_id_value, - self._transfer_admin_id_value, - self._keep_account_value, + self._photo_value, ) -MembersRemoveArg_validator = bv.Struct(MembersRemoveArg) +MembersSetProfilePhotoArg_validator = bv.Struct(MembersSetProfilePhotoArg) -class MembersTransferFilesError(MembersDeactivateError): +class MembersSetProfilePhotoError(MemberSelectorError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar - team.MembersTransferFilesError.removed_and_transfer_dest_should_differ: - Expected removed user and transfer_dest user to be different. - :ivar - team.MembersTransferFilesError.removed_and_transfer_admin_should_differ: - Expected removed user and transfer_admin user to be different. - :ivar team.MembersTransferFilesError.transfer_dest_user_not_found: No - matching user found for the argument transfer_dest_id. - :ivar team.MembersTransferFilesError.transfer_dest_user_not_in_team: The - provided transfer_dest_id does not exist on this team. - :ivar team.MembersTransferFilesError.transfer_admin_user_not_in_team: The - provided transfer_admin_id does not exist on this team. - :ivar team.MembersTransferFilesError.transfer_admin_user_not_found: No - matching user found for the argument transfer_admin_id. - :ivar team.MembersTransferFilesError.unspecified_transfer_admin_id: The - transfer_admin_id argument must be provided when file transfer is - requested. - :ivar team.MembersTransferFilesError.transfer_admin_is_not_admin: Specified - transfer_admin user is not a team admin. - :ivar team.MembersTransferFilesError.recipient_not_verified: The recipient - user's email is not verified. + :ivar team.MembersSetProfilePhotoError.set_profile_disallowed: Modifying + deleted users is not allowed. """ + _catch_all = 'other' # Attribute is overwritten below the class definition - removed_and_transfer_dest_should_differ = None - # Attribute is overwritten below the class definition - removed_and_transfer_admin_should_differ = None - # Attribute is overwritten below the class definition - transfer_dest_user_not_found = None - # Attribute is overwritten below the class definition - transfer_dest_user_not_in_team = None - # Attribute is overwritten below the class definition - transfer_admin_user_not_in_team = None - # Attribute is overwritten below the class definition - transfer_admin_user_not_found = None - # Attribute is overwritten below the class definition - unspecified_transfer_admin_id = None - # Attribute is overwritten below the class definition - transfer_admin_is_not_admin = None + set_profile_disallowed = None # Attribute is overwritten below the class definition - recipient_not_verified = None + other = None - def is_removed_and_transfer_dest_should_differ(self): + @classmethod + def photo_error(cls, val): """ - Check if the union tag is ``removed_and_transfer_dest_should_differ``. + Create an instance of this class set to the ``photo_error`` tag with + value ``val``. - :rtype: bool + :param account.SetProfilePhotoError val: + :rtype: MembersSetProfilePhotoError """ - return self._tag == 'removed_and_transfer_dest_should_differ' + return cls('photo_error', val) - def is_removed_and_transfer_admin_should_differ(self): + def is_set_profile_disallowed(self): """ - Check if the union tag is ``removed_and_transfer_admin_should_differ``. + Check if the union tag is ``set_profile_disallowed``. :rtype: bool """ - return self._tag == 'removed_and_transfer_admin_should_differ' + return self._tag == 'set_profile_disallowed' - def is_transfer_dest_user_not_found(self): + def is_photo_error(self): """ - Check if the union tag is ``transfer_dest_user_not_found``. + Check if the union tag is ``photo_error``. :rtype: bool """ - return self._tag == 'transfer_dest_user_not_found' + return self._tag == 'photo_error' - def is_transfer_dest_user_not_in_team(self): + def is_other(self): """ - Check if the union tag is ``transfer_dest_user_not_in_team``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'transfer_dest_user_not_in_team' + return self._tag == 'other' - def is_transfer_admin_user_not_in_team(self): + def get_photo_error(self): """ - Check if the union tag is ``transfer_admin_user_not_in_team``. + Only call this if :meth:`is_photo_error` is true. - :rtype: bool + :rtype: account.SetProfilePhotoError """ - return self._tag == 'transfer_admin_user_not_in_team' + if not self.is_photo_error(): + raise AttributeError("tag 'photo_error' not set") + return self._value - def is_transfer_admin_user_not_found(self): - """ - Check if the union tag is ``transfer_admin_user_not_found``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersSetProfilePhotoError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MembersSetProfilePhotoError(%r, %r)' % (self._tag, self._value) + +MembersSetProfilePhotoError_validator = bv.Union(MembersSetProfilePhotoError) + +class MembersSuspendError(MembersDeactivateError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.MembersSuspendError.suspend_inactive_user: The user is not + active, so it cannot be suspended. + :ivar team.MembersSuspendError.suspend_last_admin: The user is the last + admin of the team, so it cannot be suspended. + :ivar team.MembersSuspendError.team_license_limit: Team is full. The + organization has no available licenses. + """ - :rtype: bool - """ - return self._tag == 'transfer_admin_user_not_found' + # Attribute is overwritten below the class definition + suspend_inactive_user = None + # Attribute is overwritten below the class definition + suspend_last_admin = None + # Attribute is overwritten below the class definition + team_license_limit = None - def is_unspecified_transfer_admin_id(self): + def is_suspend_inactive_user(self): """ - Check if the union tag is ``unspecified_transfer_admin_id``. + Check if the union tag is ``suspend_inactive_user``. :rtype: bool """ - return self._tag == 'unspecified_transfer_admin_id' + return self._tag == 'suspend_inactive_user' - def is_transfer_admin_is_not_admin(self): + def is_suspend_last_admin(self): """ - Check if the union tag is ``transfer_admin_is_not_admin``. + Check if the union tag is ``suspend_last_admin``. :rtype: bool """ - return self._tag == 'transfer_admin_is_not_admin' + return self._tag == 'suspend_last_admin' - def is_recipient_not_verified(self): + def is_team_license_limit(self): """ - Check if the union tag is ``recipient_not_verified``. + Check if the union tag is ``team_license_limit``. :rtype: bool """ - return self._tag == 'recipient_not_verified' + return self._tag == 'team_license_limit' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersTransferFilesError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersSuspendError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersTransferFilesError(%r, %r)' % (self._tag, self._value) + return 'MembersSuspendError(%r, %r)' % (self._tag, self._value) -MembersTransferFilesError_validator = bv.Union(MembersTransferFilesError) +MembersSuspendError_validator = bv.Union(MembersSuspendError) -class MembersRemoveError(MembersTransferFilesError): +class MembersTransferFormerMembersFilesError(MembersTransferFilesError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.MembersRemoveError.remove_last_admin: The user is the last admin - of the team, so it cannot be removed from it. - :ivar team.MembersRemoveError.cannot_keep_account_and_transfer: Cannot keep - account and transfer the data to another user at the same time. - :ivar team.MembersRemoveError.cannot_keep_account_and_delete_data: Cannot - keep account and delete the data at the same time. To keep the account - the argument wipe_data should be set to False. - :ivar team.MembersRemoveError.email_address_too_long_to_be_disabled: The - email address of the user is too long to be disabled. - :ivar team.MembersRemoveError.cannot_keep_invited_user_account: Cannot keep - account of an invited user. + :ivar + team.MembersTransferFormerMembersFilesError.user_data_is_being_transferred: + The user's data is being transferred. Please wait some time before + retrying. + :ivar team.MembersTransferFormerMembersFilesError.user_not_removed: No + matching removed user found for the argument user. + :ivar + team.MembersTransferFormerMembersFilesError.user_data_cannot_be_transferred: + User files aren't transferable anymore. + :ivar + team.MembersTransferFormerMembersFilesError.user_data_already_transferred: + User's data has already been transferred to another user. """ # Attribute is overwritten below the class definition - remove_last_admin = None - # Attribute is overwritten below the class definition - cannot_keep_account_and_transfer = None + user_data_is_being_transferred = None # Attribute is overwritten below the class definition - cannot_keep_account_and_delete_data = None + user_not_removed = None # Attribute is overwritten below the class definition - email_address_too_long_to_be_disabled = None + user_data_cannot_be_transferred = None # Attribute is overwritten below the class definition - cannot_keep_invited_user_account = None - - def is_remove_last_admin(self): - """ - Check if the union tag is ``remove_last_admin``. - - :rtype: bool - """ - return self._tag == 'remove_last_admin' - - def is_cannot_keep_account_and_transfer(self): - """ - Check if the union tag is ``cannot_keep_account_and_transfer``. - - :rtype: bool - """ - return self._tag == 'cannot_keep_account_and_transfer' + user_data_already_transferred = None - def is_cannot_keep_account_and_delete_data(self): + def is_user_data_is_being_transferred(self): """ - Check if the union tag is ``cannot_keep_account_and_delete_data``. + Check if the union tag is ``user_data_is_being_transferred``. :rtype: bool """ - return self._tag == 'cannot_keep_account_and_delete_data' + return self._tag == 'user_data_is_being_transferred' - def is_email_address_too_long_to_be_disabled(self): + def is_user_not_removed(self): """ - Check if the union tag is ``email_address_too_long_to_be_disabled``. + Check if the union tag is ``user_not_removed``. :rtype: bool """ - return self._tag == 'email_address_too_long_to_be_disabled' + return self._tag == 'user_not_removed' - def is_cannot_keep_invited_user_account(self): + def is_user_data_cannot_be_transferred(self): """ - Check if the union tag is ``cannot_keep_invited_user_account``. + Check if the union tag is ``user_data_cannot_be_transferred``. :rtype: bool """ - return self._tag == 'cannot_keep_invited_user_account' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersRemoveError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersRemoveError(%r, %r)' % (self._tag, self._value) - -MembersRemoveError_validator = bv.Union(MembersRemoveError) - -class MembersSendWelcomeError(MemberSelectorError): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + return self._tag == 'user_data_cannot_be_transferred' - def is_other(self): + def is_user_data_already_transferred(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``user_data_already_transferred``. :rtype: bool """ - return self._tag == 'other' + return self._tag == 'user_data_already_transferred' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersSendWelcomeError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersTransferFormerMembersFilesError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersSendWelcomeError(%r, %r)' % (self._tag, self._value) + return 'MembersTransferFormerMembersFilesError(%r, %r)' % (self._tag, self._value) -MembersSendWelcomeError_validator = bv.Union(MembersSendWelcomeError) +MembersTransferFormerMembersFilesError_validator = bv.Union(MembersTransferFormerMembersFilesError) -class MembersSetPermissionsArg(bb.Struct): +class MembersUnsuspendArg(bb.Struct): """ Exactly one of team_member_id, email, or external_id must be provided to identify the user account. - :ivar team.MembersSetPermissionsArg.user: Identity of user whose role will - be set. - :ivar team.MembersSetPermissionsArg.new_role: The new role of the member. + :ivar team.MembersUnsuspendArg.user: Identity of user to unsuspend. """ __slots__ = [ '_user_value', '_user_present', - '_new_role_value', - '_new_role_present', ] _has_required_fields = True def __init__(self, - user=None, - new_role=None): + user=None): self._user_value = None self._user_present = False - self._new_role_value = None - self._new_role_present = False if user is not None: self.user = user - if new_role is not None: - self.new_role = new_role @property def user(self): """ - Identity of user whose role will be set. + Identity of user to unsuspend. :rtype: UserSelectorArg """ @@ -11172,99 +15286,125 @@ def user(self): self._user_value = None self._user_present = False - @property - def new_role(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MembersUnsuspendArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MembersUnsuspendArg(user={!r})'.format( + self._user_value, + ) + +MembersUnsuspendArg_validator = bv.Struct(MembersUnsuspendArg) + +class MembersUnsuspendError(MembersDeactivateError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.MembersUnsuspendError.unsuspend_non_suspended_member: The user is + unsuspended, so it cannot be unsuspended again. + :ivar team.MembersUnsuspendError.team_license_limit: Team is full. The + organization has no available licenses. + """ + + # Attribute is overwritten below the class definition + unsuspend_non_suspended_member = None + # Attribute is overwritten below the class definition + team_license_limit = None + + def is_unsuspend_non_suspended_member(self): """ - The new role of the member. + Check if the union tag is ``unsuspend_non_suspended_member``. - :rtype: AdminTier + :rtype: bool """ - if self._new_role_present: - return self._new_role_value - else: - raise AttributeError("missing required field 'new_role'") + return self._tag == 'unsuspend_non_suspended_member' - @new_role.setter - def new_role(self, val): - self._new_role_validator.validate_type_only(val) - self._new_role_value = val - self._new_role_present = True + def is_team_license_limit(self): + """ + Check if the union tag is ``team_license_limit``. - @new_role.deleter - def new_role(self): - self._new_role_value = None - self._new_role_present = False + :rtype: bool + """ + return self._tag == 'team_license_limit' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersSetPermissionsArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MembersUnsuspendError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersSetPermissionsArg(user={!r}, new_role={!r})'.format( - self._user_value, - self._new_role_value, - ) + return 'MembersUnsuspendError(%r, %r)' % (self._tag, self._value) -MembersSetPermissionsArg_validator = bv.Struct(MembersSetPermissionsArg) +MembersUnsuspendError_validator = bv.Union(MembersUnsuspendError) -class MembersSetPermissionsError(UserSelectorError): +class MobileClientPlatform(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.MembersSetPermissionsError.last_admin: Cannot remove the admin - setting of the last admin. - :ivar team.MembersSetPermissionsError.user_not_in_team: The user is not a - member of the team. - :ivar team.MembersSetPermissionsError.cannot_set_permissions: Cannot - remove/grant permissions. - :ivar team.MembersSetPermissionsError.team_license_limit: Team is full. The - organization has no available licenses. + :ivar team.MobileClientPlatform.iphone: Official Dropbox iPhone client. + :ivar team.MobileClientPlatform.ipad: Official Dropbox iPad client. + :ivar team.MobileClientPlatform.android: Official Dropbox Android client. + :ivar team.MobileClientPlatform.windows_phone: Official Dropbox Windows + phone client. + :ivar team.MobileClientPlatform.blackberry: Official Dropbox Blackberry + client. """ _catch_all = 'other' # Attribute is overwritten below the class definition - last_admin = None + iphone = None # Attribute is overwritten below the class definition - user_not_in_team = None + ipad = None # Attribute is overwritten below the class definition - cannot_set_permissions = None + android = None # Attribute is overwritten below the class definition - team_license_limit = None + windows_phone = None + # Attribute is overwritten below the class definition + blackberry = None # Attribute is overwritten below the class definition other = None - def is_last_admin(self): + def is_iphone(self): """ - Check if the union tag is ``last_admin``. + Check if the union tag is ``iphone``. :rtype: bool """ - return self._tag == 'last_admin' + return self._tag == 'iphone' - def is_user_not_in_team(self): + def is_ipad(self): + """ + Check if the union tag is ``ipad``. + + :rtype: bool + """ + return self._tag == 'ipad' + + def is_android(self): """ - Check if the union tag is ``user_not_in_team``. + Check if the union tag is ``android``. :rtype: bool """ - return self._tag == 'user_not_in_team' + return self._tag == 'android' - def is_cannot_set_permissions(self): + def is_windows_phone(self): """ - Check if the union tag is ``cannot_set_permissions``. + Check if the union tag is ``windows_phone``. :rtype: bool """ - return self._tag == 'cannot_set_permissions' + return self._tag == 'windows_phone' - def is_team_license_limit(self): + def is_blackberry(self): """ - Check if the union tag is ``team_license_limit``. + Check if the union tag is ``blackberry``. :rtype: bool """ - return self._tag == 'team_license_limit' + return self._tag == 'blackberry' def is_other(self): """ @@ -11275,1226 +15415,1201 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersSetPermissionsError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MobileClientPlatform, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersSetPermissionsError(%r, %r)' % (self._tag, self._value) + return 'MobileClientPlatform(%r, %r)' % (self._tag, self._value) -MembersSetPermissionsError_validator = bv.Union(MembersSetPermissionsError) +MobileClientPlatform_validator = bv.Union(MobileClientPlatform) -class MembersSetPermissionsResult(bb.Struct): +class MobileClientSession(DeviceSession): """ - :ivar team.MembersSetPermissionsResult.team_member_id: The member ID of the - user to which the change was applied. - :ivar team.MembersSetPermissionsResult.role: The role after the change. + Information about linked Dropbox mobile client sessions. + + :ivar team.MobileClientSession.device_name: The device name. + :ivar team.MobileClientSession.client_type: The mobile application type. + :ivar team.MobileClientSession.client_version: The dropbox client version. + :ivar team.MobileClientSession.os_version: The hosting OS version. + :ivar team.MobileClientSession.last_carrier: last carrier used by the + device. """ __slots__ = [ - '_team_member_id_value', - '_team_member_id_present', - '_role_value', - '_role_present', + '_device_name_value', + '_device_name_present', + '_client_type_value', + '_client_type_present', + '_client_version_value', + '_client_version_present', + '_os_version_value', + '_os_version_present', + '_last_carrier_value', + '_last_carrier_present', ] _has_required_fields = True def __init__(self, - team_member_id=None, - role=None): - self._team_member_id_value = None - self._team_member_id_present = False - self._role_value = None - self._role_present = False - if team_member_id is not None: - self.team_member_id = team_member_id - if role is not None: - self.role = role + session_id=None, + device_name=None, + client_type=None, + ip_address=None, + country=None, + created=None, + updated=None, + client_version=None, + os_version=None, + last_carrier=None): + super(MobileClientSession, self).__init__(session_id, + ip_address, + country, + created, + updated) + self._device_name_value = None + self._device_name_present = False + self._client_type_value = None + self._client_type_present = False + self._client_version_value = None + self._client_version_present = False + self._os_version_value = None + self._os_version_present = False + self._last_carrier_value = None + self._last_carrier_present = False + if device_name is not None: + self.device_name = device_name + if client_type is not None: + self.client_type = client_type + if client_version is not None: + self.client_version = client_version + if os_version is not None: + self.os_version = os_version + if last_carrier is not None: + self.last_carrier = last_carrier @property - def team_member_id(self): + def device_name(self): """ - The member ID of the user to which the change was applied. + The device name. :rtype: str """ - if self._team_member_id_present: - return self._team_member_id_value - else: - raise AttributeError("missing required field 'team_member_id'") - - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True - - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False - - @property - def role(self): - """ - The role after the change. - - :rtype: AdminTier - """ - if self._role_present: - return self._role_value + if self._device_name_present: + return self._device_name_value else: - raise AttributeError("missing required field 'role'") - - @role.setter - def role(self, val): - self._role_validator.validate_type_only(val) - self._role_value = val - self._role_present = True - - @role.deleter - def role(self): - self._role_value = None - self._role_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersSetPermissionsResult, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersSetPermissionsResult(team_member_id={!r}, role={!r})'.format( - self._team_member_id_value, - self._role_value, - ) - -MembersSetPermissionsResult_validator = bv.Struct(MembersSetPermissionsResult) - -class MembersSetProfileArg(bb.Struct): - """ - Exactly one of team_member_id, email, or external_id must be provided to - identify the user account. At least one of new_email, new_external_id, - new_given_name, and/or new_surname must be provided. - - :ivar team.MembersSetProfileArg.user: Identity of user whose profile will be - set. - :ivar team.MembersSetProfileArg.new_email: New email for member. - :ivar team.MembersSetProfileArg.new_external_id: New external ID for member. - :ivar team.MembersSetProfileArg.new_given_name: New given name for member. - :ivar team.MembersSetProfileArg.new_surname: New surname for member. - :ivar team.MembersSetProfileArg.new_persistent_id: New persistent ID. This - field only available to teams using persistent ID SAML configuration. - :ivar team.MembersSetProfileArg.new_is_directory_restricted: New value for - whether the user is a directory restricted user. - """ - - __slots__ = [ - '_user_value', - '_user_present', - '_new_email_value', - '_new_email_present', - '_new_external_id_value', - '_new_external_id_present', - '_new_given_name_value', - '_new_given_name_present', - '_new_surname_value', - '_new_surname_present', - '_new_persistent_id_value', - '_new_persistent_id_present', - '_new_is_directory_restricted_value', - '_new_is_directory_restricted_present', - ] + raise AttributeError("missing required field 'device_name'") - _has_required_fields = True + @device_name.setter + def device_name(self, val): + val = self._device_name_validator.validate(val) + self._device_name_value = val + self._device_name_present = True - def __init__(self, - user=None, - new_email=None, - new_external_id=None, - new_given_name=None, - new_surname=None, - new_persistent_id=None, - new_is_directory_restricted=None): - self._user_value = None - self._user_present = False - self._new_email_value = None - self._new_email_present = False - self._new_external_id_value = None - self._new_external_id_present = False - self._new_given_name_value = None - self._new_given_name_present = False - self._new_surname_value = None - self._new_surname_present = False - self._new_persistent_id_value = None - self._new_persistent_id_present = False - self._new_is_directory_restricted_value = None - self._new_is_directory_restricted_present = False - if user is not None: - self.user = user - if new_email is not None: - self.new_email = new_email - if new_external_id is not None: - self.new_external_id = new_external_id - if new_given_name is not None: - self.new_given_name = new_given_name - if new_surname is not None: - self.new_surname = new_surname - if new_persistent_id is not None: - self.new_persistent_id = new_persistent_id - if new_is_directory_restricted is not None: - self.new_is_directory_restricted = new_is_directory_restricted + @device_name.deleter + def device_name(self): + self._device_name_value = None + self._device_name_present = False @property - def user(self): + def client_type(self): """ - Identity of user whose profile will be set. + The mobile application type. - :rtype: UserSelectorArg + :rtype: MobileClientPlatform """ - if self._user_present: - return self._user_value + if self._client_type_present: + return self._client_type_value else: - raise AttributeError("missing required field 'user'") - - @user.setter - def user(self, val): - self._user_validator.validate_type_only(val) - self._user_value = val - self._user_present = True + raise AttributeError("missing required field 'client_type'") - @user.deleter - def user(self): - self._user_value = None - self._user_present = False + @client_type.setter + def client_type(self, val): + self._client_type_validator.validate_type_only(val) + self._client_type_value = val + self._client_type_present = True + + @client_type.deleter + def client_type(self): + self._client_type_value = None + self._client_type_present = False @property - def new_email(self): + def client_version(self): """ - New email for member. + The dropbox client version. :rtype: str """ - if self._new_email_present: - return self._new_email_value + if self._client_version_present: + return self._client_version_value else: return None - @new_email.setter - def new_email(self, val): + @client_version.setter + def client_version(self, val): if val is None: - del self.new_email + del self.client_version return - val = self._new_email_validator.validate(val) - self._new_email_value = val - self._new_email_present = True + val = self._client_version_validator.validate(val) + self._client_version_value = val + self._client_version_present = True - @new_email.deleter - def new_email(self): - self._new_email_value = None - self._new_email_present = False + @client_version.deleter + def client_version(self): + self._client_version_value = None + self._client_version_present = False @property - def new_external_id(self): + def os_version(self): """ - New external ID for member. + The hosting OS version. :rtype: str """ - if self._new_external_id_present: - return self._new_external_id_value + if self._os_version_present: + return self._os_version_value else: return None - @new_external_id.setter - def new_external_id(self, val): + @os_version.setter + def os_version(self, val): if val is None: - del self.new_external_id + del self.os_version return - val = self._new_external_id_validator.validate(val) - self._new_external_id_value = val - self._new_external_id_present = True + val = self._os_version_validator.validate(val) + self._os_version_value = val + self._os_version_present = True - @new_external_id.deleter - def new_external_id(self): - self._new_external_id_value = None - self._new_external_id_present = False + @os_version.deleter + def os_version(self): + self._os_version_value = None + self._os_version_present = False @property - def new_given_name(self): + def last_carrier(self): """ - New given name for member. + last carrier used by the device. :rtype: str """ - if self._new_given_name_present: - return self._new_given_name_value + if self._last_carrier_present: + return self._last_carrier_value else: return None - @new_given_name.setter - def new_given_name(self, val): + @last_carrier.setter + def last_carrier(self, val): if val is None: - del self.new_given_name + del self.last_carrier return - val = self._new_given_name_validator.validate(val) - self._new_given_name_value = val - self._new_given_name_present = True + val = self._last_carrier_validator.validate(val) + self._last_carrier_value = val + self._last_carrier_present = True - @new_given_name.deleter - def new_given_name(self): - self._new_given_name_value = None - self._new_given_name_present = False + @last_carrier.deleter + def last_carrier(self): + self._last_carrier_value = None + self._last_carrier_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MobileClientSession, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MobileClientSession(session_id={!r}, device_name={!r}, client_type={!r}, ip_address={!r}, country={!r}, created={!r}, updated={!r}, client_version={!r}, os_version={!r}, last_carrier={!r})'.format( + self._session_id_value, + self._device_name_value, + self._client_type_value, + self._ip_address_value, + self._country_value, + self._created_value, + self._updated_value, + self._client_version_value, + self._os_version_value, + self._last_carrier_value, + ) + +MobileClientSession_validator = bv.Struct(MobileClientSession) + +class NamespaceMetadata(bb.Struct): + """ + Properties of a namespace. + + :ivar team.NamespaceMetadata.name: The name of this namespace. + :ivar team.NamespaceMetadata.namespace_id: The ID of this namespace. + :ivar team.NamespaceMetadata.namespace_type: The type of this namespace. + :ivar team.NamespaceMetadata.team_member_id: If this is a team member or app + folder, the ID of the owning team member. Otherwise, this field is not + present. + """ + + __slots__ = [ + '_name_value', + '_name_present', + '_namespace_id_value', + '_namespace_id_present', + '_namespace_type_value', + '_namespace_type_present', + '_team_member_id_value', + '_team_member_id_present', + ] + + _has_required_fields = True + + def __init__(self, + name=None, + namespace_id=None, + namespace_type=None, + team_member_id=None): + self._name_value = None + self._name_present = False + self._namespace_id_value = None + self._namespace_id_present = False + self._namespace_type_value = None + self._namespace_type_present = False + self._team_member_id_value = None + self._team_member_id_present = False + if name is not None: + self.name = name + if namespace_id is not None: + self.namespace_id = namespace_id + if namespace_type is not None: + self.namespace_type = namespace_type + if team_member_id is not None: + self.team_member_id = team_member_id @property - def new_surname(self): + def name(self): """ - New surname for member. + The name of this namespace. :rtype: str """ - if self._new_surname_present: - return self._new_surname_value + if self._name_present: + return self._name_value else: - return None + raise AttributeError("missing required field 'name'") - @new_surname.setter - def new_surname(self, val): - if val is None: - del self.new_surname - return - val = self._new_surname_validator.validate(val) - self._new_surname_value = val - self._new_surname_present = True + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True - @new_surname.deleter - def new_surname(self): - self._new_surname_value = None - self._new_surname_present = False + @name.deleter + def name(self): + self._name_value = None + self._name_present = False @property - def new_persistent_id(self): + def namespace_id(self): """ - New persistent ID. This field only available to teams using persistent - ID SAML configuration. + The ID of this namespace. :rtype: str """ - if self._new_persistent_id_present: - return self._new_persistent_id_value + if self._namespace_id_present: + return self._namespace_id_value else: - return None + raise AttributeError("missing required field 'namespace_id'") - @new_persistent_id.setter - def new_persistent_id(self, val): - if val is None: - del self.new_persistent_id - return - val = self._new_persistent_id_validator.validate(val) - self._new_persistent_id_value = val - self._new_persistent_id_present = True + @namespace_id.setter + def namespace_id(self, val): + val = self._namespace_id_validator.validate(val) + self._namespace_id_value = val + self._namespace_id_present = True - @new_persistent_id.deleter - def new_persistent_id(self): - self._new_persistent_id_value = None - self._new_persistent_id_present = False + @namespace_id.deleter + def namespace_id(self): + self._namespace_id_value = None + self._namespace_id_present = False @property - def new_is_directory_restricted(self): + def namespace_type(self): """ - New value for whether the user is a directory restricted user. + The type of this namespace. - :rtype: bool + :rtype: NamespaceType """ - if self._new_is_directory_restricted_present: - return self._new_is_directory_restricted_value + if self._namespace_type_present: + return self._namespace_type_value + else: + raise AttributeError("missing required field 'namespace_type'") + + @namespace_type.setter + def namespace_type(self, val): + self._namespace_type_validator.validate_type_only(val) + self._namespace_type_value = val + self._namespace_type_present = True + + @namespace_type.deleter + def namespace_type(self): + self._namespace_type_value = None + self._namespace_type_present = False + + @property + def team_member_id(self): + """ + If this is a team member or app folder, the ID of the owning team + member. Otherwise, this field is not present. + + :rtype: str + """ + if self._team_member_id_present: + return self._team_member_id_value else: return None - @new_is_directory_restricted.setter - def new_is_directory_restricted(self, val): + @team_member_id.setter + def team_member_id(self, val): if val is None: - del self.new_is_directory_restricted + del self.team_member_id return - val = self._new_is_directory_restricted_validator.validate(val) - self._new_is_directory_restricted_value = val - self._new_is_directory_restricted_present = True + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - @new_is_directory_restricted.deleter - def new_is_directory_restricted(self): - self._new_is_directory_restricted_value = None - self._new_is_directory_restricted_present = False + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersSetProfileArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NamespaceMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersSetProfileArg(user={!r}, new_email={!r}, new_external_id={!r}, new_given_name={!r}, new_surname={!r}, new_persistent_id={!r}, new_is_directory_restricted={!r})'.format( - self._user_value, - self._new_email_value, - self._new_external_id_value, - self._new_given_name_value, - self._new_surname_value, - self._new_persistent_id_value, - self._new_is_directory_restricted_value, + return 'NamespaceMetadata(name={!r}, namespace_id={!r}, namespace_type={!r}, team_member_id={!r})'.format( + self._name_value, + self._namespace_id_value, + self._namespace_type_value, + self._team_member_id_value, ) -MembersSetProfileArg_validator = bv.Struct(MembersSetProfileArg) +NamespaceMetadata_validator = bv.Struct(NamespaceMetadata) -class MembersSetProfileError(MemberSelectorError): +class NamespaceType(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.MembersSetProfileError.external_id_and_new_external_id_unsafe: It - is unsafe to use both external_id and new_external_id. - :ivar team.MembersSetProfileError.no_new_data_specified: None of new_email, - new_given_name, new_surname, or new_external_id are specified. - :ivar team.MembersSetProfileError.email_reserved_for_other_user: Email is - already reserved for another user. - :ivar team.MembersSetProfileError.external_id_used_by_other_user: The - external ID is already in use by another team member. - :ivar team.MembersSetProfileError.set_profile_disallowed: Modifying deleted - users is not allowed. - :ivar team.MembersSetProfileError.param_cannot_be_empty: Parameter new_email - cannot be empty. - :ivar team.MembersSetProfileError.persistent_id_disabled: Persistent ID is - only available to teams with persistent ID SAML configuration. Please - contact Dropbox for more information. - :ivar team.MembersSetProfileError.persistent_id_used_by_other_user: The - persistent ID is already in use by another team member. - :ivar team.MembersSetProfileError.directory_restricted_off: Directory - Restrictions option is not available. + :ivar team.NamespaceType.app_folder: App sandbox folder. + :ivar team.NamespaceType.shared_folder: Shared folder. + :ivar team.NamespaceType.team_folder: Top-level team-owned folder. + :ivar team.NamespaceType.team_member_folder: Team member's home folder. """ _catch_all = 'other' # Attribute is overwritten below the class definition - external_id_and_new_external_id_unsafe = None - # Attribute is overwritten below the class definition - no_new_data_specified = None - # Attribute is overwritten below the class definition - email_reserved_for_other_user = None - # Attribute is overwritten below the class definition - external_id_used_by_other_user = None - # Attribute is overwritten below the class definition - set_profile_disallowed = None - # Attribute is overwritten below the class definition - param_cannot_be_empty = None + app_folder = None # Attribute is overwritten below the class definition - persistent_id_disabled = None + shared_folder = None # Attribute is overwritten below the class definition - persistent_id_used_by_other_user = None + team_folder = None # Attribute is overwritten below the class definition - directory_restricted_off = None + team_member_folder = None # Attribute is overwritten below the class definition other = None - def is_external_id_and_new_external_id_unsafe(self): + def is_app_folder(self): """ - Check if the union tag is ``external_id_and_new_external_id_unsafe``. + Check if the union tag is ``app_folder``. :rtype: bool """ - return self._tag == 'external_id_and_new_external_id_unsafe' + return self._tag == 'app_folder' - def is_no_new_data_specified(self): + def is_shared_folder(self): """ - Check if the union tag is ``no_new_data_specified``. + Check if the union tag is ``shared_folder``. :rtype: bool """ - return self._tag == 'no_new_data_specified' + return self._tag == 'shared_folder' - def is_email_reserved_for_other_user(self): + def is_team_folder(self): """ - Check if the union tag is ``email_reserved_for_other_user``. + Check if the union tag is ``team_folder``. :rtype: bool """ - return self._tag == 'email_reserved_for_other_user' + return self._tag == 'team_folder' - def is_external_id_used_by_other_user(self): + def is_team_member_folder(self): """ - Check if the union tag is ``external_id_used_by_other_user``. + Check if the union tag is ``team_member_folder``. :rtype: bool """ - return self._tag == 'external_id_used_by_other_user' + return self._tag == 'team_member_folder' - def is_set_profile_disallowed(self): + def is_other(self): """ - Check if the union tag is ``set_profile_disallowed``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'set_profile_disallowed' + return self._tag == 'other' - def is_param_cannot_be_empty(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(NamespaceType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'NamespaceType(%r, %r)' % (self._tag, self._value) + +NamespaceType_validator = bv.Union(NamespaceType) + +class RemoveCustomQuotaResult(bb.Union): + """ + User result for setting member custom quota. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar UserSelectorArg RemoveCustomQuotaResult.success: Successfully removed + user. + :ivar UserSelectorArg RemoveCustomQuotaResult.invalid_user: Invalid user + (not in team). + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def success(cls, val): """ - Check if the union tag is ``param_cannot_be_empty``. + Create an instance of this class set to the ``success`` tag with value + ``val``. + + :param UserSelectorArg val: + :rtype: RemoveCustomQuotaResult + """ + return cls('success', val) + + @classmethod + def invalid_user(cls, val): + """ + Create an instance of this class set to the ``invalid_user`` tag with + value ``val``. + + :param UserSelectorArg val: + :rtype: RemoveCustomQuotaResult + """ + return cls('invalid_user', val) + + def is_success(self): + """ + Check if the union tag is ``success``. :rtype: bool """ - return self._tag == 'param_cannot_be_empty' + return self._tag == 'success' - def is_persistent_id_disabled(self): + def is_invalid_user(self): """ - Check if the union tag is ``persistent_id_disabled``. + Check if the union tag is ``invalid_user``. :rtype: bool """ - return self._tag == 'persistent_id_disabled' + return self._tag == 'invalid_user' - def is_persistent_id_used_by_other_user(self): + def is_other(self): """ - Check if the union tag is ``persistent_id_used_by_other_user``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'persistent_id_used_by_other_user' + return self._tag == 'other' - def is_directory_restricted_off(self): + def get_success(self): """ - Check if the union tag is ``directory_restricted_off``. + Successfully removed user. + + Only call this if :meth:`is_success` is true. + + :rtype: UserSelectorArg + """ + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value + + def get_invalid_user(self): + """ + Invalid user (not in team). + + Only call this if :meth:`is_invalid_user` is true. + + :rtype: UserSelectorArg + """ + if not self.is_invalid_user(): + raise AttributeError("tag 'invalid_user' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RemoveCustomQuotaResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RemoveCustomQuotaResult(%r, %r)' % (self._tag, self._value) + +RemoveCustomQuotaResult_validator = bv.Union(RemoveCustomQuotaResult) + +class RemovedStatus(bb.Struct): + """ + :ivar team.RemovedStatus.is_recoverable: True if the removed team member is + recoverable. + :ivar team.RemovedStatus.is_disconnected: True if the team member's account + was converted to individual account. + """ + + __slots__ = [ + '_is_recoverable_value', + '_is_recoverable_present', + '_is_disconnected_value', + '_is_disconnected_present', + ] + + _has_required_fields = True + + def __init__(self, + is_recoverable=None, + is_disconnected=None): + self._is_recoverable_value = None + self._is_recoverable_present = False + self._is_disconnected_value = None + self._is_disconnected_present = False + if is_recoverable is not None: + self.is_recoverable = is_recoverable + if is_disconnected is not None: + self.is_disconnected = is_disconnected + + @property + def is_recoverable(self): + """ + True if the removed team member is recoverable. :rtype: bool """ - return self._tag == 'directory_restricted_off' + if self._is_recoverable_present: + return self._is_recoverable_value + else: + raise AttributeError("missing required field 'is_recoverable'") + + @is_recoverable.setter + def is_recoverable(self, val): + val = self._is_recoverable_validator.validate(val) + self._is_recoverable_value = val + self._is_recoverable_present = True + + @is_recoverable.deleter + def is_recoverable(self): + self._is_recoverable_value = None + self._is_recoverable_present = False - def is_other(self): + @property + def is_disconnected(self): """ - Check if the union tag is ``other``. + True if the team member's account was converted to individual account. :rtype: bool """ - return self._tag == 'other' + if self._is_disconnected_present: + return self._is_disconnected_value + else: + raise AttributeError("missing required field 'is_disconnected'") + + @is_disconnected.setter + def is_disconnected(self, val): + val = self._is_disconnected_validator.validate(val) + self._is_disconnected_value = val + self._is_disconnected_present = True + + @is_disconnected.deleter + def is_disconnected(self): + self._is_disconnected_value = None + self._is_disconnected_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersSetProfileError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RemovedStatus, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersSetProfileError(%r, %r)' % (self._tag, self._value) + return 'RemovedStatus(is_recoverable={!r}, is_disconnected={!r})'.format( + self._is_recoverable_value, + self._is_disconnected_value, + ) -MembersSetProfileError_validator = bv.Union(MembersSetProfileError) +RemovedStatus_validator = bv.Struct(RemovedStatus) -class MembersSuspendError(MembersDeactivateError): +class ResendSecondaryEmailResult(bb.Union): """ + Result of trying to resend verification email to a secondary email address. + 'success' is the only value indicating that a verification email was + successfully sent. The other values explain the type of error that occurred, + and include the email for which the error occured. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.MembersSuspendError.suspend_inactive_user: The user is not - active, so it cannot be suspended. - :ivar team.MembersSuspendError.suspend_last_admin: The user is the last - admin of the team, so it cannot be suspended. - :ivar team.MembersSuspendError.team_license_limit: Team is full. The - organization has no available licenses. + :ivar str team.ResendSecondaryEmailResult.success: A verification email was + successfully sent to the secondary email address. + :ivar str team.ResendSecondaryEmailResult.not_pending: This secondary email + address is not pending for the user. + :ivar str team.ResendSecondaryEmailResult.rate_limited: Too many emails are + being sent to this email address. Please try again later. """ + _catch_all = 'other' # Attribute is overwritten below the class definition - suspend_inactive_user = None - # Attribute is overwritten below the class definition - suspend_last_admin = None - # Attribute is overwritten below the class definition - team_license_limit = None + other = None - def is_suspend_inactive_user(self): + @classmethod + def success(cls, val): """ - Check if the union tag is ``suspend_inactive_user``. + Create an instance of this class set to the ``success`` tag with value + ``val``. - :rtype: bool + :param str val: + :rtype: ResendSecondaryEmailResult """ - return self._tag == 'suspend_inactive_user' + return cls('success', val) - def is_suspend_last_admin(self): + @classmethod + def not_pending(cls, val): """ - Check if the union tag is ``suspend_last_admin``. + Create an instance of this class set to the ``not_pending`` tag with + value ``val``. - :rtype: bool + :param str val: + :rtype: ResendSecondaryEmailResult """ - return self._tag == 'suspend_last_admin' + return cls('not_pending', val) - def is_team_license_limit(self): + @classmethod + def rate_limited(cls, val): """ - Check if the union tag is ``team_license_limit``. + Create an instance of this class set to the ``rate_limited`` tag with + value ``val``. - :rtype: bool + :param str val: + :rtype: ResendSecondaryEmailResult """ - return self._tag == 'team_license_limit' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersSuspendError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersSuspendError(%r, %r)' % (self._tag, self._value) - -MembersSuspendError_validator = bv.Union(MembersSuspendError) - -class MembersTransferFormerMembersFilesError(MembersTransferFilesError): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar - team.MembersTransferFormerMembersFilesError.user_data_is_being_transferred: - The user's data is being transferred. Please wait some time before - retrying. - :ivar team.MembersTransferFormerMembersFilesError.user_not_removed: No - matching removed user found for the argument user. - :ivar - team.MembersTransferFormerMembersFilesError.user_data_cannot_be_transferred: - User files aren't transferable anymore. - :ivar - team.MembersTransferFormerMembersFilesError.user_data_already_transferred: - User's data has already been transferred to another user. - """ - - # Attribute is overwritten below the class definition - user_data_is_being_transferred = None - # Attribute is overwritten below the class definition - user_not_removed = None - # Attribute is overwritten below the class definition - user_data_cannot_be_transferred = None - # Attribute is overwritten below the class definition - user_data_already_transferred = None + return cls('rate_limited', val) - def is_user_data_is_being_transferred(self): + def is_success(self): """ - Check if the union tag is ``user_data_is_being_transferred``. + Check if the union tag is ``success``. :rtype: bool """ - return self._tag == 'user_data_is_being_transferred' + return self._tag == 'success' - def is_user_not_removed(self): + def is_not_pending(self): """ - Check if the union tag is ``user_not_removed``. + Check if the union tag is ``not_pending``. :rtype: bool """ - return self._tag == 'user_not_removed' + return self._tag == 'not_pending' - def is_user_data_cannot_be_transferred(self): + def is_rate_limited(self): """ - Check if the union tag is ``user_data_cannot_be_transferred``. + Check if the union tag is ``rate_limited``. :rtype: bool """ - return self._tag == 'user_data_cannot_be_transferred' + return self._tag == 'rate_limited' - def is_user_data_already_transferred(self): + def is_other(self): """ - Check if the union tag is ``user_data_already_transferred``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'user_data_already_transferred' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersTransferFormerMembersFilesError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersTransferFormerMembersFilesError(%r, %r)' % (self._tag, self._value) - -MembersTransferFormerMembersFilesError_validator = bv.Union(MembersTransferFormerMembersFilesError) + return self._tag == 'other' -class MembersUnsuspendArg(bb.Struct): - """ - Exactly one of team_member_id, email, or external_id must be provided to - identify the user account. + def get_success(self): + """ + A verification email was successfully sent to the secondary email + address. - :ivar team.MembersUnsuspendArg.user: Identity of user to unsuspend. - """ + Only call this if :meth:`is_success` is true. - __slots__ = [ - '_user_value', - '_user_present', - ] + :rtype: str + """ + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value - _has_required_fields = True + def get_not_pending(self): + """ + This secondary email address is not pending for the user. - def __init__(self, - user=None): - self._user_value = None - self._user_present = False - if user is not None: - self.user = user + Only call this if :meth:`is_not_pending` is true. - @property - def user(self): + :rtype: str """ - Identity of user to unsuspend. + if not self.is_not_pending(): + raise AttributeError("tag 'not_pending' not set") + return self._value - :rtype: UserSelectorArg + def get_rate_limited(self): """ - if self._user_present: - return self._user_value - else: - raise AttributeError("missing required field 'user'") + Too many emails are being sent to this email address. Please try again + later. - @user.setter - def user(self, val): - self._user_validator.validate_type_only(val) - self._user_value = val - self._user_present = True + Only call this if :meth:`is_rate_limited` is true. - @user.deleter - def user(self): - self._user_value = None - self._user_present = False + :rtype: str + """ + if not self.is_rate_limited(): + raise AttributeError("tag 'rate_limited' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersUnsuspendArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResendSecondaryEmailResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MembersUnsuspendArg(user={!r})'.format( - self._user_value, - ) + return 'ResendSecondaryEmailResult(%r, %r)' % (self._tag, self._value) -MembersUnsuspendArg_validator = bv.Struct(MembersUnsuspendArg) +ResendSecondaryEmailResult_validator = bv.Union(ResendSecondaryEmailResult) -class MembersUnsuspendError(MembersDeactivateError): +class ResendVerificationEmailArg(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.MembersUnsuspendError.unsuspend_non_suspended_member: The user is - unsuspended, so it cannot be unsuspended again. - :ivar team.MembersUnsuspendError.team_license_limit: Team is full. The - organization has no available licenses. + :ivar team.ResendVerificationEmailArg.emails_to_resend: List of users and + secondary emails to resend verification emails to. """ - # Attribute is overwritten below the class definition - unsuspend_non_suspended_member = None - # Attribute is overwritten below the class definition - team_license_limit = None + __slots__ = [ + '_emails_to_resend_value', + '_emails_to_resend_present', + ] - def is_unsuspend_non_suspended_member(self): - """ - Check if the union tag is ``unsuspend_non_suspended_member``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'unsuspend_non_suspended_member' + def __init__(self, + emails_to_resend=None): + self._emails_to_resend_value = None + self._emails_to_resend_present = False + if emails_to_resend is not None: + self.emails_to_resend = emails_to_resend - def is_team_license_limit(self): + @property + def emails_to_resend(self): """ - Check if the union tag is ``team_license_limit``. + List of users and secondary emails to resend verification emails to. - :rtype: bool + :rtype: list of [UserSecondaryEmailsArg] """ - return self._tag == 'team_license_limit' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MembersUnsuspendError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MembersUnsuspendError(%r, %r)' % (self._tag, self._value) - -MembersUnsuspendError_validator = bv.Union(MembersUnsuspendError) - -class MobileClientPlatform(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.MobileClientPlatform.iphone: Official Dropbox iPhone client. - :ivar team.MobileClientPlatform.ipad: Official Dropbox iPad client. - :ivar team.MobileClientPlatform.android: Official Dropbox Android client. - :ivar team.MobileClientPlatform.windows_phone: Official Dropbox Windows - phone client. - :ivar team.MobileClientPlatform.blackberry: Official Dropbox Blackberry - client. - """ + if self._emails_to_resend_present: + return self._emails_to_resend_value + else: + raise AttributeError("missing required field 'emails_to_resend'") - _catch_all = 'other' - # Attribute is overwritten below the class definition - iphone = None - # Attribute is overwritten below the class definition - ipad = None - # Attribute is overwritten below the class definition - android = None - # Attribute is overwritten below the class definition - windows_phone = None - # Attribute is overwritten below the class definition - blackberry = None - # Attribute is overwritten below the class definition - other = None + @emails_to_resend.setter + def emails_to_resend(self, val): + val = self._emails_to_resend_validator.validate(val) + self._emails_to_resend_value = val + self._emails_to_resend_present = True - def is_iphone(self): - """ - Check if the union tag is ``iphone``. + @emails_to_resend.deleter + def emails_to_resend(self): + self._emails_to_resend_value = None + self._emails_to_resend_present = False - :rtype: bool - """ - return self._tag == 'iphone' + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ResendVerificationEmailArg, self)._process_custom_annotations(annotation_type, field_path, processor) - def is_ipad(self): - """ - Check if the union tag is ``ipad``. + def __repr__(self): + return 'ResendVerificationEmailArg(emails_to_resend={!r})'.format( + self._emails_to_resend_value, + ) - :rtype: bool - """ - return self._tag == 'ipad' +ResendVerificationEmailArg_validator = bv.Struct(ResendVerificationEmailArg) - def is_android(self): - """ - Check if the union tag is ``android``. +class ResendVerificationEmailResult(bb.Struct): + """ + List of users and resend results. + """ - :rtype: bool - """ - return self._tag == 'android' + __slots__ = [ + '_results_value', + '_results_present', + ] - def is_windows_phone(self): - """ - Check if the union tag is ``windows_phone``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'windows_phone' + def __init__(self, + results=None): + self._results_value = None + self._results_present = False + if results is not None: + self.results = results - def is_blackberry(self): + @property + def results(self): """ - Check if the union tag is ``blackberry``. - - :rtype: bool + :rtype: list of [UserResendResult] """ - return self._tag == 'blackberry' + if self._results_present: + return self._results_value + else: + raise AttributeError("missing required field 'results'") - def is_other(self): - """ - Check if the union tag is ``other``. + @results.setter + def results(self, val): + val = self._results_validator.validate(val) + self._results_value = val + self._results_present = True - :rtype: bool - """ - return self._tag == 'other' + @results.deleter + def results(self): + self._results_value = None + self._results_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MobileClientPlatform, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResendVerificationEmailResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MobileClientPlatform(%r, %r)' % (self._tag, self._value) + return 'ResendVerificationEmailResult(results={!r})'.format( + self._results_value, + ) -MobileClientPlatform_validator = bv.Union(MobileClientPlatform) +ResendVerificationEmailResult_validator = bv.Struct(ResendVerificationEmailResult) -class MobileClientSession(DeviceSession): +class RevokeDesktopClientArg(DeviceSessionArg): """ - Information about linked Dropbox mobile client sessions. - - :ivar team.MobileClientSession.device_name: The device name. - :ivar team.MobileClientSession.client_type: The mobile application type. - :ivar team.MobileClientSession.client_version: The dropbox client version. - :ivar team.MobileClientSession.os_version: The hosting OS version. - :ivar team.MobileClientSession.last_carrier: last carrier used by the - device. + :ivar team.RevokeDesktopClientArg.delete_on_unlink: Whether to delete all + files of the account (this is possible only if supported by the desktop + client and will be made the next time the client access the account). """ __slots__ = [ - '_device_name_value', - '_device_name_present', - '_client_type_value', - '_client_type_present', - '_client_version_value', - '_client_version_present', - '_os_version_value', - '_os_version_present', - '_last_carrier_value', - '_last_carrier_present', + '_delete_on_unlink_value', + '_delete_on_unlink_present', ] _has_required_fields = True def __init__(self, session_id=None, - device_name=None, - client_type=None, - ip_address=None, - country=None, - created=None, - updated=None, - client_version=None, - os_version=None, - last_carrier=None): - super(MobileClientSession, self).__init__(session_id, - ip_address, - country, - created, - updated) - self._device_name_value = None - self._device_name_present = False - self._client_type_value = None - self._client_type_present = False - self._client_version_value = None - self._client_version_present = False - self._os_version_value = None - self._os_version_present = False - self._last_carrier_value = None - self._last_carrier_present = False - if device_name is not None: - self.device_name = device_name - if client_type is not None: - self.client_type = client_type - if client_version is not None: - self.client_version = client_version - if os_version is not None: - self.os_version = os_version - if last_carrier is not None: - self.last_carrier = last_carrier + team_member_id=None, + delete_on_unlink=None): + super(RevokeDesktopClientArg, self).__init__(session_id, + team_member_id) + self._delete_on_unlink_value = None + self._delete_on_unlink_present = False + if delete_on_unlink is not None: + self.delete_on_unlink = delete_on_unlink @property - def device_name(self): + def delete_on_unlink(self): """ - The device name. + Whether to delete all files of the account (this is possible only if + supported by the desktop client and will be made the next time the + client access the account). - :rtype: str + :rtype: bool """ - if self._device_name_present: - return self._device_name_value + if self._delete_on_unlink_present: + return self._delete_on_unlink_value else: - raise AttributeError("missing required field 'device_name'") + return False - @device_name.setter - def device_name(self, val): - val = self._device_name_validator.validate(val) - self._device_name_value = val - self._device_name_present = True + @delete_on_unlink.setter + def delete_on_unlink(self, val): + val = self._delete_on_unlink_validator.validate(val) + self._delete_on_unlink_value = val + self._delete_on_unlink_present = True - @device_name.deleter - def device_name(self): - self._device_name_value = None - self._device_name_present = False + @delete_on_unlink.deleter + def delete_on_unlink(self): + self._delete_on_unlink_value = None + self._delete_on_unlink_present = False - @property - def client_type(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RevokeDesktopClientArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'RevokeDesktopClientArg(session_id={!r}, team_member_id={!r}, delete_on_unlink={!r})'.format( + self._session_id_value, + self._team_member_id_value, + self._delete_on_unlink_value, + ) + +RevokeDesktopClientArg_validator = bv.Struct(RevokeDesktopClientArg) + +class RevokeDeviceSessionArg(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar DeviceSessionArg RevokeDeviceSessionArg.web_session: End an active + session. + :ivar RevokeDesktopClientArg RevokeDeviceSessionArg.desktop_client: Unlink a + linked desktop device. + :ivar DeviceSessionArg RevokeDeviceSessionArg.mobile_client: Unlink a linked + mobile device. + """ + + _catch_all = None + + @classmethod + def web_session(cls, val): """ - The mobile application type. + Create an instance of this class set to the ``web_session`` tag with + value ``val``. - :rtype: MobileClientPlatform + :param DeviceSessionArg val: + :rtype: RevokeDeviceSessionArg """ - if self._client_type_present: - return self._client_type_value - else: - raise AttributeError("missing required field 'client_type'") + return cls('web_session', val) - @client_type.setter - def client_type(self, val): - self._client_type_validator.validate_type_only(val) - self._client_type_value = val - self._client_type_present = True + @classmethod + def desktop_client(cls, val): + """ + Create an instance of this class set to the ``desktop_client`` tag with + value ``val``. - @client_type.deleter - def client_type(self): - self._client_type_value = None - self._client_type_present = False + :param RevokeDesktopClientArg val: + :rtype: RevokeDeviceSessionArg + """ + return cls('desktop_client', val) - @property - def client_version(self): + @classmethod + def mobile_client(cls, val): """ - The dropbox client version. + Create an instance of this class set to the ``mobile_client`` tag with + value ``val``. - :rtype: str + :param DeviceSessionArg val: + :rtype: RevokeDeviceSessionArg """ - if self._client_version_present: - return self._client_version_value - else: - return None + return cls('mobile_client', val) - @client_version.setter - def client_version(self, val): - if val is None: - del self.client_version - return - val = self._client_version_validator.validate(val) - self._client_version_value = val - self._client_version_present = True + def is_web_session(self): + """ + Check if the union tag is ``web_session``. - @client_version.deleter - def client_version(self): - self._client_version_value = None - self._client_version_present = False + :rtype: bool + """ + return self._tag == 'web_session' - @property - def os_version(self): + def is_desktop_client(self): + """ + Check if the union tag is ``desktop_client``. + + :rtype: bool + """ + return self._tag == 'desktop_client' + + def is_mobile_client(self): + """ + Check if the union tag is ``mobile_client``. + + :rtype: bool + """ + return self._tag == 'mobile_client' + + def get_web_session(self): """ - The hosting OS version. + End an active session. - :rtype: str + Only call this if :meth:`is_web_session` is true. + + :rtype: DeviceSessionArg """ - if self._os_version_present: - return self._os_version_value - else: - return None + if not self.is_web_session(): + raise AttributeError("tag 'web_session' not set") + return self._value - @os_version.setter - def os_version(self, val): - if val is None: - del self.os_version - return - val = self._os_version_validator.validate(val) - self._os_version_value = val - self._os_version_present = True + def get_desktop_client(self): + """ + Unlink a linked desktop device. - @os_version.deleter - def os_version(self): - self._os_version_value = None - self._os_version_present = False + Only call this if :meth:`is_desktop_client` is true. - @property - def last_carrier(self): + :rtype: RevokeDesktopClientArg """ - last carrier used by the device. + if not self.is_desktop_client(): + raise AttributeError("tag 'desktop_client' not set") + return self._value - :rtype: str + def get_mobile_client(self): """ - if self._last_carrier_present: - return self._last_carrier_value - else: - return None + Unlink a linked mobile device. - @last_carrier.setter - def last_carrier(self, val): - if val is None: - del self.last_carrier - return - val = self._last_carrier_validator.validate(val) - self._last_carrier_value = val - self._last_carrier_present = True + Only call this if :meth:`is_mobile_client` is true. - @last_carrier.deleter - def last_carrier(self): - self._last_carrier_value = None - self._last_carrier_present = False + :rtype: DeviceSessionArg + """ + if not self.is_mobile_client(): + raise AttributeError("tag 'mobile_client' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MobileClientSession, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeDeviceSessionArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MobileClientSession(session_id={!r}, device_name={!r}, client_type={!r}, ip_address={!r}, country={!r}, created={!r}, updated={!r}, client_version={!r}, os_version={!r}, last_carrier={!r})'.format( - self._session_id_value, - self._device_name_value, - self._client_type_value, - self._ip_address_value, - self._country_value, - self._created_value, - self._updated_value, - self._client_version_value, - self._os_version_value, - self._last_carrier_value, - ) - -MobileClientSession_validator = bv.Struct(MobileClientSession) + return 'RevokeDeviceSessionArg(%r, %r)' % (self._tag, self._value) -class NamespaceMetadata(bb.Struct): - """ - Properties of a namespace. +RevokeDeviceSessionArg_validator = bv.Union(RevokeDeviceSessionArg) - :ivar team.NamespaceMetadata.name: The name of this namespace. - :ivar team.NamespaceMetadata.namespace_id: The ID of this namespace. - :ivar team.NamespaceMetadata.namespace_type: The type of this namespace. - :ivar team.NamespaceMetadata.team_member_id: If this is a team member or app - folder, the ID of the owning team member. Otherwise, this field is not - present. - """ +class RevokeDeviceSessionBatchArg(bb.Struct): __slots__ = [ - '_name_value', - '_name_present', - '_namespace_id_value', - '_namespace_id_present', - '_namespace_type_value', - '_namespace_type_present', - '_team_member_id_value', - '_team_member_id_present', + '_revoke_devices_value', + '_revoke_devices_present', ] _has_required_fields = True def __init__(self, - name=None, - namespace_id=None, - namespace_type=None, - team_member_id=None): - self._name_value = None - self._name_present = False - self._namespace_id_value = None - self._namespace_id_present = False - self._namespace_type_value = None - self._namespace_type_present = False - self._team_member_id_value = None - self._team_member_id_present = False - if name is not None: - self.name = name - if namespace_id is not None: - self.namespace_id = namespace_id - if namespace_type is not None: - self.namespace_type = namespace_type - if team_member_id is not None: - self.team_member_id = team_member_id + revoke_devices=None): + self._revoke_devices_value = None + self._revoke_devices_present = False + if revoke_devices is not None: + self.revoke_devices = revoke_devices @property - def name(self): + def revoke_devices(self): """ - The name of this namespace. - - :rtype: str + :rtype: list of [RevokeDeviceSessionArg] """ - if self._name_present: - return self._name_value + if self._revoke_devices_present: + return self._revoke_devices_value else: - raise AttributeError("missing required field 'name'") + raise AttributeError("missing required field 'revoke_devices'") - @name.setter - def name(self, val): - val = self._name_validator.validate(val) - self._name_value = val - self._name_present = True + @revoke_devices.setter + def revoke_devices(self, val): + val = self._revoke_devices_validator.validate(val) + self._revoke_devices_value = val + self._revoke_devices_present = True - @name.deleter - def name(self): - self._name_value = None - self._name_present = False + @revoke_devices.deleter + def revoke_devices(self): + self._revoke_devices_value = None + self._revoke_devices_present = False - @property - def namespace_id(self): - """ - The ID of this namespace. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RevokeDeviceSessionBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: str - """ - if self._namespace_id_present: - return self._namespace_id_value - else: - raise AttributeError("missing required field 'namespace_id'") + def __repr__(self): + return 'RevokeDeviceSessionBatchArg(revoke_devices={!r})'.format( + self._revoke_devices_value, + ) - @namespace_id.setter - def namespace_id(self, val): - val = self._namespace_id_validator.validate(val) - self._namespace_id_value = val - self._namespace_id_present = True +RevokeDeviceSessionBatchArg_validator = bv.Struct(RevokeDeviceSessionBatchArg) - @namespace_id.deleter - def namespace_id(self): - self._namespace_id_value = None - self._namespace_id_present = False +class RevokeDeviceSessionBatchError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - @property - def namespace_type(self): + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + def is_other(self): """ - The type of this namespace. + Check if the union tag is ``other``. - :rtype: NamespaceType + :rtype: bool """ - if self._namespace_type_present: - return self._namespace_type_value - else: - raise AttributeError("missing required field 'namespace_type'") + return self._tag == 'other' - @namespace_type.setter - def namespace_type(self, val): - self._namespace_type_validator.validate_type_only(val) - self._namespace_type_value = val - self._namespace_type_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(RevokeDeviceSessionBatchError, self)._process_custom_annotations(annotation_type, field_path, processor) - @namespace_type.deleter - def namespace_type(self): - self._namespace_type_value = None - self._namespace_type_present = False + def __repr__(self): + return 'RevokeDeviceSessionBatchError(%r, %r)' % (self._tag, self._value) + +RevokeDeviceSessionBatchError_validator = bv.Union(RevokeDeviceSessionBatchError) + +class RevokeDeviceSessionBatchResult(bb.Struct): + + __slots__ = [ + '_revoke_devices_status_value', + '_revoke_devices_status_present', + ] + + _has_required_fields = True + + def __init__(self, + revoke_devices_status=None): + self._revoke_devices_status_value = None + self._revoke_devices_status_present = False + if revoke_devices_status is not None: + self.revoke_devices_status = revoke_devices_status @property - def team_member_id(self): + def revoke_devices_status(self): """ - If this is a team member or app folder, the ID of the owning team - member. Otherwise, this field is not present. - - :rtype: str + :rtype: list of [RevokeDeviceSessionStatus] """ - if self._team_member_id_present: - return self._team_member_id_value + if self._revoke_devices_status_present: + return self._revoke_devices_status_value else: - return None + raise AttributeError("missing required field 'revoke_devices_status'") - @team_member_id.setter - def team_member_id(self, val): - if val is None: - del self.team_member_id - return - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True + @revoke_devices_status.setter + def revoke_devices_status(self, val): + val = self._revoke_devices_status_validator.validate(val) + self._revoke_devices_status_value = val + self._revoke_devices_status_present = True - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False + @revoke_devices_status.deleter + def revoke_devices_status(self): + self._revoke_devices_status_value = None + self._revoke_devices_status_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NamespaceMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeDeviceSessionBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NamespaceMetadata(name={!r}, namespace_id={!r}, namespace_type={!r}, team_member_id={!r})'.format( - self._name_value, - self._namespace_id_value, - self._namespace_type_value, - self._team_member_id_value, + return 'RevokeDeviceSessionBatchResult(revoke_devices_status={!r})'.format( + self._revoke_devices_status_value, ) -NamespaceMetadata_validator = bv.Struct(NamespaceMetadata) +RevokeDeviceSessionBatchResult_validator = bv.Struct(RevokeDeviceSessionBatchResult) -class NamespaceType(bb.Union): +class RevokeDeviceSessionError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.NamespaceType.app_folder: App sandbox folder. - :ivar team.NamespaceType.shared_folder: Shared folder. - :ivar team.NamespaceType.team_folder: Top-level team-owned folder. - :ivar team.NamespaceType.team_member_folder: Team member's home folder. + :ivar team.RevokeDeviceSessionError.device_session_not_found: Device session + not found. + :ivar team.RevokeDeviceSessionError.member_not_found: Member not found. """ _catch_all = 'other' # Attribute is overwritten below the class definition - app_folder = None - # Attribute is overwritten below the class definition - shared_folder = None - # Attribute is overwritten below the class definition - team_folder = None + device_session_not_found = None # Attribute is overwritten below the class definition - team_member_folder = None + member_not_found = None # Attribute is overwritten below the class definition other = None - def is_app_folder(self): - """ - Check if the union tag is ``app_folder``. - - :rtype: bool - """ - return self._tag == 'app_folder' - - def is_shared_folder(self): - """ - Check if the union tag is ``shared_folder``. - - :rtype: bool - """ - return self._tag == 'shared_folder' - - def is_team_folder(self): + def is_device_session_not_found(self): """ - Check if the union tag is ``team_folder``. + Check if the union tag is ``device_session_not_found``. :rtype: bool """ - return self._tag == 'team_folder' + return self._tag == 'device_session_not_found' - def is_team_member_folder(self): + def is_member_not_found(self): """ - Check if the union tag is ``team_member_folder``. + Check if the union tag is ``member_not_found``. :rtype: bool """ - return self._tag == 'team_member_folder' + return self._tag == 'member_not_found' def is_other(self): """ @@ -12505,432 +16620,382 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NamespaceType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeDeviceSessionError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NamespaceType(%r, %r)' % (self._tag, self._value) + return 'RevokeDeviceSessionError(%r, %r)' % (self._tag, self._value) -NamespaceType_validator = bv.Union(NamespaceType) +RevokeDeviceSessionError_validator = bv.Union(RevokeDeviceSessionError) -class RemoveCustomQuotaResult(bb.Union): +class RevokeDeviceSessionStatus(bb.Struct): """ - User result for setting member custom quota. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar UserSelectorArg RemoveCustomQuotaResult.success: Successfully removed - user. - :ivar UserSelectorArg RemoveCustomQuotaResult.invalid_user: Invalid user - (not in team). + :ivar team.RevokeDeviceSessionStatus.success: Result of the revoking + request. + :ivar team.RevokeDeviceSessionStatus.error_type: The error cause in case of + a failure. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None - - @classmethod - def success(cls, val): - """ - Create an instance of this class set to the ``success`` tag with value - ``val``. - - :param UserSelectorArg val: - :rtype: RemoveCustomQuotaResult - """ - return cls('success', val) - - @classmethod - def invalid_user(cls, val): - """ - Create an instance of this class set to the ``invalid_user`` tag with - value ``val``. - - :param UserSelectorArg val: - :rtype: RemoveCustomQuotaResult - """ - return cls('invalid_user', val) - - def is_success(self): - """ - Check if the union tag is ``success``. - - :rtype: bool - """ - return self._tag == 'success' + __slots__ = [ + '_success_value', + '_success_present', + '_error_type_value', + '_error_type_present', + ] - def is_invalid_user(self): - """ - Check if the union tag is ``invalid_user``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'invalid_user' + def __init__(self, + success=None, + error_type=None): + self._success_value = None + self._success_present = False + self._error_type_value = None + self._error_type_present = False + if success is not None: + self.success = success + if error_type is not None: + self.error_type = error_type - def is_other(self): + @property + def success(self): """ - Check if the union tag is ``other``. + Result of the revoking request. :rtype: bool """ - return self._tag == 'other' + if self._success_present: + return self._success_value + else: + raise AttributeError("missing required field 'success'") - def get_success(self): - """ - Successfully removed user. + @success.setter + def success(self, val): + val = self._success_validator.validate(val) + self._success_value = val + self._success_present = True - Only call this if :meth:`is_success` is true. + @success.deleter + def success(self): + self._success_value = None + self._success_present = False - :rtype: UserSelectorArg + @property + def error_type(self): """ - if not self.is_success(): - raise AttributeError("tag 'success' not set") - return self._value + The error cause in case of a failure. - def get_invalid_user(self): + :rtype: RevokeDeviceSessionError """ - Invalid user (not in team). + if self._error_type_present: + return self._error_type_value + else: + return None - Only call this if :meth:`is_invalid_user` is true. + @error_type.setter + def error_type(self, val): + if val is None: + del self.error_type + return + self._error_type_validator.validate_type_only(val) + self._error_type_value = val + self._error_type_present = True - :rtype: UserSelectorArg - """ - if not self.is_invalid_user(): - raise AttributeError("tag 'invalid_user' not set") - return self._value + @error_type.deleter + def error_type(self): + self._error_type_value = None + self._error_type_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RemoveCustomQuotaResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeDeviceSessionStatus, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RemoveCustomQuotaResult(%r, %r)' % (self._tag, self._value) + return 'RevokeDeviceSessionStatus(success={!r}, error_type={!r})'.format( + self._success_value, + self._error_type_value, + ) -RemoveCustomQuotaResult_validator = bv.Union(RemoveCustomQuotaResult) +RevokeDeviceSessionStatus_validator = bv.Struct(RevokeDeviceSessionStatus) -class RemovedStatus(bb.Struct): +class RevokeLinkedApiAppArg(bb.Struct): """ - :ivar team.RemovedStatus.is_recoverable: True if the removed team member is - recoverable. - :ivar team.RemovedStatus.is_disconnected: True if the team member's account - was converted to individual account. + :ivar team.RevokeLinkedApiAppArg.app_id: The application's unique id. + :ivar team.RevokeLinkedApiAppArg.team_member_id: The unique id of the member + owning the device. + :ivar team.RevokeLinkedApiAppArg.keep_app_folder: Whether to keep the + application dedicated folder (in case the application uses one). """ __slots__ = [ - '_is_recoverable_value', - '_is_recoverable_present', - '_is_disconnected_value', - '_is_disconnected_present', + '_app_id_value', + '_app_id_present', + '_team_member_id_value', + '_team_member_id_present', + '_keep_app_folder_value', + '_keep_app_folder_present', ] - _has_required_fields = True + _has_required_fields = True + + def __init__(self, + app_id=None, + team_member_id=None, + keep_app_folder=None): + self._app_id_value = None + self._app_id_present = False + self._team_member_id_value = None + self._team_member_id_present = False + self._keep_app_folder_value = None + self._keep_app_folder_present = False + if app_id is not None: + self.app_id = app_id + if team_member_id is not None: + self.team_member_id = team_member_id + if keep_app_folder is not None: + self.keep_app_folder = keep_app_folder + + @property + def app_id(self): + """ + The application's unique id. + + :rtype: str + """ + if self._app_id_present: + return self._app_id_value + else: + raise AttributeError("missing required field 'app_id'") - def __init__(self, - is_recoverable=None, - is_disconnected=None): - self._is_recoverable_value = None - self._is_recoverable_present = False - self._is_disconnected_value = None - self._is_disconnected_present = False - if is_recoverable is not None: - self.is_recoverable = is_recoverable - if is_disconnected is not None: - self.is_disconnected = is_disconnected + @app_id.setter + def app_id(self, val): + val = self._app_id_validator.validate(val) + self._app_id_value = val + self._app_id_present = True + + @app_id.deleter + def app_id(self): + self._app_id_value = None + self._app_id_present = False @property - def is_recoverable(self): + def team_member_id(self): """ - True if the removed team member is recoverable. + The unique id of the member owning the device. - :rtype: bool + :rtype: str """ - if self._is_recoverable_present: - return self._is_recoverable_value + if self._team_member_id_present: + return self._team_member_id_value else: - raise AttributeError("missing required field 'is_recoverable'") + raise AttributeError("missing required field 'team_member_id'") - @is_recoverable.setter - def is_recoverable(self, val): - val = self._is_recoverable_validator.validate(val) - self._is_recoverable_value = val - self._is_recoverable_present = True + @team_member_id.setter + def team_member_id(self, val): + val = self._team_member_id_validator.validate(val) + self._team_member_id_value = val + self._team_member_id_present = True - @is_recoverable.deleter - def is_recoverable(self): - self._is_recoverable_value = None - self._is_recoverable_present = False + @team_member_id.deleter + def team_member_id(self): + self._team_member_id_value = None + self._team_member_id_present = False @property - def is_disconnected(self): + def keep_app_folder(self): """ - True if the team member's account was converted to individual account. + Whether to keep the application dedicated folder (in case the + application uses one). :rtype: bool """ - if self._is_disconnected_present: - return self._is_disconnected_value + if self._keep_app_folder_present: + return self._keep_app_folder_value else: - raise AttributeError("missing required field 'is_disconnected'") + return True - @is_disconnected.setter - def is_disconnected(self, val): - val = self._is_disconnected_validator.validate(val) - self._is_disconnected_value = val - self._is_disconnected_present = True + @keep_app_folder.setter + def keep_app_folder(self, val): + val = self._keep_app_folder_validator.validate(val) + self._keep_app_folder_value = val + self._keep_app_folder_present = True - @is_disconnected.deleter - def is_disconnected(self): - self._is_disconnected_value = None - self._is_disconnected_present = False + @keep_app_folder.deleter + def keep_app_folder(self): + self._keep_app_folder_value = None + self._keep_app_folder_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RemovedStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeLinkedApiAppArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RemovedStatus(is_recoverable={!r}, is_disconnected={!r})'.format( - self._is_recoverable_value, - self._is_disconnected_value, + return 'RevokeLinkedApiAppArg(app_id={!r}, team_member_id={!r}, keep_app_folder={!r})'.format( + self._app_id_value, + self._team_member_id_value, + self._keep_app_folder_value, ) -RemovedStatus_validator = bv.Struct(RemovedStatus) +RevokeLinkedApiAppArg_validator = bv.Struct(RevokeLinkedApiAppArg) -class RevokeDesktopClientArg(DeviceSessionArg): - """ - :ivar team.RevokeDesktopClientArg.delete_on_unlink: Whether to delete all - files of the account (this is possible only if supported by the desktop - client and will be made the next time the client access the account). - """ +class RevokeLinkedApiAppBatchArg(bb.Struct): __slots__ = [ - '_delete_on_unlink_value', - '_delete_on_unlink_present', + '_revoke_linked_app_value', + '_revoke_linked_app_present', ] _has_required_fields = True def __init__(self, - session_id=None, - team_member_id=None, - delete_on_unlink=None): - super(RevokeDesktopClientArg, self).__init__(session_id, - team_member_id) - self._delete_on_unlink_value = None - self._delete_on_unlink_present = False - if delete_on_unlink is not None: - self.delete_on_unlink = delete_on_unlink + revoke_linked_app=None): + self._revoke_linked_app_value = None + self._revoke_linked_app_present = False + if revoke_linked_app is not None: + self.revoke_linked_app = revoke_linked_app @property - def delete_on_unlink(self): + def revoke_linked_app(self): """ - Whether to delete all files of the account (this is possible only if - supported by the desktop client and will be made the next time the - client access the account). - - :rtype: bool + :rtype: list of [RevokeLinkedApiAppArg] """ - if self._delete_on_unlink_present: - return self._delete_on_unlink_value + if self._revoke_linked_app_present: + return self._revoke_linked_app_value else: - return False + raise AttributeError("missing required field 'revoke_linked_app'") - @delete_on_unlink.setter - def delete_on_unlink(self, val): - val = self._delete_on_unlink_validator.validate(val) - self._delete_on_unlink_value = val - self._delete_on_unlink_present = True + @revoke_linked_app.setter + def revoke_linked_app(self, val): + val = self._revoke_linked_app_validator.validate(val) + self._revoke_linked_app_value = val + self._revoke_linked_app_present = True - @delete_on_unlink.deleter - def delete_on_unlink(self): - self._delete_on_unlink_value = None - self._delete_on_unlink_present = False + @revoke_linked_app.deleter + def revoke_linked_app(self): + self._revoke_linked_app_value = None + self._revoke_linked_app_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeDesktopClientArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeLinkedApiAppBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeDesktopClientArg(session_id={!r}, team_member_id={!r}, delete_on_unlink={!r})'.format( - self._session_id_value, - self._team_member_id_value, - self._delete_on_unlink_value, + return 'RevokeLinkedApiAppBatchArg(revoke_linked_app={!r})'.format( + self._revoke_linked_app_value, ) -RevokeDesktopClientArg_validator = bv.Struct(RevokeDesktopClientArg) +RevokeLinkedApiAppBatchArg_validator = bv.Struct(RevokeLinkedApiAppBatchArg) -class RevokeDeviceSessionArg(bb.Union): +class RevokeLinkedAppBatchError(bb.Union): """ + Error returned by + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_revoke_linked_app_batch`. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar DeviceSessionArg RevokeDeviceSessionArg.web_session: End an active - session. - :ivar RevokeDesktopClientArg RevokeDeviceSessionArg.desktop_client: Unlink a - linked desktop device. - :ivar DeviceSessionArg RevokeDeviceSessionArg.mobile_client: Unlink a linked - mobile device. - """ - - _catch_all = None - - @classmethod - def web_session(cls, val): - """ - Create an instance of this class set to the ``web_session`` tag with - value ``val``. - - :param DeviceSessionArg val: - :rtype: RevokeDeviceSessionArg - """ - return cls('web_session', val) - - @classmethod - def desktop_client(cls, val): - """ - Create an instance of this class set to the ``desktop_client`` tag with - value ``val``. - - :param RevokeDesktopClientArg val: - :rtype: RevokeDeviceSessionArg - """ - return cls('desktop_client', val) - - @classmethod - def mobile_client(cls, val): - """ - Create an instance of this class set to the ``mobile_client`` tag with - value ``val``. - - :param DeviceSessionArg val: - :rtype: RevokeDeviceSessionArg - """ - return cls('mobile_client', val) - - def is_web_session(self): - """ - Check if the union tag is ``web_session``. - - :rtype: bool - """ - return self._tag == 'web_session' - - def is_desktop_client(self): - """ - Check if the union tag is ``desktop_client``. - - :rtype: bool - """ - return self._tag == 'desktop_client' - - def is_mobile_client(self): - """ - Check if the union tag is ``mobile_client``. - - :rtype: bool - """ - return self._tag == 'mobile_client' - - def get_web_session(self): - """ - End an active session. - - Only call this if :meth:`is_web_session` is true. - - :rtype: DeviceSessionArg - """ - if not self.is_web_session(): - raise AttributeError("tag 'web_session' not set") - return self._value - - def get_desktop_client(self): - """ - Unlink a linked desktop device. - - Only call this if :meth:`is_desktop_client` is true. + corresponding ``get_*`` method. + """ - :rtype: RevokeDesktopClientArg - """ - if not self.is_desktop_client(): - raise AttributeError("tag 'desktop_client' not set") - return self._value + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None - def get_mobile_client(self): + def is_other(self): """ - Unlink a linked mobile device. - - Only call this if :meth:`is_mobile_client` is true. + Check if the union tag is ``other``. - :rtype: DeviceSessionArg + :rtype: bool """ - if not self.is_mobile_client(): - raise AttributeError("tag 'mobile_client' not set") - return self._value + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeDeviceSessionArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeLinkedAppBatchError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeDeviceSessionArg(%r, %r)' % (self._tag, self._value) + return 'RevokeLinkedAppBatchError(%r, %r)' % (self._tag, self._value) -RevokeDeviceSessionArg_validator = bv.Union(RevokeDeviceSessionArg) +RevokeLinkedAppBatchError_validator = bv.Union(RevokeLinkedAppBatchError) -class RevokeDeviceSessionBatchArg(bb.Struct): +class RevokeLinkedAppBatchResult(bb.Struct): __slots__ = [ - '_revoke_devices_value', - '_revoke_devices_present', + '_revoke_linked_app_status_value', + '_revoke_linked_app_status_present', ] _has_required_fields = True def __init__(self, - revoke_devices=None): - self._revoke_devices_value = None - self._revoke_devices_present = False - if revoke_devices is not None: - self.revoke_devices = revoke_devices + revoke_linked_app_status=None): + self._revoke_linked_app_status_value = None + self._revoke_linked_app_status_present = False + if revoke_linked_app_status is not None: + self.revoke_linked_app_status = revoke_linked_app_status @property - def revoke_devices(self): + def revoke_linked_app_status(self): """ - :rtype: list of [RevokeDeviceSessionArg] + :rtype: list of [RevokeLinkedAppStatus] """ - if self._revoke_devices_present: - return self._revoke_devices_value + if self._revoke_linked_app_status_present: + return self._revoke_linked_app_status_value else: - raise AttributeError("missing required field 'revoke_devices'") + raise AttributeError("missing required field 'revoke_linked_app_status'") - @revoke_devices.setter - def revoke_devices(self, val): - val = self._revoke_devices_validator.validate(val) - self._revoke_devices_value = val - self._revoke_devices_present = True + @revoke_linked_app_status.setter + def revoke_linked_app_status(self, val): + val = self._revoke_linked_app_status_validator.validate(val) + self._revoke_linked_app_status_value = val + self._revoke_linked_app_status_present = True - @revoke_devices.deleter - def revoke_devices(self): - self._revoke_devices_value = None - self._revoke_devices_present = False + @revoke_linked_app_status.deleter + def revoke_linked_app_status(self): + self._revoke_linked_app_status_value = None + self._revoke_linked_app_status_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeDeviceSessionBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeLinkedAppBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeDeviceSessionBatchArg(revoke_devices={!r})'.format( - self._revoke_devices_value, + return 'RevokeLinkedAppBatchResult(revoke_linked_app_status={!r})'.format( + self._revoke_linked_app_status_value, ) -RevokeDeviceSessionBatchArg_validator = bv.Struct(RevokeDeviceSessionBatchArg) +RevokeLinkedAppBatchResult_validator = bv.Struct(RevokeLinkedAppBatchResult) -class RevokeDeviceSessionBatchError(bb.Union): +class RevokeLinkedAppError(bb.Union): """ + Error returned by + :meth:`dropbox.dropbox.Dropbox.team_linked_apps_revoke_linked_app`. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. + + :ivar team.RevokeLinkedAppError.app_not_found: Application not found. + :ivar team.RevokeLinkedAppError.member_not_found: Member not found. """ _catch_all = 'other' # Attribute is overwritten below the class definition + app_not_found = None + # Attribute is overwritten below the class definition + member_not_found = None + # Attribute is overwritten below the class definition other = None + def is_app_not_found(self): + """ + Check if the union tag is ``app_not_found``. + + :rtype: bool + """ + return self._tag == 'app_not_found' + + def is_member_not_found(self): + """ + Check if the union tag is ``member_not_found``. + + :rtype: bool + """ + return self._tag == 'member_not_found' + def is_other(self): """ Check if the union tag is ``other``. @@ -12940,1111 +17005,1399 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeDeviceSessionBatchError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeLinkedAppError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeDeviceSessionBatchError(%r, %r)' % (self._tag, self._value) + return 'RevokeLinkedAppError(%r, %r)' % (self._tag, self._value) -RevokeDeviceSessionBatchError_validator = bv.Union(RevokeDeviceSessionBatchError) +RevokeLinkedAppError_validator = bv.Union(RevokeLinkedAppError) -class RevokeDeviceSessionBatchResult(bb.Struct): +class RevokeLinkedAppStatus(bb.Struct): + """ + :ivar team.RevokeLinkedAppStatus.success: Result of the revoking request. + :ivar team.RevokeLinkedAppStatus.error_type: The error cause in case of a + failure. + """ __slots__ = [ - '_revoke_devices_status_value', - '_revoke_devices_status_present', + '_success_value', + '_success_present', + '_error_type_value', + '_error_type_present', ] _has_required_fields = True def __init__(self, - revoke_devices_status=None): - self._revoke_devices_status_value = None - self._revoke_devices_status_present = False - if revoke_devices_status is not None: - self.revoke_devices_status = revoke_devices_status + success=None, + error_type=None): + self._success_value = None + self._success_present = False + self._error_type_value = None + self._error_type_present = False + if success is not None: + self.success = success + if error_type is not None: + self.error_type = error_type @property - def revoke_devices_status(self): + def success(self): """ - :rtype: list of [RevokeDeviceSessionStatus] + Result of the revoking request. + + :rtype: bool """ - if self._revoke_devices_status_present: - return self._revoke_devices_status_value + if self._success_present: + return self._success_value else: - raise AttributeError("missing required field 'revoke_devices_status'") + raise AttributeError("missing required field 'success'") - @revoke_devices_status.setter - def revoke_devices_status(self, val): - val = self._revoke_devices_status_validator.validate(val) - self._revoke_devices_status_value = val - self._revoke_devices_status_present = True + @success.setter + def success(self, val): + val = self._success_validator.validate(val) + self._success_value = val + self._success_present = True - @revoke_devices_status.deleter - def revoke_devices_status(self): - self._revoke_devices_status_value = None - self._revoke_devices_status_present = False + @success.deleter + def success(self): + self._success_value = None + self._success_present = False + + @property + def error_type(self): + """ + The error cause in case of a failure. + + :rtype: RevokeLinkedAppError + """ + if self._error_type_present: + return self._error_type_value + else: + return None + + @error_type.setter + def error_type(self, val): + if val is None: + del self.error_type + return + self._error_type_validator.validate_type_only(val) + self._error_type_value = val + self._error_type_present = True + + @error_type.deleter + def error_type(self): + self._error_type_value = None + self._error_type_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeDeviceSessionBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RevokeLinkedAppStatus, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeDeviceSessionBatchResult(revoke_devices_status={!r})'.format( - self._revoke_devices_status_value, + return 'RevokeLinkedAppStatus(success={!r}, error_type={!r})'.format( + self._success_value, + self._error_type_value, + ) + +RevokeLinkedAppStatus_validator = bv.Struct(RevokeLinkedAppStatus) + +class SetCustomQuotaArg(bb.Struct): + """ + :ivar team.SetCustomQuotaArg.users_and_quotas: List of users and their + custom quotas. + """ + + __slots__ = [ + '_users_and_quotas_value', + '_users_and_quotas_present', + ] + + _has_required_fields = True + + def __init__(self, + users_and_quotas=None): + self._users_and_quotas_value = None + self._users_and_quotas_present = False + if users_and_quotas is not None: + self.users_and_quotas = users_and_quotas + + @property + def users_and_quotas(self): + """ + List of users and their custom quotas. + + :rtype: list of [UserCustomQuotaArg] + """ + if self._users_and_quotas_present: + return self._users_and_quotas_value + else: + raise AttributeError("missing required field 'users_and_quotas'") + + @users_and_quotas.setter + def users_and_quotas(self, val): + val = self._users_and_quotas_validator.validate(val) + self._users_and_quotas_value = val + self._users_and_quotas_present = True + + @users_and_quotas.deleter + def users_and_quotas(self): + self._users_and_quotas_value = None + self._users_and_quotas_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SetCustomQuotaArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SetCustomQuotaArg(users_and_quotas={!r})'.format( + self._users_and_quotas_value, ) -RevokeDeviceSessionBatchResult_validator = bv.Struct(RevokeDeviceSessionBatchResult) +SetCustomQuotaArg_validator = bv.Struct(SetCustomQuotaArg) -class RevokeDeviceSessionError(bb.Union): +class SetCustomQuotaError(CustomQuotaError): """ + Error returned when setting member custom quota. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.RevokeDeviceSessionError.device_session_not_found: Device session - not found. - :ivar team.RevokeDeviceSessionError.member_not_found: Member not found. + :ivar team.SetCustomQuotaError.some_users_are_excluded: Some of the users + are on the excluded users list and can't have custom quota set. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - device_session_not_found = None # Attribute is overwritten below the class definition - member_not_found = None - # Attribute is overwritten below the class definition - other = None - - def is_device_session_not_found(self): - """ - Check if the union tag is ``device_session_not_found``. - - :rtype: bool - """ - return self._tag == 'device_session_not_found' - - def is_member_not_found(self): - """ - Check if the union tag is ``member_not_found``. - - :rtype: bool - """ - return self._tag == 'member_not_found' + some_users_are_excluded = None - def is_other(self): + def is_some_users_are_excluded(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``some_users_are_excluded``. :rtype: bool """ - return self._tag == 'other' + return self._tag == 'some_users_are_excluded' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeDeviceSessionError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SetCustomQuotaError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeDeviceSessionError(%r, %r)' % (self._tag, self._value) + return 'SetCustomQuotaError(%r, %r)' % (self._tag, self._value) -RevokeDeviceSessionError_validator = bv.Union(RevokeDeviceSessionError) +SetCustomQuotaError_validator = bv.Union(SetCustomQuotaError) -class RevokeDeviceSessionStatus(bb.Struct): +class StorageBucket(bb.Struct): """ - :ivar team.RevokeDeviceSessionStatus.success: Result of the revoking - request. - :ivar team.RevokeDeviceSessionStatus.error_type: The error cause in case of - a failure. + Describes the number of users in a specific storage bucket. + + :ivar team.StorageBucket.bucket: The name of the storage bucket. For + example, '1G' is a bucket of users with storage size up to 1 Giga. + :ivar team.StorageBucket.users: The number of people whose storage is in the + range of this storage bucket. """ __slots__ = [ - '_success_value', - '_success_present', - '_error_type_value', - '_error_type_present', + '_bucket_value', + '_bucket_present', + '_users_value', + '_users_present', ] _has_required_fields = True def __init__(self, - success=None, - error_type=None): - self._success_value = None - self._success_present = False - self._error_type_value = None - self._error_type_present = False - if success is not None: - self.success = success - if error_type is not None: - self.error_type = error_type + bucket=None, + users=None): + self._bucket_value = None + self._bucket_present = False + self._users_value = None + self._users_present = False + if bucket is not None: + self.bucket = bucket + if users is not None: + self.users = users @property - def success(self): + def bucket(self): """ - Result of the revoking request. + The name of the storage bucket. For example, '1G' is a bucket of users + with storage size up to 1 Giga. - :rtype: bool + :rtype: str """ - if self._success_present: - return self._success_value + if self._bucket_present: + return self._bucket_value else: - raise AttributeError("missing required field 'success'") + raise AttributeError("missing required field 'bucket'") - @success.setter - def success(self, val): - val = self._success_validator.validate(val) - self._success_value = val - self._success_present = True + @bucket.setter + def bucket(self, val): + val = self._bucket_validator.validate(val) + self._bucket_value = val + self._bucket_present = True - @success.deleter - def success(self): - self._success_value = None - self._success_present = False + @bucket.deleter + def bucket(self): + self._bucket_value = None + self._bucket_present = False @property - def error_type(self): + def users(self): """ - The error cause in case of a failure. + The number of people whose storage is in the range of this storage + bucket. - :rtype: RevokeDeviceSessionError + :rtype: int """ - if self._error_type_present: - return self._error_type_value + if self._users_present: + return self._users_value else: - return None + raise AttributeError("missing required field 'users'") - @error_type.setter - def error_type(self, val): - if val is None: - del self.error_type - return - self._error_type_validator.validate_type_only(val) - self._error_type_value = val - self._error_type_present = True + @users.setter + def users(self, val): + val = self._users_validator.validate(val) + self._users_value = val + self._users_present = True - @error_type.deleter - def error_type(self): - self._error_type_value = None - self._error_type_present = False + @users.deleter + def users(self): + self._users_value = None + self._users_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeDeviceSessionStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(StorageBucket, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeDeviceSessionStatus(success={!r}, error_type={!r})'.format( - self._success_value, - self._error_type_value, + return 'StorageBucket(bucket={!r}, users={!r})'.format( + self._bucket_value, + self._users_value, ) -RevokeDeviceSessionStatus_validator = bv.Struct(RevokeDeviceSessionStatus) +StorageBucket_validator = bv.Struct(StorageBucket) -class RevokeLinkedApiAppArg(bb.Struct): +class TeamFolderAccessError(bb.Union): """ - :ivar team.RevokeLinkedApiAppArg.app_id: The application's unique id. - :ivar team.RevokeLinkedApiAppArg.team_member_id: The unique id of the member - owning the device. - :ivar team.RevokeLinkedApiAppArg.keep_app_folder: Whether to keep the - application dedicated folder (in case the application uses one). + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.TeamFolderAccessError.invalid_team_folder_id: The team folder ID + is invalid. + :ivar team.TeamFolderAccessError.no_access: The authenticated app does not + have permission to manage that team folder. """ - __slots__ = [ - '_app_id_value', - '_app_id_present', - '_team_member_id_value', - '_team_member_id_present', - '_keep_app_folder_value', - '_keep_app_folder_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_team_folder_id = None + # Attribute is overwritten below the class definition + no_access = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_invalid_team_folder_id(self): + """ + Check if the union tag is ``invalid_team_folder_id``. - def __init__(self, - app_id=None, - team_member_id=None, - keep_app_folder=None): - self._app_id_value = None - self._app_id_present = False - self._team_member_id_value = None - self._team_member_id_present = False - self._keep_app_folder_value = None - self._keep_app_folder_present = False - if app_id is not None: - self.app_id = app_id - if team_member_id is not None: - self.team_member_id = team_member_id - if keep_app_folder is not None: - self.keep_app_folder = keep_app_folder + :rtype: bool + """ + return self._tag == 'invalid_team_folder_id' - @property - def app_id(self): + def is_no_access(self): """ - The application's unique id. + Check if the union tag is ``no_access``. - :rtype: str + :rtype: bool """ - if self._app_id_present: - return self._app_id_value - else: - raise AttributeError("missing required field 'app_id'") + return self._tag == 'no_access' - @app_id.setter - def app_id(self, val): - val = self._app_id_validator.validate(val) - self._app_id_value = val - self._app_id_present = True + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamFolderAccessError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamFolderAccessError(%r, %r)' % (self._tag, self._value) + +TeamFolderAccessError_validator = bv.Union(TeamFolderAccessError) + +class TeamFolderActivateError(BaseTeamFolderError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamFolderActivateError, self)._process_custom_annotations(annotation_type, field_path, processor) - @app_id.deleter - def app_id(self): - self._app_id_value = None - self._app_id_present = False + def __repr__(self): + return 'TeamFolderActivateError(%r, %r)' % (self._tag, self._value) - @property - def team_member_id(self): - """ - The unique id of the member owning the device. +TeamFolderActivateError_validator = bv.Union(TeamFolderActivateError) - :rtype: str - """ - if self._team_member_id_present: - return self._team_member_id_value - else: - raise AttributeError("missing required field 'team_member_id'") +class TeamFolderIdArg(bb.Struct): + """ + :ivar team.TeamFolderIdArg.team_folder_id: The ID of the team folder. + """ - @team_member_id.setter - def team_member_id(self, val): - val = self._team_member_id_validator.validate(val) - self._team_member_id_value = val - self._team_member_id_present = True + __slots__ = [ + '_team_folder_id_value', + '_team_folder_id_present', + ] - @team_member_id.deleter - def team_member_id(self): - self._team_member_id_value = None - self._team_member_id_present = False + _has_required_fields = True + + def __init__(self, + team_folder_id=None): + self._team_folder_id_value = None + self._team_folder_id_present = False + if team_folder_id is not None: + self.team_folder_id = team_folder_id @property - def keep_app_folder(self): + def team_folder_id(self): """ - Whether to keep the application dedicated folder (in case the - application uses one). + The ID of the team folder. - :rtype: bool + :rtype: str """ - if self._keep_app_folder_present: - return self._keep_app_folder_value + if self._team_folder_id_present: + return self._team_folder_id_value else: - return True + raise AttributeError("missing required field 'team_folder_id'") - @keep_app_folder.setter - def keep_app_folder(self, val): - val = self._keep_app_folder_validator.validate(val) - self._keep_app_folder_value = val - self._keep_app_folder_present = True + @team_folder_id.setter + def team_folder_id(self, val): + val = self._team_folder_id_validator.validate(val) + self._team_folder_id_value = val + self._team_folder_id_present = True - @keep_app_folder.deleter - def keep_app_folder(self): - self._keep_app_folder_value = None - self._keep_app_folder_present = False + @team_folder_id.deleter + def team_folder_id(self): + self._team_folder_id_value = None + self._team_folder_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeLinkedApiAppArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderIdArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeLinkedApiAppArg(app_id={!r}, team_member_id={!r}, keep_app_folder={!r})'.format( - self._app_id_value, - self._team_member_id_value, - self._keep_app_folder_value, + return 'TeamFolderIdArg(team_folder_id={!r})'.format( + self._team_folder_id_value, ) -RevokeLinkedApiAppArg_validator = bv.Struct(RevokeLinkedApiAppArg) +TeamFolderIdArg_validator = bv.Struct(TeamFolderIdArg) -class RevokeLinkedApiAppBatchArg(bb.Struct): +class TeamFolderArchiveArg(TeamFolderIdArg): + """ + :ivar team.TeamFolderArchiveArg.force_async_off: Whether to force the + archive to happen synchronously. + """ __slots__ = [ - '_revoke_linked_app_value', - '_revoke_linked_app_present', + '_force_async_off_value', + '_force_async_off_present', ] _has_required_fields = True def __init__(self, - revoke_linked_app=None): - self._revoke_linked_app_value = None - self._revoke_linked_app_present = False - if revoke_linked_app is not None: - self.revoke_linked_app = revoke_linked_app + team_folder_id=None, + force_async_off=None): + super(TeamFolderArchiveArg, self).__init__(team_folder_id) + self._force_async_off_value = None + self._force_async_off_present = False + if force_async_off is not None: + self.force_async_off = force_async_off @property - def revoke_linked_app(self): + def force_async_off(self): """ - :rtype: list of [RevokeLinkedApiAppArg] + Whether to force the archive to happen synchronously. + + :rtype: bool """ - if self._revoke_linked_app_present: - return self._revoke_linked_app_value + if self._force_async_off_present: + return self._force_async_off_value else: - raise AttributeError("missing required field 'revoke_linked_app'") + return False - @revoke_linked_app.setter - def revoke_linked_app(self, val): - val = self._revoke_linked_app_validator.validate(val) - self._revoke_linked_app_value = val - self._revoke_linked_app_present = True + @force_async_off.setter + def force_async_off(self, val): + val = self._force_async_off_validator.validate(val) + self._force_async_off_value = val + self._force_async_off_present = True - @revoke_linked_app.deleter - def revoke_linked_app(self): - self._revoke_linked_app_value = None - self._revoke_linked_app_present = False + @force_async_off.deleter + def force_async_off(self): + self._force_async_off_value = None + self._force_async_off_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeLinkedApiAppBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderArchiveArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeLinkedApiAppBatchArg(revoke_linked_app={!r})'.format( - self._revoke_linked_app_value, + return 'TeamFolderArchiveArg(team_folder_id={!r}, force_async_off={!r})'.format( + self._team_folder_id_value, + self._force_async_off_value, ) -RevokeLinkedApiAppBatchArg_validator = bv.Struct(RevokeLinkedApiAppBatchArg) +TeamFolderArchiveArg_validator = bv.Struct(TeamFolderArchiveArg) -class RevokeLinkedAppBatchError(bb.Union): +class TeamFolderArchiveError(BaseTeamFolderError): """ - Error returned by - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_revoke_linked_app_batch`. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamFolderArchiveError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamFolderArchiveError(%r, %r)' % (self._tag, self._value) +TeamFolderArchiveError_validator = bv.Union(TeamFolderArchiveError) + +class TeamFolderArchiveJobStatus(async_.PollResultBase): + """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. + + :ivar TeamFolderMetadata TeamFolderArchiveJobStatus.complete: The archive + job has finished. The value is the metadata for the resulting team + folder. + :ivar TeamFolderArchiveError TeamFolderArchiveJobStatus.failed: Error + occurred while performing an asynchronous job from + :meth:`dropbox.dropbox.Dropbox.team_team_folder_archive`. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + @classmethod + def complete(cls, val): + """ + Create an instance of this class set to the ``complete`` tag with value + ``val``. - def is_other(self): + :param TeamFolderMetadata val: + :rtype: TeamFolderArchiveJobStatus """ - Check if the union tag is ``other``. + return cls('complete', val) - :rtype: bool + @classmethod + def failed(cls, val): """ - return self._tag == 'other' + Create an instance of this class set to the ``failed`` tag with value + ``val``. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeLinkedAppBatchError, self)._process_custom_annotations(annotation_type, field_path, processor) + :param TeamFolderArchiveError val: + :rtype: TeamFolderArchiveJobStatus + """ + return cls('failed', val) - def __repr__(self): - return 'RevokeLinkedAppBatchError(%r, %r)' % (self._tag, self._value) + def is_complete(self): + """ + Check if the union tag is ``complete``. -RevokeLinkedAppBatchError_validator = bv.Union(RevokeLinkedAppBatchError) + :rtype: bool + """ + return self._tag == 'complete' -class RevokeLinkedAppBatchResult(bb.Struct): + def is_failed(self): + """ + Check if the union tag is ``failed``. - __slots__ = [ - '_revoke_linked_app_status_value', - '_revoke_linked_app_status_present', - ] + :rtype: bool + """ + return self._tag == 'failed' - _has_required_fields = True + def get_complete(self): + """ + The archive job has finished. The value is the metadata for the + resulting team folder. - def __init__(self, - revoke_linked_app_status=None): - self._revoke_linked_app_status_value = None - self._revoke_linked_app_status_present = False - if revoke_linked_app_status is not None: - self.revoke_linked_app_status = revoke_linked_app_status + Only call this if :meth:`is_complete` is true. - @property - def revoke_linked_app_status(self): + :rtype: TeamFolderMetadata """ - :rtype: list of [RevokeLinkedAppStatus] + if not self.is_complete(): + raise AttributeError("tag 'complete' not set") + return self._value + + def get_failed(self): """ - if self._revoke_linked_app_status_present: - return self._revoke_linked_app_status_value - else: - raise AttributeError("missing required field 'revoke_linked_app_status'") + Error occurred while performing an asynchronous job from + :meth:`dropbox.dropbox.Dropbox.team_team_folder_archive`. - @revoke_linked_app_status.setter - def revoke_linked_app_status(self, val): - val = self._revoke_linked_app_status_validator.validate(val) - self._revoke_linked_app_status_value = val - self._revoke_linked_app_status_present = True + Only call this if :meth:`is_failed` is true. - @revoke_linked_app_status.deleter - def revoke_linked_app_status(self): - self._revoke_linked_app_status_value = None - self._revoke_linked_app_status_present = False + :rtype: TeamFolderArchiveError + """ + if not self.is_failed(): + raise AttributeError("tag 'failed' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeLinkedAppBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderArchiveJobStatus, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeLinkedAppBatchResult(revoke_linked_app_status={!r})'.format( - self._revoke_linked_app_status_value, - ) + return 'TeamFolderArchiveJobStatus(%r, %r)' % (self._tag, self._value) -RevokeLinkedAppBatchResult_validator = bv.Struct(RevokeLinkedAppBatchResult) +TeamFolderArchiveJobStatus_validator = bv.Union(TeamFolderArchiveJobStatus) -class RevokeLinkedAppError(bb.Union): +class TeamFolderArchiveLaunch(async_.LaunchResultBase): """ - Error returned by - :meth:`dropbox.dropbox.Dropbox.team_linked_apps_revoke_linked_app`. - This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - - :ivar team.RevokeLinkedAppError.app_not_found: Application not found. - :ivar team.RevokeLinkedAppError.member_not_found: Member not found. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - app_not_found = None - # Attribute is overwritten below the class definition - member_not_found = None - # Attribute is overwritten below the class definition - other = None - - def is_app_not_found(self): + @classmethod + def complete(cls, val): """ - Check if the union tag is ``app_not_found``. + Create an instance of this class set to the ``complete`` tag with value + ``val``. - :rtype: bool + :param TeamFolderMetadata val: + :rtype: TeamFolderArchiveLaunch """ - return self._tag == 'app_not_found' + return cls('complete', val) - def is_member_not_found(self): + def is_complete(self): """ - Check if the union tag is ``member_not_found``. + Check if the union tag is ``complete``. :rtype: bool """ - return self._tag == 'member_not_found' + return self._tag == 'complete' - def is_other(self): + def get_complete(self): """ - Check if the union tag is ``other``. + Only call this if :meth:`is_complete` is true. - :rtype: bool + :rtype: TeamFolderMetadata """ - return self._tag == 'other' + if not self.is_complete(): + raise AttributeError("tag 'complete' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeLinkedAppError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderArchiveLaunch, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeLinkedAppError(%r, %r)' % (self._tag, self._value) + return 'TeamFolderArchiveLaunch(%r, %r)' % (self._tag, self._value) -RevokeLinkedAppError_validator = bv.Union(RevokeLinkedAppError) +TeamFolderArchiveLaunch_validator = bv.Union(TeamFolderArchiveLaunch) -class RevokeLinkedAppStatus(bb.Struct): +class TeamFolderCreateArg(bb.Struct): """ - :ivar team.RevokeLinkedAppStatus.success: Result of the revoking request. - :ivar team.RevokeLinkedAppStatus.error_type: The error cause in case of a - failure. + :ivar team.TeamFolderCreateArg.name: Name for the new team folder. + :ivar team.TeamFolderCreateArg.sync_setting: The sync setting to apply to + this team folder. Only permitted if the team has team selective sync + enabled. """ __slots__ = [ - '_success_value', - '_success_present', - '_error_type_value', - '_error_type_present', + '_name_value', + '_name_present', + '_sync_setting_value', + '_sync_setting_present', ] _has_required_fields = True def __init__(self, - success=None, - error_type=None): - self._success_value = None - self._success_present = False - self._error_type_value = None - self._error_type_present = False - if success is not None: - self.success = success - if error_type is not None: - self.error_type = error_type + name=None, + sync_setting=None): + self._name_value = None + self._name_present = False + self._sync_setting_value = None + self._sync_setting_present = False + if name is not None: + self.name = name + if sync_setting is not None: + self.sync_setting = sync_setting @property - def success(self): + def name(self): """ - Result of the revoking request. + Name for the new team folder. - :rtype: bool + :rtype: str """ - if self._success_present: - return self._success_value + if self._name_present: + return self._name_value else: - raise AttributeError("missing required field 'success'") + raise AttributeError("missing required field 'name'") - @success.setter - def success(self, val): - val = self._success_validator.validate(val) - self._success_value = val - self._success_present = True + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True - @success.deleter - def success(self): - self._success_value = None - self._success_present = False + @name.deleter + def name(self): + self._name_value = None + self._name_present = False @property - def error_type(self): + def sync_setting(self): """ - The error cause in case of a failure. + The sync setting to apply to this team folder. Only permitted if the + team has team selective sync enabled. - :rtype: RevokeLinkedAppError + :rtype: files.SyncSettingArg """ - if self._error_type_present: - return self._error_type_value + if self._sync_setting_present: + return self._sync_setting_value else: return None - @error_type.setter - def error_type(self, val): + @sync_setting.setter + def sync_setting(self, val): if val is None: - del self.error_type + del self.sync_setting return - self._error_type_validator.validate_type_only(val) - self._error_type_value = val - self._error_type_present = True + self._sync_setting_validator.validate_type_only(val) + self._sync_setting_value = val + self._sync_setting_present = True - @error_type.deleter - def error_type(self): - self._error_type_value = None - self._error_type_present = False + @sync_setting.deleter + def sync_setting(self): + self._sync_setting_value = None + self._sync_setting_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RevokeLinkedAppStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderCreateArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RevokeLinkedAppStatus(success={!r}, error_type={!r})'.format( - self._success_value, - self._error_type_value, + return 'TeamFolderCreateArg(name={!r}, sync_setting={!r})'.format( + self._name_value, + self._sync_setting_value, ) -RevokeLinkedAppStatus_validator = bv.Struct(RevokeLinkedAppStatus) +TeamFolderCreateArg_validator = bv.Struct(TeamFolderCreateArg) -class SetCustomQuotaArg(bb.Struct): +class TeamFolderCreateError(bb.Union): """ - :ivar team.SetCustomQuotaArg.users_and_quotas: List of users and their - custom quotas. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.TeamFolderCreateError.invalid_folder_name: The provided name + cannot be used. + :ivar team.TeamFolderCreateError.folder_name_already_used: There is already + a team folder with the provided name. + :ivar team.TeamFolderCreateError.folder_name_reserved: The provided name + cannot be used because it is reserved. + :ivar SyncSettingsError TeamFolderCreateError.sync_settings_error: An error + occurred setting the sync settings. """ - __slots__ = [ - '_users_and_quotas_value', - '_users_and_quotas_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_folder_name = None + # Attribute is overwritten below the class definition + folder_name_already_used = None + # Attribute is overwritten below the class definition + folder_name_reserved = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + @classmethod + def sync_settings_error(cls, val): + """ + Create an instance of this class set to the ``sync_settings_error`` tag + with value ``val``. - def __init__(self, - users_and_quotas=None): - self._users_and_quotas_value = None - self._users_and_quotas_present = False - if users_and_quotas is not None: - self.users_and_quotas = users_and_quotas + :param files.SyncSettingsError val: + :rtype: TeamFolderCreateError + """ + return cls('sync_settings_error', val) - @property - def users_and_quotas(self): + def is_invalid_folder_name(self): """ - List of users and their custom quotas. + Check if the union tag is ``invalid_folder_name``. - :rtype: list of [UserCustomQuotaArg] + :rtype: bool """ - if self._users_and_quotas_present: - return self._users_and_quotas_value - else: - raise AttributeError("missing required field 'users_and_quotas'") + return self._tag == 'invalid_folder_name' + + def is_folder_name_already_used(self): + """ + Check if the union tag is ``folder_name_already_used``. + + :rtype: bool + """ + return self._tag == 'folder_name_already_used' + + def is_folder_name_reserved(self): + """ + Check if the union tag is ``folder_name_reserved``. + + :rtype: bool + """ + return self._tag == 'folder_name_reserved' + + def is_sync_settings_error(self): + """ + Check if the union tag is ``sync_settings_error``. + + :rtype: bool + """ + return self._tag == 'sync_settings_error' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' - @users_and_quotas.setter - def users_and_quotas(self, val): - val = self._users_and_quotas_validator.validate(val) - self._users_and_quotas_value = val - self._users_and_quotas_present = True + def get_sync_settings_error(self): + """ + An error occurred setting the sync settings. - @users_and_quotas.deleter - def users_and_quotas(self): - self._users_and_quotas_value = None - self._users_and_quotas_present = False + Only call this if :meth:`is_sync_settings_error` is true. + + :rtype: files.SyncSettingsError + """ + if not self.is_sync_settings_error(): + raise AttributeError("tag 'sync_settings_error' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SetCustomQuotaArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderCreateError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SetCustomQuotaArg(users_and_quotas={!r})'.format( - self._users_and_quotas_value, - ) + return 'TeamFolderCreateError(%r, %r)' % (self._tag, self._value) -SetCustomQuotaArg_validator = bv.Struct(SetCustomQuotaArg) +TeamFolderCreateError_validator = bv.Union(TeamFolderCreateError) -class SetCustomQuotaError(CustomQuotaError): +class TeamFolderGetInfoItem(bb.Union): """ - Error returned when setting member custom quota. - This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.SetCustomQuotaError.some_users_are_excluded: Some of the users - are on the excluded users list and can't have custom quota set. + :ivar str team.TeamFolderGetInfoItem.id_not_found: An ID that was provided + as a parameter to :route:`team_folder/get_info` did not match any of the + team's team folders. + :ivar TeamFolderMetadata TeamFolderGetInfoItem.team_folder_metadata: + Properties of a team folder. """ - # Attribute is overwritten below the class definition - some_users_are_excluded = None + _catch_all = None - def is_some_users_are_excluded(self): + @classmethod + def id_not_found(cls, val): """ - Check if the union tag is ``some_users_are_excluded``. + Create an instance of this class set to the ``id_not_found`` tag with + value ``val``. + + :param str val: + :rtype: TeamFolderGetInfoItem + """ + return cls('id_not_found', val) + + @classmethod + def team_folder_metadata(cls, val): + """ + Create an instance of this class set to the ``team_folder_metadata`` tag + with value ``val``. + + :param TeamFolderMetadata val: + :rtype: TeamFolderGetInfoItem + """ + return cls('team_folder_metadata', val) + + def is_id_not_found(self): + """ + Check if the union tag is ``id_not_found``. :rtype: bool """ - return self._tag == 'some_users_are_excluded' + return self._tag == 'id_not_found' + + def is_team_folder_metadata(self): + """ + Check if the union tag is ``team_folder_metadata``. + + :rtype: bool + """ + return self._tag == 'team_folder_metadata' + + def get_id_not_found(self): + """ + An ID that was provided as a parameter to + :meth:`dropbox.dropbox.Dropbox.team_team_folder_get_info` did not match + any of the team's team folders. + + Only call this if :meth:`is_id_not_found` is true. + + :rtype: str + """ + if not self.is_id_not_found(): + raise AttributeError("tag 'id_not_found' not set") + return self._value + + def get_team_folder_metadata(self): + """ + Properties of a team folder. + + Only call this if :meth:`is_team_folder_metadata` is true. + + :rtype: TeamFolderMetadata + """ + if not self.is_team_folder_metadata(): + raise AttributeError("tag 'team_folder_metadata' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SetCustomQuotaError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderGetInfoItem, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SetCustomQuotaError(%r, %r)' % (self._tag, self._value) + return 'TeamFolderGetInfoItem(%r, %r)' % (self._tag, self._value) -SetCustomQuotaError_validator = bv.Union(SetCustomQuotaError) +TeamFolderGetInfoItem_validator = bv.Union(TeamFolderGetInfoItem) -class StorageBucket(bb.Struct): +class TeamFolderIdListArg(bb.Struct): """ - Describes the number of users in a specific storage bucket. - - :ivar team.StorageBucket.bucket: The name of the storage bucket. For - example, '1G' is a bucket of users with storage size up to 1 Giga. - :ivar team.StorageBucket.users: The number of people whose storage is in the - range of this storage bucket. + :ivar team.TeamFolderIdListArg.team_folder_ids: The list of team folder IDs. """ __slots__ = [ - '_bucket_value', - '_bucket_present', - '_users_value', - '_users_present', + '_team_folder_ids_value', + '_team_folder_ids_present', ] _has_required_fields = True def __init__(self, - bucket=None, - users=None): - self._bucket_value = None - self._bucket_present = False - self._users_value = None - self._users_present = False - if bucket is not None: - self.bucket = bucket - if users is not None: - self.users = users - - @property - def bucket(self): - """ - The name of the storage bucket. For example, '1G' is a bucket of users - with storage size up to 1 Giga. - - :rtype: str - """ - if self._bucket_present: - return self._bucket_value - else: - raise AttributeError("missing required field 'bucket'") - - @bucket.setter - def bucket(self, val): - val = self._bucket_validator.validate(val) - self._bucket_value = val - self._bucket_present = True - - @bucket.deleter - def bucket(self): - self._bucket_value = None - self._bucket_present = False + team_folder_ids=None): + self._team_folder_ids_value = None + self._team_folder_ids_present = False + if team_folder_ids is not None: + self.team_folder_ids = team_folder_ids @property - def users(self): + def team_folder_ids(self): """ - The number of people whose storage is in the range of this storage - bucket. + The list of team folder IDs. - :rtype: int + :rtype: list of [str] """ - if self._users_present: - return self._users_value + if self._team_folder_ids_present: + return self._team_folder_ids_value else: - raise AttributeError("missing required field 'users'") + raise AttributeError("missing required field 'team_folder_ids'") - @users.setter - def users(self, val): - val = self._users_validator.validate(val) - self._users_value = val - self._users_present = True + @team_folder_ids.setter + def team_folder_ids(self, val): + val = self._team_folder_ids_validator.validate(val) + self._team_folder_ids_value = val + self._team_folder_ids_present = True - @users.deleter - def users(self): - self._users_value = None - self._users_present = False + @team_folder_ids.deleter + def team_folder_ids(self): + self._team_folder_ids_value = None + self._team_folder_ids_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(StorageBucket, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderIdListArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'StorageBucket(bucket={!r}, users={!r})'.format( - self._bucket_value, - self._users_value, + return 'TeamFolderIdListArg(team_folder_ids={!r})'.format( + self._team_folder_ids_value, ) -StorageBucket_validator = bv.Struct(StorageBucket) +TeamFolderIdListArg_validator = bv.Struct(TeamFolderIdListArg) -class TeamFolderAccessError(bb.Union): +class TeamFolderInvalidStatusError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamFolderAccessError.invalid_team_folder_id: The team folder ID - is invalid. - :ivar team.TeamFolderAccessError.no_access: The authenticated app does not - have permission to manage that team folder. + :ivar team.TeamFolderInvalidStatusError.active: The folder is active and the + operation did not succeed. + :ivar team.TeamFolderInvalidStatusError.archived: The folder is archived and + the operation did not succeed. + :ivar team.TeamFolderInvalidStatusError.archive_in_progress: The folder is + being archived and the operation did not succeed. """ _catch_all = 'other' # Attribute is overwritten below the class definition - invalid_team_folder_id = None + active = None # Attribute is overwritten below the class definition - no_access = None + archived = None + # Attribute is overwritten below the class definition + archive_in_progress = None # Attribute is overwritten below the class definition other = None - def is_invalid_team_folder_id(self): + def is_active(self): """ - Check if the union tag is ``invalid_team_folder_id``. + Check if the union tag is ``active``. :rtype: bool """ - return self._tag == 'invalid_team_folder_id' + return self._tag == 'active' - def is_no_access(self): + def is_archived(self): """ - Check if the union tag is ``no_access``. + Check if the union tag is ``archived``. :rtype: bool """ - return self._tag == 'no_access' + return self._tag == 'archived' - def is_other(self): + def is_archive_in_progress(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``archive_in_progress``. :rtype: bool """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderAccessError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamFolderAccessError(%r, %r)' % (self._tag, self._value) - -TeamFolderAccessError_validator = bv.Union(TeamFolderAccessError) + return self._tag == 'archive_in_progress' -class TeamFolderActivateError(BaseTeamFolderError): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderActivateError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderInvalidStatusError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderActivateError(%r, %r)' % (self._tag, self._value) + return 'TeamFolderInvalidStatusError(%r, %r)' % (self._tag, self._value) -TeamFolderActivateError_validator = bv.Union(TeamFolderActivateError) +TeamFolderInvalidStatusError_validator = bv.Union(TeamFolderInvalidStatusError) -class TeamFolderIdArg(bb.Struct): +class TeamFolderListArg(bb.Struct): """ - :ivar team.TeamFolderIdArg.team_folder_id: The ID of the team folder. + :ivar team.TeamFolderListArg.limit: The maximum number of results to return + per request. """ __slots__ = [ - '_team_folder_id_value', - '_team_folder_id_present', + '_limit_value', + '_limit_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - team_folder_id=None): - self._team_folder_id_value = None - self._team_folder_id_present = False - if team_folder_id is not None: - self.team_folder_id = team_folder_id + limit=None): + self._limit_value = None + self._limit_present = False + if limit is not None: + self.limit = limit @property - def team_folder_id(self): + def limit(self): """ - The ID of the team folder. + The maximum number of results to return per request. - :rtype: str + :rtype: int """ - if self._team_folder_id_present: - return self._team_folder_id_value + if self._limit_present: + return self._limit_value else: - raise AttributeError("missing required field 'team_folder_id'") + return 1000 - @team_folder_id.setter - def team_folder_id(self, val): - val = self._team_folder_id_validator.validate(val) - self._team_folder_id_value = val - self._team_folder_id_present = True + @limit.setter + def limit(self, val): + val = self._limit_validator.validate(val) + self._limit_value = val + self._limit_present = True - @team_folder_id.deleter - def team_folder_id(self): - self._team_folder_id_value = None - self._team_folder_id_present = False + @limit.deleter + def limit(self): + self._limit_value = None + self._limit_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderIdArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderListArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderIdArg(team_folder_id={!r})'.format( - self._team_folder_id_value, + return 'TeamFolderListArg(limit={!r})'.format( + self._limit_value, ) -TeamFolderIdArg_validator = bv.Struct(TeamFolderIdArg) +TeamFolderListArg_validator = bv.Struct(TeamFolderListArg) -class TeamFolderArchiveArg(TeamFolderIdArg): +class TeamFolderListContinueArg(bb.Struct): """ - :ivar team.TeamFolderArchiveArg.force_async_off: Whether to force the - archive to happen synchronously. + :ivar team.TeamFolderListContinueArg.cursor: Indicates from what point to + get the next set of team folders. """ __slots__ = [ - '_force_async_off_value', - '_force_async_off_present', + '_cursor_value', + '_cursor_present', ] _has_required_fields = True def __init__(self, - team_folder_id=None, - force_async_off=None): - super(TeamFolderArchiveArg, self).__init__(team_folder_id) - self._force_async_off_value = None - self._force_async_off_present = False - if force_async_off is not None: - self.force_async_off = force_async_off + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def force_async_off(self): + def cursor(self): """ - Whether to force the archive to happen synchronously. + Indicates from what point to get the next set of team folders. - :rtype: bool + :rtype: str """ - if self._force_async_off_present: - return self._force_async_off_value + if self._cursor_present: + return self._cursor_value else: - return False + raise AttributeError("missing required field 'cursor'") - @force_async_off.setter - def force_async_off(self, val): - val = self._force_async_off_validator.validate(val) - self._force_async_off_value = val - self._force_async_off_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @force_async_off.deleter - def force_async_off(self): - self._force_async_off_value = None - self._force_async_off_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderArchiveArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderArchiveArg(team_folder_id={!r}, force_async_off={!r})'.format( - self._team_folder_id_value, - self._force_async_off_value, + return 'TeamFolderListContinueArg(cursor={!r})'.format( + self._cursor_value, ) -TeamFolderArchiveArg_validator = bv.Struct(TeamFolderArchiveArg) +TeamFolderListContinueArg_validator = bv.Struct(TeamFolderListContinueArg) -class TeamFolderArchiveError(BaseTeamFolderError): +class TeamFolderListContinueError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. + + :ivar team.TeamFolderListContinueError.invalid_cursor: The cursor is + invalid. """ + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_cursor = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_cursor(self): + """ + Check if the union tag is ``invalid_cursor``. + + :rtype: bool + """ + return self._tag == 'invalid_cursor' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderArchiveError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderArchiveError(%r, %r)' % (self._tag, self._value) + return 'TeamFolderListContinueError(%r, %r)' % (self._tag, self._value) -TeamFolderArchiveError_validator = bv.Union(TeamFolderArchiveError) +TeamFolderListContinueError_validator = bv.Union(TeamFolderListContinueError) -class TeamFolderArchiveJobStatus(async_.PollResultBase): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. +class TeamFolderListError(bb.Struct): - :ivar TeamFolderMetadata TeamFolderArchiveJobStatus.complete: The archive - job has finished. The value is the metadata for the resulting team - folder. - :ivar TeamFolderArchiveError TeamFolderArchiveJobStatus.failed: Error - occurred while performing an asynchronous job from - :meth:`dropbox.dropbox.Dropbox.team_team_folder_archive`. - """ + __slots__ = [ + '_access_error_value', + '_access_error_present', + ] - @classmethod - def complete(cls, val): - """ - Create an instance of this class set to the ``complete`` tag with value - ``val``. + _has_required_fields = True - :param TeamFolderMetadata val: - :rtype: TeamFolderArchiveJobStatus - """ - return cls('complete', val) + def __init__(self, + access_error=None): + self._access_error_value = None + self._access_error_present = False + if access_error is not None: + self.access_error = access_error - @classmethod - def failed(cls, val): + @property + def access_error(self): """ - Create an instance of this class set to the ``failed`` tag with value - ``val``. - - :param TeamFolderArchiveError val: - :rtype: TeamFolderArchiveJobStatus + :rtype: TeamFolderAccessError """ - return cls('failed', val) + if self._access_error_present: + return self._access_error_value + else: + raise AttributeError("missing required field 'access_error'") - def is_complete(self): - """ - Check if the union tag is ``complete``. + @access_error.setter + def access_error(self, val): + self._access_error_validator.validate_type_only(val) + self._access_error_value = val + self._access_error_present = True + + @access_error.deleter + def access_error(self): + self._access_error_value = None + self._access_error_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamFolderListError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamFolderListError(access_error={!r})'.format( + self._access_error_value, + ) + +TeamFolderListError_validator = bv.Struct(TeamFolderListError) + +class TeamFolderListResult(bb.Struct): + """ + Result for :meth:`dropbox.dropbox.Dropbox.team_team_folder_list` and + :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue`. + + :ivar team.TeamFolderListResult.team_folders: List of all team folders in + the authenticated team. + :ivar team.TeamFolderListResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` to obtain + additional team folders. + :ivar team.TeamFolderListResult.has_more: Is true if there are additional + team folders that have not been returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` can + retrieve them. + """ + + __slots__ = [ + '_team_folders_value', + '_team_folders_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', + ] - :rtype: bool - """ - return self._tag == 'complete' + _has_required_fields = True - def is_failed(self): - """ - Check if the union tag is ``failed``. + def __init__(self, + team_folders=None, + cursor=None, + has_more=None): + self._team_folders_value = None + self._team_folders_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if team_folders is not None: + self.team_folders = team_folders + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more - :rtype: bool + @property + def team_folders(self): """ - return self._tag == 'failed' + List of all team folders in the authenticated team. - def get_complete(self): + :rtype: list of [TeamFolderMetadata] """ - The archive job has finished. The value is the metadata for the - resulting team folder. + if self._team_folders_present: + return self._team_folders_value + else: + raise AttributeError("missing required field 'team_folders'") - Only call this if :meth:`is_complete` is true. + @team_folders.setter + def team_folders(self, val): + val = self._team_folders_validator.validate(val) + self._team_folders_value = val + self._team_folders_present = True - :rtype: TeamFolderMetadata - """ - if not self.is_complete(): - raise AttributeError("tag 'complete' not set") - return self._value + @team_folders.deleter + def team_folders(self): + self._team_folders_value = None + self._team_folders_present = False - def get_failed(self): + @property + def cursor(self): """ - Error occurred while performing an asynchronous job from - :meth:`dropbox.dropbox.Dropbox.team_team_folder_archive`. - - Only call this if :meth:`is_failed` is true. + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` to obtain + additional team folders. - :rtype: TeamFolderArchiveError + :rtype: str """ - if not self.is_failed(): - raise AttributeError("tag 'failed' not set") - return self._value - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderArchiveJobStatus, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamFolderArchiveJobStatus(%r, %r)' % (self._tag, self._value) - -TeamFolderArchiveJobStatus_validator = bv.Union(TeamFolderArchiveJobStatus) - -class TeamFolderArchiveLaunch(async_.LaunchResultBase): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + if self._cursor_present: + return self._cursor_value + else: + raise AttributeError("missing required field 'cursor'") - @classmethod - def complete(cls, val): - """ - Create an instance of this class set to the ``complete`` tag with value - ``val``. + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - :param TeamFolderMetadata val: - :rtype: TeamFolderArchiveLaunch - """ - return cls('complete', val) + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False - def is_complete(self): + @property + def has_more(self): """ - Check if the union tag is ``complete``. + Is true if there are additional team folders that have not been returned + yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` can + retrieve them. :rtype: bool """ - return self._tag == 'complete' + if self._has_more_present: + return self._has_more_value + else: + raise AttributeError("missing required field 'has_more'") - def get_complete(self): - """ - Only call this if :meth:`is_complete` is true. + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - :rtype: TeamFolderMetadata - """ - if not self.is_complete(): - raise AttributeError("tag 'complete' not set") - return self._value + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderArchiveLaunch, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderListResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderArchiveLaunch(%r, %r)' % (self._tag, self._value) + return 'TeamFolderListResult(team_folders={!r}, cursor={!r}, has_more={!r})'.format( + self._team_folders_value, + self._cursor_value, + self._has_more_value, + ) -TeamFolderArchiveLaunch_validator = bv.Union(TeamFolderArchiveLaunch) +TeamFolderListResult_validator = bv.Struct(TeamFolderListResult) -class TeamFolderCreateArg(bb.Struct): +class TeamFolderMetadata(bb.Struct): """ - :ivar team.TeamFolderCreateArg.name: Name for the new team folder. - :ivar team.TeamFolderCreateArg.sync_setting: The sync setting to apply to - this team folder. Only permitted if the team has team selective sync - enabled. + Properties of a team folder. + + :ivar team.TeamFolderMetadata.team_folder_id: The ID of the team folder. + :ivar team.TeamFolderMetadata.name: The name of the team folder. + :ivar team.TeamFolderMetadata.status: The status of the team folder. + :ivar team.TeamFolderMetadata.is_team_shared_dropbox: True if this team + folder is a shared team root. + :ivar team.TeamFolderMetadata.sync_setting: The sync setting applied to this + team folder. + :ivar team.TeamFolderMetadata.content_sync_settings: Sync settings applied + to contents of this team folder. """ __slots__ = [ + '_team_folder_id_value', + '_team_folder_id_present', '_name_value', '_name_present', + '_status_value', + '_status_present', + '_is_team_shared_dropbox_value', + '_is_team_shared_dropbox_present', '_sync_setting_value', '_sync_setting_present', + '_content_sync_settings_value', + '_content_sync_settings_present', ] _has_required_fields = True def __init__(self, + team_folder_id=None, name=None, - sync_setting=None): + status=None, + is_team_shared_dropbox=None, + sync_setting=None, + content_sync_settings=None): + self._team_folder_id_value = None + self._team_folder_id_present = False self._name_value = None self._name_present = False + self._status_value = None + self._status_present = False + self._is_team_shared_dropbox_value = None + self._is_team_shared_dropbox_present = False self._sync_setting_value = None self._sync_setting_present = False + self._content_sync_settings_value = None + self._content_sync_settings_present = False + if team_folder_id is not None: + self.team_folder_id = team_folder_id if name is not None: self.name = name + if status is not None: + self.status = status + if is_team_shared_dropbox is not None: + self.is_team_shared_dropbox = is_team_shared_dropbox if sync_setting is not None: self.sync_setting = sync_setting + if content_sync_settings is not None: + self.content_sync_settings = content_sync_settings + + @property + def team_folder_id(self): + """ + The ID of the team folder. + + :rtype: str + """ + if self._team_folder_id_present: + return self._team_folder_id_value + else: + raise AttributeError("missing required field 'team_folder_id'") + + @team_folder_id.setter + def team_folder_id(self, val): + val = self._team_folder_id_validator.validate(val) + self._team_folder_id_value = val + self._team_folder_id_present = True + + @team_folder_id.deleter + def team_folder_id(self): + self._team_folder_id_value = None + self._team_folder_id_present = False @property def name(self): """ - Name for the new team folder. + The name of the team folder. :rtype: str """ @@ -14059,29 +18412,71 @@ def name(self, val): self._name_value = val self._name_present = True - @name.deleter - def name(self): - self._name_value = None - self._name_present = False + @name.deleter + def name(self): + self._name_value = None + self._name_present = False + + @property + def status(self): + """ + The status of the team folder. + + :rtype: TeamFolderStatus + """ + if self._status_present: + return self._status_value + else: + raise AttributeError("missing required field 'status'") + + @status.setter + def status(self, val): + self._status_validator.validate_type_only(val) + self._status_value = val + self._status_present = True + + @status.deleter + def status(self): + self._status_value = None + self._status_present = False + + @property + def is_team_shared_dropbox(self): + """ + True if this team folder is a shared team root. + + :rtype: bool + """ + if self._is_team_shared_dropbox_present: + return self._is_team_shared_dropbox_value + else: + raise AttributeError("missing required field 'is_team_shared_dropbox'") + + @is_team_shared_dropbox.setter + def is_team_shared_dropbox(self, val): + val = self._is_team_shared_dropbox_validator.validate(val) + self._is_team_shared_dropbox_value = val + self._is_team_shared_dropbox_present = True + + @is_team_shared_dropbox.deleter + def is_team_shared_dropbox(self): + self._is_team_shared_dropbox_value = None + self._is_team_shared_dropbox_present = False @property def sync_setting(self): """ - The sync setting to apply to this team folder. Only permitted if the - team has team selective sync enabled. + The sync setting applied to this team folder. - :rtype: files.SyncSettingArg + :rtype: files.SyncSetting """ if self._sync_setting_present: return self._sync_setting_value else: - return None + raise AttributeError("missing required field 'sync_setting'") @sync_setting.setter def sync_setting(self, val): - if val is None: - del self.sync_setting - return self._sync_setting_validator.validate_type_only(val) self._sync_setting_value = val self._sync_setting_present = True @@ -14091,265 +18486,179 @@ def sync_setting(self): self._sync_setting_value = None self._sync_setting_present = False + @property + def content_sync_settings(self): + """ + Sync settings applied to contents of this team folder. + + :rtype: list of [files.ContentSyncSetting] + """ + if self._content_sync_settings_present: + return self._content_sync_settings_value + else: + raise AttributeError("missing required field 'content_sync_settings'") + + @content_sync_settings.setter + def content_sync_settings(self, val): + val = self._content_sync_settings_validator.validate(val) + self._content_sync_settings_value = val + self._content_sync_settings_present = True + + @content_sync_settings.deleter + def content_sync_settings(self): + self._content_sync_settings_value = None + self._content_sync_settings_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderCreateArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderCreateArg(name={!r}, sync_setting={!r})'.format( + return 'TeamFolderMetadata(team_folder_id={!r}, name={!r}, status={!r}, is_team_shared_dropbox={!r}, sync_setting={!r}, content_sync_settings={!r})'.format( + self._team_folder_id_value, self._name_value, + self._status_value, + self._is_team_shared_dropbox_value, self._sync_setting_value, + self._content_sync_settings_value, ) -TeamFolderCreateArg_validator = bv.Struct(TeamFolderCreateArg) +TeamFolderMetadata_validator = bv.Struct(TeamFolderMetadata) -class TeamFolderCreateError(bb.Union): +class TeamFolderPermanentlyDeleteError(BaseTeamFolderError): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - - :ivar team.TeamFolderCreateError.invalid_folder_name: The provided name - cannot be used. - :ivar team.TeamFolderCreateError.folder_name_already_used: There is already - a team folder with the provided name. - :ivar team.TeamFolderCreateError.folder_name_reserved: The provided name - cannot be used because it is reserved. - :ivar SyncSettingsError TeamFolderCreateError.sync_settings_error: An error - occurred setting the sync settings. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - invalid_folder_name = None - # Attribute is overwritten below the class definition - folder_name_already_used = None - # Attribute is overwritten below the class definition - folder_name_reserved = None - # Attribute is overwritten below the class definition - other = None - - @classmethod - def sync_settings_error(cls, val): - """ - Create an instance of this class set to the ``sync_settings_error`` tag - with value ``val``. - - :param files.SyncSettingsError val: - :rtype: TeamFolderCreateError - """ - return cls('sync_settings_error', val) - - def is_invalid_folder_name(self): - """ - Check if the union tag is ``invalid_folder_name``. - - :rtype: bool - """ - return self._tag == 'invalid_folder_name' - - def is_folder_name_already_used(self): - """ - Check if the union tag is ``folder_name_already_used``. - - :rtype: bool - """ - return self._tag == 'folder_name_already_used' - - def is_folder_name_reserved(self): - """ - Check if the union tag is ``folder_name_reserved``. - - :rtype: bool - """ - return self._tag == 'folder_name_reserved' - - def is_sync_settings_error(self): - """ - Check if the union tag is ``sync_settings_error``. - - :rtype: bool - """ - return self._tag == 'sync_settings_error' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def get_sync_settings_error(self): - """ - An error occurred setting the sync settings. - - Only call this if :meth:`is_sync_settings_error` is true. - - :rtype: files.SyncSettingsError - """ - if not self.is_sync_settings_error(): - raise AttributeError("tag 'sync_settings_error' not set") - return self._value - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderCreateError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderPermanentlyDeleteError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderCreateError(%r, %r)' % (self._tag, self._value) + return 'TeamFolderPermanentlyDeleteError(%r, %r)' % (self._tag, self._value) -TeamFolderCreateError_validator = bv.Union(TeamFolderCreateError) +TeamFolderPermanentlyDeleteError_validator = bv.Union(TeamFolderPermanentlyDeleteError) -class TeamFolderGetInfoItem(bb.Union): +class TeamFolderRenameArg(TeamFolderIdArg): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar str team.TeamFolderGetInfoItem.id_not_found: An ID that was provided - as a parameter to :route:`team_folder/get_info` did not match any of the - team's team folders. - :ivar TeamFolderMetadata TeamFolderGetInfoItem.team_folder_metadata: - Properties of a team folder. + :ivar team.TeamFolderRenameArg.name: New team folder name. """ - _catch_all = None - - @classmethod - def id_not_found(cls, val): - """ - Create an instance of this class set to the ``id_not_found`` tag with - value ``val``. - - :param str val: - :rtype: TeamFolderGetInfoItem - """ - return cls('id_not_found', val) - - @classmethod - def team_folder_metadata(cls, val): - """ - Create an instance of this class set to the ``team_folder_metadata`` tag - with value ``val``. - - :param TeamFolderMetadata val: - :rtype: TeamFolderGetInfoItem - """ - return cls('team_folder_metadata', val) - - def is_id_not_found(self): - """ - Check if the union tag is ``id_not_found``. - - :rtype: bool - """ - return self._tag == 'id_not_found' + __slots__ = [ + '_name_value', + '_name_present', + ] - def is_team_folder_metadata(self): - """ - Check if the union tag is ``team_folder_metadata``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'team_folder_metadata' + def __init__(self, + team_folder_id=None, + name=None): + super(TeamFolderRenameArg, self).__init__(team_folder_id) + self._name_value = None + self._name_present = False + if name is not None: + self.name = name - def get_id_not_found(self): + @property + def name(self): """ - An ID that was provided as a parameter to - :meth:`dropbox.dropbox.Dropbox.team_team_folder_get_info` did not match - any of the team's team folders. - - Only call this if :meth:`is_id_not_found` is true. + New team folder name. :rtype: str """ - if not self.is_id_not_found(): - raise AttributeError("tag 'id_not_found' not set") - return self._value - - def get_team_folder_metadata(self): - """ - Properties of a team folder. + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") - Only call this if :meth:`is_team_folder_metadata` is true. + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True - :rtype: TeamFolderMetadata - """ - if not self.is_team_folder_metadata(): - raise AttributeError("tag 'team_folder_metadata' not set") - return self._value + @name.deleter + def name(self): + self._name_value = None + self._name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderGetInfoItem, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderRenameArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderGetInfoItem(%r, %r)' % (self._tag, self._value) + return 'TeamFolderRenameArg(team_folder_id={!r}, name={!r})'.format( + self._team_folder_id_value, + self._name_value, + ) -TeamFolderGetInfoItem_validator = bv.Union(TeamFolderGetInfoItem) +TeamFolderRenameArg_validator = bv.Struct(TeamFolderRenameArg) -class TeamFolderIdListArg(bb.Struct): +class TeamFolderRenameError(BaseTeamFolderError): """ - :ivar team.TeamFolderIdListArg.team_folder_ids: The list of team folder IDs. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.TeamFolderRenameError.invalid_folder_name: The provided folder + name cannot be used. + :ivar team.TeamFolderRenameError.folder_name_already_used: There is already + a team folder with the same name. + :ivar team.TeamFolderRenameError.folder_name_reserved: The provided name + cannot be used because it is reserved. """ - __slots__ = [ - '_team_folder_ids_value', - '_team_folder_ids_present', - ] + # Attribute is overwritten below the class definition + invalid_folder_name = None + # Attribute is overwritten below the class definition + folder_name_already_used = None + # Attribute is overwritten below the class definition + folder_name_reserved = None - _has_required_fields = True + def is_invalid_folder_name(self): + """ + Check if the union tag is ``invalid_folder_name``. - def __init__(self, - team_folder_ids=None): - self._team_folder_ids_value = None - self._team_folder_ids_present = False - if team_folder_ids is not None: - self.team_folder_ids = team_folder_ids + :rtype: bool + """ + return self._tag == 'invalid_folder_name' - @property - def team_folder_ids(self): + def is_folder_name_already_used(self): """ - The list of team folder IDs. + Check if the union tag is ``folder_name_already_used``. - :rtype: list of [str] + :rtype: bool """ - if self._team_folder_ids_present: - return self._team_folder_ids_value - else: - raise AttributeError("missing required field 'team_folder_ids'") + return self._tag == 'folder_name_already_used' - @team_folder_ids.setter - def team_folder_ids(self, val): - val = self._team_folder_ids_validator.validate(val) - self._team_folder_ids_value = val - self._team_folder_ids_present = True + def is_folder_name_reserved(self): + """ + Check if the union tag is ``folder_name_reserved``. - @team_folder_ids.deleter - def team_folder_ids(self): - self._team_folder_ids_value = None - self._team_folder_ids_present = False + :rtype: bool + """ + return self._tag == 'folder_name_reserved' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderIdListArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderRenameError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderIdListArg(team_folder_ids={!r})'.format( - self._team_folder_ids_value, - ) + return 'TeamFolderRenameError(%r, %r)' % (self._tag, self._value) -TeamFolderIdListArg_validator = bv.Struct(TeamFolderIdListArg) +TeamFolderRenameError_validator = bv.Union(TeamFolderRenameError) -class TeamFolderInvalidStatusError(bb.Union): +class TeamFolderStatus(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamFolderInvalidStatusError.active: The folder is active and the - operation did not succeed. - :ivar team.TeamFolderInvalidStatusError.archived: The folder is archived and - the operation did not succeed. - :ivar team.TeamFolderInvalidStatusError.archive_in_progress: The folder is - being archived and the operation did not succeed. + :ivar team.TeamFolderStatus.active: The team folder and sub-folders are + available to all members. + :ivar team.TeamFolderStatus.archived: The team folder is not accessible + outside of the team folder manager. + :ivar team.TeamFolderStatus.archive_in_progress: The team folder is not + accessible outside of the team folder manager. """ _catch_all = 'other' @@ -14395,142 +18704,36 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderInvalidStatusError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamFolderInvalidStatusError(%r, %r)' % (self._tag, self._value) - -TeamFolderInvalidStatusError_validator = bv.Union(TeamFolderInvalidStatusError) - -class TeamFolderListArg(bb.Struct): - """ - :ivar team.TeamFolderListArg.limit: The maximum number of results to return - per request. - """ - - __slots__ = [ - '_limit_value', - '_limit_present', - ] - - _has_required_fields = False - - def __init__(self, - limit=None): - self._limit_value = None - self._limit_present = False - if limit is not None: - self.limit = limit - - @property - def limit(self): - """ - The maximum number of results to return per request. - - :rtype: int - """ - if self._limit_present: - return self._limit_value - else: - return 1000 - - @limit.setter - def limit(self, val): - val = self._limit_validator.validate(val) - self._limit_value = val - self._limit_present = True - - @limit.deleter - def limit(self): - self._limit_value = None - self._limit_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderListArg, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamFolderListArg(limit={!r})'.format( - self._limit_value, - ) - -TeamFolderListArg_validator = bv.Struct(TeamFolderListArg) - -class TeamFolderListContinueArg(bb.Struct): - """ - :ivar team.TeamFolderListContinueArg.cursor: Indicates from what point to - get the next set of team folders. - """ - - __slots__ = [ - '_cursor_value', - '_cursor_present', - ] - - _has_required_fields = True - - def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor - - @property - def cursor(self): - """ - Indicates from what point to get the next set of team folders. - - :rtype: str - """ - if self._cursor_present: - return self._cursor_value - else: - raise AttributeError("missing required field 'cursor'") - - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True - - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderStatus, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderListContinueArg(cursor={!r})'.format( - self._cursor_value, - ) + return 'TeamFolderStatus(%r, %r)' % (self._tag, self._value) -TeamFolderListContinueArg_validator = bv.Struct(TeamFolderListContinueArg) +TeamFolderStatus_validator = bv.Union(TeamFolderStatus) -class TeamFolderListContinueError(bb.Union): +class TeamFolderTeamSharedDropboxError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamFolderListContinueError.invalid_cursor: The cursor is - invalid. + :ivar team.TeamFolderTeamSharedDropboxError.disallowed: This action is not + allowed for a shared team root. """ _catch_all = 'other' # Attribute is overwritten below the class definition - invalid_cursor = None + disallowed = None # Attribute is overwritten below the class definition other = None - def is_invalid_cursor(self): + def is_disallowed(self): """ - Check if the union tag is ``invalid_cursor``. + Check if the union tag is ``disallowed``. :rtype: bool """ - return self._tag == 'invalid_cursor' + return self._tag == 'disallowed' def is_other(self): """ @@ -14541,281 +18744,216 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamFolderListContinueError(%r, %r)' % (self._tag, self._value) - -TeamFolderListContinueError_validator = bv.Union(TeamFolderListContinueError) - -class TeamFolderListError(bb.Struct): - - __slots__ = [ - '_access_error_value', - '_access_error_present', - ] - - _has_required_fields = True - - def __init__(self, - access_error=None): - self._access_error_value = None - self._access_error_present = False - if access_error is not None: - self.access_error = access_error - - @property - def access_error(self): - """ - :rtype: TeamFolderAccessError - """ - if self._access_error_present: - return self._access_error_value - else: - raise AttributeError("missing required field 'access_error'") - - @access_error.setter - def access_error(self, val): - self._access_error_validator.validate_type_only(val) - self._access_error_value = val - self._access_error_present = True - - @access_error.deleter - def access_error(self): - self._access_error_value = None - self._access_error_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderListError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderTeamSharedDropboxError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderListError(access_error={!r})'.format( - self._access_error_value, - ) + return 'TeamFolderTeamSharedDropboxError(%r, %r)' % (self._tag, self._value) -TeamFolderListError_validator = bv.Struct(TeamFolderListError) +TeamFolderTeamSharedDropboxError_validator = bv.Union(TeamFolderTeamSharedDropboxError) -class TeamFolderListResult(bb.Struct): +class TeamFolderUpdateSyncSettingsArg(TeamFolderIdArg): """ - Result for :meth:`dropbox.dropbox.Dropbox.team_team_folder_list` and - :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue`. - - :ivar team.TeamFolderListResult.team_folders: List of all team folders in - the authenticated team. - :ivar team.TeamFolderListResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` to obtain - additional team folders. - :ivar team.TeamFolderListResult.has_more: Is true if there are additional - team folders that have not been returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` can - retrieve them. + :ivar team.TeamFolderUpdateSyncSettingsArg.sync_setting: Sync setting to + apply to the team folder itself. Only meaningful if the team folder is + not a shared team root. + :ivar team.TeamFolderUpdateSyncSettingsArg.content_sync_settings: Sync + settings to apply to contents of this team folder. """ __slots__ = [ - '_team_folders_value', - '_team_folders_present', - '_cursor_value', - '_cursor_present', - '_has_more_value', - '_has_more_present', + '_sync_setting_value', + '_sync_setting_present', + '_content_sync_settings_value', + '_content_sync_settings_present', ] _has_required_fields = True def __init__(self, - team_folders=None, - cursor=None, - has_more=None): - self._team_folders_value = None - self._team_folders_present = False - self._cursor_value = None - self._cursor_present = False - self._has_more_value = None - self._has_more_present = False - if team_folders is not None: - self.team_folders = team_folders - if cursor is not None: - self.cursor = cursor - if has_more is not None: - self.has_more = has_more + team_folder_id=None, + sync_setting=None, + content_sync_settings=None): + super(TeamFolderUpdateSyncSettingsArg, self).__init__(team_folder_id) + self._sync_setting_value = None + self._sync_setting_present = False + self._content_sync_settings_value = None + self._content_sync_settings_present = False + if sync_setting is not None: + self.sync_setting = sync_setting + if content_sync_settings is not None: + self.content_sync_settings = content_sync_settings @property - def team_folders(self): + def sync_setting(self): """ - List of all team folders in the authenticated team. + Sync setting to apply to the team folder itself. Only meaningful if the + team folder is not a shared team root. - :rtype: list of [TeamFolderMetadata] + :rtype: files.SyncSettingArg """ - if self._team_folders_present: - return self._team_folders_value + if self._sync_setting_present: + return self._sync_setting_value else: - raise AttributeError("missing required field 'team_folders'") + return None - @team_folders.setter - def team_folders(self, val): - val = self._team_folders_validator.validate(val) - self._team_folders_value = val - self._team_folders_present = True + @sync_setting.setter + def sync_setting(self, val): + if val is None: + del self.sync_setting + return + self._sync_setting_validator.validate_type_only(val) + self._sync_setting_value = val + self._sync_setting_present = True - @team_folders.deleter - def team_folders(self): - self._team_folders_value = None - self._team_folders_present = False + @sync_setting.deleter + def sync_setting(self): + self._sync_setting_value = None + self._sync_setting_present = False @property - def cursor(self): + def content_sync_settings(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` to obtain - additional team folders. + Sync settings to apply to contents of this team folder. - :rtype: str + :rtype: list of [files.ContentSyncSettingArg] """ - if self._cursor_present: - return self._cursor_value + if self._content_sync_settings_present: + return self._content_sync_settings_value else: - raise AttributeError("missing required field 'cursor'") + return None - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @content_sync_settings.setter + def content_sync_settings(self, val): + if val is None: + del self.content_sync_settings + return + val = self._content_sync_settings_validator.validate(val) + self._content_sync_settings_value = val + self._content_sync_settings_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @content_sync_settings.deleter + def content_sync_settings(self): + self._content_sync_settings_value = None + self._content_sync_settings_present = False - @property - def has_more(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamFolderUpdateSyncSettingsArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamFolderUpdateSyncSettingsArg(team_folder_id={!r}, sync_setting={!r}, content_sync_settings={!r})'.format( + self._team_folder_id_value, + self._sync_setting_value, + self._content_sync_settings_value, + ) + +TeamFolderUpdateSyncSettingsArg_validator = bv.Struct(TeamFolderUpdateSyncSettingsArg) + +class TeamFolderUpdateSyncSettingsError(BaseTeamFolderError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar SyncSettingsError + TeamFolderUpdateSyncSettingsError.sync_settings_error: An error occurred + setting the sync settings. + """ + + @classmethod + def sync_settings_error(cls, val): """ - Is true if there are additional team folders that have not been returned - yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_team_folder_list_continue` can - retrieve them. + Create an instance of this class set to the ``sync_settings_error`` tag + with value ``val``. + + :param files.SyncSettingsError val: + :rtype: TeamFolderUpdateSyncSettingsError + """ + return cls('sync_settings_error', val) + + def is_sync_settings_error(self): + """ + Check if the union tag is ``sync_settings_error``. :rtype: bool """ - if self._has_more_present: - return self._has_more_value - else: - raise AttributeError("missing required field 'has_more'") + return self._tag == 'sync_settings_error' - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + def get_sync_settings_error(self): + """ + An error occurred setting the sync settings. - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + Only call this if :meth:`is_sync_settings_error` is true. + + :rtype: files.SyncSettingsError + """ + if not self.is_sync_settings_error(): + raise AttributeError("tag 'sync_settings_error' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamFolderUpdateSyncSettingsError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderListResult(team_folders={!r}, cursor={!r}, has_more={!r})'.format( - self._team_folders_value, - self._cursor_value, - self._has_more_value, - ) + return 'TeamFolderUpdateSyncSettingsError(%r, %r)' % (self._tag, self._value) -TeamFolderListResult_validator = bv.Struct(TeamFolderListResult) +TeamFolderUpdateSyncSettingsError_validator = bv.Union(TeamFolderUpdateSyncSettingsError) -class TeamFolderMetadata(bb.Struct): +class TeamGetInfoResult(bb.Struct): """ - Properties of a team folder. - - :ivar team.TeamFolderMetadata.team_folder_id: The ID of the team folder. - :ivar team.TeamFolderMetadata.name: The name of the team folder. - :ivar team.TeamFolderMetadata.status: The status of the team folder. - :ivar team.TeamFolderMetadata.is_team_shared_dropbox: True if this team - folder is a shared team root. - :ivar team.TeamFolderMetadata.sync_setting: The sync setting applied to this - team folder. - :ivar team.TeamFolderMetadata.content_sync_settings: Sync settings applied - to contents of this team folder. + :ivar team.TeamGetInfoResult.name: The name of the team. + :ivar team.TeamGetInfoResult.team_id: The ID of the team. + :ivar team.TeamGetInfoResult.num_licensed_users: The number of licenses + available to the team. + :ivar team.TeamGetInfoResult.num_provisioned_users: The number of accounts + that have been invited or are already active members of the team. """ __slots__ = [ - '_team_folder_id_value', - '_team_folder_id_present', '_name_value', '_name_present', - '_status_value', - '_status_present', - '_is_team_shared_dropbox_value', - '_is_team_shared_dropbox_present', - '_sync_setting_value', - '_sync_setting_present', - '_content_sync_settings_value', - '_content_sync_settings_present', + '_team_id_value', + '_team_id_present', + '_num_licensed_users_value', + '_num_licensed_users_present', + '_num_provisioned_users_value', + '_num_provisioned_users_present', + '_policies_value', + '_policies_present', ] _has_required_fields = True def __init__(self, - team_folder_id=None, name=None, - status=None, - is_team_shared_dropbox=None, - sync_setting=None, - content_sync_settings=None): - self._team_folder_id_value = None - self._team_folder_id_present = False + team_id=None, + num_licensed_users=None, + num_provisioned_users=None, + policies=None): self._name_value = None self._name_present = False - self._status_value = None - self._status_present = False - self._is_team_shared_dropbox_value = None - self._is_team_shared_dropbox_present = False - self._sync_setting_value = None - self._sync_setting_present = False - self._content_sync_settings_value = None - self._content_sync_settings_present = False - if team_folder_id is not None: - self.team_folder_id = team_folder_id + self._team_id_value = None + self._team_id_present = False + self._num_licensed_users_value = None + self._num_licensed_users_present = False + self._num_provisioned_users_value = None + self._num_provisioned_users_present = False + self._policies_value = None + self._policies_present = False if name is not None: self.name = name - if status is not None: - self.status = status - if is_team_shared_dropbox is not None: - self.is_team_shared_dropbox = is_team_shared_dropbox - if sync_setting is not None: - self.sync_setting = sync_setting - if content_sync_settings is not None: - self.content_sync_settings = content_sync_settings - - @property - def team_folder_id(self): - """ - The ID of the team folder. - - :rtype: str - """ - if self._team_folder_id_present: - return self._team_folder_id_value - else: - raise AttributeError("missing required field 'team_folder_id'") - - @team_folder_id.setter - def team_folder_id(self, val): - val = self._team_folder_id_validator.validate(val) - self._team_folder_id_value = val - self._team_folder_id_present = True - - @team_folder_id.deleter - def team_folder_id(self): - self._team_folder_id_value = None - self._team_folder_id_present = False + if team_id is not None: + self.team_id = team_id + if num_licensed_users is not None: + self.num_licensed_users = num_licensed_users + if num_provisioned_users is not None: + self.num_provisioned_users = num_provisioned_users + if policies is not None: + self.policies = policies @property def name(self): """ - The name of the team folder. + The name of the team. :rtype: str """ @@ -14836,1362 +18974,1481 @@ def name(self): self._name_present = False @property - def status(self): + def team_id(self): """ - The status of the team folder. + The ID of the team. - :rtype: TeamFolderStatus + :rtype: str """ - if self._status_present: - return self._status_value + if self._team_id_present: + return self._team_id_value else: - raise AttributeError("missing required field 'status'") + raise AttributeError("missing required field 'team_id'") - @status.setter - def status(self, val): - self._status_validator.validate_type_only(val) - self._status_value = val - self._status_present = True + @team_id.setter + def team_id(self, val): + val = self._team_id_validator.validate(val) + self._team_id_value = val + self._team_id_present = True - @status.deleter - def status(self): - self._status_value = None - self._status_present = False + @team_id.deleter + def team_id(self): + self._team_id_value = None + self._team_id_present = False @property - def is_team_shared_dropbox(self): + def num_licensed_users(self): """ - True if this team folder is a shared team root. + The number of licenses available to the team. - :rtype: bool + :rtype: int """ - if self._is_team_shared_dropbox_present: - return self._is_team_shared_dropbox_value + if self._num_licensed_users_present: + return self._num_licensed_users_value else: - raise AttributeError("missing required field 'is_team_shared_dropbox'") + raise AttributeError("missing required field 'num_licensed_users'") - @is_team_shared_dropbox.setter - def is_team_shared_dropbox(self, val): - val = self._is_team_shared_dropbox_validator.validate(val) - self._is_team_shared_dropbox_value = val - self._is_team_shared_dropbox_present = True + @num_licensed_users.setter + def num_licensed_users(self, val): + val = self._num_licensed_users_validator.validate(val) + self._num_licensed_users_value = val + self._num_licensed_users_present = True - @is_team_shared_dropbox.deleter - def is_team_shared_dropbox(self): - self._is_team_shared_dropbox_value = None - self._is_team_shared_dropbox_present = False + @num_licensed_users.deleter + def num_licensed_users(self): + self._num_licensed_users_value = None + self._num_licensed_users_present = False @property - def sync_setting(self): + def num_provisioned_users(self): """ - The sync setting applied to this team folder. + The number of accounts that have been invited or are already active + members of the team. - :rtype: files.SyncSetting + :rtype: int """ - if self._sync_setting_present: - return self._sync_setting_value + if self._num_provisioned_users_present: + return self._num_provisioned_users_value else: - raise AttributeError("missing required field 'sync_setting'") + raise AttributeError("missing required field 'num_provisioned_users'") - @sync_setting.setter - def sync_setting(self, val): - self._sync_setting_validator.validate_type_only(val) - self._sync_setting_value = val - self._sync_setting_present = True + @num_provisioned_users.setter + def num_provisioned_users(self, val): + val = self._num_provisioned_users_validator.validate(val) + self._num_provisioned_users_value = val + self._num_provisioned_users_present = True - @sync_setting.deleter - def sync_setting(self): - self._sync_setting_value = None - self._sync_setting_present = False + @num_provisioned_users.deleter + def num_provisioned_users(self): + self._num_provisioned_users_value = None + self._num_provisioned_users_present = False @property - def content_sync_settings(self): + def policies(self): """ - Sync settings applied to contents of this team folder. - - :rtype: list of [files.ContentSyncSetting] + :rtype: team_policies.TeamMemberPolicies """ - if self._content_sync_settings_present: - return self._content_sync_settings_value + if self._policies_present: + return self._policies_value else: - raise AttributeError("missing required field 'content_sync_settings'") + raise AttributeError("missing required field 'policies'") - @content_sync_settings.setter - def content_sync_settings(self, val): - val = self._content_sync_settings_validator.validate(val) - self._content_sync_settings_value = val - self._content_sync_settings_present = True + @policies.setter + def policies(self, val): + self._policies_validator.validate_type_only(val) + self._policies_value = val + self._policies_present = True - @content_sync_settings.deleter - def content_sync_settings(self): - self._content_sync_settings_value = None - self._content_sync_settings_present = False + @policies.deleter + def policies(self): + self._policies_value = None + self._policies_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderMetadata, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamGetInfoResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderMetadata(team_folder_id={!r}, name={!r}, status={!r}, is_team_shared_dropbox={!r}, sync_setting={!r}, content_sync_settings={!r})'.format( - self._team_folder_id_value, + return 'TeamGetInfoResult(name={!r}, team_id={!r}, num_licensed_users={!r}, num_provisioned_users={!r}, policies={!r})'.format( self._name_value, - self._status_value, - self._is_team_shared_dropbox_value, - self._sync_setting_value, - self._content_sync_settings_value, + self._team_id_value, + self._num_licensed_users_value, + self._num_provisioned_users_value, + self._policies_value, ) -TeamFolderMetadata_validator = bv.Struct(TeamFolderMetadata) +TeamGetInfoResult_validator = bv.Struct(TeamGetInfoResult) + +class TeamMemberInfo(bb.Struct): + """ + Information about a team member. + + :ivar team.TeamMemberInfo.profile: Profile of a user as a member of a team. + :ivar team.TeamMemberInfo.role: The user's role in the team. + """ + + __slots__ = [ + '_profile_value', + '_profile_present', + '_role_value', + '_role_present', + ] + + _has_required_fields = True + + def __init__(self, + profile=None, + role=None): + self._profile_value = None + self._profile_present = False + self._role_value = None + self._role_present = False + if profile is not None: + self.profile = profile + if role is not None: + self.role = role + + @property + def profile(self): + """ + Profile of a user as a member of a team. + + :rtype: TeamMemberProfile + """ + if self._profile_present: + return self._profile_value + else: + raise AttributeError("missing required field 'profile'") + + @profile.setter + def profile(self, val): + self._profile_validator.validate_type_only(val) + self._profile_value = val + self._profile_present = True + + @profile.deleter + def profile(self): + self._profile_value = None + self._profile_present = False + + @property + def role(self): + """ + The user's role in the team. + + :rtype: AdminTier + """ + if self._role_present: + return self._role_value + else: + raise AttributeError("missing required field 'role'") + + @role.setter + def role(self, val): + self._role_validator.validate_type_only(val) + self._role_value = val + self._role_present = True -class TeamFolderPermanentlyDeleteError(BaseTeamFolderError): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + @role.deleter + def role(self): + self._role_value = None + self._role_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderPermanentlyDeleteError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamMemberInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderPermanentlyDeleteError(%r, %r)' % (self._tag, self._value) + return 'TeamMemberInfo(profile={!r}, role={!r})'.format( + self._profile_value, + self._role_value, + ) -TeamFolderPermanentlyDeleteError_validator = bv.Union(TeamFolderPermanentlyDeleteError) +TeamMemberInfo_validator = bv.Struct(TeamMemberInfo) -class TeamFolderRenameArg(TeamFolderIdArg): +class TeamMemberProfile(MemberProfile): """ - :ivar team.TeamFolderRenameArg.name: New team folder name. + Profile of a user as a member of a team. + + :ivar team.TeamMemberProfile.groups: List of group IDs of groups that the + user belongs to. + :ivar team.TeamMemberProfile.member_folder_id: The namespace id of the + user's root folder. """ __slots__ = [ - '_name_value', - '_name_present', + '_groups_value', + '_groups_present', + '_member_folder_id_value', + '_member_folder_id_present', ] _has_required_fields = True def __init__(self, - team_folder_id=None, - name=None): - super(TeamFolderRenameArg, self).__init__(team_folder_id) - self._name_value = None - self._name_present = False - if name is not None: - self.name = name + team_member_id=None, + email=None, + email_verified=None, + status=None, + name=None, + membership_type=None, + groups=None, + member_folder_id=None, + external_id=None, + account_id=None, + secondary_emails=None, + invited_on=None, + joined_on=None, + suspended_on=None, + persistent_id=None, + is_directory_restricted=None, + profile_photo_url=None): + super(TeamMemberProfile, self).__init__(team_member_id, + email, + email_verified, + status, + name, + membership_type, + external_id, + account_id, + secondary_emails, + invited_on, + joined_on, + suspended_on, + persistent_id, + is_directory_restricted, + profile_photo_url) + self._groups_value = None + self._groups_present = False + self._member_folder_id_value = None + self._member_folder_id_present = False + if groups is not None: + self.groups = groups + if member_folder_id is not None: + self.member_folder_id = member_folder_id @property - def name(self): + def groups(self): """ - New team folder name. + List of group IDs of groups that the user belongs to. + + :rtype: list of [str] + """ + if self._groups_present: + return self._groups_value + else: + raise AttributeError("missing required field 'groups'") + + @groups.setter + def groups(self, val): + val = self._groups_validator.validate(val) + self._groups_value = val + self._groups_present = True + + @groups.deleter + def groups(self): + self._groups_value = None + self._groups_present = False + + @property + def member_folder_id(self): + """ + The namespace id of the user's root folder. :rtype: str """ - if self._name_present: - return self._name_value + if self._member_folder_id_present: + return self._member_folder_id_value else: - raise AttributeError("missing required field 'name'") + raise AttributeError("missing required field 'member_folder_id'") - @name.setter - def name(self, val): - val = self._name_validator.validate(val) - self._name_value = val - self._name_present = True + @member_folder_id.setter + def member_folder_id(self, val): + val = self._member_folder_id_validator.validate(val) + self._member_folder_id_value = val + self._member_folder_id_present = True - @name.deleter - def name(self): - self._name_value = None - self._name_present = False + @member_folder_id.deleter + def member_folder_id(self): + self._member_folder_id_value = None + self._member_folder_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderRenameArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamMemberProfile, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderRenameArg(team_folder_id={!r}, name={!r})'.format( - self._team_folder_id_value, + return 'TeamMemberProfile(team_member_id={!r}, email={!r}, email_verified={!r}, status={!r}, name={!r}, membership_type={!r}, groups={!r}, member_folder_id={!r}, external_id={!r}, account_id={!r}, secondary_emails={!r}, invited_on={!r}, joined_on={!r}, suspended_on={!r}, persistent_id={!r}, is_directory_restricted={!r}, profile_photo_url={!r})'.format( + self._team_member_id_value, + self._email_value, + self._email_verified_value, + self._status_value, self._name_value, + self._membership_type_value, + self._groups_value, + self._member_folder_id_value, + self._external_id_value, + self._account_id_value, + self._secondary_emails_value, + self._invited_on_value, + self._joined_on_value, + self._suspended_on_value, + self._persistent_id_value, + self._is_directory_restricted_value, + self._profile_photo_url_value, ) -TeamFolderRenameArg_validator = bv.Struct(TeamFolderRenameArg) +TeamMemberProfile_validator = bv.Struct(TeamMemberProfile) -class TeamFolderRenameError(BaseTeamFolderError): +class TeamMemberStatus(bb.Union): """ + The user's status as a member of a specific team. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamFolderRenameError.invalid_folder_name: The provided folder - name cannot be used. - :ivar team.TeamFolderRenameError.folder_name_already_used: There is already - a team folder with the same name. - :ivar team.TeamFolderRenameError.folder_name_reserved: The provided name - cannot be used because it is reserved. + :ivar team.TeamMemberStatus.active: User has successfully joined the team. + :ivar team.TeamMemberStatus.invited: User has been invited to a team, but + has not joined the team yet. + :ivar team.TeamMemberStatus.suspended: User is no longer a member of the + team, but the account can be un-suspended, re-establishing the user as a + team member. + :ivar RemovedStatus TeamMemberStatus.removed: User is no longer a member of + the team. Removed users are only listed when include_removed is true in + members/list. """ + _catch_all = None # Attribute is overwritten below the class definition - invalid_folder_name = None + active = None # Attribute is overwritten below the class definition - folder_name_already_used = None + invited = None # Attribute is overwritten below the class definition - folder_name_reserved = None - - def is_invalid_folder_name(self): - """ - Check if the union tag is ``invalid_folder_name``. - - :rtype: bool - """ - return self._tag == 'invalid_folder_name' + suspended = None - def is_folder_name_already_used(self): + @classmethod + def removed(cls, val): """ - Check if the union tag is ``folder_name_already_used``. + Create an instance of this class set to the ``removed`` tag with value + ``val``. - :rtype: bool + :param RemovedStatus val: + :rtype: TeamMemberStatus """ - return self._tag == 'folder_name_already_used' + return cls('removed', val) - def is_folder_name_reserved(self): + def is_active(self): """ - Check if the union tag is ``folder_name_reserved``. + Check if the union tag is ``active``. :rtype: bool """ - return self._tag == 'folder_name_reserved' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderRenameError, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamFolderRenameError(%r, %r)' % (self._tag, self._value) - -TeamFolderRenameError_validator = bv.Union(TeamFolderRenameError) - -class TeamFolderStatus(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.TeamFolderStatus.active: The team folder and sub-folders are - available to all members. - :ivar team.TeamFolderStatus.archived: The team folder is not accessible - outside of the team folder manager. - :ivar team.TeamFolderStatus.archive_in_progress: The team folder is not - accessible outside of the team folder manager. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - active = None - # Attribute is overwritten below the class definition - archived = None - # Attribute is overwritten below the class definition - archive_in_progress = None - # Attribute is overwritten below the class definition - other = None + return self._tag == 'active' - def is_active(self): + def is_invited(self): """ - Check if the union tag is ``active``. + Check if the union tag is ``invited``. :rtype: bool """ - return self._tag == 'active' + return self._tag == 'invited' - def is_archived(self): + def is_suspended(self): """ - Check if the union tag is ``archived``. + Check if the union tag is ``suspended``. :rtype: bool """ - return self._tag == 'archived' + return self._tag == 'suspended' - def is_archive_in_progress(self): + def is_removed(self): """ - Check if the union tag is ``archive_in_progress``. + Check if the union tag is ``removed``. :rtype: bool """ - return self._tag == 'archive_in_progress' + return self._tag == 'removed' - def is_other(self): + def get_removed(self): """ - Check if the union tag is ``other``. + User is no longer a member of the team. Removed users are only listed + when include_removed is true in members/list. - :rtype: bool + Only call this if :meth:`is_removed` is true. + + :rtype: RemovedStatus """ - return self._tag == 'other' + if not self.is_removed(): + raise AttributeError("tag 'removed' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamMemberStatus, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderStatus(%r, %r)' % (self._tag, self._value) + return 'TeamMemberStatus(%r, %r)' % (self._tag, self._value) -TeamFolderStatus_validator = bv.Union(TeamFolderStatus) +TeamMemberStatus_validator = bv.Union(TeamMemberStatus) -class TeamFolderTeamSharedDropboxError(bb.Union): +class TeamMembershipType(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamFolderTeamSharedDropboxError.disallowed: This action is not - allowed for a shared team root. + :ivar team.TeamMembershipType.full: User uses a license and has full access + to team resources like the shared quota. + :ivar team.TeamMembershipType.limited: User does not have access to the + shared quota and team admins have restricted administrative control. """ - _catch_all = 'other' + _catch_all = None # Attribute is overwritten below the class definition - disallowed = None + full = None # Attribute is overwritten below the class definition - other = None + limited = None - def is_disallowed(self): + def is_full(self): """ - Check if the union tag is ``disallowed``. + Check if the union tag is ``full``. :rtype: bool """ - return self._tag == 'disallowed' + return self._tag == 'full' - def is_other(self): + def is_limited(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``limited``. :rtype: bool """ - return self._tag == 'other' + return self._tag == 'limited' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderTeamSharedDropboxError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamMembershipType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderTeamSharedDropboxError(%r, %r)' % (self._tag, self._value) + return 'TeamMembershipType(%r, %r)' % (self._tag, self._value) -TeamFolderTeamSharedDropboxError_validator = bv.Union(TeamFolderTeamSharedDropboxError) +TeamMembershipType_validator = bv.Union(TeamMembershipType) -class TeamFolderUpdateSyncSettingsArg(TeamFolderIdArg): +class TeamNamespacesListArg(bb.Struct): """ - :ivar team.TeamFolderUpdateSyncSettingsArg.sync_setting: Sync setting to - apply to the team folder itself. Only meaningful if the team folder is - not a shared team root. - :ivar team.TeamFolderUpdateSyncSettingsArg.content_sync_settings: Sync - settings to apply to contents of this team folder. + :ivar team.TeamNamespacesListArg.limit: Specifying a value here has no + effect. """ __slots__ = [ - '_sync_setting_value', - '_sync_setting_present', - '_content_sync_settings_value', - '_content_sync_settings_present', + '_limit_value', + '_limit_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - team_folder_id=None, - sync_setting=None, - content_sync_settings=None): - super(TeamFolderUpdateSyncSettingsArg, self).__init__(team_folder_id) - self._sync_setting_value = None - self._sync_setting_present = False - self._content_sync_settings_value = None - self._content_sync_settings_present = False - if sync_setting is not None: - self.sync_setting = sync_setting - if content_sync_settings is not None: - self.content_sync_settings = content_sync_settings + limit=None): + self._limit_value = None + self._limit_present = False + if limit is not None: + self.limit = limit @property - def sync_setting(self): + def limit(self): """ - Sync setting to apply to the team folder itself. Only meaningful if the - team folder is not a shared team root. + Specifying a value here has no effect. - :rtype: files.SyncSettingArg + :rtype: int """ - if self._sync_setting_present: - return self._sync_setting_value + if self._limit_present: + return self._limit_value else: - return None + return 1000 - @sync_setting.setter - def sync_setting(self, val): - if val is None: - del self.sync_setting - return - self._sync_setting_validator.validate_type_only(val) - self._sync_setting_value = val - self._sync_setting_present = True + @limit.setter + def limit(self, val): + val = self._limit_validator.validate(val) + self._limit_value = val + self._limit_present = True - @sync_setting.deleter - def sync_setting(self): - self._sync_setting_value = None - self._sync_setting_present = False + @limit.deleter + def limit(self): + self._limit_value = None + self._limit_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamNamespacesListArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamNamespacesListArg(limit={!r})'.format( + self._limit_value, + ) + +TeamNamespacesListArg_validator = bv.Struct(TeamNamespacesListArg) + +class TeamNamespacesListContinueArg(bb.Struct): + """ + :ivar team.TeamNamespacesListContinueArg.cursor: Indicates from what point + to get the next set of team-accessible namespaces. + """ + + __slots__ = [ + '_cursor_value', + '_cursor_present', + ] + + _has_required_fields = True + + def __init__(self, + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def content_sync_settings(self): + def cursor(self): """ - Sync settings to apply to contents of this team folder. + Indicates from what point to get the next set of team-accessible + namespaces. - :rtype: list of [files.ContentSyncSettingArg] + :rtype: str """ - if self._content_sync_settings_present: - return self._content_sync_settings_value + if self._cursor_present: + return self._cursor_value else: - return None + raise AttributeError("missing required field 'cursor'") - @content_sync_settings.setter - def content_sync_settings(self, val): - if val is None: - del self.content_sync_settings - return - val = self._content_sync_settings_validator.validate(val) - self._content_sync_settings_value = val - self._content_sync_settings_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @content_sync_settings.deleter - def content_sync_settings(self): - self._content_sync_settings_value = None - self._content_sync_settings_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderUpdateSyncSettingsArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamNamespacesListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderUpdateSyncSettingsArg(team_folder_id={!r}, sync_setting={!r}, content_sync_settings={!r})'.format( - self._team_folder_id_value, - self._sync_setting_value, - self._content_sync_settings_value, + return 'TeamNamespacesListContinueArg(cursor={!r})'.format( + self._cursor_value, ) -TeamFolderUpdateSyncSettingsArg_validator = bv.Struct(TeamFolderUpdateSyncSettingsArg) +TeamNamespacesListContinueArg_validator = bv.Struct(TeamNamespacesListContinueArg) -class TeamFolderUpdateSyncSettingsError(BaseTeamFolderError): +class TeamNamespacesListError(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar SyncSettingsError - TeamFolderUpdateSyncSettingsError.sync_settings_error: An error occurred - setting the sync settings. + :ivar team.TeamNamespacesListError.invalid_arg: Argument passed in is + invalid. """ - @classmethod - def sync_settings_error(cls, val): + _catch_all = 'other' + # Attribute is overwritten below the class definition + invalid_arg = None + # Attribute is overwritten below the class definition + other = None + + def is_invalid_arg(self): """ - Create an instance of this class set to the ``sync_settings_error`` tag - with value ``val``. + Check if the union tag is ``invalid_arg``. - :param files.SyncSettingsError val: - :rtype: TeamFolderUpdateSyncSettingsError + :rtype: bool """ - return cls('sync_settings_error', val) + return self._tag == 'invalid_arg' - def is_sync_settings_error(self): + def is_other(self): """ - Check if the union tag is ``sync_settings_error``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'sync_settings_error' + return self._tag == 'other' - def get_sync_settings_error(self): - """ - An error occurred setting the sync settings. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamNamespacesListError, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_sync_settings_error` is true. + def __repr__(self): + return 'TeamNamespacesListError(%r, %r)' % (self._tag, self._value) - :rtype: files.SyncSettingsError +TeamNamespacesListError_validator = bv.Union(TeamNamespacesListError) + +class TeamNamespacesListContinueError(TeamNamespacesListError): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.TeamNamespacesListContinueError.invalid_cursor: The cursor is + invalid. + """ + + # Attribute is overwritten below the class definition + invalid_cursor = None + + def is_invalid_cursor(self): """ - if not self.is_sync_settings_error(): - raise AttributeError("tag 'sync_settings_error' not set") - return self._value + Check if the union tag is ``invalid_cursor``. + + :rtype: bool + """ + return self._tag == 'invalid_cursor' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamFolderUpdateSyncSettingsError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamNamespacesListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamFolderUpdateSyncSettingsError(%r, %r)' % (self._tag, self._value) + return 'TeamNamespacesListContinueError(%r, %r)' % (self._tag, self._value) -TeamFolderUpdateSyncSettingsError_validator = bv.Union(TeamFolderUpdateSyncSettingsError) +TeamNamespacesListContinueError_validator = bv.Union(TeamNamespacesListContinueError) -class TeamGetInfoResult(bb.Struct): +class TeamNamespacesListResult(bb.Struct): """ - :ivar team.TeamGetInfoResult.name: The name of the team. - :ivar team.TeamGetInfoResult.team_id: The ID of the team. - :ivar team.TeamGetInfoResult.num_licensed_users: The number of licenses - available to the team. - :ivar team.TeamGetInfoResult.num_provisioned_users: The number of accounts - that have been invited or are already active members of the team. + Result for :meth:`dropbox.dropbox.Dropbox.team_namespaces_list`. + + :ivar team.TeamNamespacesListResult.namespaces: List of all namespaces the + team can access. + :ivar team.TeamNamespacesListResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_namespaces_list_continue` to obtain + additional namespaces. Note that duplicate namespaces may be returned. + :ivar team.TeamNamespacesListResult.has_more: Is true if there are + additional namespaces that have not been returned yet. """ __slots__ = [ - '_name_value', - '_name_present', - '_team_id_value', - '_team_id_present', - '_num_licensed_users_value', - '_num_licensed_users_present', - '_num_provisioned_users_value', - '_num_provisioned_users_present', - '_policies_value', - '_policies_present', + '_namespaces_value', + '_namespaces_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', ] _has_required_fields = True def __init__(self, - name=None, - team_id=None, - num_licensed_users=None, - num_provisioned_users=None, - policies=None): - self._name_value = None - self._name_present = False - self._team_id_value = None - self._team_id_present = False - self._num_licensed_users_value = None - self._num_licensed_users_present = False - self._num_provisioned_users_value = None - self._num_provisioned_users_present = False - self._policies_value = None - self._policies_present = False - if name is not None: - self.name = name - if team_id is not None: - self.team_id = team_id - if num_licensed_users is not None: - self.num_licensed_users = num_licensed_users - if num_provisioned_users is not None: - self.num_provisioned_users = num_provisioned_users - if policies is not None: - self.policies = policies + namespaces=None, + cursor=None, + has_more=None): + self._namespaces_value = None + self._namespaces_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if namespaces is not None: + self.namespaces = namespaces + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more @property - def name(self): + def namespaces(self): """ - The name of the team. + List of all namespaces the team can access. - :rtype: str + :rtype: list of [NamespaceMetadata] """ - if self._name_present: - return self._name_value + if self._namespaces_present: + return self._namespaces_value else: - raise AttributeError("missing required field 'name'") + raise AttributeError("missing required field 'namespaces'") - @name.setter - def name(self, val): - val = self._name_validator.validate(val) - self._name_value = val - self._name_present = True + @namespaces.setter + def namespaces(self, val): + val = self._namespaces_validator.validate(val) + self._namespaces_value = val + self._namespaces_present = True - @name.deleter - def name(self): - self._name_value = None - self._name_present = False + @namespaces.deleter + def namespaces(self): + self._namespaces_value = None + self._namespaces_present = False @property - def team_id(self): + def cursor(self): """ - The ID of the team. + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_namespaces_list_continue` to obtain + additional namespaces. Note that duplicate namespaces may be returned. :rtype: str """ - if self._team_id_present: - return self._team_id_value + if self._cursor_present: + return self._cursor_value else: - raise AttributeError("missing required field 'team_id'") + raise AttributeError("missing required field 'cursor'") - @team_id.setter - def team_id(self, val): - val = self._team_id_validator.validate(val) - self._team_id_value = val - self._team_id_present = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - @team_id.deleter - def team_id(self): - self._team_id_value = None - self._team_id_present = False + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False @property - def num_licensed_users(self): + def has_more(self): """ - The number of licenses available to the team. + Is true if there are additional namespaces that have not been returned + yet. - :rtype: int + :rtype: bool """ - if self._num_licensed_users_present: - return self._num_licensed_users_value + if self._has_more_present: + return self._has_more_value else: - raise AttributeError("missing required field 'num_licensed_users'") + raise AttributeError("missing required field 'has_more'") - @num_licensed_users.setter - def num_licensed_users(self, val): - val = self._num_licensed_users_validator.validate(val) - self._num_licensed_users_value = val - self._num_licensed_users_present = True + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - @num_licensed_users.deleter - def num_licensed_users(self): - self._num_licensed_users_value = None - self._num_licensed_users_present = False + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False - @property - def num_provisioned_users(self): - """ - The number of accounts that have been invited or are already active - members of the team. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamNamespacesListResult, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: int + def __repr__(self): + return 'TeamNamespacesListResult(namespaces={!r}, cursor={!r}, has_more={!r})'.format( + self._namespaces_value, + self._cursor_value, + self._has_more_value, + ) + +TeamNamespacesListResult_validator = bv.Struct(TeamNamespacesListResult) + +class TeamReportFailureReason(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team.TeamReportFailureReason.temporary_error: We couldn't create the + report, but we think this was a fluke. Everything should work if you try + it again. + :ivar team.TeamReportFailureReason.many_reports_at_once: Too many other + reports are being created right now. Try creating this report again once + the others finish. + :ivar team.TeamReportFailureReason.too_much_data: We couldn't create the + report. Try creating the report again with less data. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + temporary_error = None + # Attribute is overwritten below the class definition + many_reports_at_once = None + # Attribute is overwritten below the class definition + too_much_data = None + # Attribute is overwritten below the class definition + other = None + + def is_temporary_error(self): """ - if self._num_provisioned_users_present: - return self._num_provisioned_users_value - else: - raise AttributeError("missing required field 'num_provisioned_users'") + Check if the union tag is ``temporary_error``. - @num_provisioned_users.setter - def num_provisioned_users(self, val): - val = self._num_provisioned_users_validator.validate(val) - self._num_provisioned_users_value = val - self._num_provisioned_users_present = True + :rtype: bool + """ + return self._tag == 'temporary_error' - @num_provisioned_users.deleter - def num_provisioned_users(self): - self._num_provisioned_users_value = None - self._num_provisioned_users_present = False + def is_many_reports_at_once(self): + """ + Check if the union tag is ``many_reports_at_once``. - @property - def policies(self): + :rtype: bool """ - :rtype: team_policies.TeamMemberPolicies + return self._tag == 'many_reports_at_once' + + def is_too_much_data(self): """ - if self._policies_present: - return self._policies_value - else: - raise AttributeError("missing required field 'policies'") + Check if the union tag is ``too_much_data``. - @policies.setter - def policies(self, val): - self._policies_validator.validate_type_only(val) - self._policies_value = val - self._policies_present = True + :rtype: bool + """ + return self._tag == 'too_much_data' - @policies.deleter - def policies(self): - self._policies_value = None - self._policies_present = False + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamGetInfoResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamReportFailureReason, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamGetInfoResult(name={!r}, team_id={!r}, num_licensed_users={!r}, num_provisioned_users={!r}, policies={!r})'.format( - self._name_value, - self._team_id_value, - self._num_licensed_users_value, - self._num_provisioned_users_value, - self._policies_value, - ) - -TeamGetInfoResult_validator = bv.Struct(TeamGetInfoResult) + return 'TeamReportFailureReason(%r, %r)' % (self._tag, self._value) -class TeamMemberInfo(bb.Struct): - """ - Information about a team member. +TeamReportFailureReason_validator = bv.Union(TeamReportFailureReason) - :ivar team.TeamMemberInfo.profile: Profile of a user as a member of a team. - :ivar team.TeamMemberInfo.role: The user's role in the team. +class TokenGetAuthenticatedAdminError(bb.Union): """ + Error returned by + :meth:`dropbox.dropbox.Dropbox.team_token_get_authenticated_admin`. - __slots__ = [ - '_profile_value', - '_profile_present', - '_role_value', - '_role_present', - ] + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - _has_required_fields = True + :ivar team.TokenGetAuthenticatedAdminError.mapping_not_found: The current + token is not associated with a team admin, because mappings were not + recorded when the token was created. Consider re-authorizing a new + access token to record its authenticating admin. + :ivar team.TokenGetAuthenticatedAdminError.admin_not_active: Either the team + admin that authorized this token is no longer an active member of the + team or no longer a team admin. + """ - def __init__(self, - profile=None, - role=None): - self._profile_value = None - self._profile_present = False - self._role_value = None - self._role_present = False - if profile is not None: - self.profile = profile - if role is not None: - self.role = role + _catch_all = 'other' + # Attribute is overwritten below the class definition + mapping_not_found = None + # Attribute is overwritten below the class definition + admin_not_active = None + # Attribute is overwritten below the class definition + other = None - @property - def profile(self): + def is_mapping_not_found(self): """ - Profile of a user as a member of a team. + Check if the union tag is ``mapping_not_found``. - :rtype: TeamMemberProfile + :rtype: bool """ - if self._profile_present: - return self._profile_value - else: - raise AttributeError("missing required field 'profile'") - - @profile.setter - def profile(self, val): - self._profile_validator.validate_type_only(val) - self._profile_value = val - self._profile_present = True - - @profile.deleter - def profile(self): - self._profile_value = None - self._profile_present = False + return self._tag == 'mapping_not_found' - @property - def role(self): + def is_admin_not_active(self): """ - The user's role in the team. + Check if the union tag is ``admin_not_active``. - :rtype: AdminTier + :rtype: bool """ - if self._role_present: - return self._role_value - else: - raise AttributeError("missing required field 'role'") + return self._tag == 'admin_not_active' - @role.setter - def role(self, val): - self._role_validator.validate_type_only(val) - self._role_value = val - self._role_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @role.deleter - def role(self): - self._role_value = None - self._role_present = False + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamMemberInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TokenGetAuthenticatedAdminError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamMemberInfo(profile={!r}, role={!r})'.format( - self._profile_value, - self._role_value, - ) + return 'TokenGetAuthenticatedAdminError(%r, %r)' % (self._tag, self._value) -TeamMemberInfo_validator = bv.Struct(TeamMemberInfo) +TokenGetAuthenticatedAdminError_validator = bv.Union(TokenGetAuthenticatedAdminError) -class TeamMemberProfile(MemberProfile): +class TokenGetAuthenticatedAdminResult(bb.Struct): """ - Profile of a user as a member of a team. + Results for + :meth:`dropbox.dropbox.Dropbox.team_token_get_authenticated_admin`. - :ivar team.TeamMemberProfile.groups: List of group IDs of groups that the - user belongs to. - :ivar team.TeamMemberProfile.member_folder_id: The namespace id of the - user's root folder. + :ivar team.TokenGetAuthenticatedAdminResult.admin_profile: The admin who + authorized the token. """ __slots__ = [ - '_groups_value', - '_groups_present', - '_member_folder_id_value', - '_member_folder_id_present', + '_admin_profile_value', + '_admin_profile_present', ] _has_required_fields = True def __init__(self, - team_member_id=None, - email=None, - email_verified=None, - status=None, - name=None, - membership_type=None, - groups=None, - member_folder_id=None, - external_id=None, - account_id=None, - joined_on=None, - suspended_on=None, - persistent_id=None, - is_directory_restricted=None, - profile_photo_url=None): - super(TeamMemberProfile, self).__init__(team_member_id, - email, - email_verified, - status, - name, - membership_type, - external_id, - account_id, - joined_on, - suspended_on, - persistent_id, - is_directory_restricted, - profile_photo_url) - self._groups_value = None - self._groups_present = False - self._member_folder_id_value = None - self._member_folder_id_present = False - if groups is not None: - self.groups = groups - if member_folder_id is not None: - self.member_folder_id = member_folder_id - - @property - def groups(self): - """ - List of group IDs of groups that the user belongs to. - - :rtype: list of [str] - """ - if self._groups_present: - return self._groups_value - else: - raise AttributeError("missing required field 'groups'") - - @groups.setter - def groups(self, val): - val = self._groups_validator.validate(val) - self._groups_value = val - self._groups_present = True - - @groups.deleter - def groups(self): - self._groups_value = None - self._groups_present = False + admin_profile=None): + self._admin_profile_value = None + self._admin_profile_present = False + if admin_profile is not None: + self.admin_profile = admin_profile @property - def member_folder_id(self): + def admin_profile(self): """ - The namespace id of the user's root folder. + The admin who authorized the token. - :rtype: str + :rtype: TeamMemberProfile """ - if self._member_folder_id_present: - return self._member_folder_id_value + if self._admin_profile_present: + return self._admin_profile_value else: - raise AttributeError("missing required field 'member_folder_id'") + raise AttributeError("missing required field 'admin_profile'") - @member_folder_id.setter - def member_folder_id(self, val): - val = self._member_folder_id_validator.validate(val) - self._member_folder_id_value = val - self._member_folder_id_present = True + @admin_profile.setter + def admin_profile(self, val): + self._admin_profile_validator.validate_type_only(val) + self._admin_profile_value = val + self._admin_profile_present = True - @member_folder_id.deleter - def member_folder_id(self): - self._member_folder_id_value = None - self._member_folder_id_present = False + @admin_profile.deleter + def admin_profile(self): + self._admin_profile_value = None + self._admin_profile_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamMemberProfile, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TokenGetAuthenticatedAdminResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamMemberProfile(team_member_id={!r}, email={!r}, email_verified={!r}, status={!r}, name={!r}, membership_type={!r}, groups={!r}, member_folder_id={!r}, external_id={!r}, account_id={!r}, joined_on={!r}, suspended_on={!r}, persistent_id={!r}, is_directory_restricted={!r}, profile_photo_url={!r})'.format( - self._team_member_id_value, - self._email_value, - self._email_verified_value, - self._status_value, - self._name_value, - self._membership_type_value, - self._groups_value, - self._member_folder_id_value, - self._external_id_value, - self._account_id_value, - self._joined_on_value, - self._suspended_on_value, - self._persistent_id_value, - self._is_directory_restricted_value, - self._profile_photo_url_value, + return 'TokenGetAuthenticatedAdminResult(admin_profile={!r})'.format( + self._admin_profile_value, ) -TeamMemberProfile_validator = bv.Struct(TeamMemberProfile) +TokenGetAuthenticatedAdminResult_validator = bv.Struct(TokenGetAuthenticatedAdminResult) -class TeamMemberStatus(bb.Union): +class UploadApiRateLimitValue(bb.Union): """ - The user's status as a member of a specific team. + The value for ``Feature.upload_api_rate_limit``. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamMemberStatus.active: User has successfully joined the team. - :ivar team.TeamMemberStatus.invited: User has been invited to a team, but - has not joined the team yet. - :ivar team.TeamMemberStatus.suspended: User is no longer a member of the - team, but the account can be un-suspended, re-establishing the user as a - team member. - :ivar RemovedStatus TeamMemberStatus.removed: User is no longer a member of - the team. Removed users are only listed when include_removed is true in - members/list. + :ivar team.UploadApiRateLimitValue.unlimited: This team has unlimited upload + API quota. So far both server version account and legacy account type + have unlimited monthly upload api quota. + :ivar int team.UploadApiRateLimitValue.limit: The number of upload API calls + allowed per month. """ - _catch_all = None - # Attribute is overwritten below the class definition - active = None + _catch_all = 'other' # Attribute is overwritten below the class definition - invited = None + unlimited = None # Attribute is overwritten below the class definition - suspended = None + other = None @classmethod - def removed(cls, val): + def limit(cls, val): """ - Create an instance of this class set to the ``removed`` tag with value + Create an instance of this class set to the ``limit`` tag with value ``val``. - :param RemovedStatus val: - :rtype: TeamMemberStatus - """ - return cls('removed', val) - - def is_active(self): - """ - Check if the union tag is ``active``. - - :rtype: bool + :param int val: + :rtype: UploadApiRateLimitValue """ - return self._tag == 'active' + return cls('limit', val) - def is_invited(self): + def is_unlimited(self): """ - Check if the union tag is ``invited``. + Check if the union tag is ``unlimited``. :rtype: bool """ - return self._tag == 'invited' + return self._tag == 'unlimited' - def is_suspended(self): + def is_limit(self): """ - Check if the union tag is ``suspended``. + Check if the union tag is ``limit``. :rtype: bool """ - return self._tag == 'suspended' + return self._tag == 'limit' - def is_removed(self): + def is_other(self): """ - Check if the union tag is ``removed``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'removed' + return self._tag == 'other' - def get_removed(self): + def get_limit(self): """ - User is no longer a member of the team. Removed users are only listed - when include_removed is true in members/list. + The number of upload API calls allowed per month. - Only call this if :meth:`is_removed` is true. + Only call this if :meth:`is_limit` is true. - :rtype: RemovedStatus + :rtype: int """ - if not self.is_removed(): - raise AttributeError("tag 'removed' not set") + if not self.is_limit(): + raise AttributeError("tag 'limit' not set") return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamMemberStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UploadApiRateLimitValue, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamMemberStatus(%r, %r)' % (self._tag, self._value) + return 'UploadApiRateLimitValue(%r, %r)' % (self._tag, self._value) -TeamMemberStatus_validator = bv.Union(TeamMemberStatus) +UploadApiRateLimitValue_validator = bv.Union(UploadApiRateLimitValue) -class TeamMembershipType(bb.Union): +class UserAddResult(bb.Union): """ + Result of trying to add secondary emails to a user. 'success' is the only + value indicating that a user was successfully retrieved for adding secondary + emails. The other values explain the type of error that occurred, and + include the user for which the error occured. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamMembershipType.full: User uses a license and has full access - to team resources like the shared quota. - :ivar team.TeamMembershipType.limited: User does not have access to the - shared quota and team admins have restricted administrative control. + :ivar UserSecondaryEmailsResult UserAddResult.success: Describes a user and + the results for each attempt to add a secondary email. + :ivar UserSelectorArg UserAddResult.invalid_user: Specified user is not a + valid target for adding secondary emails. + :ivar UserSelectorArg UserAddResult.unverified: Secondary emails can only be + added to verified users. + :ivar UserSelectorArg UserAddResult.placeholder_user: Secondary emails + cannot be added to placeholder users. """ - _catch_all = None - # Attribute is overwritten below the class definition - full = None + _catch_all = 'other' # Attribute is overwritten below the class definition - limited = None + other = None - def is_full(self): + @classmethod + def success(cls, val): """ - Check if the union tag is ``full``. + Create an instance of this class set to the ``success`` tag with value + ``val``. - :rtype: bool + :param UserSecondaryEmailsResult val: + :rtype: UserAddResult """ - return self._tag == 'full' + return cls('success', val) - def is_limited(self): + @classmethod + def invalid_user(cls, val): """ - Check if the union tag is ``limited``. + Create an instance of this class set to the ``invalid_user`` tag with + value ``val``. - :rtype: bool + :param UserSelectorArg val: + :rtype: UserAddResult """ - return self._tag == 'limited' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamMembershipType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamMembershipType(%r, %r)' % (self._tag, self._value) - -TeamMembershipType_validator = bv.Union(TeamMembershipType) - -class TeamNamespacesListArg(bb.Struct): - """ - :ivar team.TeamNamespacesListArg.limit: Specifying a value here has no - effect. - """ - - __slots__ = [ - '_limit_value', - '_limit_present', - ] - - _has_required_fields = False - - def __init__(self, - limit=None): - self._limit_value = None - self._limit_present = False - if limit is not None: - self.limit = limit + return cls('invalid_user', val) - @property - def limit(self): + @classmethod + def unverified(cls, val): """ - Specifying a value here has no effect. + Create an instance of this class set to the ``unverified`` tag with + value ``val``. - :rtype: int + :param UserSelectorArg val: + :rtype: UserAddResult """ - if self._limit_present: - return self._limit_value - else: - return 1000 - - @limit.setter - def limit(self, val): - val = self._limit_validator.validate(val) - self._limit_value = val - self._limit_present = True + return cls('unverified', val) - @limit.deleter - def limit(self): - self._limit_value = None - self._limit_present = False + @classmethod + def placeholder_user(cls, val): + """ + Create an instance of this class set to the ``placeholder_user`` tag + with value ``val``. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamNamespacesListArg, self)._process_custom_annotations(annotation_type, field_path, processor) + :param UserSelectorArg val: + :rtype: UserAddResult + """ + return cls('placeholder_user', val) - def __repr__(self): - return 'TeamNamespacesListArg(limit={!r})'.format( - self._limit_value, - ) + def is_success(self): + """ + Check if the union tag is ``success``. -TeamNamespacesListArg_validator = bv.Struct(TeamNamespacesListArg) + :rtype: bool + """ + return self._tag == 'success' -class TeamNamespacesListContinueArg(bb.Struct): - """ - :ivar team.TeamNamespacesListContinueArg.cursor: Indicates from what point - to get the next set of team-accessible namespaces. - """ + def is_invalid_user(self): + """ + Check if the union tag is ``invalid_user``. - __slots__ = [ - '_cursor_value', - '_cursor_present', - ] + :rtype: bool + """ + return self._tag == 'invalid_user' - _has_required_fields = True + def is_unverified(self): + """ + Check if the union tag is ``unverified``. - def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + :rtype: bool + """ + return self._tag == 'unverified' - @property - def cursor(self): + def is_placeholder_user(self): """ - Indicates from what point to get the next set of team-accessible - namespaces. + Check if the union tag is ``placeholder_user``. - :rtype: str + :rtype: bool """ - if self._cursor_present: - return self._cursor_value - else: - raise AttributeError("missing required field 'cursor'") + return self._tag == 'placeholder_user' - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + :rtype: bool + """ + return self._tag == 'other' - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamNamespacesListContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + def get_success(self): + """ + Describes a user and the results for each attempt to add a secondary + email. - def __repr__(self): - return 'TeamNamespacesListContinueArg(cursor={!r})'.format( - self._cursor_value, - ) + Only call this if :meth:`is_success` is true. -TeamNamespacesListContinueArg_validator = bv.Struct(TeamNamespacesListContinueArg) + :rtype: UserSecondaryEmailsResult + """ + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value -class TeamNamespacesListError(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + def get_invalid_user(self): + """ + Specified user is not a valid target for adding secondary emails. - :ivar team.TeamNamespacesListError.invalid_arg: Argument passed in is - invalid. - """ + Only call this if :meth:`is_invalid_user` is true. - _catch_all = 'other' - # Attribute is overwritten below the class definition - invalid_arg = None - # Attribute is overwritten below the class definition - other = None + :rtype: UserSelectorArg + """ + if not self.is_invalid_user(): + raise AttributeError("tag 'invalid_user' not set") + return self._value - def is_invalid_arg(self): + def get_unverified(self): """ - Check if the union tag is ``invalid_arg``. + Secondary emails can only be added to verified users. - :rtype: bool + Only call this if :meth:`is_unverified` is true. + + :rtype: UserSelectorArg """ - return self._tag == 'invalid_arg' + if not self.is_unverified(): + raise AttributeError("tag 'unverified' not set") + return self._value - def is_other(self): + def get_placeholder_user(self): """ - Check if the union tag is ``other``. + Secondary emails cannot be added to placeholder users. - :rtype: bool + Only call this if :meth:`is_placeholder_user` is true. + + :rtype: UserSelectorArg """ - return self._tag == 'other' + if not self.is_placeholder_user(): + raise AttributeError("tag 'placeholder_user' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamNamespacesListError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserAddResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamNamespacesListError(%r, %r)' % (self._tag, self._value) + return 'UserAddResult(%r, %r)' % (self._tag, self._value) -TeamNamespacesListError_validator = bv.Union(TeamNamespacesListError) +UserAddResult_validator = bv.Union(UserAddResult) -class TeamNamespacesListContinueError(TeamNamespacesListError): +class UserCustomQuotaArg(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.TeamNamespacesListContinueError.invalid_cursor: The cursor is - invalid. + User and their required custom quota in GB (1 TB = 1024 GB). """ - # Attribute is overwritten below the class definition - invalid_cursor = None + __slots__ = [ + '_user_value', + '_user_present', + '_quota_gb_value', + '_quota_gb_present', + ] - def is_invalid_cursor(self): + _has_required_fields = True + + def __init__(self, + user=None, + quota_gb=None): + self._user_value = None + self._user_present = False + self._quota_gb_value = None + self._quota_gb_present = False + if user is not None: + self.user = user + if quota_gb is not None: + self.quota_gb = quota_gb + + @property + def user(self): """ - Check if the union tag is ``invalid_cursor``. + :rtype: UserSelectorArg + """ + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") - :rtype: bool + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False + + @property + def quota_gb(self): """ - return self._tag == 'invalid_cursor' + :rtype: int + """ + if self._quota_gb_present: + return self._quota_gb_value + else: + raise AttributeError("missing required field 'quota_gb'") + + @quota_gb.setter + def quota_gb(self, val): + val = self._quota_gb_validator.validate(val) + self._quota_gb_value = val + self._quota_gb_present = True + + @quota_gb.deleter + def quota_gb(self): + self._quota_gb_value = None + self._quota_gb_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamNamespacesListContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserCustomQuotaArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamNamespacesListContinueError(%r, %r)' % (self._tag, self._value) + return 'UserCustomQuotaArg(user={!r}, quota_gb={!r})'.format( + self._user_value, + self._quota_gb_value, + ) -TeamNamespacesListContinueError_validator = bv.Union(TeamNamespacesListContinueError) +UserCustomQuotaArg_validator = bv.Struct(UserCustomQuotaArg) -class TeamNamespacesListResult(bb.Struct): +class UserCustomQuotaResult(bb.Struct): """ - Result for :meth:`dropbox.dropbox.Dropbox.team_namespaces_list`. - - :ivar team.TeamNamespacesListResult.namespaces: List of all namespaces the - team can access. - :ivar team.TeamNamespacesListResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_namespaces_list_continue` to obtain - additional namespaces. Note that duplicate namespaces may be returned. - :ivar team.TeamNamespacesListResult.has_more: Is true if there are - additional namespaces that have not been returned yet. + User and their custom quota in GB (1 TB = 1024 GB). No quota returns if the + user has no custom quota set. """ __slots__ = [ - '_namespaces_value', - '_namespaces_present', - '_cursor_value', - '_cursor_present', - '_has_more_value', - '_has_more_present', + '_user_value', + '_user_present', + '_quota_gb_value', + '_quota_gb_present', ] _has_required_fields = True def __init__(self, - namespaces=None, - cursor=None, - has_more=None): - self._namespaces_value = None - self._namespaces_present = False - self._cursor_value = None - self._cursor_present = False - self._has_more_value = None - self._has_more_present = False - if namespaces is not None: - self.namespaces = namespaces - if cursor is not None: - self.cursor = cursor - if has_more is not None: - self.has_more = has_more + user=None, + quota_gb=None): + self._user_value = None + self._user_present = False + self._quota_gb_value = None + self._quota_gb_present = False + if user is not None: + self.user = user + if quota_gb is not None: + self.quota_gb = quota_gb @property - def namespaces(self): + def user(self): """ - List of all namespaces the team can access. - - :rtype: list of [NamespaceMetadata] + :rtype: UserSelectorArg """ - if self._namespaces_present: - return self._namespaces_value + if self._user_present: + return self._user_value else: - raise AttributeError("missing required field 'namespaces'") + raise AttributeError("missing required field 'user'") - @namespaces.setter - def namespaces(self, val): - val = self._namespaces_validator.validate(val) - self._namespaces_value = val - self._namespaces_present = True + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True - @namespaces.deleter - def namespaces(self): - self._namespaces_value = None - self._namespaces_present = False + @user.deleter + def user(self): + self._user_value = None + self._user_present = False @property - def cursor(self): + def quota_gb(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_namespaces_list_continue` to obtain - additional namespaces. Note that duplicate namespaces may be returned. - - :rtype: str + :rtype: int """ - if self._cursor_present: - return self._cursor_value + if self._quota_gb_present: + return self._quota_gb_value else: - raise AttributeError("missing required field 'cursor'") + return None - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @quota_gb.setter + def quota_gb(self, val): + if val is None: + del self.quota_gb + return + val = self._quota_gb_validator.validate(val) + self._quota_gb_value = val + self._quota_gb_present = True + + @quota_gb.deleter + def quota_gb(self): + self._quota_gb_value = None + self._quota_gb_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserCustomQuotaResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserCustomQuotaResult(user={!r}, quota_gb={!r})'.format( + self._user_value, + self._quota_gb_value, + ) + +UserCustomQuotaResult_validator = bv.Struct(UserCustomQuotaResult) + +class UserDeleteEmailsResult(bb.Struct): + + __slots__ = [ + '_user_value', + '_user_present', + '_results_value', + '_results_present', + ] + + _has_required_fields = True + + def __init__(self, + user=None, + results=None): + self._user_value = None + self._user_present = False + self._results_value = None + self._results_present = False + if user is not None: + self.user = user + if results is not None: + self.results = results + + @property + def user(self): + """ + :rtype: UserSelectorArg + """ + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False @property - def has_more(self): + def results(self): """ - Is true if there are additional namespaces that have not been returned - yet. - - :rtype: bool + :rtype: list of [DeleteSecondaryEmailResult] """ - if self._has_more_present: - return self._has_more_value + if self._results_present: + return self._results_value else: - raise AttributeError("missing required field 'has_more'") + raise AttributeError("missing required field 'results'") - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True + @results.setter + def results(self, val): + val = self._results_validator.validate(val) + self._results_value = val + self._results_present = True - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False + @results.deleter + def results(self): + self._results_value = None + self._results_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamNamespacesListResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserDeleteEmailsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamNamespacesListResult(namespaces={!r}, cursor={!r}, has_more={!r})'.format( - self._namespaces_value, - self._cursor_value, - self._has_more_value, + return 'UserDeleteEmailsResult(user={!r}, results={!r})'.format( + self._user_value, + self._results_value, ) -TeamNamespacesListResult_validator = bv.Struct(TeamNamespacesListResult) +UserDeleteEmailsResult_validator = bv.Struct(UserDeleteEmailsResult) -class TeamReportFailureReason(bb.Union): +class UserDeleteResult(bb.Union): """ + Result of trying to delete a user's secondary emails. 'success' is the only + value indicating that a user was successfully retrieved for deleting + secondary emails. The other values explain the type of error that occurred, + and include the user for which the error occured. + This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.TeamReportFailureReason.temporary_error: We couldn't create the - report, but we think this was a fluke. Everything should work if you try - it again. - :ivar team.TeamReportFailureReason.many_reports_at_once: Too many other - reports are being created right now. Try creating this report again once - the others finish. - :ivar team.TeamReportFailureReason.too_much_data: We couldn't create the - report. Try creating the report again with less data. + :ivar UserDeleteEmailsResult UserDeleteResult.success: Describes a user and + the results for each attempt to delete a secondary email. + :ivar UserSelectorArg UserDeleteResult.invalid_user: Specified user is not a + valid target for deleting secondary emails. """ _catch_all = 'other' # Attribute is overwritten below the class definition - temporary_error = None - # Attribute is overwritten below the class definition - many_reports_at_once = None - # Attribute is overwritten below the class definition - too_much_data = None - # Attribute is overwritten below the class definition other = None - def is_temporary_error(self): + @classmethod + def success(cls, val): """ - Check if the union tag is ``temporary_error``. + Create an instance of this class set to the ``success`` tag with value + ``val``. - :rtype: bool + :param UserDeleteEmailsResult val: + :rtype: UserDeleteResult """ - return self._tag == 'temporary_error' + return cls('success', val) - def is_many_reports_at_once(self): + @classmethod + def invalid_user(cls, val): """ - Check if the union tag is ``many_reports_at_once``. + Create an instance of this class set to the ``invalid_user`` tag with + value ``val``. + + :param UserSelectorArg val: + :rtype: UserDeleteResult + """ + return cls('invalid_user', val) + + def is_success(self): + """ + Check if the union tag is ``success``. :rtype: bool """ - return self._tag == 'many_reports_at_once' + return self._tag == 'success' - def is_too_much_data(self): + def is_invalid_user(self): """ - Check if the union tag is ``too_much_data``. + Check if the union tag is ``invalid_user``. :rtype: bool """ - return self._tag == 'too_much_data' + return self._tag == 'invalid_user' def is_other(self): """ @@ -16201,175 +20458,173 @@ def is_other(self): """ return self._tag == 'other' - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamReportFailureReason, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamReportFailureReason(%r, %r)' % (self._tag, self._value) - -TeamReportFailureReason_validator = bv.Union(TeamReportFailureReason) - -class TokenGetAuthenticatedAdminError(bb.Union): - """ - Error returned by - :meth:`dropbox.dropbox.Dropbox.team_token_get_authenticated_admin`. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - - :ivar team.TokenGetAuthenticatedAdminError.mapping_not_found: The current - token is not associated with a team admin, because mappings were not - recorded when the token was created. Consider re-authorizing a new - access token to record its authenticating admin. - :ivar team.TokenGetAuthenticatedAdminError.admin_not_active: Either the team - admin that authorized this token is no longer an active member of the - team or no longer a team admin. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - mapping_not_found = None - # Attribute is overwritten below the class definition - admin_not_active = None - # Attribute is overwritten below the class definition - other = None - - def is_mapping_not_found(self): + def get_success(self): """ - Check if the union tag is ``mapping_not_found``. + Describes a user and the results for each attempt to delete a secondary + email. - :rtype: bool - """ - return self._tag == 'mapping_not_found' + Only call this if :meth:`is_success` is true. - def is_admin_not_active(self): + :rtype: UserDeleteEmailsResult """ - Check if the union tag is ``admin_not_active``. + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value - :rtype: bool + def get_invalid_user(self): """ - return self._tag == 'admin_not_active' + Specified user is not a valid target for deleting secondary emails. - def is_other(self): - """ - Check if the union tag is ``other``. + Only call this if :meth:`is_invalid_user` is true. - :rtype: bool + :rtype: UserSelectorArg """ - return self._tag == 'other' + if not self.is_invalid_user(): + raise AttributeError("tag 'invalid_user' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TokenGetAuthenticatedAdminError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserDeleteResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TokenGetAuthenticatedAdminError(%r, %r)' % (self._tag, self._value) - -TokenGetAuthenticatedAdminError_validator = bv.Union(TokenGetAuthenticatedAdminError) + return 'UserDeleteResult(%r, %r)' % (self._tag, self._value) -class TokenGetAuthenticatedAdminResult(bb.Struct): - """ - Results for - :meth:`dropbox.dropbox.Dropbox.team_token_get_authenticated_admin`. +UserDeleteResult_validator = bv.Union(UserDeleteResult) - :ivar team.TokenGetAuthenticatedAdminResult.admin_profile: The admin who - authorized the token. - """ +class UserResendEmailsResult(bb.Struct): __slots__ = [ - '_admin_profile_value', - '_admin_profile_present', + '_user_value', + '_user_present', + '_results_value', + '_results_present', ] _has_required_fields = True def __init__(self, - admin_profile=None): - self._admin_profile_value = None - self._admin_profile_present = False - if admin_profile is not None: - self.admin_profile = admin_profile + user=None, + results=None): + self._user_value = None + self._user_present = False + self._results_value = None + self._results_present = False + if user is not None: + self.user = user + if results is not None: + self.results = results @property - def admin_profile(self): + def user(self): """ - The admin who authorized the token. + :rtype: UserSelectorArg + """ + if self._user_present: + return self._user_value + else: + raise AttributeError("missing required field 'user'") - :rtype: TeamMemberProfile + @user.setter + def user(self, val): + self._user_validator.validate_type_only(val) + self._user_value = val + self._user_present = True + + @user.deleter + def user(self): + self._user_value = None + self._user_present = False + + @property + def results(self): """ - if self._admin_profile_present: - return self._admin_profile_value + :rtype: list of [ResendSecondaryEmailResult] + """ + if self._results_present: + return self._results_value else: - raise AttributeError("missing required field 'admin_profile'") + raise AttributeError("missing required field 'results'") - @admin_profile.setter - def admin_profile(self, val): - self._admin_profile_validator.validate_type_only(val) - self._admin_profile_value = val - self._admin_profile_present = True + @results.setter + def results(self, val): + val = self._results_validator.validate(val) + self._results_value = val + self._results_present = True - @admin_profile.deleter - def admin_profile(self): - self._admin_profile_value = None - self._admin_profile_present = False + @results.deleter + def results(self): + self._results_value = None + self._results_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TokenGetAuthenticatedAdminResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserResendEmailsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TokenGetAuthenticatedAdminResult(admin_profile={!r})'.format( - self._admin_profile_value, + return 'UserResendEmailsResult(user={!r}, results={!r})'.format( + self._user_value, + self._results_value, ) -TokenGetAuthenticatedAdminResult_validator = bv.Struct(TokenGetAuthenticatedAdminResult) +UserResendEmailsResult_validator = bv.Struct(UserResendEmailsResult) -class UploadApiRateLimitValue(bb.Union): +class UserResendResult(bb.Union): """ - The value for ``Feature.upload_api_rate_limit``. + Result of trying to resend verification emails to a user. 'success' is the + only value indicating that a user was successfully retrieved for sending + verification emails. The other values explain the type of error that + occurred, and include the user for which the error occured. This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - :ivar team.UploadApiRateLimitValue.unlimited: This team has unlimited upload - API quota. So far both server version account and legacy account type - have unlimited monthly upload api quota. - :ivar int team.UploadApiRateLimitValue.limit: The number of upload API calls - allowed per month. + :ivar UserResendEmailsResult UserResendResult.success: Describes a user and + the results for each attempt to resend verification emails. + :ivar UserSelectorArg UserResendResult.invalid_user: Specified user is not a + valid target for resending verification emails. """ _catch_all = 'other' # Attribute is overwritten below the class definition - unlimited = None - # Attribute is overwritten below the class definition other = None @classmethod - def limit(cls, val): + def success(cls, val): """ - Create an instance of this class set to the ``limit`` tag with value + Create an instance of this class set to the ``success`` tag with value ``val``. - :param int val: - :rtype: UploadApiRateLimitValue + :param UserResendEmailsResult val: + :rtype: UserResendResult """ - return cls('limit', val) + return cls('success', val) - def is_unlimited(self): + @classmethod + def invalid_user(cls, val): """ - Check if the union tag is ``unlimited``. + Create an instance of this class set to the ``invalid_user`` tag with + value ``val``. + + :param UserSelectorArg val: + :rtype: UserResendResult + """ + return cls('invalid_user', val) + + def is_success(self): + """ + Check if the union tag is ``success``. :rtype: bool """ - return self._tag == 'unlimited' + return self._tag == 'success' - def is_limit(self): + def is_invalid_user(self): """ - Check if the union tag is ``limit``. + Check if the union tag is ``invalid_user``. :rtype: bool """ - return self._tag == 'limit' + return self._tag == 'invalid_user' def is_other(self): """ @@ -16379,51 +20634,64 @@ def is_other(self): """ return self._tag == 'other' - def get_limit(self): + def get_success(self): + """ + Describes a user and the results for each attempt to resend verification + emails. + + Only call this if :meth:`is_success` is true. + + :rtype: UserResendEmailsResult + """ + if not self.is_success(): + raise AttributeError("tag 'success' not set") + return self._value + + def get_invalid_user(self): """ - The number of upload API calls allowed per month. + Specified user is not a valid target for resending verification emails. - Only call this if :meth:`is_limit` is true. + Only call this if :meth:`is_invalid_user` is true. - :rtype: int + :rtype: UserSelectorArg """ - if not self.is_limit(): - raise AttributeError("tag 'limit' not set") + if not self.is_invalid_user(): + raise AttributeError("tag 'invalid_user' not set") return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(UploadApiRateLimitValue, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserResendResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'UploadApiRateLimitValue(%r, %r)' % (self._tag, self._value) + return 'UserResendResult(%r, %r)' % (self._tag, self._value) -UploadApiRateLimitValue_validator = bv.Union(UploadApiRateLimitValue) +UserResendResult_validator = bv.Union(UserResendResult) -class UserCustomQuotaArg(bb.Struct): +class UserSecondaryEmailsArg(bb.Struct): """ - User and their required custom quota in GB (1 TB = 1024 GB). + User and a list of secondary emails. """ __slots__ = [ '_user_value', '_user_present', - '_quota_gb_value', - '_quota_gb_present', + '_secondary_emails_value', + '_secondary_emails_present', ] _has_required_fields = True def __init__(self, user=None, - quota_gb=None): + secondary_emails=None): self._user_value = None self._user_present = False - self._quota_gb_value = None - self._quota_gb_present = False + self._secondary_emails_value = None + self._secondary_emails_present = False if user is not None: self.user = user - if quota_gb is not None: - self.quota_gb = quota_gb + if secondary_emails is not None: + self.secondary_emails = secondary_emails @property def user(self): @@ -16447,63 +20715,59 @@ def user(self): self._user_present = False @property - def quota_gb(self): + def secondary_emails(self): """ - :rtype: int + :rtype: list of [str] """ - if self._quota_gb_present: - return self._quota_gb_value + if self._secondary_emails_present: + return self._secondary_emails_value else: - raise AttributeError("missing required field 'quota_gb'") + raise AttributeError("missing required field 'secondary_emails'") - @quota_gb.setter - def quota_gb(self, val): - val = self._quota_gb_validator.validate(val) - self._quota_gb_value = val - self._quota_gb_present = True + @secondary_emails.setter + def secondary_emails(self, val): + val = self._secondary_emails_validator.validate(val) + self._secondary_emails_value = val + self._secondary_emails_present = True - @quota_gb.deleter - def quota_gb(self): - self._quota_gb_value = None - self._quota_gb_present = False + @secondary_emails.deleter + def secondary_emails(self): + self._secondary_emails_value = None + self._secondary_emails_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(UserCustomQuotaArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserSecondaryEmailsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'UserCustomQuotaArg(user={!r}, quota_gb={!r})'.format( + return 'UserSecondaryEmailsArg(user={!r}, secondary_emails={!r})'.format( self._user_value, - self._quota_gb_value, + self._secondary_emails_value, ) -UserCustomQuotaArg_validator = bv.Struct(UserCustomQuotaArg) +UserSecondaryEmailsArg_validator = bv.Struct(UserSecondaryEmailsArg) -class UserCustomQuotaResult(bb.Struct): - """ - User and their custom quota in GB (1 TB = 1024 GB). No quota returns if the - user has no custom quota set. - """ +class UserSecondaryEmailsResult(bb.Struct): __slots__ = [ '_user_value', '_user_present', - '_quota_gb_value', - '_quota_gb_present', + '_results_value', + '_results_present', ] _has_required_fields = True def __init__(self, user=None, - quota_gb=None): + results=None): self._user_value = None self._user_present = False - self._quota_gb_value = None - self._quota_gb_present = False + self._results_value = None + self._results_present = False if user is not None: self.user = user - if quota_gb is not None: - self.quota_gb = quota_gb + if results is not None: + self.results = results @property def user(self): @@ -16527,39 +20791,36 @@ def user(self): self._user_present = False @property - def quota_gb(self): + def results(self): """ - :rtype: int + :rtype: list of [AddSecondaryEmailResult] """ - if self._quota_gb_present: - return self._quota_gb_value + if self._results_present: + return self._results_value else: - return None + raise AttributeError("missing required field 'results'") - @quota_gb.setter - def quota_gb(self, val): - if val is None: - del self.quota_gb - return - val = self._quota_gb_validator.validate(val) - self._quota_gb_value = val - self._quota_gb_present = True + @results.setter + def results(self, val): + val = self._results_validator.validate(val) + self._results_value = val + self._results_present = True - @quota_gb.deleter - def quota_gb(self): - self._quota_gb_value = None - self._quota_gb_present = False + @results.deleter + def results(self): + self._results_value = None + self._results_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(UserCustomQuotaResult, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserSecondaryEmailsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'UserCustomQuotaResult(user={!r}, quota_gb={!r})'.format( + return 'UserSecondaryEmailsResult(user={!r}, results={!r})'.format( self._user_value, - self._quota_gb_value, + self._results_value, ) -UserCustomQuotaResult_validator = bv.Struct(UserCustomQuotaResult) +UserSecondaryEmailsResult_validator = bv.Struct(UserSecondaryEmailsResult) class UserSelectorArg(bb.Union): """ @@ -16788,8 +21049,21 @@ def __repr__(self): UsersSelectorArg_validator = bv.Union(UsersSelectorArg) GroupsGetInfoResult_validator = bv.List(GroupsGetInfoItem_validator) +LegalHoldId_validator = bv.String(pattern=u'^pid_dbhid:.+') +LegalHoldPolicyDescription_validator = bv.String(max_length=501) +LegalHoldPolicyName_validator = bv.String(max_length=140) +LegalHoldsGetPolicyResult_validator = LegalHoldPolicy_validator +LegalHoldsGetPolicyResult = LegalHoldPolicy +LegalHoldsPolicyCreateResult_validator = LegalHoldPolicy_validator +LegalHoldsPolicyCreateResult = LegalHoldPolicy +LegalHoldsPolicyUpdateResult_validator = LegalHoldPolicy_validator +LegalHoldsPolicyUpdateResult = LegalHoldPolicy +ListHeldRevisionCursor_validator = bv.String(min_length=1) MembersGetInfoResult_validator = bv.List(MembersGetInfoItem_validator) NumberPerDay_validator = bv.List(bv.Nullable(bv.UInt64())) +Path_validator = bv.String(pattern=u'(/(.|[\\r\\n])*)?') +SecondaryEmail_validator = secondary_emails.SecondaryEmail_validator +SecondaryEmail = secondary_emails.SecondaryEmail UserQuota_validator = bv.UInt32(min_value=15) DeviceSession._session_id_validator = bv.String() DeviceSession._ip_address_validator = bv.Nullable(bv.String()) @@ -16828,6 +21102,52 @@ def __repr__(self): ('expires', ActiveWebSession._expires_validator), ] +AddSecondaryEmailResult._success_validator = SecondaryEmail_validator +AddSecondaryEmailResult._unavailable_validator = common.EmailAddress_validator +AddSecondaryEmailResult._already_pending_validator = common.EmailAddress_validator +AddSecondaryEmailResult._already_owned_by_user_validator = common.EmailAddress_validator +AddSecondaryEmailResult._reached_limit_validator = common.EmailAddress_validator +AddSecondaryEmailResult._transient_error_validator = common.EmailAddress_validator +AddSecondaryEmailResult._too_many_updates_validator = common.EmailAddress_validator +AddSecondaryEmailResult._unknown_error_validator = common.EmailAddress_validator +AddSecondaryEmailResult._rate_limited_validator = common.EmailAddress_validator +AddSecondaryEmailResult._other_validator = bv.Void() +AddSecondaryEmailResult._tagmap = { + 'success': AddSecondaryEmailResult._success_validator, + 'unavailable': AddSecondaryEmailResult._unavailable_validator, + 'already_pending': AddSecondaryEmailResult._already_pending_validator, + 'already_owned_by_user': AddSecondaryEmailResult._already_owned_by_user_validator, + 'reached_limit': AddSecondaryEmailResult._reached_limit_validator, + 'transient_error': AddSecondaryEmailResult._transient_error_validator, + 'too_many_updates': AddSecondaryEmailResult._too_many_updates_validator, + 'unknown_error': AddSecondaryEmailResult._unknown_error_validator, + 'rate_limited': AddSecondaryEmailResult._rate_limited_validator, + 'other': AddSecondaryEmailResult._other_validator, +} + +AddSecondaryEmailResult.other = AddSecondaryEmailResult('other') + +AddSecondaryEmailsArg._new_secondary_emails_validator = bv.List(UserSecondaryEmailsArg_validator) +AddSecondaryEmailsArg._all_field_names_ = set(['new_secondary_emails']) +AddSecondaryEmailsArg._all_fields_ = [('new_secondary_emails', AddSecondaryEmailsArg._new_secondary_emails_validator)] + +AddSecondaryEmailsError._secondary_emails_disabled_validator = bv.Void() +AddSecondaryEmailsError._too_many_emails_validator = bv.Void() +AddSecondaryEmailsError._other_validator = bv.Void() +AddSecondaryEmailsError._tagmap = { + 'secondary_emails_disabled': AddSecondaryEmailsError._secondary_emails_disabled_validator, + 'too_many_emails': AddSecondaryEmailsError._too_many_emails_validator, + 'other': AddSecondaryEmailsError._other_validator, +} + +AddSecondaryEmailsError.secondary_emails_disabled = AddSecondaryEmailsError('secondary_emails_disabled') +AddSecondaryEmailsError.too_many_emails = AddSecondaryEmailsError('too_many_emails') +AddSecondaryEmailsError.other = AddSecondaryEmailsError('other') + +AddSecondaryEmailsResult._results_validator = bv.List(UserAddResult_validator) +AddSecondaryEmailsResult._all_field_names_ = set(['results']) +AddSecondaryEmailsResult._all_fields_ = [('results', AddSecondaryEmailsResult._results_validator)] + AdminTier._team_admin_validator = bv.Void() AdminTier._user_management_admin_validator = bv.Void() AdminTier._support_admin_validator = bv.Void() @@ -16927,6 +21247,27 @@ def __repr__(self): DateRangeError.other = DateRangeError('other') +DeleteSecondaryEmailResult._success_validator = common.EmailAddress_validator +DeleteSecondaryEmailResult._not_found_validator = common.EmailAddress_validator +DeleteSecondaryEmailResult._cannot_remove_primary_validator = common.EmailAddress_validator +DeleteSecondaryEmailResult._other_validator = bv.Void() +DeleteSecondaryEmailResult._tagmap = { + 'success': DeleteSecondaryEmailResult._success_validator, + 'not_found': DeleteSecondaryEmailResult._not_found_validator, + 'cannot_remove_primary': DeleteSecondaryEmailResult._cannot_remove_primary_validator, + 'other': DeleteSecondaryEmailResult._other_validator, +} + +DeleteSecondaryEmailResult.other = DeleteSecondaryEmailResult('other') + +DeleteSecondaryEmailsArg._emails_to_delete_validator = bv.List(UserSecondaryEmailsArg_validator) +DeleteSecondaryEmailsArg._all_field_names_ = set(['emails_to_delete']) +DeleteSecondaryEmailsArg._all_fields_ = [('emails_to_delete', DeleteSecondaryEmailsArg._emails_to_delete_validator)] + +DeleteSecondaryEmailsResult._results_validator = bv.List(UserDeleteResult_validator) +DeleteSecondaryEmailsResult._all_field_names_ = set(['results']) +DeleteSecondaryEmailsResult._all_fields_ = [('results', DeleteSecondaryEmailsResult._results_validator)] + DesktopClientSession._host_name_validator = bv.String() DesktopClientSession._client_type_validator = DesktopPlatform_validator DesktopClientSession._client_version_validator = bv.String() @@ -17237,15 +21578,18 @@ def __repr__(self): GroupAccessType.owner = GroupAccessType('owner') GroupCreateArg._group_name_validator = bv.String() +GroupCreateArg._add_creator_as_owner_validator = bv.Boolean() GroupCreateArg._group_external_id_validator = bv.Nullable(team_common.GroupExternalId_validator) GroupCreateArg._group_management_type_validator = bv.Nullable(team_common.GroupManagementType_validator) GroupCreateArg._all_field_names_ = set([ 'group_name', + 'add_creator_as_owner', 'group_external_id', 'group_management_type', ]) GroupCreateArg._all_fields_ = [ ('group_name', GroupCreateArg._group_name_validator), + ('add_creator_as_owner', GroupCreateArg._add_creator_as_owner_validator), ('group_external_id', GroupCreateArg._group_external_id_validator), ('group_management_type', GroupCreateArg._group_management_type_validator), ] @@ -17611,6 +21955,302 @@ def __repr__(self): HasTeamSharedDropboxValue.other = HasTeamSharedDropboxValue('other') +LegalHoldHeldRevisionMetadata._new_filename_validator = bv.String() +LegalHoldHeldRevisionMetadata._original_revision_id_validator = files.Rev_validator +LegalHoldHeldRevisionMetadata._original_file_path_validator = Path_validator +LegalHoldHeldRevisionMetadata._server_modified_validator = common.DropboxTimestamp_validator +LegalHoldHeldRevisionMetadata._author_member_id_validator = team_common.TeamMemberId_validator +LegalHoldHeldRevisionMetadata._author_member_status_validator = TeamMemberStatus_validator +LegalHoldHeldRevisionMetadata._author_email_validator = common.EmailAddress_validator +LegalHoldHeldRevisionMetadata._file_type_validator = bv.String() +LegalHoldHeldRevisionMetadata._size_validator = bv.UInt64() +LegalHoldHeldRevisionMetadata._content_hash_validator = files.Sha256HexHash_validator +LegalHoldHeldRevisionMetadata._all_field_names_ = set([ + 'new_filename', + 'original_revision_id', + 'original_file_path', + 'server_modified', + 'author_member_id', + 'author_member_status', + 'author_email', + 'file_type', + 'size', + 'content_hash', +]) +LegalHoldHeldRevisionMetadata._all_fields_ = [ + ('new_filename', LegalHoldHeldRevisionMetadata._new_filename_validator), + ('original_revision_id', LegalHoldHeldRevisionMetadata._original_revision_id_validator), + ('original_file_path', LegalHoldHeldRevisionMetadata._original_file_path_validator), + ('server_modified', LegalHoldHeldRevisionMetadata._server_modified_validator), + ('author_member_id', LegalHoldHeldRevisionMetadata._author_member_id_validator), + ('author_member_status', LegalHoldHeldRevisionMetadata._author_member_status_validator), + ('author_email', LegalHoldHeldRevisionMetadata._author_email_validator), + ('file_type', LegalHoldHeldRevisionMetadata._file_type_validator), + ('size', LegalHoldHeldRevisionMetadata._size_validator), + ('content_hash', LegalHoldHeldRevisionMetadata._content_hash_validator), +] + +LegalHoldPolicy._id_validator = LegalHoldId_validator +LegalHoldPolicy._name_validator = LegalHoldPolicyName_validator +LegalHoldPolicy._description_validator = bv.Nullable(LegalHoldPolicyDescription_validator) +LegalHoldPolicy._activation_time_validator = bv.Nullable(common.DropboxTimestamp_validator) +LegalHoldPolicy._members_validator = MembersInfo_validator +LegalHoldPolicy._status_validator = LegalHoldStatus_validator +LegalHoldPolicy._start_date_validator = common.DropboxTimestamp_validator +LegalHoldPolicy._end_date_validator = bv.Nullable(common.DropboxTimestamp_validator) +LegalHoldPolicy._all_field_names_ = set([ + 'id', + 'name', + 'description', + 'activation_time', + 'members', + 'status', + 'start_date', + 'end_date', +]) +LegalHoldPolicy._all_fields_ = [ + ('id', LegalHoldPolicy._id_validator), + ('name', LegalHoldPolicy._name_validator), + ('description', LegalHoldPolicy._description_validator), + ('activation_time', LegalHoldPolicy._activation_time_validator), + ('members', LegalHoldPolicy._members_validator), + ('status', LegalHoldPolicy._status_validator), + ('start_date', LegalHoldPolicy._start_date_validator), + ('end_date', LegalHoldPolicy._end_date_validator), +] + +LegalHoldStatus._active_validator = bv.Void() +LegalHoldStatus._released_validator = bv.Void() +LegalHoldStatus._activating_validator = bv.Void() +LegalHoldStatus._updating_validator = bv.Void() +LegalHoldStatus._exporting_validator = bv.Void() +LegalHoldStatus._releasing_validator = bv.Void() +LegalHoldStatus._other_validator = bv.Void() +LegalHoldStatus._tagmap = { + 'active': LegalHoldStatus._active_validator, + 'released': LegalHoldStatus._released_validator, + 'activating': LegalHoldStatus._activating_validator, + 'updating': LegalHoldStatus._updating_validator, + 'exporting': LegalHoldStatus._exporting_validator, + 'releasing': LegalHoldStatus._releasing_validator, + 'other': LegalHoldStatus._other_validator, +} + +LegalHoldStatus.active = LegalHoldStatus('active') +LegalHoldStatus.released = LegalHoldStatus('released') +LegalHoldStatus.activating = LegalHoldStatus('activating') +LegalHoldStatus.updating = LegalHoldStatus('updating') +LegalHoldStatus.exporting = LegalHoldStatus('exporting') +LegalHoldStatus.releasing = LegalHoldStatus('releasing') +LegalHoldStatus.other = LegalHoldStatus('other') + +LegalHoldsError._unknown_legal_hold_error_validator = bv.Void() +LegalHoldsError._insufficient_permissions_validator = bv.Void() +LegalHoldsError._other_validator = bv.Void() +LegalHoldsError._tagmap = { + 'unknown_legal_hold_error': LegalHoldsError._unknown_legal_hold_error_validator, + 'insufficient_permissions': LegalHoldsError._insufficient_permissions_validator, + 'other': LegalHoldsError._other_validator, +} + +LegalHoldsError.unknown_legal_hold_error = LegalHoldsError('unknown_legal_hold_error') +LegalHoldsError.insufficient_permissions = LegalHoldsError('insufficient_permissions') +LegalHoldsError.other = LegalHoldsError('other') + +LegalHoldsGetPolicyArg._id_validator = LegalHoldId_validator +LegalHoldsGetPolicyArg._all_field_names_ = set(['id']) +LegalHoldsGetPolicyArg._all_fields_ = [('id', LegalHoldsGetPolicyArg._id_validator)] + +LegalHoldsGetPolicyError._legal_hold_policy_not_found_validator = bv.Void() +LegalHoldsGetPolicyError._tagmap = { + 'legal_hold_policy_not_found': LegalHoldsGetPolicyError._legal_hold_policy_not_found_validator, +} +LegalHoldsGetPolicyError._tagmap.update(LegalHoldsError._tagmap) + +LegalHoldsGetPolicyError.legal_hold_policy_not_found = LegalHoldsGetPolicyError('legal_hold_policy_not_found') + +LegalHoldsListHeldRevisionResult._entries_validator = bv.List(LegalHoldHeldRevisionMetadata_validator) +LegalHoldsListHeldRevisionResult._cursor_validator = bv.Nullable(ListHeldRevisionCursor_validator) +LegalHoldsListHeldRevisionResult._has_more_validator = bv.Boolean() +LegalHoldsListHeldRevisionResult._all_field_names_ = set([ + 'entries', + 'cursor', + 'has_more', +]) +LegalHoldsListHeldRevisionResult._all_fields_ = [ + ('entries', LegalHoldsListHeldRevisionResult._entries_validator), + ('cursor', LegalHoldsListHeldRevisionResult._cursor_validator), + ('has_more', LegalHoldsListHeldRevisionResult._has_more_validator), +] + +LegalHoldsListHeldRevisionsArg._id_validator = LegalHoldId_validator +LegalHoldsListHeldRevisionsArg._all_field_names_ = set(['id']) +LegalHoldsListHeldRevisionsArg._all_fields_ = [('id', LegalHoldsListHeldRevisionsArg._id_validator)] + +LegalHoldsListHeldRevisionsContinueArg._id_validator = LegalHoldId_validator +LegalHoldsListHeldRevisionsContinueArg._cursor_validator = bv.Nullable(ListHeldRevisionCursor_validator) +LegalHoldsListHeldRevisionsContinueArg._all_field_names_ = set([ + 'id', + 'cursor', +]) +LegalHoldsListHeldRevisionsContinueArg._all_fields_ = [ + ('id', LegalHoldsListHeldRevisionsContinueArg._id_validator), + ('cursor', LegalHoldsListHeldRevisionsContinueArg._cursor_validator), +] + +LegalHoldsListHeldRevisionsContinueError._unknown_legal_hold_error_validator = bv.Void() +LegalHoldsListHeldRevisionsContinueError._transient_error_validator = bv.Void() +LegalHoldsListHeldRevisionsContinueError._reset_validator = bv.Void() +LegalHoldsListHeldRevisionsContinueError._other_validator = bv.Void() +LegalHoldsListHeldRevisionsContinueError._tagmap = { + 'unknown_legal_hold_error': LegalHoldsListHeldRevisionsContinueError._unknown_legal_hold_error_validator, + 'transient_error': LegalHoldsListHeldRevisionsContinueError._transient_error_validator, + 'reset': LegalHoldsListHeldRevisionsContinueError._reset_validator, + 'other': LegalHoldsListHeldRevisionsContinueError._other_validator, +} + +LegalHoldsListHeldRevisionsContinueError.unknown_legal_hold_error = LegalHoldsListHeldRevisionsContinueError('unknown_legal_hold_error') +LegalHoldsListHeldRevisionsContinueError.transient_error = LegalHoldsListHeldRevisionsContinueError('transient_error') +LegalHoldsListHeldRevisionsContinueError.reset = LegalHoldsListHeldRevisionsContinueError('reset') +LegalHoldsListHeldRevisionsContinueError.other = LegalHoldsListHeldRevisionsContinueError('other') + +LegalHoldsListHeldRevisionsError._transient_error_validator = bv.Void() +LegalHoldsListHeldRevisionsError._legal_hold_still_empty_validator = bv.Void() +LegalHoldsListHeldRevisionsError._inactive_legal_hold_validator = bv.Void() +LegalHoldsListHeldRevisionsError._tagmap = { + 'transient_error': LegalHoldsListHeldRevisionsError._transient_error_validator, + 'legal_hold_still_empty': LegalHoldsListHeldRevisionsError._legal_hold_still_empty_validator, + 'inactive_legal_hold': LegalHoldsListHeldRevisionsError._inactive_legal_hold_validator, +} +LegalHoldsListHeldRevisionsError._tagmap.update(LegalHoldsError._tagmap) + +LegalHoldsListHeldRevisionsError.transient_error = LegalHoldsListHeldRevisionsError('transient_error') +LegalHoldsListHeldRevisionsError.legal_hold_still_empty = LegalHoldsListHeldRevisionsError('legal_hold_still_empty') +LegalHoldsListHeldRevisionsError.inactive_legal_hold = LegalHoldsListHeldRevisionsError('inactive_legal_hold') + +LegalHoldsListPoliciesArg._include_released_validator = bv.Boolean() +LegalHoldsListPoliciesArg._all_field_names_ = set(['include_released']) +LegalHoldsListPoliciesArg._all_fields_ = [('include_released', LegalHoldsListPoliciesArg._include_released_validator)] + +LegalHoldsListPoliciesError._transient_error_validator = bv.Void() +LegalHoldsListPoliciesError._tagmap = { + 'transient_error': LegalHoldsListPoliciesError._transient_error_validator, +} +LegalHoldsListPoliciesError._tagmap.update(LegalHoldsError._tagmap) + +LegalHoldsListPoliciesError.transient_error = LegalHoldsListPoliciesError('transient_error') + +LegalHoldsListPoliciesResult._policies_validator = bv.List(LegalHoldPolicy_validator) +LegalHoldsListPoliciesResult._all_field_names_ = set(['policies']) +LegalHoldsListPoliciesResult._all_fields_ = [('policies', LegalHoldsListPoliciesResult._policies_validator)] + +LegalHoldsPolicyCreateArg._name_validator = LegalHoldPolicyName_validator +LegalHoldsPolicyCreateArg._description_validator = bv.Nullable(LegalHoldPolicyDescription_validator) +LegalHoldsPolicyCreateArg._members_validator = bv.List(team_common.TeamMemberId_validator) +LegalHoldsPolicyCreateArg._start_date_validator = bv.Nullable(common.DropboxTimestamp_validator) +LegalHoldsPolicyCreateArg._end_date_validator = bv.Nullable(common.DropboxTimestamp_validator) +LegalHoldsPolicyCreateArg._all_field_names_ = set([ + 'name', + 'description', + 'members', + 'start_date', + 'end_date', +]) +LegalHoldsPolicyCreateArg._all_fields_ = [ + ('name', LegalHoldsPolicyCreateArg._name_validator), + ('description', LegalHoldsPolicyCreateArg._description_validator), + ('members', LegalHoldsPolicyCreateArg._members_validator), + ('start_date', LegalHoldsPolicyCreateArg._start_date_validator), + ('end_date', LegalHoldsPolicyCreateArg._end_date_validator), +] + +LegalHoldsPolicyCreateError._start_date_is_later_than_end_date_validator = bv.Void() +LegalHoldsPolicyCreateError._empty_members_list_validator = bv.Void() +LegalHoldsPolicyCreateError._invalid_members_validator = bv.Void() +LegalHoldsPolicyCreateError._number_of_users_on_hold_is_greater_than_hold_limitation_validator = bv.Void() +LegalHoldsPolicyCreateError._transient_error_validator = bv.Void() +LegalHoldsPolicyCreateError._name_must_be_unique_validator = bv.Void() +LegalHoldsPolicyCreateError._team_exceeded_legal_hold_quota_validator = bv.Void() +LegalHoldsPolicyCreateError._tagmap = { + 'start_date_is_later_than_end_date': LegalHoldsPolicyCreateError._start_date_is_later_than_end_date_validator, + 'empty_members_list': LegalHoldsPolicyCreateError._empty_members_list_validator, + 'invalid_members': LegalHoldsPolicyCreateError._invalid_members_validator, + 'number_of_users_on_hold_is_greater_than_hold_limitation': LegalHoldsPolicyCreateError._number_of_users_on_hold_is_greater_than_hold_limitation_validator, + 'transient_error': LegalHoldsPolicyCreateError._transient_error_validator, + 'name_must_be_unique': LegalHoldsPolicyCreateError._name_must_be_unique_validator, + 'team_exceeded_legal_hold_quota': LegalHoldsPolicyCreateError._team_exceeded_legal_hold_quota_validator, +} +LegalHoldsPolicyCreateError._tagmap.update(LegalHoldsError._tagmap) + +LegalHoldsPolicyCreateError.start_date_is_later_than_end_date = LegalHoldsPolicyCreateError('start_date_is_later_than_end_date') +LegalHoldsPolicyCreateError.empty_members_list = LegalHoldsPolicyCreateError('empty_members_list') +LegalHoldsPolicyCreateError.invalid_members = LegalHoldsPolicyCreateError('invalid_members') +LegalHoldsPolicyCreateError.number_of_users_on_hold_is_greater_than_hold_limitation = LegalHoldsPolicyCreateError('number_of_users_on_hold_is_greater_than_hold_limitation') +LegalHoldsPolicyCreateError.transient_error = LegalHoldsPolicyCreateError('transient_error') +LegalHoldsPolicyCreateError.name_must_be_unique = LegalHoldsPolicyCreateError('name_must_be_unique') +LegalHoldsPolicyCreateError.team_exceeded_legal_hold_quota = LegalHoldsPolicyCreateError('team_exceeded_legal_hold_quota') + +LegalHoldsPolicyReleaseArg._id_validator = LegalHoldId_validator +LegalHoldsPolicyReleaseArg._all_field_names_ = set(['id']) +LegalHoldsPolicyReleaseArg._all_fields_ = [('id', LegalHoldsPolicyReleaseArg._id_validator)] + +LegalHoldsPolicyReleaseError._legal_hold_performing_another_operation_validator = bv.Void() +LegalHoldsPolicyReleaseError._legal_hold_already_releasing_validator = bv.Void() +LegalHoldsPolicyReleaseError._legal_hold_policy_not_found_validator = bv.Void() +LegalHoldsPolicyReleaseError._tagmap = { + 'legal_hold_performing_another_operation': LegalHoldsPolicyReleaseError._legal_hold_performing_another_operation_validator, + 'legal_hold_already_releasing': LegalHoldsPolicyReleaseError._legal_hold_already_releasing_validator, + 'legal_hold_policy_not_found': LegalHoldsPolicyReleaseError._legal_hold_policy_not_found_validator, +} +LegalHoldsPolicyReleaseError._tagmap.update(LegalHoldsError._tagmap) + +LegalHoldsPolicyReleaseError.legal_hold_performing_another_operation = LegalHoldsPolicyReleaseError('legal_hold_performing_another_operation') +LegalHoldsPolicyReleaseError.legal_hold_already_releasing = LegalHoldsPolicyReleaseError('legal_hold_already_releasing') +LegalHoldsPolicyReleaseError.legal_hold_policy_not_found = LegalHoldsPolicyReleaseError('legal_hold_policy_not_found') + +LegalHoldsPolicyUpdateArg._id_validator = LegalHoldId_validator +LegalHoldsPolicyUpdateArg._name_validator = bv.Nullable(LegalHoldPolicyName_validator) +LegalHoldsPolicyUpdateArg._description_validator = bv.Nullable(LegalHoldPolicyDescription_validator) +LegalHoldsPolicyUpdateArg._members_validator = bv.List(team_common.TeamMemberId_validator) +LegalHoldsPolicyUpdateArg._all_field_names_ = set([ + 'id', + 'name', + 'description', + 'members', +]) +LegalHoldsPolicyUpdateArg._all_fields_ = [ + ('id', LegalHoldsPolicyUpdateArg._id_validator), + ('name', LegalHoldsPolicyUpdateArg._name_validator), + ('description', LegalHoldsPolicyUpdateArg._description_validator), + ('members', LegalHoldsPolicyUpdateArg._members_validator), +] + +LegalHoldsPolicyUpdateError._inactive_legal_hold_validator = bv.Void() +LegalHoldsPolicyUpdateError._legal_hold_performing_another_operation_validator = bv.Void() +LegalHoldsPolicyUpdateError._invalid_members_validator = bv.Void() +LegalHoldsPolicyUpdateError._number_of_users_on_hold_is_greater_than_hold_limitation_validator = bv.Void() +LegalHoldsPolicyUpdateError._empty_members_list_validator = bv.Void() +LegalHoldsPolicyUpdateError._name_must_be_unique_validator = bv.Void() +LegalHoldsPolicyUpdateError._legal_hold_policy_not_found_validator = bv.Void() +LegalHoldsPolicyUpdateError._tagmap = { + 'inactive_legal_hold': LegalHoldsPolicyUpdateError._inactive_legal_hold_validator, + 'legal_hold_performing_another_operation': LegalHoldsPolicyUpdateError._legal_hold_performing_another_operation_validator, + 'invalid_members': LegalHoldsPolicyUpdateError._invalid_members_validator, + 'number_of_users_on_hold_is_greater_than_hold_limitation': LegalHoldsPolicyUpdateError._number_of_users_on_hold_is_greater_than_hold_limitation_validator, + 'empty_members_list': LegalHoldsPolicyUpdateError._empty_members_list_validator, + 'name_must_be_unique': LegalHoldsPolicyUpdateError._name_must_be_unique_validator, + 'legal_hold_policy_not_found': LegalHoldsPolicyUpdateError._legal_hold_policy_not_found_validator, +} +LegalHoldsPolicyUpdateError._tagmap.update(LegalHoldsError._tagmap) + +LegalHoldsPolicyUpdateError.inactive_legal_hold = LegalHoldsPolicyUpdateError('inactive_legal_hold') +LegalHoldsPolicyUpdateError.legal_hold_performing_another_operation = LegalHoldsPolicyUpdateError('legal_hold_performing_another_operation') +LegalHoldsPolicyUpdateError.invalid_members = LegalHoldsPolicyUpdateError('invalid_members') +LegalHoldsPolicyUpdateError.number_of_users_on_hold_is_greater_than_hold_limitation = LegalHoldsPolicyUpdateError('number_of_users_on_hold_is_greater_than_hold_limitation') +LegalHoldsPolicyUpdateError.empty_members_list = LegalHoldsPolicyUpdateError('empty_members_list') +LegalHoldsPolicyUpdateError.name_must_be_unique = LegalHoldsPolicyUpdateError('name_must_be_unique') +LegalHoldsPolicyUpdateError.legal_hold_policy_not_found = LegalHoldsPolicyUpdateError('legal_hold_policy_not_found') + ListMemberAppsArg._team_member_id_validator = bv.String() ListMemberAppsArg._all_field_names_ = set(['team_member_id']) ListMemberAppsArg._all_fields_ = [('team_member_id', ListMemberAppsArg._team_member_id_validator)] @@ -17906,9 +22546,11 @@ def __repr__(self): MemberProfile._account_id_validator = bv.Nullable(users_common.AccountId_validator) MemberProfile._email_validator = bv.String() MemberProfile._email_verified_validator = bv.Boolean() +MemberProfile._secondary_emails_validator = bv.Nullable(bv.List(secondary_emails.SecondaryEmail_validator)) MemberProfile._status_validator = TeamMemberStatus_validator MemberProfile._name_validator = users.Name_validator MemberProfile._membership_type_validator = TeamMembershipType_validator +MemberProfile._invited_on_validator = bv.Nullable(common.DropboxTimestamp_validator) MemberProfile._joined_on_validator = bv.Nullable(common.DropboxTimestamp_validator) MemberProfile._suspended_on_validator = bv.Nullable(common.DropboxTimestamp_validator) MemberProfile._persistent_id_validator = bv.Nullable(bv.String()) @@ -17920,9 +22562,11 @@ def __repr__(self): 'account_id', 'email', 'email_verified', + 'secondary_emails', 'status', 'name', 'membership_type', + 'invited_on', 'joined_on', 'suspended_on', 'persistent_id', @@ -17935,9 +22579,11 @@ def __repr__(self): ('account_id', MemberProfile._account_id_validator), ('email', MemberProfile._email_validator), ('email_verified', MemberProfile._email_verified_validator), + ('secondary_emails', MemberProfile._secondary_emails_validator), ('status', MemberProfile._status_validator), ('name', MemberProfile._name_validator), ('membership_type', MemberProfile._membership_type_validator), + ('invited_on', MemberProfile._invited_on_validator), ('joined_on', MemberProfile._joined_on_validator), ('suspended_on', MemberProfile._suspended_on_validator), ('persistent_id', MemberProfile._persistent_id_validator), @@ -18015,6 +22661,21 @@ def __repr__(self): MembersDeactivateError.user_not_in_team = MembersDeactivateError('user_not_in_team') MembersDeactivateError.other = MembersDeactivateError('other') +MembersDeleteProfilePhotoArg._user_validator = UserSelectorArg_validator +MembersDeleteProfilePhotoArg._all_field_names_ = set(['user']) +MembersDeleteProfilePhotoArg._all_fields_ = [('user', MembersDeleteProfilePhotoArg._user_validator)] + +MembersDeleteProfilePhotoError._set_profile_disallowed_validator = bv.Void() +MembersDeleteProfilePhotoError._other_validator = bv.Void() +MembersDeleteProfilePhotoError._tagmap = { + 'set_profile_disallowed': MembersDeleteProfilePhotoError._set_profile_disallowed_validator, + 'other': MembersDeleteProfilePhotoError._other_validator, +} +MembersDeleteProfilePhotoError._tagmap.update(MemberSelectorError._tagmap) + +MembersDeleteProfilePhotoError.set_profile_disallowed = MembersDeleteProfilePhotoError('set_profile_disallowed') +MembersDeleteProfilePhotoError.other = MembersDeleteProfilePhotoError('other') + MembersGetInfoArgs._members_validator = bv.List(UserSelectorArg_validator) MembersGetInfoArgs._all_field_names_ = set(['members']) MembersGetInfoArgs._all_fields_ = [('members', MembersGetInfoArgs._members_validator)] @@ -18033,6 +22694,17 @@ def __repr__(self): 'member_info': MembersGetInfoItem._member_info_validator, } +MembersInfo._team_member_ids_validator = bv.List(team_common.TeamMemberId_validator) +MembersInfo._permanently_deleted_users_validator = bv.UInt64() +MembersInfo._all_field_names_ = set([ + 'team_member_ids', + 'permanently_deleted_users', +]) +MembersInfo._all_fields_ = [ + ('team_member_ids', MembersInfo._team_member_ids_validator), + ('permanently_deleted_users', MembersInfo._permanently_deleted_users_validator), +] + MembersListArg._limit_validator = bv.UInt32(min_value=1, max_value=1000) MembersListArg._include_removed_validator = bv.Boolean() MembersListArg._all_field_names_ = set([ @@ -18103,15 +22775,18 @@ def __repr__(self): MembersRemoveArg._transfer_dest_id_validator = bv.Nullable(UserSelectorArg_validator) MembersRemoveArg._transfer_admin_id_validator = bv.Nullable(UserSelectorArg_validator) MembersRemoveArg._keep_account_validator = bv.Boolean() +MembersRemoveArg._retain_team_shares_validator = bv.Boolean() MembersRemoveArg._all_field_names_ = MembersDeactivateArg._all_field_names_.union(set([ 'transfer_dest_id', 'transfer_admin_id', 'keep_account', + 'retain_team_shares', ])) MembersRemoveArg._all_fields_ = MembersDeactivateArg._all_fields_ + [ ('transfer_dest_id', MembersRemoveArg._transfer_dest_id_validator), ('transfer_admin_id', MembersRemoveArg._transfer_admin_id_validator), ('keep_account', MembersRemoveArg._keep_account_validator), + ('retain_team_shares', MembersRemoveArg._retain_team_shares_validator), ] MembersTransferFilesError._removed_and_transfer_dest_should_differ_validator = bv.Void() @@ -18151,12 +22826,24 @@ def __repr__(self): MembersRemoveError._cannot_keep_account_and_delete_data_validator = bv.Void() MembersRemoveError._email_address_too_long_to_be_disabled_validator = bv.Void() MembersRemoveError._cannot_keep_invited_user_account_validator = bv.Void() +MembersRemoveError._cannot_retain_shares_when_data_wiped_validator = bv.Void() +MembersRemoveError._cannot_retain_shares_when_no_account_kept_validator = bv.Void() +MembersRemoveError._cannot_retain_shares_when_team_external_sharing_off_validator = bv.Void() +MembersRemoveError._cannot_keep_account_validator = bv.Void() +MembersRemoveError._cannot_keep_account_under_legal_hold_validator = bv.Void() +MembersRemoveError._cannot_keep_account_required_to_sign_tos_validator = bv.Void() MembersRemoveError._tagmap = { 'remove_last_admin': MembersRemoveError._remove_last_admin_validator, 'cannot_keep_account_and_transfer': MembersRemoveError._cannot_keep_account_and_transfer_validator, 'cannot_keep_account_and_delete_data': MembersRemoveError._cannot_keep_account_and_delete_data_validator, 'email_address_too_long_to_be_disabled': MembersRemoveError._email_address_too_long_to_be_disabled_validator, 'cannot_keep_invited_user_account': MembersRemoveError._cannot_keep_invited_user_account_validator, + 'cannot_retain_shares_when_data_wiped': MembersRemoveError._cannot_retain_shares_when_data_wiped_validator, + 'cannot_retain_shares_when_no_account_kept': MembersRemoveError._cannot_retain_shares_when_no_account_kept_validator, + 'cannot_retain_shares_when_team_external_sharing_off': MembersRemoveError._cannot_retain_shares_when_team_external_sharing_off_validator, + 'cannot_keep_account': MembersRemoveError._cannot_keep_account_validator, + 'cannot_keep_account_under_legal_hold': MembersRemoveError._cannot_keep_account_under_legal_hold_validator, + 'cannot_keep_account_required_to_sign_tos': MembersRemoveError._cannot_keep_account_required_to_sign_tos_validator, } MembersRemoveError._tagmap.update(MembersTransferFilesError._tagmap) @@ -18165,6 +22852,12 @@ def __repr__(self): MembersRemoveError.cannot_keep_account_and_delete_data = MembersRemoveError('cannot_keep_account_and_delete_data') MembersRemoveError.email_address_too_long_to_be_disabled = MembersRemoveError('email_address_too_long_to_be_disabled') MembersRemoveError.cannot_keep_invited_user_account = MembersRemoveError('cannot_keep_invited_user_account') +MembersRemoveError.cannot_retain_shares_when_data_wiped = MembersRemoveError('cannot_retain_shares_when_data_wiped') +MembersRemoveError.cannot_retain_shares_when_no_account_kept = MembersRemoveError('cannot_retain_shares_when_no_account_kept') +MembersRemoveError.cannot_retain_shares_when_team_external_sharing_off = MembersRemoveError('cannot_retain_shares_when_team_external_sharing_off') +MembersRemoveError.cannot_keep_account = MembersRemoveError('cannot_keep_account') +MembersRemoveError.cannot_keep_account_under_legal_hold = MembersRemoveError('cannot_keep_account_under_legal_hold') +MembersRemoveError.cannot_keep_account_required_to_sign_tos = MembersRemoveError('cannot_keep_account_required_to_sign_tos') MembersSendWelcomeError._other_validator = bv.Void() MembersSendWelcomeError._tagmap = { @@ -18277,6 +22970,30 @@ def __repr__(self): MembersSetProfileError.directory_restricted_off = MembersSetProfileError('directory_restricted_off') MembersSetProfileError.other = MembersSetProfileError('other') +MembersSetProfilePhotoArg._user_validator = UserSelectorArg_validator +MembersSetProfilePhotoArg._photo_validator = account.PhotoSourceArg_validator +MembersSetProfilePhotoArg._all_field_names_ = set([ + 'user', + 'photo', +]) +MembersSetProfilePhotoArg._all_fields_ = [ + ('user', MembersSetProfilePhotoArg._user_validator), + ('photo', MembersSetProfilePhotoArg._photo_validator), +] + +MembersSetProfilePhotoError._set_profile_disallowed_validator = bv.Void() +MembersSetProfilePhotoError._photo_error_validator = account.SetProfilePhotoError_validator +MembersSetProfilePhotoError._other_validator = bv.Void() +MembersSetProfilePhotoError._tagmap = { + 'set_profile_disallowed': MembersSetProfilePhotoError._set_profile_disallowed_validator, + 'photo_error': MembersSetProfilePhotoError._photo_error_validator, + 'other': MembersSetProfilePhotoError._other_validator, +} +MembersSetProfilePhotoError._tagmap.update(MemberSelectorError._tagmap) + +MembersSetProfilePhotoError.set_profile_disallowed = MembersSetProfilePhotoError('set_profile_disallowed') +MembersSetProfilePhotoError.other = MembersSetProfilePhotoError('other') + MembersSuspendError._suspend_inactive_user_validator = bv.Void() MembersSuspendError._suspend_last_admin_validator = bv.Void() MembersSuspendError._team_license_limit_validator = bv.Void() @@ -18423,6 +23140,27 @@ def __repr__(self): ('is_disconnected', RemovedStatus._is_disconnected_validator), ] +ResendSecondaryEmailResult._success_validator = common.EmailAddress_validator +ResendSecondaryEmailResult._not_pending_validator = common.EmailAddress_validator +ResendSecondaryEmailResult._rate_limited_validator = common.EmailAddress_validator +ResendSecondaryEmailResult._other_validator = bv.Void() +ResendSecondaryEmailResult._tagmap = { + 'success': ResendSecondaryEmailResult._success_validator, + 'not_pending': ResendSecondaryEmailResult._not_pending_validator, + 'rate_limited': ResendSecondaryEmailResult._rate_limited_validator, + 'other': ResendSecondaryEmailResult._other_validator, +} + +ResendSecondaryEmailResult.other = ResendSecondaryEmailResult('other') + +ResendVerificationEmailArg._emails_to_resend_validator = bv.List(UserSecondaryEmailsArg_validator) +ResendVerificationEmailArg._all_field_names_ = set(['emails_to_resend']) +ResendVerificationEmailArg._all_fields_ = [('emails_to_resend', ResendVerificationEmailArg._emails_to_resend_validator)] + +ResendVerificationEmailResult._results_validator = bv.List(UserResendResult_validator) +ResendVerificationEmailResult._all_field_names_ = set(['results']) +ResendVerificationEmailResult._all_fields_ = [('results', ResendVerificationEmailResult._results_validator)] + RevokeDesktopClientArg._delete_on_unlink_validator = bv.Boolean() RevokeDesktopClientArg._all_field_names_ = DeviceSessionArg._all_field_names_.union(set(['delete_on_unlink'])) RevokeDesktopClientArg._all_fields_ = DeviceSessionArg._all_fields_ + [('delete_on_unlink', RevokeDesktopClientArg._delete_on_unlink_validator)] @@ -18926,6 +23664,21 @@ def __repr__(self): UploadApiRateLimitValue.unlimited = UploadApiRateLimitValue('unlimited') UploadApiRateLimitValue.other = UploadApiRateLimitValue('other') +UserAddResult._success_validator = UserSecondaryEmailsResult_validator +UserAddResult._invalid_user_validator = UserSelectorArg_validator +UserAddResult._unverified_validator = UserSelectorArg_validator +UserAddResult._placeholder_user_validator = UserSelectorArg_validator +UserAddResult._other_validator = bv.Void() +UserAddResult._tagmap = { + 'success': UserAddResult._success_validator, + 'invalid_user': UserAddResult._invalid_user_validator, + 'unverified': UserAddResult._unverified_validator, + 'placeholder_user': UserAddResult._placeholder_user_validator, + 'other': UserAddResult._other_validator, +} + +UserAddResult.other = UserAddResult('other') + UserCustomQuotaArg._user_validator = UserSelectorArg_validator UserCustomQuotaArg._quota_gb_validator = UserQuota_validator UserCustomQuotaArg._all_field_names_ = set([ @@ -18948,6 +23701,72 @@ def __repr__(self): ('quota_gb', UserCustomQuotaResult._quota_gb_validator), ] +UserDeleteEmailsResult._user_validator = UserSelectorArg_validator +UserDeleteEmailsResult._results_validator = bv.List(DeleteSecondaryEmailResult_validator) +UserDeleteEmailsResult._all_field_names_ = set([ + 'user', + 'results', +]) +UserDeleteEmailsResult._all_fields_ = [ + ('user', UserDeleteEmailsResult._user_validator), + ('results', UserDeleteEmailsResult._results_validator), +] + +UserDeleteResult._success_validator = UserDeleteEmailsResult_validator +UserDeleteResult._invalid_user_validator = UserSelectorArg_validator +UserDeleteResult._other_validator = bv.Void() +UserDeleteResult._tagmap = { + 'success': UserDeleteResult._success_validator, + 'invalid_user': UserDeleteResult._invalid_user_validator, + 'other': UserDeleteResult._other_validator, +} + +UserDeleteResult.other = UserDeleteResult('other') + +UserResendEmailsResult._user_validator = UserSelectorArg_validator +UserResendEmailsResult._results_validator = bv.List(ResendSecondaryEmailResult_validator) +UserResendEmailsResult._all_field_names_ = set([ + 'user', + 'results', +]) +UserResendEmailsResult._all_fields_ = [ + ('user', UserResendEmailsResult._user_validator), + ('results', UserResendEmailsResult._results_validator), +] + +UserResendResult._success_validator = UserResendEmailsResult_validator +UserResendResult._invalid_user_validator = UserSelectorArg_validator +UserResendResult._other_validator = bv.Void() +UserResendResult._tagmap = { + 'success': UserResendResult._success_validator, + 'invalid_user': UserResendResult._invalid_user_validator, + 'other': UserResendResult._other_validator, +} + +UserResendResult.other = UserResendResult('other') + +UserSecondaryEmailsArg._user_validator = UserSelectorArg_validator +UserSecondaryEmailsArg._secondary_emails_validator = bv.List(common.EmailAddress_validator) +UserSecondaryEmailsArg._all_field_names_ = set([ + 'user', + 'secondary_emails', +]) +UserSecondaryEmailsArg._all_fields_ = [ + ('user', UserSecondaryEmailsArg._user_validator), + ('secondary_emails', UserSecondaryEmailsArg._secondary_emails_validator), +] + +UserSecondaryEmailsResult._user_validator = UserSelectorArg_validator +UserSecondaryEmailsResult._results_validator = bv.List(AddSecondaryEmailResult_validator) +UserSecondaryEmailsResult._all_field_names_ = set([ + 'user', + 'results', +]) +UserSecondaryEmailsResult._all_fields_ = [ + ('user', UserSecondaryEmailsResult._user_validator), + ('results', UserSecondaryEmailsResult._results_validator), +] + UserSelectorArg._team_member_id_validator = team_common.TeamMemberId_validator UserSelectorArg._external_id_validator = team_common.MemberExternalId_validator UserSelectorArg._email_validator = common.EmailAddress_validator @@ -19156,6 +23975,76 @@ def __repr__(self): {'host': u'api', 'style': u'rpc'}, ) +legal_holds_create_policy = bb.Route( + 'legal_holds/create_policy', + 1, + False, + LegalHoldsPolicyCreateArg_validator, + LegalHoldsPolicyCreateResult_validator, + LegalHoldsPolicyCreateError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +legal_holds_get_policy = bb.Route( + 'legal_holds/get_policy', + 1, + False, + LegalHoldsGetPolicyArg_validator, + LegalHoldsGetPolicyResult_validator, + LegalHoldsGetPolicyError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +legal_holds_list_held_revisions = bb.Route( + 'legal_holds/list_held_revisions', + 1, + False, + LegalHoldsListHeldRevisionsArg_validator, + LegalHoldsListHeldRevisionResult_validator, + LegalHoldsListHeldRevisionsError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +legal_holds_list_held_revisions_continue = bb.Route( + 'legal_holds/list_held_revisions_continue', + 1, + False, + LegalHoldsListHeldRevisionsContinueArg_validator, + LegalHoldsListHeldRevisionResult_validator, + LegalHoldsListHeldRevisionsError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +legal_holds_list_policies = bb.Route( + 'legal_holds/list_policies', + 1, + False, + LegalHoldsListPoliciesArg_validator, + LegalHoldsListPoliciesResult_validator, + LegalHoldsListPoliciesError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +legal_holds_release_policy = bb.Route( + 'legal_holds/release_policy', + 1, + False, + LegalHoldsPolicyReleaseArg_validator, + bv.Void(), + LegalHoldsPolicyReleaseError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +legal_holds_update_policy = bb.Route( + 'legal_holds/update_policy', + 1, + False, + LegalHoldsPolicyUpdateArg_validator, + LegalHoldsPolicyUpdateResult_validator, + LegalHoldsPolicyUpdateError_validator, + {'host': u'api', + 'style': u'rpc'}, +) linked_apps_list_member_linked_apps = bb.Route( 'linked_apps/list_member_linked_apps', 1, @@ -19296,6 +24185,16 @@ def __repr__(self): {'host': u'api', 'style': u'rpc'}, ) +members_delete_profile_photo = bb.Route( + 'members/delete_profile_photo', + 1, + False, + MembersDeleteProfilePhotoArg_validator, + TeamMemberInfo_validator, + MembersDeleteProfilePhotoError_validator, + {'host': u'api', + 'style': u'rpc'}, +) members_get_info = bb.Route( 'members/get_info', 1, @@ -19376,6 +24275,36 @@ def __repr__(self): {'host': u'api', 'style': u'rpc'}, ) +members_secondary_emails_add = bb.Route( + 'members/secondary_emails/add', + 1, + False, + AddSecondaryEmailsArg_validator, + AddSecondaryEmailsResult_validator, + AddSecondaryEmailsError_validator, + {'host': u'api', + 'style': u'rpc'}, +) +members_secondary_emails_delete = bb.Route( + 'members/secondary_emails/delete', + 1, + False, + DeleteSecondaryEmailsArg_validator, + DeleteSecondaryEmailsResult_validator, + bv.Void(), + {'host': u'api', + 'style': u'rpc'}, +) +members_secondary_emails_resend_verification_emails = bb.Route( + 'members/secondary_emails/resend_verification_emails', + 1, + False, + ResendVerificationEmailArg_validator, + ResendVerificationEmailResult_validator, + bv.Void(), + {'host': u'api', + 'style': u'rpc'}, +) members_send_welcome_email = bb.Route( 'members/send_welcome_email', 1, @@ -19406,6 +24335,16 @@ def __repr__(self): {'host': u'api', 'style': u'rpc'}, ) +members_set_profile_photo = bb.Route( + 'members/set_profile_photo', + 1, + False, + MembersSetProfilePhotoArg_validator, + TeamMemberInfo_validator, + MembersSetProfilePhotoError_validator, + {'host': u'api', + 'style': u'rpc'}, +) members_suspend = bb.Route( 'members/suspend', 1, @@ -19657,6 +24596,13 @@ def __repr__(self): 'groups/members/remove': groups_members_remove, 'groups/members/set_access_type': groups_members_set_access_type, 'groups/update': groups_update, + 'legal_holds/create_policy': legal_holds_create_policy, + 'legal_holds/get_policy': legal_holds_get_policy, + 'legal_holds/list_held_revisions': legal_holds_list_held_revisions, + 'legal_holds/list_held_revisions_continue': legal_holds_list_held_revisions_continue, + 'legal_holds/list_policies': legal_holds_list_policies, + 'legal_holds/release_policy': legal_holds_release_policy, + 'legal_holds/update_policy': legal_holds_update_policy, 'linked_apps/list_member_linked_apps': linked_apps_list_member_linked_apps, 'linked_apps/list_members_linked_apps': linked_apps_list_members_linked_apps, 'linked_apps/list_team_linked_apps': linked_apps_list_team_linked_apps, @@ -19671,6 +24617,7 @@ def __repr__(self): 'member_space_limits/set_custom_quota': member_space_limits_set_custom_quota, 'members/add': members_add, 'members/add/job_status/get': members_add_job_status_get, + 'members/delete_profile_photo': members_delete_profile_photo, 'members/get_info': members_get_info, 'members/list': members_list, 'members/list/continue': members_list_continue, @@ -19679,9 +24626,13 @@ def __repr__(self): 'members/recover': members_recover, 'members/remove': members_remove, 'members/remove/job_status/get': members_remove_job_status_get, + 'members/secondary_emails/add': members_secondary_emails_add, + 'members/secondary_emails/delete': members_secondary_emails_delete, + 'members/secondary_emails/resend_verification_emails': members_secondary_emails_resend_verification_emails, 'members/send_welcome_email': members_send_welcome_email, 'members/set_admin_permissions': members_set_admin_permissions, 'members/set_profile': members_set_profile, + 'members/set_profile_photo': members_set_profile_photo, 'members/suspend': members_suspend, 'members/unsuspend': members_unsuspend, 'namespaces/list': namespaces_list, diff --git a/script.module.dropbox/lib/dropbox/team_log.py b/script.module.dropbox/lib/dropbox/team_log.py index 381c174da..2b659de54 100644 --- a/script.module.dropbox/lib/dropbox/team_log.py +++ b/script.module.dropbox/lib/dropbox/team_log.py @@ -48,6 +48,8 @@ class AccessMethodLogInfo(bb.Union): session details. :ivar WebSessionLogInfo AccessMethodLogInfo.admin_console: Admin console session details. + :ivar WebSessionLogInfo AccessMethodLogInfo.enterprise_console: Enterprise + console session details. :ivar ApiSessionLogInfo AccessMethodLogInfo.api: Api session details. """ @@ -99,6 +101,17 @@ def admin_console(cls, val): """ return cls('admin_console', val) + @classmethod + def enterprise_console(cls, val): + """ + Create an instance of this class set to the ``enterprise_console`` tag + with value ``val``. + + :param WebSessionLogInfo val: + :rtype: AccessMethodLogInfo + """ + return cls('enterprise_console', val) + @classmethod def api(cls, val): """ @@ -142,6 +155,14 @@ def is_admin_console(self): """ return self._tag == 'admin_console' + def is_enterprise_console(self): + """ + Check if the union tag is ``enterprise_console``. + + :rtype: bool + """ + return self._tag == 'enterprise_console' + def is_api(self): """ Check if the union tag is ``api``. @@ -206,6 +227,18 @@ def get_admin_console(self): raise AttributeError("tag 'admin_console' not set") return self._value + def get_enterprise_console(self): + """ + Enterprise console session details. + + Only call this if :meth:`is_enterprise_console` is true. + + :rtype: WebSessionLogInfo + """ + if not self.is_enterprise_console(): + raise AttributeError("tag 'enterprise_console' not set") + return self._value + def get_api(self): """ Api session details. @@ -655,25 +688,35 @@ def __repr__(self): class AccountCaptureNotificationEmailsSentDetails(bb.Struct): """ - Sent proactive account capture email to all unmanaged members. + Sent account capture email to all unmanaged members. :ivar team_log.AccountCaptureNotificationEmailsSentDetails.domain_name: Domain name. + :ivar + team_log.AccountCaptureNotificationEmailsSentDetails.notification_type: + Account-capture email notification type. """ __slots__ = [ '_domain_name_value', '_domain_name_present', + '_notification_type_value', + '_notification_type_present', ] _has_required_fields = True def __init__(self, - domain_name=None): + domain_name=None, + notification_type=None): self._domain_name_value = None self._domain_name_present = False + self._notification_type_value = None + self._notification_type_present = False if domain_name is not None: self.domain_name = domain_name + if notification_type is not None: + self.notification_type = notification_type @property def domain_name(self): @@ -698,12 +741,39 @@ def domain_name(self): self._domain_name_value = None self._domain_name_present = False + @property + def notification_type(self): + """ + Account-capture email notification type. + + :rtype: AccountCaptureNotificationType + """ + if self._notification_type_present: + return self._notification_type_value + else: + return None + + @notification_type.setter + def notification_type(self, val): + if val is None: + del self.notification_type + return + self._notification_type_validator.validate_type_only(val) + self._notification_type_value = val + self._notification_type_present = True + + @notification_type.deleter + def notification_type(self): + self._notification_type_value = None + self._notification_type_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): super(AccountCaptureNotificationEmailsSentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'AccountCaptureNotificationEmailsSentDetails(domain_name={!r})'.format( + return 'AccountCaptureNotificationEmailsSentDetails(domain_name={!r}, notification_type={!r})'.format( self._domain_name_value, + self._notification_type_value, ) AccountCaptureNotificationEmailsSentDetails_validator = bv.Struct(AccountCaptureNotificationEmailsSentDetails) @@ -755,6 +825,53 @@ def __repr__(self): AccountCaptureNotificationEmailsSentType_validator = bv.Struct(AccountCaptureNotificationEmailsSentType) +class AccountCaptureNotificationType(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + proactive_warning_notification = None + # Attribute is overwritten below the class definition + actionable_notification = None + # Attribute is overwritten below the class definition + other = None + + def is_proactive_warning_notification(self): + """ + Check if the union tag is ``proactive_warning_notification``. + + :rtype: bool + """ + return self._tag == 'proactive_warning_notification' + + def is_actionable_notification(self): + """ + Check if the union tag is ``actionable_notification``. + + :rtype: bool + """ + return self._tag == 'actionable_notification' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(AccountCaptureNotificationType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'AccountCaptureNotificationType(%r, %r)' % (self._tag, self._value) + +AccountCaptureNotificationType_validator = bv.Union(AccountCaptureNotificationType) + class AccountCapturePolicy(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will @@ -914,6 +1031,188 @@ def __repr__(self): AccountCaptureRelinquishAccountType_validator = bv.Struct(AccountCaptureRelinquishAccountType) +class AccountLockOrUnlockedDetails(bb.Struct): + """ + Unlocked/locked account after failed sign in attempts. + + :ivar team_log.AccountLockOrUnlockedDetails.previous_value: The previous + account status. + :ivar team_log.AccountLockOrUnlockedDetails.new_value: The new account + status. + """ + + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] + + _has_required_fields = True + + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value + + @property + def previous_value(self): + """ + The previous account status. + + :rtype: AccountState + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + @property + def new_value(self): + """ + The new account status. + + :rtype: AccountState + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(AccountLockOrUnlockedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'AccountLockOrUnlockedDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, + ) + +AccountLockOrUnlockedDetails_validator = bv.Struct(AccountLockOrUnlockedDetails) + +class AccountLockOrUnlockedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(AccountLockOrUnlockedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'AccountLockOrUnlockedType(description={!r})'.format( + self._description_value, + ) + +AccountLockOrUnlockedType_validator = bv.Struct(AccountLockOrUnlockedType) + +class AccountState(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + locked = None + # Attribute is overwritten below the class definition + unlocked = None + # Attribute is overwritten below the class definition + other = None + + def is_locked(self): + """ + Check if the union tag is ``locked``. + + :rtype: bool + """ + return self._tag == 'locked' + + def is_unlocked(self): + """ + Check if the union tag is ``unlocked``. + + :rtype: bool + """ + return self._tag == 'unlocked' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(AccountState, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'AccountState(%r, %r)' % (self._tag, self._value) + +AccountState_validator = bv.Union(AccountState) + class ActionDetails(bb.Union): """ Additional information indicating the action taken that caused status @@ -927,6 +1226,8 @@ class ActionDetails(bb.Union): information relevant when a new member joins the team. :ivar MemberRemoveActionType ActionDetails.remove_action: Define how the user was removed from the team. + :ivar TeamInviteDetails ActionDetails.team_invite_details: Additional + information relevant when someone is invited to the team. """ _catch_all = 'other' @@ -955,6 +1256,17 @@ def remove_action(cls, val): """ return cls('remove_action', val) + @classmethod + def team_invite_details(cls, val): + """ + Create an instance of this class set to the ``team_invite_details`` tag + with value ``val``. + + :param TeamInviteDetails val: + :rtype: ActionDetails + """ + return cls('team_invite_details', val) + def is_team_join_details(self): """ Check if the union tag is ``team_join_details``. @@ -971,6 +1283,14 @@ def is_remove_action(self): """ return self._tag == 'remove_action' + def is_team_invite_details(self): + """ + Check if the union tag is ``team_invite_details``. + + :rtype: bool + """ + return self._tag == 'team_invite_details' + def is_other(self): """ Check if the union tag is ``other``. @@ -1003,6 +1323,18 @@ def get_remove_action(self): raise AttributeError("tag 'remove_action' not set") return self._value + def get_team_invite_details(self): + """ + Additional information relevant when someone is invited to the team. + + Only call this if :meth:`is_team_invite_details` is true. + + :rtype: TeamInviteDetails + """ + if not self.is_team_invite_details(): + raise AttributeError("tag 'team_invite_details' not set") + return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): super(ActionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) @@ -2148,144 +2480,126 @@ def __repr__(self): AssetLogInfo_validator = bv.Union(AssetLogInfo) -class CameraUploadsPolicy(bb.Union): +class BinderAddPageDetails(bb.Struct): """ - Policy for controlling if team members can activate camera uploads + Added Binder page. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team_log.BinderAddPageDetails.event_uuid: Event unique identifier. + :ivar team_log.BinderAddPageDetails.doc_title: Title of the Binder doc. + :ivar team_log.BinderAddPageDetails.binder_item_name: Name of the Binder + page/section. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None - - def is_disabled(self): - """ - Check if the union tag is ``disabled``. - - :rtype: bool - """ - return self._tag == 'disabled' + __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', + ] - def is_enabled(self): - """ - Check if the union tag is ``enabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'enabled' + def __init__(self, + event_uuid=None, + doc_title=None, + binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name - def is_other(self): + @property + def event_uuid(self): """ - Check if the union tag is ``other``. + Event unique identifier. - :rtype: bool + :rtype: str """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CameraUploadsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'CameraUploadsPolicy(%r, %r)' % (self._tag, self._value) - -CameraUploadsPolicy_validator = bv.Union(CameraUploadsPolicy) - -class CameraUploadsPolicyChangedDetails(bb.Struct): - """ - Changed camera uploads setting for team. - - :ivar team_log.CameraUploadsPolicyChangedDetails.new_value: New camera - uploads setting. - :ivar team_log.CameraUploadsPolicyChangedDetails.previous_value: Previous - camera uploads setting. - """ - - __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', - ] + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") - _has_required_fields = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def new_value(self): + def doc_title(self): """ - New camera uploads setting. + Title of the Binder doc. - :rtype: CameraUploadsPolicy + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._doc_title_present: + return self._doc_title_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'doc_title'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False @property - def previous_value(self): + def binder_item_name(self): """ - Previous camera uploads setting. + Name of the Binder page/section. - :rtype: CameraUploadsPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._binder_item_name_present: + return self._binder_item_name_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'binder_item_name'") - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CameraUploadsPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderAddPageDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CameraUploadsPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'BinderAddPageDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, ) -CameraUploadsPolicyChangedDetails_validator = bv.Struct(CameraUploadsPolicyChangedDetails) +BinderAddPageDetails_validator = bv.Struct(BinderAddPageDetails) -class CameraUploadsPolicyChangedType(bb.Struct): +class BinderAddPageType(bb.Struct): __slots__ = [ '_description_value', @@ -2323,319 +2637,469 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CameraUploadsPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderAddPageType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CameraUploadsPolicyChangedType(description={!r})'.format( + return 'BinderAddPageType(description={!r})'.format( self._description_value, ) -CameraUploadsPolicyChangedType_validator = bv.Struct(CameraUploadsPolicyChangedType) +BinderAddPageType_validator = bv.Struct(BinderAddPageType) -class Certificate(bb.Struct): +class BinderAddSectionDetails(bb.Struct): """ - Certificate details. + Added Binder section. - :ivar team_log.Certificate.subject: Certificate subject. - :ivar team_log.Certificate.issuer: Certificate issuer. - :ivar team_log.Certificate.issue_date: Certificate issue date. - :ivar team_log.Certificate.expiration_date: Certificate expiration date. - :ivar team_log.Certificate.serial_number: Certificate serial number. - :ivar team_log.Certificate.sha1_fingerprint: Certificate sha1 fingerprint. - :ivar team_log.Certificate.common_name: Certificate common name. + :ivar team_log.BinderAddSectionDetails.event_uuid: Event unique identifier. + :ivar team_log.BinderAddSectionDetails.doc_title: Title of the Binder doc. + :ivar team_log.BinderAddSectionDetails.binder_item_name: Name of the Binder + page/section. """ __slots__ = [ - '_subject_value', - '_subject_present', - '_issuer_value', - '_issuer_present', - '_issue_date_value', - '_issue_date_present', - '_expiration_date_value', - '_expiration_date_present', - '_serial_number_value', - '_serial_number_present', - '_sha1_fingerprint_value', - '_sha1_fingerprint_present', - '_common_name_value', - '_common_name_present', + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', ] _has_required_fields = True def __init__(self, - subject=None, - issuer=None, - issue_date=None, - expiration_date=None, - serial_number=None, - sha1_fingerprint=None, - common_name=None): - self._subject_value = None - self._subject_present = False - self._issuer_value = None - self._issuer_present = False - self._issue_date_value = None - self._issue_date_present = False - self._expiration_date_value = None - self._expiration_date_present = False - self._serial_number_value = None - self._serial_number_present = False - self._sha1_fingerprint_value = None - self._sha1_fingerprint_present = False - self._common_name_value = None - self._common_name_present = False - if subject is not None: - self.subject = subject - if issuer is not None: - self.issuer = issuer - if issue_date is not None: - self.issue_date = issue_date - if expiration_date is not None: - self.expiration_date = expiration_date - if serial_number is not None: - self.serial_number = serial_number - if sha1_fingerprint is not None: - self.sha1_fingerprint = sha1_fingerprint - if common_name is not None: - self.common_name = common_name + event_uuid=None, + doc_title=None, + binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name @property - def subject(self): + def event_uuid(self): """ - Certificate subject. + Event unique identifier. :rtype: str """ - if self._subject_present: - return self._subject_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'subject'") + raise AttributeError("missing required field 'event_uuid'") - @subject.setter - def subject(self, val): - val = self._subject_validator.validate(val) - self._subject_value = val - self._subject_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @subject.deleter - def subject(self): - self._subject_value = None - self._subject_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def issuer(self): + def doc_title(self): """ - Certificate issuer. + Title of the Binder doc. :rtype: str """ - if self._issuer_present: - return self._issuer_value + if self._doc_title_present: + return self._doc_title_value else: - raise AttributeError("missing required field 'issuer'") + raise AttributeError("missing required field 'doc_title'") - @issuer.setter - def issuer(self, val): - val = self._issuer_validator.validate(val) - self._issuer_value = val - self._issuer_present = True + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True - @issuer.deleter - def issuer(self): - self._issuer_value = None - self._issuer_present = False + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False @property - def issue_date(self): + def binder_item_name(self): """ - Certificate issue date. + Name of the Binder page/section. :rtype: str """ - if self._issue_date_present: - return self._issue_date_value + if self._binder_item_name_present: + return self._binder_item_name_value else: - raise AttributeError("missing required field 'issue_date'") + raise AttributeError("missing required field 'binder_item_name'") - @issue_date.setter - def issue_date(self, val): - val = self._issue_date_validator.validate(val) - self._issue_date_value = val - self._issue_date_present = True + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True - @issue_date.deleter - def issue_date(self): - self._issue_date_value = None - self._issue_date_present = False + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(BinderAddSectionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'BinderAddSectionDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, + ) + +BinderAddSectionDetails_validator = bv.Struct(BinderAddSectionDetails) + +class BinderAddSectionType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def expiration_date(self): + def description(self): """ - Certificate expiration date. - :rtype: str """ - if self._expiration_date_present: - return self._expiration_date_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'expiration_date'") + raise AttributeError("missing required field 'description'") - @expiration_date.setter - def expiration_date(self, val): - val = self._expiration_date_validator.validate(val) - self._expiration_date_value = val - self._expiration_date_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @expiration_date.deleter - def expiration_date(self): - self._expiration_date_value = None - self._expiration_date_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(BinderAddSectionType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'BinderAddSectionType(description={!r})'.format( + self._description_value, + ) + +BinderAddSectionType_validator = bv.Struct(BinderAddSectionType) + +class BinderRemovePageDetails(bb.Struct): + """ + Removed Binder page. + + :ivar team_log.BinderRemovePageDetails.event_uuid: Event unique identifier. + :ivar team_log.BinderRemovePageDetails.doc_title: Title of the Binder doc. + :ivar team_log.BinderRemovePageDetails.binder_item_name: Name of the Binder + page/section. + """ + + __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', + ] + + _has_required_fields = True + + def __init__(self, + event_uuid=None, + doc_title=None, + binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name @property - def serial_number(self): + def event_uuid(self): """ - Certificate serial number. + Event unique identifier. :rtype: str """ - if self._serial_number_present: - return self._serial_number_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'serial_number'") + raise AttributeError("missing required field 'event_uuid'") - @serial_number.setter - def serial_number(self, val): - val = self._serial_number_validator.validate(val) - self._serial_number_value = val - self._serial_number_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @serial_number.deleter - def serial_number(self): - self._serial_number_value = None - self._serial_number_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def sha1_fingerprint(self): + def doc_title(self): """ - Certificate sha1 fingerprint. + Title of the Binder doc. :rtype: str """ - if self._sha1_fingerprint_present: - return self._sha1_fingerprint_value + if self._doc_title_present: + return self._doc_title_value else: - raise AttributeError("missing required field 'sha1_fingerprint'") + raise AttributeError("missing required field 'doc_title'") - @sha1_fingerprint.setter - def sha1_fingerprint(self, val): - val = self._sha1_fingerprint_validator.validate(val) - self._sha1_fingerprint_value = val - self._sha1_fingerprint_present = True + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True - @sha1_fingerprint.deleter - def sha1_fingerprint(self): - self._sha1_fingerprint_value = None - self._sha1_fingerprint_present = False + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False @property - def common_name(self): + def binder_item_name(self): """ - Certificate common name. + Name of the Binder page/section. :rtype: str """ - if self._common_name_present: - return self._common_name_value + if self._binder_item_name_present: + return self._binder_item_name_value else: - return None + raise AttributeError("missing required field 'binder_item_name'") - @common_name.setter - def common_name(self, val): - if val is None: - del self.common_name - return - val = self._common_name_validator.validate(val) - self._common_name_value = val - self._common_name_present = True + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True - @common_name.deleter - def common_name(self): - self._common_name_value = None - self._common_name_present = False + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(Certificate, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderRemovePageDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'Certificate(subject={!r}, issuer={!r}, issue_date={!r}, expiration_date={!r}, serial_number={!r}, sha1_fingerprint={!r}, common_name={!r})'.format( - self._subject_value, - self._issuer_value, - self._issue_date_value, - self._expiration_date_value, - self._serial_number_value, - self._sha1_fingerprint_value, - self._common_name_value, + return 'BinderRemovePageDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, ) -Certificate_validator = bv.Struct(Certificate) +BinderRemovePageDetails_validator = bv.Struct(BinderRemovePageDetails) -class CollectionShareDetails(bb.Struct): +class BinderRemovePageType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(BinderRemovePageType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'BinderRemovePageType(description={!r})'.format( + self._description_value, + ) + +BinderRemovePageType_validator = bv.Struct(BinderRemovePageType) + +class BinderRemoveSectionDetails(bb.Struct): """ - Shared album. + Removed Binder section. - :ivar team_log.CollectionShareDetails.album_name: Album name. + :ivar team_log.BinderRemoveSectionDetails.event_uuid: Event unique + identifier. + :ivar team_log.BinderRemoveSectionDetails.doc_title: Title of the Binder + doc. + :ivar team_log.BinderRemoveSectionDetails.binder_item_name: Name of the + Binder page/section. """ __slots__ = [ - '_album_name_value', - '_album_name_present', + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', ] _has_required_fields = True def __init__(self, - album_name=None): - self._album_name_value = None - self._album_name_present = False - if album_name is not None: - self.album_name = album_name + event_uuid=None, + doc_title=None, + binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name @property - def album_name(self): + def event_uuid(self): """ - Album name. + Event unique identifier. :rtype: str """ - if self._album_name_present: - return self._album_name_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'album_name'") + raise AttributeError("missing required field 'event_uuid'") - @album_name.setter - def album_name(self, val): - val = self._album_name_validator.validate(val) - self._album_name_value = val - self._album_name_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @album_name.deleter - def album_name(self): - self._album_name_value = None - self._album_name_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + @property + def doc_title(self): + """ + Title of the Binder doc. + + :rtype: str + """ + if self._doc_title_present: + return self._doc_title_value + else: + raise AttributeError("missing required field 'doc_title'") + + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True + + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False + + @property + def binder_item_name(self): + """ + Name of the Binder page/section. + + :rtype: str + """ + if self._binder_item_name_present: + return self._binder_item_name_value + else: + raise AttributeError("missing required field 'binder_item_name'") + + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True + + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CollectionShareDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderRemoveSectionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CollectionShareDetails(album_name={!r})'.format( - self._album_name_value, + return 'BinderRemoveSectionDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, ) -CollectionShareDetails_validator = bv.Struct(CollectionShareDetails) +BinderRemoveSectionDetails_validator = bv.Struct(BinderRemoveSectionDetails) -class CollectionShareType(bb.Struct): +class BinderRemoveSectionType(bb.Struct): __slots__ = [ '_description_value', @@ -2673,237 +3137,375 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CollectionShareType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderRemoveSectionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CollectionShareType(description={!r})'.format( + return 'BinderRemoveSectionType(description={!r})'.format( self._description_value, ) -CollectionShareType_validator = bv.Struct(CollectionShareType) +BinderRemoveSectionType_validator = bv.Struct(BinderRemoveSectionType) -class ContentPermanentDeletePolicy(bb.Union): +class BinderRenamePageDetails(bb.Struct): """ - Policy for pemanent content deletion + Renamed Binder page. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team_log.BinderRenamePageDetails.event_uuid: Event unique identifier. + :ivar team_log.BinderRenamePageDetails.doc_title: Title of the Binder doc. + :ivar team_log.BinderRenamePageDetails.binder_item_name: Name of the Binder + page/section. + :ivar team_log.BinderRenamePageDetails.previous_binder_item_name: Previous + name of the Binder page/section. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', + '_previous_binder_item_name_value', + '_previous_binder_item_name_present', + ] - def is_disabled(self): - """ - Check if the union tag is ``disabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'disabled' + def __init__(self, + event_uuid=None, + doc_title=None, + binder_item_name=None, + previous_binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + self._previous_binder_item_name_value = None + self._previous_binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name + if previous_binder_item_name is not None: + self.previous_binder_item_name = previous_binder_item_name - def is_enabled(self): + @property + def event_uuid(self): """ - Check if the union tag is ``enabled``. + Event unique identifier. - :rtype: bool + :rtype: str """ - return self._tag == 'enabled' + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") - def is_other(self): - """ - Check if the union tag is ``other``. + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - :rtype: bool - """ - return self._tag == 'other' + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ContentPermanentDeletePolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def doc_title(self): + """ + Title of the Binder doc. - def __repr__(self): - return 'ContentPermanentDeletePolicy(%r, %r)' % (self._tag, self._value) + :rtype: str + """ + if self._doc_title_present: + return self._doc_title_value + else: + raise AttributeError("missing required field 'doc_title'") -ContentPermanentDeletePolicy_validator = bv.Union(ContentPermanentDeletePolicy) + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True -class ContextLogInfo(bb.Union): - """ - The primary entity on which the action was done. + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + @property + def binder_item_name(self): + """ + Name of the Binder page/section. - :ivar TeamMemberLogInfo ContextLogInfo.team_member: Action was done on - behalf of a team member. - :ivar NonTeamMemberLogInfo ContextLogInfo.non_team_member: Action was done - on behalf of a non team member. - :ivar team_log.ContextLogInfo.anonymous: Anonymous context. - :ivar team_log.ContextLogInfo.team: Action was done on behalf of the team. - :ivar TrustedNonTeamMemberLogInfo ContextLogInfo.trusted_non_team_member: - Action was done on behalf of a trusted non team member. - """ + :rtype: str + """ + if self._binder_item_name_present: + return self._binder_item_name_value + else: + raise AttributeError("missing required field 'binder_item_name'") - _catch_all = 'other' - # Attribute is overwritten below the class definition - anonymous = None - # Attribute is overwritten below the class definition - team = None - # Attribute is overwritten below the class definition - other = None + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True - @classmethod - def team_member(cls, val): - """ - Create an instance of this class set to the ``team_member`` tag with - value ``val``. + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False - :param TeamMemberLogInfo val: - :rtype: ContextLogInfo + @property + def previous_binder_item_name(self): """ - return cls('team_member', val) + Previous name of the Binder page/section. - @classmethod - def non_team_member(cls, val): + :rtype: str """ - Create an instance of this class set to the ``non_team_member`` tag with - value ``val``. + if self._previous_binder_item_name_present: + return self._previous_binder_item_name_value + else: + return None - :param NonTeamMemberLogInfo val: - :rtype: ContextLogInfo - """ - return cls('non_team_member', val) + @previous_binder_item_name.setter + def previous_binder_item_name(self, val): + if val is None: + del self.previous_binder_item_name + return + val = self._previous_binder_item_name_validator.validate(val) + self._previous_binder_item_name_value = val + self._previous_binder_item_name_present = True - @classmethod - def trusted_non_team_member(cls, val): - """ - Create an instance of this class set to the ``trusted_non_team_member`` - tag with value ``val``. + @previous_binder_item_name.deleter + def previous_binder_item_name(self): + self._previous_binder_item_name_value = None + self._previous_binder_item_name_present = False - :param TrustedNonTeamMemberLogInfo val: - :rtype: ContextLogInfo - """ - return cls('trusted_non_team_member', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(BinderRenamePageDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - def is_team_member(self): - """ - Check if the union tag is ``team_member``. + def __repr__(self): + return 'BinderRenamePageDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r}, previous_binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, + self._previous_binder_item_name_value, + ) - :rtype: bool - """ - return self._tag == 'team_member' +BinderRenamePageDetails_validator = bv.Struct(BinderRenamePageDetails) - def is_non_team_member(self): - """ - Check if the union tag is ``non_team_member``. +class BinderRenamePageType(bb.Struct): - :rtype: bool - """ - return self._tag == 'non_team_member' + __slots__ = [ + '_description_value', + '_description_present', + ] - def is_anonymous(self): - """ - Check if the union tag is ``anonymous``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'anonymous' + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def is_team(self): + @property + def description(self): """ - Check if the union tag is ``team``. - - :rtype: bool + :rtype: str """ - return self._tag == 'team' + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - def is_trusted_non_team_member(self): - """ - Check if the union tag is ``trusted_non_team_member``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: bool - """ - return self._tag == 'trusted_non_team_member' + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def is_other(self): - """ - Check if the union tag is ``other``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(BinderRenamePageType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'other' + def __repr__(self): + return 'BinderRenamePageType(description={!r})'.format( + self._description_value, + ) - def get_team_member(self): - """ - Action was done on behalf of a team member. +BinderRenamePageType_validator = bv.Struct(BinderRenamePageType) - Only call this if :meth:`is_team_member` is true. +class BinderRenameSectionDetails(bb.Struct): + """ + Renamed Binder section. - :rtype: TeamMemberLogInfo + :ivar team_log.BinderRenameSectionDetails.event_uuid: Event unique + identifier. + :ivar team_log.BinderRenameSectionDetails.doc_title: Title of the Binder + doc. + :ivar team_log.BinderRenameSectionDetails.binder_item_name: Name of the + Binder page/section. + :ivar team_log.BinderRenameSectionDetails.previous_binder_item_name: + Previous name of the Binder page/section. + """ + + __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', + '_previous_binder_item_name_value', + '_previous_binder_item_name_present', + ] + + _has_required_fields = True + + def __init__(self, + event_uuid=None, + doc_title=None, + binder_item_name=None, + previous_binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + self._previous_binder_item_name_value = None + self._previous_binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name + if previous_binder_item_name is not None: + self.previous_binder_item_name = previous_binder_item_name + + @property + def event_uuid(self): """ - if not self.is_team_member(): - raise AttributeError("tag 'team_member' not set") - return self._value + Event unique identifier. - def get_non_team_member(self): + :rtype: str """ - Action was done on behalf of a non team member. + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") - Only call this if :meth:`is_non_team_member` is true. + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - :rtype: NonTeamMemberLogInfo + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + @property + def doc_title(self): """ - if not self.is_non_team_member(): - raise AttributeError("tag 'non_team_member' not set") - return self._value + Title of the Binder doc. - def get_trusted_non_team_member(self): + :rtype: str """ - Action was done on behalf of a trusted non team member. + if self._doc_title_present: + return self._doc_title_value + else: + raise AttributeError("missing required field 'doc_title'") - Only call this if :meth:`is_trusted_non_team_member` is true. + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True - :rtype: TrustedNonTeamMemberLogInfo + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False + + @property + def binder_item_name(self): """ - if not self.is_trusted_non_team_member(): - raise AttributeError("tag 'trusted_non_team_member' not set") - return self._value + Name of the Binder page/section. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ContextLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: str + """ + if self._binder_item_name_present: + return self._binder_item_name_value + else: + raise AttributeError("missing required field 'binder_item_name'") - def __repr__(self): - return 'ContextLogInfo(%r, %r)' % (self._tag, self._value) + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True -ContextLogInfo_validator = bv.Union(ContextLogInfo) + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False -class CreateFolderDetails(bb.Struct): - """ - Created folders. - """ + @property + def previous_binder_item_name(self): + """ + Previous name of the Binder page/section. - __slots__ = [ - ] + :rtype: str + """ + if self._previous_binder_item_name_present: + return self._previous_binder_item_name_value + else: + return None - _has_required_fields = False + @previous_binder_item_name.setter + def previous_binder_item_name(self, val): + if val is None: + del self.previous_binder_item_name + return + val = self._previous_binder_item_name_validator.validate(val) + self._previous_binder_item_name_value = val + self._previous_binder_item_name_present = True - def __init__(self): - pass + @previous_binder_item_name.deleter + def previous_binder_item_name(self): + self._previous_binder_item_name_value = None + self._previous_binder_item_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CreateFolderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderRenameSectionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CreateFolderDetails()' + return 'BinderRenameSectionDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r}, previous_binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, + self._previous_binder_item_name_value, + ) -CreateFolderDetails_validator = bv.Struct(CreateFolderDetails) +BinderRenameSectionDetails_validator = bv.Struct(BinderRenameSectionDetails) -class CreateFolderType(bb.Struct): +class BinderRenameSectionType(bb.Struct): __slots__ = [ '_description_value', @@ -2941,104 +3543,135 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(CreateFolderType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderRenameSectionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'CreateFolderType(description={!r})'.format( + return 'BinderRenameSectionType(description={!r})'.format( self._description_value, ) -CreateFolderType_validator = bv.Struct(CreateFolderType) +BinderRenameSectionType_validator = bv.Struct(BinderRenameSectionType) -class DataPlacementRestrictionChangePolicyDetails(bb.Struct): +class BinderReorderPageDetails(bb.Struct): """ - Set restrictions on data center locations where team data resides. + Reordered Binder page. - :ivar team_log.DataPlacementRestrictionChangePolicyDetails.previous_value: - Previous placement restriction. - :ivar team_log.DataPlacementRestrictionChangePolicyDetails.new_value: New - placement restriction. + :ivar team_log.BinderReorderPageDetails.event_uuid: Event unique identifier. + :ivar team_log.BinderReorderPageDetails.doc_title: Title of the Binder doc. + :ivar team_log.BinderReorderPageDetails.binder_item_name: Name of the Binder + page/section. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', ] _has_required_fields = True def __init__(self, - previous_value=None, - new_value=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value + event_uuid=None, + doc_title=None, + binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name @property - def previous_value(self): + def event_uuid(self): """ - Previous placement restriction. + Event unique identifier. - :rtype: PlacementRestriction + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'event_uuid'") - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def new_value(self): + def doc_title(self): """ - New placement restriction. + Title of the Binder doc. - :rtype: PlacementRestriction + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._doc_title_present: + return self._doc_title_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'doc_title'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False + + @property + def binder_item_name(self): + """ + Name of the Binder page/section. + + :rtype: str + """ + if self._binder_item_name_present: + return self._binder_item_name_value + else: + raise AttributeError("missing required field 'binder_item_name'") + + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True + + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DataPlacementRestrictionChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderReorderPageDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DataPlacementRestrictionChangePolicyDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, - self._new_value_value, + return 'BinderReorderPageDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, ) -DataPlacementRestrictionChangePolicyDetails_validator = bv.Struct(DataPlacementRestrictionChangePolicyDetails) +BinderReorderPageDetails_validator = bv.Struct(BinderReorderPageDetails) -class DataPlacementRestrictionChangePolicyType(bb.Struct): +class BinderReorderPageType(bb.Struct): __slots__ = [ '_description_value', @@ -3076,72 +3709,137 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DataPlacementRestrictionChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderReorderPageType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DataPlacementRestrictionChangePolicyType(description={!r})'.format( + return 'BinderReorderPageType(description={!r})'.format( self._description_value, ) -DataPlacementRestrictionChangePolicyType_validator = bv.Struct(DataPlacementRestrictionChangePolicyType) +BinderReorderPageType_validator = bv.Struct(BinderReorderPageType) -class DataPlacementRestrictionSatisfyPolicyDetails(bb.Struct): +class BinderReorderSectionDetails(bb.Struct): """ - Completed restrictions on data center locations where team data resides. + Reordered Binder section. - :ivar - team_log.DataPlacementRestrictionSatisfyPolicyDetails.placement_restriction: - Placement restriction. + :ivar team_log.BinderReorderSectionDetails.event_uuid: Event unique + identifier. + :ivar team_log.BinderReorderSectionDetails.doc_title: Title of the Binder + doc. + :ivar team_log.BinderReorderSectionDetails.binder_item_name: Name of the + Binder page/section. """ __slots__ = [ - '_placement_restriction_value', - '_placement_restriction_present', + '_event_uuid_value', + '_event_uuid_present', + '_doc_title_value', + '_doc_title_present', + '_binder_item_name_value', + '_binder_item_name_present', ] _has_required_fields = True def __init__(self, - placement_restriction=None): - self._placement_restriction_value = None - self._placement_restriction_present = False - if placement_restriction is not None: - self.placement_restriction = placement_restriction + event_uuid=None, + doc_title=None, + binder_item_name=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._doc_title_value = None + self._doc_title_present = False + self._binder_item_name_value = None + self._binder_item_name_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if doc_title is not None: + self.doc_title = doc_title + if binder_item_name is not None: + self.binder_item_name = binder_item_name @property - def placement_restriction(self): + def event_uuid(self): """ - Placement restriction. + Event unique identifier. - :rtype: PlacementRestriction + :rtype: str """ - if self._placement_restriction_present: - return self._placement_restriction_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'placement_restriction'") + raise AttributeError("missing required field 'event_uuid'") - @placement_restriction.setter - def placement_restriction(self, val): - self._placement_restriction_validator.validate_type_only(val) - self._placement_restriction_value = val - self._placement_restriction_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @placement_restriction.deleter - def placement_restriction(self): - self._placement_restriction_value = None - self._placement_restriction_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + @property + def doc_title(self): + """ + Title of the Binder doc. + + :rtype: str + """ + if self._doc_title_present: + return self._doc_title_value + else: + raise AttributeError("missing required field 'doc_title'") + + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True + + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False + + @property + def binder_item_name(self): + """ + Name of the Binder page/section. + + :rtype: str + """ + if self._binder_item_name_present: + return self._binder_item_name_value + else: + raise AttributeError("missing required field 'binder_item_name'") + + @binder_item_name.setter + def binder_item_name(self, val): + val = self._binder_item_name_validator.validate(val) + self._binder_item_name_value = val + self._binder_item_name_present = True + + @binder_item_name.deleter + def binder_item_name(self): + self._binder_item_name_value = None + self._binder_item_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DataPlacementRestrictionSatisfyPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderReorderSectionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DataPlacementRestrictionSatisfyPolicyDetails(placement_restriction={!r})'.format( - self._placement_restriction_value, + return 'BinderReorderSectionDetails(event_uuid={!r}, doc_title={!r}, binder_item_name={!r})'.format( + self._event_uuid_value, + self._doc_title_value, + self._binder_item_name_value, ) -DataPlacementRestrictionSatisfyPolicyDetails_validator = bv.Struct(DataPlacementRestrictionSatisfyPolicyDetails) +BinderReorderSectionDetails_validator = bv.Struct(BinderReorderSectionDetails) -class DataPlacementRestrictionSatisfyPolicyType(bb.Struct): +class BinderReorderSectionType(bb.Struct): __slots__ = [ '_description_value', @@ -3179,478 +3877,72 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DataPlacementRestrictionSatisfyPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(BinderReorderSectionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DataPlacementRestrictionSatisfyPolicyType(description={!r})'.format( + return 'BinderReorderSectionType(description={!r})'.format( self._description_value, ) -DataPlacementRestrictionSatisfyPolicyType_validator = bv.Struct(DataPlacementRestrictionSatisfyPolicyType) +BinderReorderSectionType_validator = bv.Struct(BinderReorderSectionType) -class DeviceSessionLogInfo(bb.Struct): +class CameraUploadsPolicy(bb.Union): """ - Device's session logged information. + Policy for controlling if team members can activate camera uploads - :ivar team_log.DeviceSessionLogInfo.ip_address: The IP address of the last - activity from this session. Might be missing due to historical data gap. - :ivar team_log.DeviceSessionLogInfo.created: The time this session was - created. Might be missing due to historical data gap. - :ivar team_log.DeviceSessionLogInfo.updated: The time of the last activity - from this session. Might be missing due to historical data gap. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_ip_address_value', - '_ip_address_present', - '_created_value', - '_created_present', - '_updated_value', - '_updated_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = False + def is_disabled(self): + """ + Check if the union tag is ``disabled``. - def __init__(self, - ip_address=None, - created=None, - updated=None): - self._ip_address_value = None - self._ip_address_present = False - self._created_value = None - self._created_present = False - self._updated_value = None - self._updated_present = False - if ip_address is not None: - self.ip_address = ip_address - if created is not None: - self.created = created - if updated is not None: - self.updated = updated - - @property - def ip_address(self): - """ - The IP address of the last activity from this session. Might be missing - due to historical data gap. - - :rtype: str - """ - if self._ip_address_present: - return self._ip_address_value - else: - return None - - @ip_address.setter - def ip_address(self, val): - if val is None: - del self.ip_address - return - val = self._ip_address_validator.validate(val) - self._ip_address_value = val - self._ip_address_present = True - - @ip_address.deleter - def ip_address(self): - self._ip_address_value = None - self._ip_address_present = False - - @property - def created(self): - """ - The time this session was created. Might be missing due to historical - data gap. - - :rtype: datetime.datetime - """ - if self._created_present: - return self._created_value - else: - return None - - @created.setter - def created(self, val): - if val is None: - del self.created - return - val = self._created_validator.validate(val) - self._created_value = val - self._created_present = True - - @created.deleter - def created(self): - self._created_value = None - self._created_present = False - - @property - def updated(self): - """ - The time of the last activity from this session. Might be missing due to - historical data gap. - - :rtype: datetime.datetime - """ - if self._updated_present: - return self._updated_value - else: - return None - - @updated.setter - def updated(self, val): - if val is None: - del self.updated - return - val = self._updated_validator.validate(val) - self._updated_value = val - self._updated_present = True - - @updated.deleter - def updated(self): - self._updated_value = None - self._updated_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DeviceSessionLogInfo(ip_address={!r}, created={!r}, updated={!r})'.format( - self._ip_address_value, - self._created_value, - self._updated_value, - ) - -DeviceSessionLogInfo_validator = bv.StructTree(DeviceSessionLogInfo) - -class DesktopDeviceSessionLogInfo(DeviceSessionLogInfo): - """ - Information about linked Dropbox desktop client sessions - - :ivar team_log.DesktopDeviceSessionLogInfo.session_info: Desktop session - unique id. Might be missing due to historical data gap. - :ivar team_log.DesktopDeviceSessionLogInfo.host_name: Name of the hosting - desktop. - :ivar team_log.DesktopDeviceSessionLogInfo.client_type: The Dropbox desktop - client type. - :ivar team_log.DesktopDeviceSessionLogInfo.client_version: The Dropbox - client version. - :ivar team_log.DesktopDeviceSessionLogInfo.platform: Information on the - hosting platform. - :ivar team_log.DesktopDeviceSessionLogInfo.is_delete_on_unlink_supported: - Whether itu2019s possible to delete all of the account files upon - unlinking. - """ - - __slots__ = [ - '_session_info_value', - '_session_info_present', - '_host_name_value', - '_host_name_present', - '_client_type_value', - '_client_type_present', - '_client_version_value', - '_client_version_present', - '_platform_value', - '_platform_present', - '_is_delete_on_unlink_supported_value', - '_is_delete_on_unlink_supported_present', - ] - - _has_required_fields = True - - def __init__(self, - host_name=None, - client_type=None, - platform=None, - is_delete_on_unlink_supported=None, - ip_address=None, - created=None, - updated=None, - session_info=None, - client_version=None): - super(DesktopDeviceSessionLogInfo, self).__init__(ip_address, - created, - updated) - self._session_info_value = None - self._session_info_present = False - self._host_name_value = None - self._host_name_present = False - self._client_type_value = None - self._client_type_present = False - self._client_version_value = None - self._client_version_present = False - self._platform_value = None - self._platform_present = False - self._is_delete_on_unlink_supported_value = None - self._is_delete_on_unlink_supported_present = False - if session_info is not None: - self.session_info = session_info - if host_name is not None: - self.host_name = host_name - if client_type is not None: - self.client_type = client_type - if client_version is not None: - self.client_version = client_version - if platform is not None: - self.platform = platform - if is_delete_on_unlink_supported is not None: - self.is_delete_on_unlink_supported = is_delete_on_unlink_supported - - @property - def session_info(self): - """ - Desktop session unique id. Might be missing due to historical data gap. - - :rtype: DesktopSessionLogInfo - """ - if self._session_info_present: - return self._session_info_value - else: - return None - - @session_info.setter - def session_info(self, val): - if val is None: - del self.session_info - return - self._session_info_validator.validate_type_only(val) - self._session_info_value = val - self._session_info_present = True - - @session_info.deleter - def session_info(self): - self._session_info_value = None - self._session_info_present = False - - @property - def host_name(self): - """ - Name of the hosting desktop. - - :rtype: str - """ - if self._host_name_present: - return self._host_name_value - else: - raise AttributeError("missing required field 'host_name'") - - @host_name.setter - def host_name(self, val): - val = self._host_name_validator.validate(val) - self._host_name_value = val - self._host_name_present = True - - @host_name.deleter - def host_name(self): - self._host_name_value = None - self._host_name_present = False - - @property - def client_type(self): - """ - The Dropbox desktop client type. - - :rtype: team.DesktopPlatform - """ - if self._client_type_present: - return self._client_type_value - else: - raise AttributeError("missing required field 'client_type'") - - @client_type.setter - def client_type(self, val): - self._client_type_validator.validate_type_only(val) - self._client_type_value = val - self._client_type_present = True - - @client_type.deleter - def client_type(self): - self._client_type_value = None - self._client_type_present = False - - @property - def client_version(self): - """ - The Dropbox client version. - - :rtype: str - """ - if self._client_version_present: - return self._client_version_value - else: - return None - - @client_version.setter - def client_version(self, val): - if val is None: - del self.client_version - return - val = self._client_version_validator.validate(val) - self._client_version_value = val - self._client_version_present = True - - @client_version.deleter - def client_version(self): - self._client_version_value = None - self._client_version_present = False - - @property - def platform(self): - """ - Information on the hosting platform. - - :rtype: str + :rtype: bool """ - if self._platform_present: - return self._platform_value - else: - raise AttributeError("missing required field 'platform'") - - @platform.setter - def platform(self, val): - val = self._platform_validator.validate(val) - self._platform_value = val - self._platform_present = True - - @platform.deleter - def platform(self): - self._platform_value = None - self._platform_present = False + return self._tag == 'disabled' - @property - def is_delete_on_unlink_supported(self): + def is_enabled(self): """ - Whether itu2019s possible to delete all of the account files upon - unlinking. + Check if the union tag is ``enabled``. :rtype: bool """ - if self._is_delete_on_unlink_supported_present: - return self._is_delete_on_unlink_supported_value - else: - raise AttributeError("missing required field 'is_delete_on_unlink_supported'") - - @is_delete_on_unlink_supported.setter - def is_delete_on_unlink_supported(self, val): - val = self._is_delete_on_unlink_supported_validator.validate(val) - self._is_delete_on_unlink_supported_value = val - self._is_delete_on_unlink_supported_present = True - - @is_delete_on_unlink_supported.deleter - def is_delete_on_unlink_supported(self): - self._is_delete_on_unlink_supported_value = None - self._is_delete_on_unlink_supported_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DesktopDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DesktopDeviceSessionLogInfo(host_name={!r}, client_type={!r}, platform={!r}, is_delete_on_unlink_supported={!r}, ip_address={!r}, created={!r}, updated={!r}, session_info={!r}, client_version={!r})'.format( - self._host_name_value, - self._client_type_value, - self._platform_value, - self._is_delete_on_unlink_supported_value, - self._ip_address_value, - self._created_value, - self._updated_value, - self._session_info_value, - self._client_version_value, - ) - -DesktopDeviceSessionLogInfo_validator = bv.Struct(DesktopDeviceSessionLogInfo) - -class SessionLogInfo(bb.Struct): - """ - Session's logged information. - - :ivar team_log.SessionLogInfo.session_id: Session ID. Might be missing due - to historical data gap. - """ - - __slots__ = [ - '_session_id_value', - '_session_id_present', - ] - - _has_required_fields = False - - def __init__(self, - session_id=None): - self._session_id_value = None - self._session_id_present = False - if session_id is not None: - self.session_id = session_id + return self._tag == 'enabled' - @property - def session_id(self): + def is_other(self): """ - Session ID. Might be missing due to historical data gap. + Check if the union tag is ``other``. - :rtype: str + :rtype: bool """ - if self._session_id_present: - return self._session_id_value - else: - return None - - @session_id.setter - def session_id(self, val): - if val is None: - del self.session_id - return - val = self._session_id_validator.validate(val) - self._session_id_value = val - self._session_id_present = True - - @session_id.deleter - def session_id(self): - self._session_id_value = None - self._session_id_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SessionLogInfo(session_id={!r})'.format( - self._session_id_value, - ) - -SessionLogInfo_validator = bv.StructTree(SessionLogInfo) - -class DesktopSessionLogInfo(SessionLogInfo): - """ - Desktop session. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self, - session_id=None): - super(DesktopSessionLogInfo, self).__init__(session_id) + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DesktopSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CameraUploadsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DesktopSessionLogInfo(session_id={!r})'.format( - self._session_id_value, - ) + return 'CameraUploadsPolicy(%r, %r)' % (self._tag, self._value) -DesktopSessionLogInfo_validator = bv.Struct(DesktopSessionLogInfo) +CameraUploadsPolicy_validator = bv.Union(CameraUploadsPolicy) -class DeviceApprovalsChangeDesktopPolicyDetails(bb.Struct): +class CameraUploadsPolicyChangedDetails(bb.Struct): """ - Set/removed limit on number of computers member can link to team Dropbox - account. + Changed camera uploads setting for team. - :ivar team_log.DeviceApprovalsChangeDesktopPolicyDetails.new_value: New - desktop device approvals policy. Might be missing due to historical data - gap. - :ivar team_log.DeviceApprovalsChangeDesktopPolicyDetails.previous_value: - Previous desktop device approvals policy. Might be missing due to - historical data gap. + :ivar team_log.CameraUploadsPolicyChangedDetails.new_value: New camera + uploads setting. + :ivar team_log.CameraUploadsPolicyChangedDetails.previous_value: Previous + camera uploads setting. """ __slots__ = [ @@ -3660,7 +3952,7 @@ class DeviceApprovalsChangeDesktopPolicyDetails(bb.Struct): '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, new_value=None, @@ -3677,21 +3969,17 @@ def __init__(self, @property def new_value(self): """ - New desktop device approvals policy. Might be missing due to historical - data gap. + New camera uploads setting. - :rtype: DeviceApprovalsPolicy + :rtype: CameraUploadsPolicy """ if self._new_value_present: return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") @new_value.setter def new_value(self, val): - if val is None: - del self.new_value - return self._new_value_validator.validate_type_only(val) self._new_value_value = val self._new_value_present = True @@ -3704,21 +3992,17 @@ def new_value(self): @property def previous_value(self): """ - Previous desktop device approvals policy. Might be missing due to - historical data gap. + Previous camera uploads setting. - :rtype: DeviceApprovalsPolicy + :rtype: CameraUploadsPolicy """ if self._previous_value_present: return self._previous_value_value else: - return None + raise AttributeError("missing required field 'previous_value'") @previous_value.setter def previous_value(self, val): - if val is None: - del self.previous_value - return self._previous_value_validator.validate_type_only(val) self._previous_value_value = val self._previous_value_present = True @@ -3729,17 +4013,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeDesktopPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CameraUploadsPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceApprovalsChangeDesktopPolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'CameraUploadsPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -DeviceApprovalsChangeDesktopPolicyDetails_validator = bv.Struct(DeviceApprovalsChangeDesktopPolicyDetails) +CameraUploadsPolicyChangedDetails_validator = bv.Struct(CameraUploadsPolicyChangedDetails) -class DeviceApprovalsChangeDesktopPolicyType(bb.Struct): +class CameraUploadsPolicyChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -3777,210 +4061,341 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeDesktopPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CameraUploadsPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceApprovalsChangeDesktopPolicyType(description={!r})'.format( + return 'CameraUploadsPolicyChangedType(description={!r})'.format( self._description_value, ) -DeviceApprovalsChangeDesktopPolicyType_validator = bv.Struct(DeviceApprovalsChangeDesktopPolicyType) +CameraUploadsPolicyChangedType_validator = bv.Struct(CameraUploadsPolicyChangedType) -class DeviceApprovalsChangeMobilePolicyDetails(bb.Struct): +class Certificate(bb.Struct): """ - Set/removed limit on number of mobile devices member can link to team - Dropbox account. + Certificate details. - :ivar team_log.DeviceApprovalsChangeMobilePolicyDetails.new_value: New - mobile device approvals policy. Might be missing due to historical data - gap. - :ivar team_log.DeviceApprovalsChangeMobilePolicyDetails.previous_value: - Previous mobile device approvals policy. Might be missing due to - historical data gap. + :ivar team_log.Certificate.subject: Certificate subject. + :ivar team_log.Certificate.issuer: Certificate issuer. + :ivar team_log.Certificate.issue_date: Certificate issue date. + :ivar team_log.Certificate.expiration_date: Certificate expiration date. + :ivar team_log.Certificate.serial_number: Certificate serial number. + :ivar team_log.Certificate.sha1_fingerprint: Certificate sha1 fingerprint. + :ivar team_log.Certificate.common_name: Certificate common name. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_subject_value', + '_subject_present', + '_issuer_value', + '_issuer_present', + '_issue_date_value', + '_issue_date_present', + '_expiration_date_value', + '_expiration_date_present', + '_serial_number_value', + '_serial_number_present', + '_sha1_fingerprint_value', + '_sha1_fingerprint_present', + '_common_name_value', + '_common_name_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + subject=None, + issuer=None, + issue_date=None, + expiration_date=None, + serial_number=None, + sha1_fingerprint=None, + common_name=None): + self._subject_value = None + self._subject_present = False + self._issuer_value = None + self._issuer_present = False + self._issue_date_value = None + self._issue_date_present = False + self._expiration_date_value = None + self._expiration_date_present = False + self._serial_number_value = None + self._serial_number_present = False + self._sha1_fingerprint_value = None + self._sha1_fingerprint_present = False + self._common_name_value = None + self._common_name_present = False + if subject is not None: + self.subject = subject + if issuer is not None: + self.issuer = issuer + if issue_date is not None: + self.issue_date = issue_date + if expiration_date is not None: + self.expiration_date = expiration_date + if serial_number is not None: + self.serial_number = serial_number + if sha1_fingerprint is not None: + self.sha1_fingerprint = sha1_fingerprint + if common_name is not None: + self.common_name = common_name @property - def new_value(self): + def subject(self): """ - New mobile device approvals policy. Might be missing due to historical - data gap. + Certificate subject. - :rtype: DeviceApprovalsPolicy + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._subject_present: + return self._subject_value else: - return None + raise AttributeError("missing required field 'subject'") - @new_value.setter - def new_value(self, val): - if val is None: - del self.new_value - return - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @subject.setter + def subject(self, val): + val = self._subject_validator.validate(val) + self._subject_value = val + self._subject_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @subject.deleter + def subject(self): + self._subject_value = None + self._subject_present = False @property - def previous_value(self): + def issuer(self): """ - Previous mobile device approvals policy. Might be missing due to - historical data gap. + Certificate issuer. - :rtype: DeviceApprovalsPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._issuer_present: + return self._issuer_value else: - return None + raise AttributeError("missing required field 'issuer'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @issuer.setter + def issuer(self, val): + val = self._issuer_validator.validate(val) + self._issuer_value = val + self._issuer_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @issuer.deleter + def issuer(self): + self._issuer_value = None + self._issuer_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeMobilePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def issue_date(self): + """ + Certificate issue date. - def __repr__(self): - return 'DeviceApprovalsChangeMobilePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, - ) + :rtype: str + """ + if self._issue_date_present: + return self._issue_date_value + else: + raise AttributeError("missing required field 'issue_date'") -DeviceApprovalsChangeMobilePolicyDetails_validator = bv.Struct(DeviceApprovalsChangeMobilePolicyDetails) + @issue_date.setter + def issue_date(self, val): + val = self._issue_date_validator.validate(val) + self._issue_date_value = val + self._issue_date_present = True -class DeviceApprovalsChangeMobilePolicyType(bb.Struct): + @issue_date.deleter + def issue_date(self): + self._issue_date_value = None + self._issue_date_present = False - __slots__ = [ - '_description_value', - '_description_present', - ] + @property + def expiration_date(self): + """ + Certificate expiration date. - _has_required_fields = True + :rtype: str + """ + if self._expiration_date_present: + return self._expiration_date_value + else: + raise AttributeError("missing required field 'expiration_date'") - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @expiration_date.setter + def expiration_date(self, val): + val = self._expiration_date_validator.validate(val) + self._expiration_date_value = val + self._expiration_date_present = True + + @expiration_date.deleter + def expiration_date(self): + self._expiration_date_value = None + self._expiration_date_present = False @property - def description(self): + def serial_number(self): """ + Certificate serial number. + :rtype: str """ - if self._description_present: - return self._description_value + if self._serial_number_present: + return self._serial_number_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'serial_number'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @serial_number.setter + def serial_number(self, val): + val = self._serial_number_validator.validate(val) + self._serial_number_value = val + self._serial_number_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @serial_number.deleter + def serial_number(self): + self._serial_number_value = None + self._serial_number_present = False + + @property + def sha1_fingerprint(self): + """ + Certificate sha1 fingerprint. + + :rtype: str + """ + if self._sha1_fingerprint_present: + return self._sha1_fingerprint_value + else: + raise AttributeError("missing required field 'sha1_fingerprint'") + + @sha1_fingerprint.setter + def sha1_fingerprint(self, val): + val = self._sha1_fingerprint_validator.validate(val) + self._sha1_fingerprint_value = val + self._sha1_fingerprint_present = True + + @sha1_fingerprint.deleter + def sha1_fingerprint(self): + self._sha1_fingerprint_value = None + self._sha1_fingerprint_present = False + + @property + def common_name(self): + """ + Certificate common name. + + :rtype: str + """ + if self._common_name_present: + return self._common_name_value + else: + return None + + @common_name.setter + def common_name(self, val): + if val is None: + del self.common_name + return + val = self._common_name_validator.validate(val) + self._common_name_value = val + self._common_name_present = True + + @common_name.deleter + def common_name(self): + self._common_name_value = None + self._common_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeMobilePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(Certificate, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceApprovalsChangeMobilePolicyType(description={!r})'.format( - self._description_value, + return 'Certificate(subject={!r}, issuer={!r}, issue_date={!r}, expiration_date={!r}, serial_number={!r}, sha1_fingerprint={!r}, common_name={!r})'.format( + self._subject_value, + self._issuer_value, + self._issue_date_value, + self._expiration_date_value, + self._serial_number_value, + self._sha1_fingerprint_value, + self._common_name_value, ) -DeviceApprovalsChangeMobilePolicyType_validator = bv.Struct(DeviceApprovalsChangeMobilePolicyType) +Certificate_validator = bv.Struct(Certificate) -class DeviceApprovalsChangeOverageActionDetails(bb.Struct): +class ChangedEnterpriseAdminRoleDetails(bb.Struct): """ - Changed device approvals setting when member is over limit. + Changed enterprise admin role. - :ivar team_log.DeviceApprovalsChangeOverageActionDetails.new_value: New over - the limits policy. Might be missing due to historical data gap. - :ivar team_log.DeviceApprovalsChangeOverageActionDetails.previous_value: - Previous over the limit policy. Might be missing due to historical data - gap. + :ivar team_log.ChangedEnterpriseAdminRoleDetails.previous_value: The + member’s previous enterprise admin role. + :ivar team_log.ChangedEnterpriseAdminRoleDetails.new_value: The + member’s new enterprise admin role. + :ivar team_log.ChangedEnterpriseAdminRoleDetails.team_name: The name of the + member’s team. """ __slots__ = [ - '_new_value_value', - '_new_value_present', '_previous_value_value', '_previous_value_present', + '_new_value_value', + '_new_value_present', + '_team_name_value', + '_team_name_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, + previous_value=None, new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False + team_name=None): self._previous_value_value = None self._previous_value_present = False - if new_value is not None: - self.new_value = new_value + self._new_value_value = None + self._new_value_present = False + self._team_name_value = None + self._team_name_present = False if previous_value is not None: self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value + if team_name is not None: + self.team_name = team_name + + @property + def previous_value(self): + """ + The member’s previous enterprise admin role. + + :rtype: FedAdminRole + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property def new_value(self): """ - New over the limits policy. Might be missing due to historical data gap. + The member’s new enterprise admin role. - :rtype: team_policies.RolloutMethod + :rtype: FedAdminRole """ if self._new_value_present: return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") @new_value.setter def new_value(self, val): - if val is None: - del self.new_value - return self._new_value_validator.validate_type_only(val) self._new_value_value = val self._new_value_present = True @@ -3991,44 +4406,41 @@ def new_value(self): self._new_value_present = False @property - def previous_value(self): + def team_name(self): """ - Previous over the limit policy. Might be missing due to historical data - gap. + The name of the member’s team. - :rtype: team_policies.RolloutMethod + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._team_name_present: + return self._team_name_value else: - return None + raise AttributeError("missing required field 'team_name'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @team_name.setter + def team_name(self, val): + val = self._team_name_validator.validate(val) + self._team_name_value = val + self._team_name_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @team_name.deleter + def team_name(self): + self._team_name_value = None + self._team_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeOverageActionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ChangedEnterpriseAdminRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceApprovalsChangeOverageActionDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, + return 'ChangedEnterpriseAdminRoleDetails(previous_value={!r}, new_value={!r}, team_name={!r})'.format( self._previous_value_value, + self._new_value_value, + self._team_name_value, ) -DeviceApprovalsChangeOverageActionDetails_validator = bv.Struct(DeviceApprovalsChangeOverageActionDetails) +ChangedEnterpriseAdminRoleDetails_validator = bv.Struct(ChangedEnterpriseAdminRoleDetails) -class DeviceApprovalsChangeOverageActionType(bb.Struct): +class ChangedEnterpriseAdminRoleType(bb.Struct): __slots__ = [ '_description_value', @@ -4066,91 +4478,124 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeOverageActionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ChangedEnterpriseAdminRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceApprovalsChangeOverageActionType(description={!r})'.format( + return 'ChangedEnterpriseAdminRoleType(description={!r})'.format( self._description_value, ) -DeviceApprovalsChangeOverageActionType_validator = bv.Struct(DeviceApprovalsChangeOverageActionType) +ChangedEnterpriseAdminRoleType_validator = bv.Struct(ChangedEnterpriseAdminRoleType) -class DeviceApprovalsChangeUnlinkActionDetails(bb.Struct): +class ChangedEnterpriseConnectedTeamStatusDetails(bb.Struct): """ - Changed device approvals setting when member unlinks approved device. + Changed enterprise-connected team status. - :ivar team_log.DeviceApprovalsChangeUnlinkActionDetails.new_value: New - device unlink policy. Might be missing due to historical data gap. - :ivar team_log.DeviceApprovalsChangeUnlinkActionDetails.previous_value: - Previous device unlink policy. Might be missing due to historical data - gap. + :ivar team_log.ChangedEnterpriseConnectedTeamStatusDetails.action: The + preformed change in the team’s connection status. + :ivar team_log.ChangedEnterpriseConnectedTeamStatusDetails.additional_info: + Additional information about the organization or team. + :ivar team_log.ChangedEnterpriseConnectedTeamStatusDetails.previous_value: + Previous request state. + :ivar team_log.ChangedEnterpriseConnectedTeamStatusDetails.new_value: New + request state. """ __slots__ = [ - '_new_value_value', - '_new_value_present', + '_action_value', + '_action_present', + '_additional_info_value', + '_additional_info_present', '_previous_value_value', '_previous_value_present', + '_new_value_value', + '_new_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False + action=None, + additional_info=None, + previous_value=None, + new_value=None): + self._action_value = None + self._action_present = False + self._additional_info_value = None + self._additional_info_present = False self._previous_value_value = None self._previous_value_present = False - if new_value is not None: - self.new_value = new_value + self._new_value_value = None + self._new_value_present = False + if action is not None: + self.action = action + if additional_info is not None: + self.additional_info = additional_info if previous_value is not None: self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def new_value(self): + def action(self): """ - New device unlink policy. Might be missing due to historical data gap. + The preformed change in the team’s connection status. - :rtype: DeviceUnlinkPolicy + :rtype: FedHandshakeAction """ - if self._new_value_present: - return self._new_value_value + if self._action_present: + return self._action_value else: - return None + raise AttributeError("missing required field 'action'") - @new_value.setter - def new_value(self, val): - if val is None: - del self.new_value - return - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @action.setter + def action(self, val): + self._action_validator.validate_type_only(val) + self._action_value = val + self._action_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @action.deleter + def action(self): + self._action_value = None + self._action_present = False + + @property + def additional_info(self): + """ + Additional information about the organization or team. + + :rtype: FederationStatusChangeAdditionalInfo + """ + if self._additional_info_present: + return self._additional_info_value + else: + raise AttributeError("missing required field 'additional_info'") + + @additional_info.setter + def additional_info(self, val): + self._additional_info_validator.validate_type_only(val) + self._additional_info_value = val + self._additional_info_present = True + + @additional_info.deleter + def additional_info(self): + self._additional_info_value = None + self._additional_info_present = False @property def previous_value(self): """ - Previous device unlink policy. Might be missing due to historical data - gap. + Previous request state. - :rtype: DeviceUnlinkPolicy + :rtype: TrustedTeamsRequestState """ if self._previous_value_present: return self._previous_value_value else: - return None + raise AttributeError("missing required field 'previous_value'") @previous_value.setter def previous_value(self, val): - if val is None: - del self.previous_value - return self._previous_value_validator.validate_type_only(val) self._previous_value_value = val self._previous_value_present = True @@ -4160,18 +4605,43 @@ def previous_value(self): self._previous_value_value = None self._previous_value_present = False + @property + def new_value(self): + """ + New request state. + + :rtype: TrustedTeamsRequestState + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeUnlinkActionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ChangedEnterpriseConnectedTeamStatusDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceApprovalsChangeUnlinkActionDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, + return 'ChangedEnterpriseConnectedTeamStatusDetails(action={!r}, additional_info={!r}, previous_value={!r}, new_value={!r})'.format( + self._action_value, + self._additional_info_value, self._previous_value_value, + self._new_value_value, ) -DeviceApprovalsChangeUnlinkActionDetails_validator = bv.Struct(DeviceApprovalsChangeUnlinkActionDetails) +ChangedEnterpriseConnectedTeamStatusDetails_validator = bv.Struct(ChangedEnterpriseConnectedTeamStatusDetails) -class DeviceApprovalsChangeUnlinkActionType(bb.Struct): +class ChangedEnterpriseConnectedTeamStatusType(bb.Struct): __slots__ = [ '_description_value', @@ -4209,118 +4679,70 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsChangeUnlinkActionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ChangedEnterpriseConnectedTeamStatusType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceApprovalsChangeUnlinkActionType(description={!r})'.format( + return 'ChangedEnterpriseConnectedTeamStatusType(description={!r})'.format( self._description_value, ) -DeviceApprovalsChangeUnlinkActionType_validator = bv.Struct(DeviceApprovalsChangeUnlinkActionType) +ChangedEnterpriseConnectedTeamStatusType_validator = bv.Struct(ChangedEnterpriseConnectedTeamStatusType) -class DeviceApprovalsPolicy(bb.Union): +class CollectionShareDetails(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Shared album. + + :ivar team_log.CollectionShareDetails.album_name: Album name. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - unlimited = None - # Attribute is overwritten below the class definition - limited = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_album_name_value', + '_album_name_present', + ] - def is_unlimited(self): - """ - Check if the union tag is ``unlimited``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'unlimited' + def __init__(self, + album_name=None): + self._album_name_value = None + self._album_name_present = False + if album_name is not None: + self.album_name = album_name - def is_limited(self): + @property + def album_name(self): """ - Check if the union tag is ``limited``. + Album name. - :rtype: bool + :rtype: str """ - return self._tag == 'limited' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceApprovalsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DeviceApprovalsPolicy(%r, %r)' % (self._tag, self._value) - -DeviceApprovalsPolicy_validator = bv.Union(DeviceApprovalsPolicy) - -class DeviceChangeIpDesktopDetails(bb.Struct): - """ - Changed IP address associated with active desktop session. - - :ivar team_log.DeviceChangeIpDesktopDetails.device_session_info: Device's - session logged information. - """ - - __slots__ = [ - '_device_session_info_value', - '_device_session_info_present', - ] - - _has_required_fields = True - - def __init__(self, - device_session_info=None): - self._device_session_info_value = None - self._device_session_info_present = False - if device_session_info is not None: - self.device_session_info = device_session_info - - @property - def device_session_info(self): - """ - Device's session logged information. - - :rtype: DeviceSessionLogInfo - """ - if self._device_session_info_present: - return self._device_session_info_value + if self._album_name_present: + return self._album_name_value else: - raise AttributeError("missing required field 'device_session_info'") + raise AttributeError("missing required field 'album_name'") - @device_session_info.setter - def device_session_info(self, val): - self._device_session_info_validator.validate_type_only(val) - self._device_session_info_value = val - self._device_session_info_present = True + @album_name.setter + def album_name(self, val): + val = self._album_name_validator.validate(val) + self._album_name_value = val + self._album_name_present = True - @device_session_info.deleter - def device_session_info(self): - self._device_session_info_value = None - self._device_session_info_present = False + @album_name.deleter + def album_name(self): + self._album_name_value = None + self._album_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceChangeIpDesktopDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CollectionShareDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceChangeIpDesktopDetails(device_session_info={!r})'.format( - self._device_session_info_value, + return 'CollectionShareDetails(album_name={!r})'.format( + self._album_name_value, ) -DeviceChangeIpDesktopDetails_validator = bv.Struct(DeviceChangeIpDesktopDetails) +CollectionShareDetails_validator = bv.Struct(CollectionShareDetails) -class DeviceChangeIpDesktopType(bb.Struct): +class CollectionShareType(bb.Struct): __slots__ = [ '_description_value', @@ -4358,74 +4780,324 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceChangeIpDesktopType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CollectionShareType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceChangeIpDesktopType(description={!r})'.format( + return 'CollectionShareType(description={!r})'.format( self._description_value, ) -DeviceChangeIpDesktopType_validator = bv.Struct(DeviceChangeIpDesktopType) +CollectionShareType_validator = bv.Struct(CollectionShareType) -class DeviceChangeIpMobileDetails(bb.Struct): +class ConnectedTeamName(bb.Struct): """ - Changed IP address associated with active mobile session. + The name of the team - :ivar team_log.DeviceChangeIpMobileDetails.device_session_info: Device's - session logged information. + :ivar team_log.ConnectedTeamName.team: The name of the team. """ __slots__ = [ - '_device_session_info_value', - '_device_session_info_present', + '_team_value', + '_team_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - device_session_info=None): - self._device_session_info_value = None - self._device_session_info_present = False - if device_session_info is not None: - self.device_session_info = device_session_info + team=None): + self._team_value = None + self._team_present = False + if team is not None: + self.team = team @property - def device_session_info(self): + def team(self): """ - Device's session logged information. + The name of the team. - :rtype: DeviceSessionLogInfo + :rtype: str """ - if self._device_session_info_present: - return self._device_session_info_value + if self._team_present: + return self._team_value else: - return None + raise AttributeError("missing required field 'team'") - @device_session_info.setter - def device_session_info(self, val): - if val is None: - del self.device_session_info - return - self._device_session_info_validator.validate_type_only(val) - self._device_session_info_value = val - self._device_session_info_present = True + @team.setter + def team(self, val): + val = self._team_validator.validate(val) + self._team_value = val + self._team_present = True - @device_session_info.deleter - def device_session_info(self): - self._device_session_info_value = None - self._device_session_info_present = False + @team.deleter + def team(self): + self._team_value = None + self._team_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceChangeIpMobileDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ConnectedTeamName, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceChangeIpMobileDetails(device_session_info={!r})'.format( - self._device_session_info_value, + return 'ConnectedTeamName(team={!r})'.format( + self._team_value, ) -DeviceChangeIpMobileDetails_validator = bv.Struct(DeviceChangeIpMobileDetails) +ConnectedTeamName_validator = bv.Struct(ConnectedTeamName) -class DeviceChangeIpMobileType(bb.Struct): +class ContentPermanentDeletePolicy(bb.Union): + """ + Policy for pemanent content deletion + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ContentPermanentDeletePolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ContentPermanentDeletePolicy(%r, %r)' % (self._tag, self._value) + +ContentPermanentDeletePolicy_validator = bv.Union(ContentPermanentDeletePolicy) + +class ContextLogInfo(bb.Union): + """ + The primary entity on which the action was done. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar TeamMemberLogInfo ContextLogInfo.team_member: Action was done on + behalf of a team member. + :ivar NonTeamMemberLogInfo ContextLogInfo.non_team_member: Action was done + on behalf of a non team member. + :ivar team_log.ContextLogInfo.anonymous: Anonymous context. + :ivar team_log.ContextLogInfo.team: Action was done on behalf of the team. + :ivar TeamLogInfo ContextLogInfo.organization_team: Action was done on + behalf of a team that's part of an organization. + :ivar TrustedNonTeamMemberLogInfo ContextLogInfo.trusted_non_team_member: + Action was done on behalf of a trusted non team member. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + anonymous = None + # Attribute is overwritten below the class definition + team = None + # Attribute is overwritten below the class definition + other = None + + @classmethod + def team_member(cls, val): + """ + Create an instance of this class set to the ``team_member`` tag with + value ``val``. + + :param TeamMemberLogInfo val: + :rtype: ContextLogInfo + """ + return cls('team_member', val) + + @classmethod + def non_team_member(cls, val): + """ + Create an instance of this class set to the ``non_team_member`` tag with + value ``val``. + + :param NonTeamMemberLogInfo val: + :rtype: ContextLogInfo + """ + return cls('non_team_member', val) + + @classmethod + def organization_team(cls, val): + """ + Create an instance of this class set to the ``organization_team`` tag + with value ``val``. + + :param TeamLogInfo val: + :rtype: ContextLogInfo + """ + return cls('organization_team', val) + + @classmethod + def trusted_non_team_member(cls, val): + """ + Create an instance of this class set to the ``trusted_non_team_member`` + tag with value ``val``. + + :param TrustedNonTeamMemberLogInfo val: + :rtype: ContextLogInfo + """ + return cls('trusted_non_team_member', val) + + def is_team_member(self): + """ + Check if the union tag is ``team_member``. + + :rtype: bool + """ + return self._tag == 'team_member' + + def is_non_team_member(self): + """ + Check if the union tag is ``non_team_member``. + + :rtype: bool + """ + return self._tag == 'non_team_member' + + def is_anonymous(self): + """ + Check if the union tag is ``anonymous``. + + :rtype: bool + """ + return self._tag == 'anonymous' + + def is_team(self): + """ + Check if the union tag is ``team``. + + :rtype: bool + """ + return self._tag == 'team' + + def is_organization_team(self): + """ + Check if the union tag is ``organization_team``. + + :rtype: bool + """ + return self._tag == 'organization_team' + + def is_trusted_non_team_member(self): + """ + Check if the union tag is ``trusted_non_team_member``. + + :rtype: bool + """ + return self._tag == 'trusted_non_team_member' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_team_member(self): + """ + Action was done on behalf of a team member. + + Only call this if :meth:`is_team_member` is true. + + :rtype: TeamMemberLogInfo + """ + if not self.is_team_member(): + raise AttributeError("tag 'team_member' not set") + return self._value + + def get_non_team_member(self): + """ + Action was done on behalf of a non team member. + + Only call this if :meth:`is_non_team_member` is true. + + :rtype: NonTeamMemberLogInfo + """ + if not self.is_non_team_member(): + raise AttributeError("tag 'non_team_member' not set") + return self._value + + def get_organization_team(self): + """ + Action was done on behalf of a team that's part of an organization. + + Only call this if :meth:`is_organization_team` is true. + + :rtype: TeamLogInfo + """ + if not self.is_organization_team(): + raise AttributeError("tag 'organization_team' not set") + return self._value + + def get_trusted_non_team_member(self): + """ + Action was done on behalf of a trusted non team member. + + Only call this if :meth:`is_trusted_non_team_member` is true. + + :rtype: TrustedNonTeamMemberLogInfo + """ + if not self.is_trusted_non_team_member(): + raise AttributeError("tag 'trusted_non_team_member' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ContextLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ContextLogInfo(%r, %r)' % (self._tag, self._value) + +ContextLogInfo_validator = bv.Union(ContextLogInfo) + +class CreateFolderDetails(bb.Struct): + """ + Created folders. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(CreateFolderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'CreateFolderDetails()' + +CreateFolderDetails_validator = bv.Struct(CreateFolderDetails) + +class CreateFolderType(bb.Struct): __slots__ = [ '_description_value', @@ -4463,70 +5135,104 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceChangeIpMobileType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CreateFolderType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceChangeIpMobileType(description={!r})'.format( + return 'CreateFolderType(description={!r})'.format( self._description_value, ) -DeviceChangeIpMobileType_validator = bv.Struct(DeviceChangeIpMobileType) +CreateFolderType_validator = bv.Struct(CreateFolderType) -class DeviceChangeIpWebDetails(bb.Struct): +class CreateTeamInviteLinkDetails(bb.Struct): """ - Changed IP address associated with active web session. + Created team invite link. - :ivar team_log.DeviceChangeIpWebDetails.user_agent: Web browser name. + :ivar team_log.CreateTeamInviteLinkDetails.link_url: The invite link url + that was created. + :ivar team_log.CreateTeamInviteLinkDetails.expiry_date: The expiration date + of the invite link. """ __slots__ = [ - '_user_agent_value', - '_user_agent_present', + '_link_url_value', + '_link_url_present', + '_expiry_date_value', + '_expiry_date_present', ] _has_required_fields = True def __init__(self, - user_agent=None): - self._user_agent_value = None - self._user_agent_present = False - if user_agent is not None: - self.user_agent = user_agent + link_url=None, + expiry_date=None): + self._link_url_value = None + self._link_url_present = False + self._expiry_date_value = None + self._expiry_date_present = False + if link_url is not None: + self.link_url = link_url + if expiry_date is not None: + self.expiry_date = expiry_date @property - def user_agent(self): + def link_url(self): """ - Web browser name. + The invite link url that was created. :rtype: str """ - if self._user_agent_present: - return self._user_agent_value + if self._link_url_present: + return self._link_url_value else: - raise AttributeError("missing required field 'user_agent'") + raise AttributeError("missing required field 'link_url'") - @user_agent.setter - def user_agent(self, val): - val = self._user_agent_validator.validate(val) - self._user_agent_value = val - self._user_agent_present = True + @link_url.setter + def link_url(self, val): + val = self._link_url_validator.validate(val) + self._link_url_value = val + self._link_url_present = True - @user_agent.deleter - def user_agent(self): - self._user_agent_value = None - self._user_agent_present = False + @link_url.deleter + def link_url(self): + self._link_url_value = None + self._link_url_present = False + + @property + def expiry_date(self): + """ + The expiration date of the invite link. + + :rtype: str + """ + if self._expiry_date_present: + return self._expiry_date_value + else: + raise AttributeError("missing required field 'expiry_date'") + + @expiry_date.setter + def expiry_date(self, val): + val = self._expiry_date_validator.validate(val) + self._expiry_date_value = val + self._expiry_date_present = True + + @expiry_date.deleter + def expiry_date(self): + self._expiry_date_value = None + self._expiry_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceChangeIpWebDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CreateTeamInviteLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceChangeIpWebDetails(user_agent={!r})'.format( - self._user_agent_value, + return 'CreateTeamInviteLinkDetails(link_url={!r}, expiry_date={!r})'.format( + self._link_url_value, + self._expiry_date_value, ) -DeviceChangeIpWebDetails_validator = bv.Struct(DeviceChangeIpWebDetails) +CreateTeamInviteLinkDetails_validator = bv.Struct(CreateTeamInviteLinkDetails) -class DeviceChangeIpWebType(bb.Struct): +class CreateTeamInviteLinkType(bb.Struct): __slots__ = [ '_description_value', @@ -4564,143 +5270,104 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceChangeIpWebType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(CreateTeamInviteLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceChangeIpWebType(description={!r})'.format( + return 'CreateTeamInviteLinkType(description={!r})'.format( self._description_value, ) -DeviceChangeIpWebType_validator = bv.Struct(DeviceChangeIpWebType) +CreateTeamInviteLinkType_validator = bv.Struct(CreateTeamInviteLinkType) -class DeviceDeleteOnUnlinkFailDetails(bb.Struct): +class DataPlacementRestrictionChangePolicyDetails(bb.Struct): """ - Failed to delete all files from unlinked device. + Set restrictions on data center locations where team data resides. - :ivar team_log.DeviceDeleteOnUnlinkFailDetails.session_info: Session unique - id. Might be missing due to historical data gap. - :ivar team_log.DeviceDeleteOnUnlinkFailDetails.display_name: The device - name. Might be missing due to historical data gap. - :ivar team_log.DeviceDeleteOnUnlinkFailDetails.num_failures: The number of - times that remote file deletion failed. + :ivar team_log.DataPlacementRestrictionChangePolicyDetails.previous_value: + Previous placement restriction. + :ivar team_log.DataPlacementRestrictionChangePolicyDetails.new_value: New + placement restriction. """ __slots__ = [ - '_session_info_value', - '_session_info_present', - '_display_name_value', - '_display_name_present', - '_num_failures_value', - '_num_failures_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', ] _has_required_fields = True def __init__(self, - num_failures=None, - session_info=None, - display_name=None): - self._session_info_value = None - self._session_info_present = False - self._display_name_value = None - self._display_name_present = False - self._num_failures_value = None - self._num_failures_present = False - if session_info is not None: - self.session_info = session_info - if display_name is not None: - self.display_name = display_name - if num_failures is not None: - self.num_failures = num_failures + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def session_info(self): + def previous_value(self): """ - Session unique id. Might be missing due to historical data gap. + Previous placement restriction. - :rtype: SessionLogInfo + :rtype: PlacementRestriction """ - if self._session_info_present: - return self._session_info_value + if self._previous_value_present: + return self._previous_value_value else: - return None - - @session_info.setter - def session_info(self, val): - if val is None: - del self.session_info - return - self._session_info_validator.validate_type_only(val) - self._session_info_value = val - self._session_info_present = True + raise AttributeError("missing required field 'previous_value'") - @session_info.deleter - def session_info(self): - self._session_info_value = None - self._session_info_present = False + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @property - def display_name(self): - """ - The device name. Might be missing due to historical data gap. - - :rtype: str - """ - if self._display_name_present: - return self._display_name_value - else: - return None - - @display_name.setter - def display_name(self, val): - if val is None: - del self.display_name - return - val = self._display_name_validator.validate(val) - self._display_name_value = val - self._display_name_present = True - - @display_name.deleter - def display_name(self): - self._display_name_value = None - self._display_name_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property - def num_failures(self): + def new_value(self): """ - The number of times that remote file deletion failed. + New placement restriction. - :rtype: int + :rtype: PlacementRestriction """ - if self._num_failures_present: - return self._num_failures_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'num_failures'") + raise AttributeError("missing required field 'new_value'") - @num_failures.setter - def num_failures(self, val): - val = self._num_failures_validator.validate(val) - self._num_failures_value = val - self._num_failures_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @num_failures.deleter - def num_failures(self): - self._num_failures_value = None - self._num_failures_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceDeleteOnUnlinkFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DataPlacementRestrictionChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceDeleteOnUnlinkFailDetails(num_failures={!r}, session_info={!r}, display_name={!r})'.format( - self._num_failures_value, - self._session_info_value, - self._display_name_value, + return 'DataPlacementRestrictionChangePolicyDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, ) -DeviceDeleteOnUnlinkFailDetails_validator = bv.Struct(DeviceDeleteOnUnlinkFailDetails) +DataPlacementRestrictionChangePolicyDetails_validator = bv.Struct(DataPlacementRestrictionChangePolicyDetails) -class DeviceDeleteOnUnlinkFailType(bb.Struct): +class DataPlacementRestrictionChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -4738,110 +5405,72 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceDeleteOnUnlinkFailType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DataPlacementRestrictionChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceDeleteOnUnlinkFailType(description={!r})'.format( + return 'DataPlacementRestrictionChangePolicyType(description={!r})'.format( self._description_value, ) -DeviceDeleteOnUnlinkFailType_validator = bv.Struct(DeviceDeleteOnUnlinkFailType) +DataPlacementRestrictionChangePolicyType_validator = bv.Struct(DataPlacementRestrictionChangePolicyType) -class DeviceDeleteOnUnlinkSuccessDetails(bb.Struct): +class DataPlacementRestrictionSatisfyPolicyDetails(bb.Struct): """ - Deleted all files from unlinked device. + Completed restrictions on data center locations where team data resides. - :ivar team_log.DeviceDeleteOnUnlinkSuccessDetails.session_info: Session - unique id. Might be missing due to historical data gap. - :ivar team_log.DeviceDeleteOnUnlinkSuccessDetails.display_name: The device - name. Might be missing due to historical data gap. + :ivar + team_log.DataPlacementRestrictionSatisfyPolicyDetails.placement_restriction: + Placement restriction. """ __slots__ = [ - '_session_info_value', - '_session_info_present', - '_display_name_value', - '_display_name_present', + '_placement_restriction_value', + '_placement_restriction_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - session_info=None, - display_name=None): - self._session_info_value = None - self._session_info_present = False - self._display_name_value = None - self._display_name_present = False - if session_info is not None: - self.session_info = session_info - if display_name is not None: - self.display_name = display_name - - @property - def session_info(self): - """ - Session unique id. Might be missing due to historical data gap. - - :rtype: SessionLogInfo - """ - if self._session_info_present: - return self._session_info_value - else: - return None - - @session_info.setter - def session_info(self, val): - if val is None: - del self.session_info - return - self._session_info_validator.validate_type_only(val) - self._session_info_value = val - self._session_info_present = True - - @session_info.deleter - def session_info(self): - self._session_info_value = None - self._session_info_present = False + placement_restriction=None): + self._placement_restriction_value = None + self._placement_restriction_present = False + if placement_restriction is not None: + self.placement_restriction = placement_restriction @property - def display_name(self): + def placement_restriction(self): """ - The device name. Might be missing due to historical data gap. + Placement restriction. - :rtype: str + :rtype: PlacementRestriction """ - if self._display_name_present: - return self._display_name_value + if self._placement_restriction_present: + return self._placement_restriction_value else: - return None + raise AttributeError("missing required field 'placement_restriction'") - @display_name.setter - def display_name(self, val): - if val is None: - del self.display_name - return - val = self._display_name_validator.validate(val) - self._display_name_value = val - self._display_name_present = True + @placement_restriction.setter + def placement_restriction(self, val): + self._placement_restriction_validator.validate_type_only(val) + self._placement_restriction_value = val + self._placement_restriction_present = True - @display_name.deleter - def display_name(self): - self._display_name_value = None - self._display_name_present = False + @placement_restriction.deleter + def placement_restriction(self): + self._placement_restriction_value = None + self._placement_restriction_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceDeleteOnUnlinkSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DataPlacementRestrictionSatisfyPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceDeleteOnUnlinkSuccessDetails(session_info={!r}, display_name={!r})'.format( - self._session_info_value, - self._display_name_value, + return 'DataPlacementRestrictionSatisfyPolicyDetails(placement_restriction={!r})'.format( + self._placement_restriction_value, ) -DeviceDeleteOnUnlinkSuccessDetails_validator = bv.Struct(DeviceDeleteOnUnlinkSuccessDetails) +DataPlacementRestrictionSatisfyPolicyDetails_validator = bv.Struct(DataPlacementRestrictionSatisfyPolicyDetails) -class DeviceDeleteOnUnlinkSuccessType(bb.Struct): +class DataPlacementRestrictionSatisfyPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -4879,107 +5508,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceDeleteOnUnlinkSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DataPlacementRestrictionSatisfyPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceDeleteOnUnlinkSuccessType(description={!r})'.format( + return 'DataPlacementRestrictionSatisfyPolicyType(description={!r})'.format( self._description_value, ) -DeviceDeleteOnUnlinkSuccessType_validator = bv.Struct(DeviceDeleteOnUnlinkSuccessType) +DataPlacementRestrictionSatisfyPolicyType_validator = bv.Struct(DataPlacementRestrictionSatisfyPolicyType) -class DeviceLinkFailDetails(bb.Struct): +class DeleteTeamInviteLinkDetails(bb.Struct): """ - Failed to link device. + Deleted team invite link. - :ivar team_log.DeviceLinkFailDetails.ip_address: IP address. Might be - missing due to historical data gap. - :ivar team_log.DeviceLinkFailDetails.device_type: A description of the - device used while user approval blocked. + :ivar team_log.DeleteTeamInviteLinkDetails.link_url: The invite link url + that was deleted. """ __slots__ = [ - '_ip_address_value', - '_ip_address_present', - '_device_type_value', - '_device_type_present', + '_link_url_value', + '_link_url_present', ] _has_required_fields = True def __init__(self, - device_type=None, - ip_address=None): - self._ip_address_value = None - self._ip_address_present = False - self._device_type_value = None - self._device_type_present = False - if ip_address is not None: - self.ip_address = ip_address - if device_type is not None: - self.device_type = device_type + link_url=None): + self._link_url_value = None + self._link_url_present = False + if link_url is not None: + self.link_url = link_url @property - def ip_address(self): + def link_url(self): """ - IP address. Might be missing due to historical data gap. + The invite link url that was deleted. :rtype: str """ - if self._ip_address_present: - return self._ip_address_value - else: - return None - - @ip_address.setter - def ip_address(self, val): - if val is None: - del self.ip_address - return - val = self._ip_address_validator.validate(val) - self._ip_address_value = val - self._ip_address_present = True - - @ip_address.deleter - def ip_address(self): - self._ip_address_value = None - self._ip_address_present = False - - @property - def device_type(self): - """ - A description of the device used while user approval blocked. - - :rtype: DeviceType - """ - if self._device_type_present: - return self._device_type_value + if self._link_url_present: + return self._link_url_value else: - raise AttributeError("missing required field 'device_type'") + raise AttributeError("missing required field 'link_url'") - @device_type.setter - def device_type(self, val): - self._device_type_validator.validate_type_only(val) - self._device_type_value = val - self._device_type_present = True + @link_url.setter + def link_url(self, val): + val = self._link_url_validator.validate(val) + self._link_url_value = val + self._link_url_present = True - @device_type.deleter - def device_type(self): - self._device_type_value = None - self._device_type_present = False + @link_url.deleter + def link_url(self): + self._link_url_value = None + self._link_url_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceLinkFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeleteTeamInviteLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceLinkFailDetails(device_type={!r}, ip_address={!r})'.format( - self._device_type_value, - self._ip_address_value, + return 'DeleteTeamInviteLinkDetails(link_url={!r})'.format( + self._link_url_value, ) -DeviceLinkFailDetails_validator = bv.Struct(DeviceLinkFailDetails) +DeleteTeamInviteLinkDetails_validator = bv.Struct(DeleteTeamInviteLinkDetails) -class DeviceLinkFailType(bb.Struct): +class DeleteTeamInviteLinkType(bb.Struct): __slots__ = [ '_description_value', @@ -5017,478 +5610,489 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceLinkFailType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeleteTeamInviteLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceLinkFailType(description={!r})'.format( + return 'DeleteTeamInviteLinkType(description={!r})'.format( self._description_value, ) -DeviceLinkFailType_validator = bv.Struct(DeviceLinkFailType) +DeleteTeamInviteLinkType_validator = bv.Struct(DeleteTeamInviteLinkType) -class DeviceLinkSuccessDetails(bb.Struct): +class DeviceSessionLogInfo(bb.Struct): """ - Linked device. + Device's session logged information. - :ivar team_log.DeviceLinkSuccessDetails.device_session_info: Device's - session logged information. + :ivar team_log.DeviceSessionLogInfo.ip_address: The IP address of the last + activity from this session. Might be missing due to historical data gap. + :ivar team_log.DeviceSessionLogInfo.created: The time this session was + created. Might be missing due to historical data gap. + :ivar team_log.DeviceSessionLogInfo.updated: The time of the last activity + from this session. Might be missing due to historical data gap. """ __slots__ = [ - '_device_session_info_value', - '_device_session_info_present', + '_ip_address_value', + '_ip_address_present', + '_created_value', + '_created_present', + '_updated_value', + '_updated_present', ] _has_required_fields = False def __init__(self, - device_session_info=None): - self._device_session_info_value = None - self._device_session_info_present = False - if device_session_info is not None: - self.device_session_info = device_session_info + ip_address=None, + created=None, + updated=None): + self._ip_address_value = None + self._ip_address_present = False + self._created_value = None + self._created_present = False + self._updated_value = None + self._updated_present = False + if ip_address is not None: + self.ip_address = ip_address + if created is not None: + self.created = created + if updated is not None: + self.updated = updated @property - def device_session_info(self): + def ip_address(self): """ - Device's session logged information. + The IP address of the last activity from this session. Might be missing + due to historical data gap. - :rtype: DeviceSessionLogInfo + :rtype: str """ - if self._device_session_info_present: - return self._device_session_info_value + if self._ip_address_present: + return self._ip_address_value else: return None - @device_session_info.setter - def device_session_info(self, val): + @ip_address.setter + def ip_address(self, val): if val is None: - del self.device_session_info + del self.ip_address return - self._device_session_info_validator.validate_type_only(val) - self._device_session_info_value = val - self._device_session_info_present = True - - @device_session_info.deleter - def device_session_info(self): - self._device_session_info_value = None - self._device_session_info_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceLinkSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DeviceLinkSuccessDetails(device_session_info={!r})'.format( - self._device_session_info_value, - ) + val = self._ip_address_validator.validate(val) + self._ip_address_value = val + self._ip_address_present = True -DeviceLinkSuccessDetails_validator = bv.Struct(DeviceLinkSuccessDetails) + @ip_address.deleter + def ip_address(self): + self._ip_address_value = None + self._ip_address_present = False -class DeviceLinkSuccessType(bb.Struct): + @property + def created(self): + """ + The time this session was created. Might be missing due to historical + data gap. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: datetime.datetime + """ + if self._created_present: + return self._created_value + else: + return None - _has_required_fields = True + @created.setter + def created(self, val): + if val is None: + del self.created + return + val = self._created_validator.validate(val) + self._created_value = val + self._created_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @created.deleter + def created(self): + self._created_value = None + self._created_present = False @property - def description(self): + def updated(self): """ - :rtype: str + The time of the last activity from this session. Might be missing due to + historical data gap. + + :rtype: datetime.datetime """ - if self._description_present: - return self._description_value + if self._updated_present: + return self._updated_value else: - raise AttributeError("missing required field 'description'") + return None - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @updated.setter + def updated(self, val): + if val is None: + del self.updated + return + val = self._updated_validator.validate(val) + self._updated_value = val + self._updated_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @updated.deleter + def updated(self): + self._updated_value = None + self._updated_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceLinkSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceLinkSuccessType(description={!r})'.format( - self._description_value, + return 'DeviceSessionLogInfo(ip_address={!r}, created={!r}, updated={!r})'.format( + self._ip_address_value, + self._created_value, + self._updated_value, ) -DeviceLinkSuccessType_validator = bv.Struct(DeviceLinkSuccessType) +DeviceSessionLogInfo_validator = bv.StructTree(DeviceSessionLogInfo) -class DeviceManagementDisabledDetails(bb.Struct): - """ - Disabled device management. +class DesktopDeviceSessionLogInfo(DeviceSessionLogInfo): """ + Information about linked Dropbox desktop client sessions - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceManagementDisabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DeviceManagementDisabledDetails()' - -DeviceManagementDisabledDetails_validator = bv.Struct(DeviceManagementDisabledDetails) - -class DeviceManagementDisabledType(bb.Struct): + :ivar team_log.DesktopDeviceSessionLogInfo.session_info: Desktop session + unique id. Might be missing due to historical data gap. + :ivar team_log.DesktopDeviceSessionLogInfo.host_name: Name of the hosting + desktop. + :ivar team_log.DesktopDeviceSessionLogInfo.client_type: The Dropbox desktop + client type. + :ivar team_log.DesktopDeviceSessionLogInfo.client_version: The Dropbox + client version. + :ivar team_log.DesktopDeviceSessionLogInfo.platform: Information on the + hosting platform. + :ivar team_log.DesktopDeviceSessionLogInfo.is_delete_on_unlink_supported: + Whether itu2019s possible to delete all of the account files upon + unlinking. + """ __slots__ = [ - '_description_value', - '_description_present', + '_session_info_value', + '_session_info_present', + '_host_name_value', + '_host_name_present', + '_client_type_value', + '_client_type_present', + '_client_version_value', + '_client_version_present', + '_platform_value', + '_platform_present', + '_is_delete_on_unlink_supported_value', + '_is_delete_on_unlink_supported_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + host_name=None, + client_type=None, + platform=None, + is_delete_on_unlink_supported=None, + ip_address=None, + created=None, + updated=None, + session_info=None, + client_version=None): + super(DesktopDeviceSessionLogInfo, self).__init__(ip_address, + created, + updated) + self._session_info_value = None + self._session_info_present = False + self._host_name_value = None + self._host_name_present = False + self._client_type_value = None + self._client_type_present = False + self._client_version_value = None + self._client_version_present = False + self._platform_value = None + self._platform_present = False + self._is_delete_on_unlink_supported_value = None + self._is_delete_on_unlink_supported_present = False + if session_info is not None: + self.session_info = session_info + if host_name is not None: + self.host_name = host_name + if client_type is not None: + self.client_type = client_type + if client_version is not None: + self.client_version = client_version + if platform is not None: + self.platform = platform + if is_delete_on_unlink_supported is not None: + self.is_delete_on_unlink_supported = is_delete_on_unlink_supported @property - def description(self): - """ - :rtype: str + def session_info(self): """ - if self._description_present: - return self._description_value - else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceManagementDisabledType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DeviceManagementDisabledType(description={!r})'.format( - self._description_value, - ) - -DeviceManagementDisabledType_validator = bv.Struct(DeviceManagementDisabledType) + Desktop session unique id. Might be missing due to historical data gap. -class DeviceManagementEnabledDetails(bb.Struct): - """ - Enabled device management. - """ + :rtype: DesktopSessionLogInfo + """ + if self._session_info_present: + return self._session_info_value + else: + return None - __slots__ = [ - ] + @session_info.setter + def session_info(self, val): + if val is None: + del self.session_info + return + self._session_info_validator.validate_type_only(val) + self._session_info_value = val + self._session_info_present = True - _has_required_fields = False + @session_info.deleter + def session_info(self): + self._session_info_value = None + self._session_info_present = False - def __init__(self): - pass + @property + def host_name(self): + """ + Name of the hosting desktop. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceManagementEnabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: str + """ + if self._host_name_present: + return self._host_name_value + else: + raise AttributeError("missing required field 'host_name'") - def __repr__(self): - return 'DeviceManagementEnabledDetails()' + @host_name.setter + def host_name(self, val): + val = self._host_name_validator.validate(val) + self._host_name_value = val + self._host_name_present = True -DeviceManagementEnabledDetails_validator = bv.Struct(DeviceManagementEnabledDetails) + @host_name.deleter + def host_name(self): + self._host_name_value = None + self._host_name_present = False -class DeviceManagementEnabledType(bb.Struct): + @property + def client_type(self): + """ + The Dropbox desktop client type. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: team.DesktopPlatform + """ + if self._client_type_present: + return self._client_type_value + else: + raise AttributeError("missing required field 'client_type'") - _has_required_fields = True + @client_type.setter + def client_type(self, val): + self._client_type_validator.validate_type_only(val) + self._client_type_value = val + self._client_type_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @client_type.deleter + def client_type(self): + self._client_type_value = None + self._client_type_present = False @property - def description(self): + def client_version(self): """ + The Dropbox client version. + :rtype: str """ - if self._description_present: - return self._description_value + if self._client_version_present: + return self._client_version_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceManagementEnabledType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'DeviceManagementEnabledType(description={!r})'.format( - self._description_value, - ) - -DeviceManagementEnabledType_validator = bv.Struct(DeviceManagementEnabledType) + return None -class DeviceType(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + @client_version.setter + def client_version(self, val): + if val is None: + del self.client_version + return + val = self._client_version_validator.validate(val) + self._client_version_value = val + self._client_version_present = True - _catch_all = 'other' - # Attribute is overwritten below the class definition - desktop = None - # Attribute is overwritten below the class definition - mobile = None - # Attribute is overwritten below the class definition - other = None + @client_version.deleter + def client_version(self): + self._client_version_value = None + self._client_version_present = False - def is_desktop(self): + @property + def platform(self): """ - Check if the union tag is ``desktop``. + Information on the hosting platform. - :rtype: bool + :rtype: str """ - return self._tag == 'desktop' + if self._platform_present: + return self._platform_value + else: + raise AttributeError("missing required field 'platform'") - def is_mobile(self): - """ - Check if the union tag is ``mobile``. + @platform.setter + def platform(self, val): + val = self._platform_validator.validate(val) + self._platform_value = val + self._platform_present = True - :rtype: bool - """ - return self._tag == 'mobile' + @platform.deleter + def platform(self): + self._platform_value = None + self._platform_present = False - def is_other(self): + @property + def is_delete_on_unlink_supported(self): """ - Check if the union tag is ``other``. + Whether itu2019s possible to delete all of the account files upon + unlinking. :rtype: bool """ - return self._tag == 'other' + if self._is_delete_on_unlink_supported_present: + return self._is_delete_on_unlink_supported_value + else: + raise AttributeError("missing required field 'is_delete_on_unlink_supported'") + + @is_delete_on_unlink_supported.setter + def is_delete_on_unlink_supported(self, val): + val = self._is_delete_on_unlink_supported_validator.validate(val) + self._is_delete_on_unlink_supported_value = val + self._is_delete_on_unlink_supported_present = True + + @is_delete_on_unlink_supported.deleter + def is_delete_on_unlink_supported(self): + self._is_delete_on_unlink_supported_value = None + self._is_delete_on_unlink_supported_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DesktopDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceType(%r, %r)' % (self._tag, self._value) + return 'DesktopDeviceSessionLogInfo(host_name={!r}, client_type={!r}, platform={!r}, is_delete_on_unlink_supported={!r}, ip_address={!r}, created={!r}, updated={!r}, session_info={!r}, client_version={!r})'.format( + self._host_name_value, + self._client_type_value, + self._platform_value, + self._is_delete_on_unlink_supported_value, + self._ip_address_value, + self._created_value, + self._updated_value, + self._session_info_value, + self._client_version_value, + ) -DeviceType_validator = bv.Union(DeviceType) +DesktopDeviceSessionLogInfo_validator = bv.Struct(DesktopDeviceSessionLogInfo) -class DeviceUnlinkDetails(bb.Struct): +class SessionLogInfo(bb.Struct): """ - Disconnected device. + Session's logged information. - :ivar team_log.DeviceUnlinkDetails.session_info: Session unique id. - :ivar team_log.DeviceUnlinkDetails.display_name: The device name. Might be - missing due to historical data gap. - :ivar team_log.DeviceUnlinkDetails.delete_data: True if the user requested - to delete data after device unlink, false otherwise. + :ivar team_log.SessionLogInfo.session_id: Session ID. Might be missing due + to historical data gap. """ __slots__ = [ - '_session_info_value', - '_session_info_present', - '_display_name_value', - '_display_name_present', - '_delete_data_value', - '_delete_data_present', + '_session_id_value', + '_session_id_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - delete_data=None, - session_info=None, - display_name=None): - self._session_info_value = None - self._session_info_present = False - self._display_name_value = None - self._display_name_present = False - self._delete_data_value = None - self._delete_data_present = False - if session_info is not None: - self.session_info = session_info - if display_name is not None: - self.display_name = display_name - if delete_data is not None: - self.delete_data = delete_data + session_id=None): + self._session_id_value = None + self._session_id_present = False + if session_id is not None: + self.session_id = session_id @property - def session_info(self): + def session_id(self): """ - Session unique id. + Session ID. Might be missing due to historical data gap. - :rtype: SessionLogInfo + :rtype: str """ - if self._session_info_present: - return self._session_info_value + if self._session_id_present: + return self._session_id_value else: return None - @session_info.setter - def session_info(self, val): + @session_id.setter + def session_id(self, val): if val is None: - del self.session_info + del self.session_id return - self._session_info_validator.validate_type_only(val) - self._session_info_value = val - self._session_info_present = True - - @session_info.deleter - def session_info(self): - self._session_info_value = None - self._session_info_present = False + val = self._session_id_validator.validate(val) + self._session_id_value = val + self._session_id_present = True - @property - def display_name(self): - """ - The device name. Might be missing due to historical data gap. + @session_id.deleter + def session_id(self): + self._session_id_value = None + self._session_id_present = False - :rtype: str - """ - if self._display_name_present: - return self._display_name_value - else: - return None + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - @display_name.setter - def display_name(self, val): - if val is None: - del self.display_name - return - val = self._display_name_validator.validate(val) - self._display_name_value = val - self._display_name_present = True + def __repr__(self): + return 'SessionLogInfo(session_id={!r})'.format( + self._session_id_value, + ) - @display_name.deleter - def display_name(self): - self._display_name_value = None - self._display_name_present = False +SessionLogInfo_validator = bv.StructTree(SessionLogInfo) - @property - def delete_data(self): - """ - True if the user requested to delete data after device unlink, false - otherwise. +class DesktopSessionLogInfo(SessionLogInfo): + """ + Desktop session. + """ - :rtype: bool - """ - if self._delete_data_present: - return self._delete_data_value - else: - raise AttributeError("missing required field 'delete_data'") + __slots__ = [ + ] - @delete_data.setter - def delete_data(self, val): - val = self._delete_data_validator.validate(val) - self._delete_data_value = val - self._delete_data_present = True + _has_required_fields = False - @delete_data.deleter - def delete_data(self): - self._delete_data_value = None - self._delete_data_present = False + def __init__(self, + session_id=None): + super(DesktopSessionLogInfo, self).__init__(session_id) def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceUnlinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DesktopSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceUnlinkDetails(delete_data={!r}, session_info={!r}, display_name={!r})'.format( - self._delete_data_value, - self._session_info_value, - self._display_name_value, + return 'DesktopSessionLogInfo(session_id={!r})'.format( + self._session_id_value, ) -DeviceUnlinkDetails_validator = bv.Struct(DeviceUnlinkDetails) +DesktopSessionLogInfo_validator = bv.Struct(DesktopSessionLogInfo) -class DeviceUnlinkPolicy(bb.Union): +class DeviceApprovalsAddExceptionDetails(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Added members to device approvals exception list. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - remove = None - # Attribute is overwritten below the class definition - keep = None - # Attribute is overwritten below the class definition - other = None - - def is_remove(self): - """ - Check if the union tag is ``remove``. - - :rtype: bool - """ - return self._tag == 'remove' - - def is_keep(self): - """ - Check if the union tag is ``keep``. - - :rtype: bool - """ - return self._tag == 'keep' + __slots__ = [ + ] - def is_other(self): - """ - Check if the union tag is ``other``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'other' + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceUnlinkPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsAddExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceUnlinkPolicy(%r, %r)' % (self._tag, self._value) + return 'DeviceApprovalsAddExceptionDetails()' -DeviceUnlinkPolicy_validator = bv.Union(DeviceUnlinkPolicy) +DeviceApprovalsAddExceptionDetails_validator = bv.Struct(DeviceApprovalsAddExceptionDetails) -class DeviceUnlinkType(bb.Struct): +class DeviceApprovalsAddExceptionType(bb.Struct): __slots__ = [ '_description_value', @@ -5526,37 +6130,115 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DeviceUnlinkType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsAddExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DeviceUnlinkType(description={!r})'.format( + return 'DeviceApprovalsAddExceptionType(description={!r})'.format( self._description_value, ) -DeviceUnlinkType_validator = bv.Struct(DeviceUnlinkType) +DeviceApprovalsAddExceptionType_validator = bv.Struct(DeviceApprovalsAddExceptionType) -class DirectoryRestrictionsAddMembersDetails(bb.Struct): +class DeviceApprovalsChangeDesktopPolicyDetails(bb.Struct): """ - Added members to directory restrictions list. + Set/removed limit on number of computers member can link to team Dropbox + account. + + :ivar team_log.DeviceApprovalsChangeDesktopPolicyDetails.new_value: New + desktop device approvals policy. Might be missing due to historical data + gap. + :ivar team_log.DeviceApprovalsChangeDesktopPolicyDetails.previous_value: + Previous desktop device approvals policy. Might be missing due to + historical data gap. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New desktop device approvals policy. Might be missing due to historical + data gap. + + :rtype: DeviceApprovalsPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + return None + + @new_value.setter + def new_value(self, val): + if val is None: + del self.new_value + return + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous desktop device approvals policy. Might be missing due to + historical data gap. + + :rtype: DeviceApprovalsPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DirectoryRestrictionsAddMembersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeDesktopPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DirectoryRestrictionsAddMembersDetails()' + return 'DeviceApprovalsChangeDesktopPolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -DirectoryRestrictionsAddMembersDetails_validator = bv.Struct(DirectoryRestrictionsAddMembersDetails) +DeviceApprovalsChangeDesktopPolicyDetails_validator = bv.Struct(DeviceApprovalsChangeDesktopPolicyDetails) -class DirectoryRestrictionsAddMembersType(bb.Struct): +class DeviceApprovalsChangeDesktopPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -5594,37 +6276,115 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DirectoryRestrictionsAddMembersType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeDesktopPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DirectoryRestrictionsAddMembersType(description={!r})'.format( + return 'DeviceApprovalsChangeDesktopPolicyType(description={!r})'.format( self._description_value, ) -DirectoryRestrictionsAddMembersType_validator = bv.Struct(DirectoryRestrictionsAddMembersType) +DeviceApprovalsChangeDesktopPolicyType_validator = bv.Struct(DeviceApprovalsChangeDesktopPolicyType) -class DirectoryRestrictionsRemoveMembersDetails(bb.Struct): +class DeviceApprovalsChangeMobilePolicyDetails(bb.Struct): """ - Removed members from directory restrictions list. + Set/removed limit on number of mobile devices member can link to team + Dropbox account. + + :ivar team_log.DeviceApprovalsChangeMobilePolicyDetails.new_value: New + mobile device approvals policy. Might be missing due to historical data + gap. + :ivar team_log.DeviceApprovalsChangeMobilePolicyDetails.previous_value: + Previous mobile device approvals policy. Might be missing due to + historical data gap. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New mobile device approvals policy. Might be missing due to historical + data gap. + + :rtype: DeviceApprovalsPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + return None + + @new_value.setter + def new_value(self, val): + if val is None: + del self.new_value + return + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous mobile device approvals policy. Might be missing due to + historical data gap. + + :rtype: DeviceApprovalsPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DirectoryRestrictionsRemoveMembersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeMobilePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DirectoryRestrictionsRemoveMembersDetails()' + return 'DeviceApprovalsChangeMobilePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -DirectoryRestrictionsRemoveMembersDetails_validator = bv.Struct(DirectoryRestrictionsRemoveMembersDetails) +DeviceApprovalsChangeMobilePolicyDetails_validator = bv.Struct(DeviceApprovalsChangeMobilePolicyDetails) -class DirectoryRestrictionsRemoveMembersType(bb.Struct): +class DeviceApprovalsChangeMobilePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -5662,37 +6422,112 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DirectoryRestrictionsRemoveMembersType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeMobilePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DirectoryRestrictionsRemoveMembersType(description={!r})'.format( + return 'DeviceApprovalsChangeMobilePolicyType(description={!r})'.format( self._description_value, ) -DirectoryRestrictionsRemoveMembersType_validator = bv.Struct(DirectoryRestrictionsRemoveMembersType) +DeviceApprovalsChangeMobilePolicyType_validator = bv.Struct(DeviceApprovalsChangeMobilePolicyType) -class DisabledDomainInvitesDetails(bb.Struct): +class DeviceApprovalsChangeOverageActionDetails(bb.Struct): """ - Disabled domain invites. + Changed device approvals setting when member is over limit. + + :ivar team_log.DeviceApprovalsChangeOverageActionDetails.new_value: New over + the limits policy. Might be missing due to historical data gap. + :ivar team_log.DeviceApprovalsChangeOverageActionDetails.previous_value: + Previous over the limit policy. Might be missing due to historical data + gap. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New over the limits policy. Might be missing due to historical data gap. + + :rtype: team_policies.RolloutMethod + """ + if self._new_value_present: + return self._new_value_value + else: + return None + + @new_value.setter + def new_value(self, val): + if val is None: + del self.new_value + return + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous over the limit policy. Might be missing due to historical data + gap. + + :rtype: team_policies.RolloutMethod + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DisabledDomainInvitesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeOverageActionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DisabledDomainInvitesDetails()' + return 'DeviceApprovalsChangeOverageActionDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -DisabledDomainInvitesDetails_validator = bv.Struct(DisabledDomainInvitesDetails) +DeviceApprovalsChangeOverageActionDetails_validator = bv.Struct(DeviceApprovalsChangeOverageActionDetails) -class DisabledDomainInvitesType(bb.Struct): +class DeviceApprovalsChangeOverageActionType(bb.Struct): __slots__ = [ '_description_value', @@ -5730,37 +6565,112 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DisabledDomainInvitesType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeOverageActionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DisabledDomainInvitesType(description={!r})'.format( + return 'DeviceApprovalsChangeOverageActionType(description={!r})'.format( self._description_value, ) -DisabledDomainInvitesType_validator = bv.Struct(DisabledDomainInvitesType) +DeviceApprovalsChangeOverageActionType_validator = bv.Struct(DeviceApprovalsChangeOverageActionType) -class DomainInvitesApproveRequestToJoinTeamDetails(bb.Struct): +class DeviceApprovalsChangeUnlinkActionDetails(bb.Struct): """ - Approved user's request to join team. + Changed device approvals setting when member unlinks approved device. + + :ivar team_log.DeviceApprovalsChangeUnlinkActionDetails.new_value: New + device unlink policy. Might be missing due to historical data gap. + :ivar team_log.DeviceApprovalsChangeUnlinkActionDetails.previous_value: + Previous device unlink policy. Might be missing due to historical data + gap. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New device unlink policy. Might be missing due to historical data gap. + + :rtype: DeviceUnlinkPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + return None + + @new_value.setter + def new_value(self, val): + if val is None: + del self.new_value + return + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous device unlink policy. Might be missing due to historical data + gap. + + :rtype: DeviceUnlinkPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesApproveRequestToJoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeUnlinkActionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesApproveRequestToJoinTeamDetails()' + return 'DeviceApprovalsChangeUnlinkActionDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -DomainInvitesApproveRequestToJoinTeamDetails_validator = bv.Struct(DomainInvitesApproveRequestToJoinTeamDetails) +DeviceApprovalsChangeUnlinkActionDetails_validator = bv.Struct(DeviceApprovalsChangeUnlinkActionDetails) -class DomainInvitesApproveRequestToJoinTeamType(bb.Struct): +class DeviceApprovalsChangeUnlinkActionType(bb.Struct): __slots__ = [ '_description_value', @@ -5798,18 +6708,65 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesApproveRequestToJoinTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsChangeUnlinkActionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesApproveRequestToJoinTeamType(description={!r})'.format( + return 'DeviceApprovalsChangeUnlinkActionType(description={!r})'.format( self._description_value, ) -DomainInvitesApproveRequestToJoinTeamType_validator = bv.Struct(DomainInvitesApproveRequestToJoinTeamType) +DeviceApprovalsChangeUnlinkActionType_validator = bv.Struct(DeviceApprovalsChangeUnlinkActionType) -class DomainInvitesDeclineRequestToJoinTeamDetails(bb.Struct): +class DeviceApprovalsPolicy(bb.Union): """ - Declined user's request to join team. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + unlimited = None + # Attribute is overwritten below the class definition + limited = None + # Attribute is overwritten below the class definition + other = None + + def is_unlimited(self): + """ + Check if the union tag is ``unlimited``. + + :rtype: bool + """ + return self._tag == 'unlimited' + + def is_limited(self): + """ + Check if the union tag is ``limited``. + + :rtype: bool + """ + return self._tag == 'limited' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DeviceApprovalsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'DeviceApprovalsPolicy(%r, %r)' % (self._tag, self._value) + +DeviceApprovalsPolicy_validator = bv.Union(DeviceApprovalsPolicy) + +class DeviceApprovalsRemoveExceptionDetails(bb.Struct): + """ + Removed members from device approvals exception list. """ __slots__ = [ @@ -5821,14 +6778,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesDeclineRequestToJoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsRemoveExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesDeclineRequestToJoinTeamDetails()' + return 'DeviceApprovalsRemoveExceptionDetails()' -DomainInvitesDeclineRequestToJoinTeamDetails_validator = bv.Struct(DomainInvitesDeclineRequestToJoinTeamDetails) +DeviceApprovalsRemoveExceptionDetails_validator = bv.Struct(DeviceApprovalsRemoveExceptionDetails) -class DomainInvitesDeclineRequestToJoinTeamType(bb.Struct): +class DeviceApprovalsRemoveExceptionType(bb.Struct): __slots__ = [ '_description_value', @@ -5866,104 +6823,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesDeclineRequestToJoinTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceApprovalsRemoveExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesDeclineRequestToJoinTeamType(description={!r})'.format( + return 'DeviceApprovalsRemoveExceptionType(description={!r})'.format( self._description_value, ) -DomainInvitesDeclineRequestToJoinTeamType_validator = bv.Struct(DomainInvitesDeclineRequestToJoinTeamType) +DeviceApprovalsRemoveExceptionType_validator = bv.Struct(DeviceApprovalsRemoveExceptionType) -class DomainInvitesEmailExistingUsersDetails(bb.Struct): +class DeviceChangeIpDesktopDetails(bb.Struct): """ - Sent domain invites to existing domain accounts. + Changed IP address associated with active desktop session. - :ivar team_log.DomainInvitesEmailExistingUsersDetails.domain_name: Domain - names. - :ivar team_log.DomainInvitesEmailExistingUsersDetails.num_recipients: Number - of recipients. + :ivar team_log.DeviceChangeIpDesktopDetails.device_session_info: Device's + session logged information. """ __slots__ = [ - '_domain_name_value', - '_domain_name_present', - '_num_recipients_value', - '_num_recipients_present', + '_device_session_info_value', + '_device_session_info_present', ] _has_required_fields = True def __init__(self, - domain_name=None, - num_recipients=None): - self._domain_name_value = None - self._domain_name_present = False - self._num_recipients_value = None - self._num_recipients_present = False - if domain_name is not None: - self.domain_name = domain_name - if num_recipients is not None: - self.num_recipients = num_recipients - - @property - def domain_name(self): - """ - Domain names. - - :rtype: str - """ - if self._domain_name_present: - return self._domain_name_value - else: - raise AttributeError("missing required field 'domain_name'") - - @domain_name.setter - def domain_name(self, val): - val = self._domain_name_validator.validate(val) - self._domain_name_value = val - self._domain_name_present = True - - @domain_name.deleter - def domain_name(self): - self._domain_name_value = None - self._domain_name_present = False + device_session_info=None): + self._device_session_info_value = None + self._device_session_info_present = False + if device_session_info is not None: + self.device_session_info = device_session_info @property - def num_recipients(self): + def device_session_info(self): """ - Number of recipients. + Device's session logged information. - :rtype: int + :rtype: DeviceSessionLogInfo """ - if self._num_recipients_present: - return self._num_recipients_value + if self._device_session_info_present: + return self._device_session_info_value else: - raise AttributeError("missing required field 'num_recipients'") + raise AttributeError("missing required field 'device_session_info'") - @num_recipients.setter - def num_recipients(self, val): - val = self._num_recipients_validator.validate(val) - self._num_recipients_value = val - self._num_recipients_present = True + @device_session_info.setter + def device_session_info(self, val): + self._device_session_info_validator.validate_type_only(val) + self._device_session_info_value = val + self._device_session_info_present = True - @num_recipients.deleter - def num_recipients(self): - self._num_recipients_value = None - self._num_recipients_present = False + @device_session_info.deleter + def device_session_info(self): + self._device_session_info_value = None + self._device_session_info_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesEmailExistingUsersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceChangeIpDesktopDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesEmailExistingUsersDetails(domain_name={!r}, num_recipients={!r})'.format( - self._domain_name_value, - self._num_recipients_value, + return 'DeviceChangeIpDesktopDetails(device_session_info={!r})'.format( + self._device_session_info_value, ) -DomainInvitesEmailExistingUsersDetails_validator = bv.Struct(DomainInvitesEmailExistingUsersDetails) +DeviceChangeIpDesktopDetails_validator = bv.Struct(DeviceChangeIpDesktopDetails) -class DomainInvitesEmailExistingUsersType(bb.Struct): +class DeviceChangeIpDesktopType(bb.Struct): __slots__ = [ '_description_value', @@ -6001,37 +6925,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesEmailExistingUsersType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceChangeIpDesktopType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesEmailExistingUsersType(description={!r})'.format( + return 'DeviceChangeIpDesktopType(description={!r})'.format( self._description_value, ) -DomainInvitesEmailExistingUsersType_validator = bv.Struct(DomainInvitesEmailExistingUsersType) +DeviceChangeIpDesktopType_validator = bv.Struct(DeviceChangeIpDesktopType) -class DomainInvitesRequestToJoinTeamDetails(bb.Struct): +class DeviceChangeIpMobileDetails(bb.Struct): """ - Requested to join team. + Changed IP address associated with active mobile session. + + :ivar team_log.DeviceChangeIpMobileDetails.device_session_info: Device's + session logged information. """ __slots__ = [ + '_device_session_info_value', + '_device_session_info_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + device_session_info=None): + self._device_session_info_value = None + self._device_session_info_present = False + if device_session_info is not None: + self.device_session_info = device_session_info + + @property + def device_session_info(self): + """ + Device's session logged information. + + :rtype: DeviceSessionLogInfo + """ + if self._device_session_info_present: + return self._device_session_info_value + else: + return None + + @device_session_info.setter + def device_session_info(self, val): + if val is None: + del self.device_session_info + return + self._device_session_info_validator.validate_type_only(val) + self._device_session_info_value = val + self._device_session_info_present = True + + @device_session_info.deleter + def device_session_info(self): + self._device_session_info_value = None + self._device_session_info_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesRequestToJoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceChangeIpMobileDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesRequestToJoinTeamDetails()' + return 'DeviceChangeIpMobileDetails(device_session_info={!r})'.format( + self._device_session_info_value, + ) -DomainInvitesRequestToJoinTeamDetails_validator = bv.Struct(DomainInvitesRequestToJoinTeamDetails) +DeviceChangeIpMobileDetails_validator = bv.Struct(DeviceChangeIpMobileDetails) -class DomainInvitesRequestToJoinTeamType(bb.Struct): +class DeviceChangeIpMobileType(bb.Struct): __slots__ = [ '_description_value', @@ -6069,37 +7030,70 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesRequestToJoinTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceChangeIpMobileType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesRequestToJoinTeamType(description={!r})'.format( + return 'DeviceChangeIpMobileType(description={!r})'.format( self._description_value, ) -DomainInvitesRequestToJoinTeamType_validator = bv.Struct(DomainInvitesRequestToJoinTeamType) +DeviceChangeIpMobileType_validator = bv.Struct(DeviceChangeIpMobileType) -class DomainInvitesSetInviteNewUserPrefToNoDetails(bb.Struct): +class DeviceChangeIpWebDetails(bb.Struct): """ - Disabled "Automatically invite new users". + Changed IP address associated with active web session. + + :ivar team_log.DeviceChangeIpWebDetails.user_agent: Web browser name. """ __slots__ = [ + '_user_agent_value', + '_user_agent_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + user_agent=None): + self._user_agent_value = None + self._user_agent_present = False + if user_agent is not None: + self.user_agent = user_agent + + @property + def user_agent(self): + """ + Web browser name. + + :rtype: str + """ + if self._user_agent_present: + return self._user_agent_value + else: + raise AttributeError("missing required field 'user_agent'") + + @user_agent.setter + def user_agent(self, val): + val = self._user_agent_validator.validate(val) + self._user_agent_value = val + self._user_agent_present = True + + @user_agent.deleter + def user_agent(self): + self._user_agent_value = None + self._user_agent_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesSetInviteNewUserPrefToNoDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceChangeIpWebDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesSetInviteNewUserPrefToNoDetails()' + return 'DeviceChangeIpWebDetails(user_agent={!r})'.format( + self._user_agent_value, + ) -DomainInvitesSetInviteNewUserPrefToNoDetails_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToNoDetails) +DeviceChangeIpWebDetails_validator = bv.Struct(DeviceChangeIpWebDetails) -class DomainInvitesSetInviteNewUserPrefToNoType(bb.Struct): +class DeviceChangeIpWebType(bb.Struct): __slots__ = [ '_description_value', @@ -6137,37 +7131,143 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesSetInviteNewUserPrefToNoType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceChangeIpWebType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesSetInviteNewUserPrefToNoType(description={!r})'.format( + return 'DeviceChangeIpWebType(description={!r})'.format( self._description_value, ) -DomainInvitesSetInviteNewUserPrefToNoType_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToNoType) +DeviceChangeIpWebType_validator = bv.Struct(DeviceChangeIpWebType) -class DomainInvitesSetInviteNewUserPrefToYesDetails(bb.Struct): +class DeviceDeleteOnUnlinkFailDetails(bb.Struct): """ - Enabled "Automatically invite new users". + Failed to delete all files from unlinked device. + + :ivar team_log.DeviceDeleteOnUnlinkFailDetails.session_info: Session unique + id. Might be missing due to historical data gap. + :ivar team_log.DeviceDeleteOnUnlinkFailDetails.display_name: The device + name. Might be missing due to historical data gap. + :ivar team_log.DeviceDeleteOnUnlinkFailDetails.num_failures: The number of + times that remote file deletion failed. """ __slots__ = [ + '_session_info_value', + '_session_info_present', + '_display_name_value', + '_display_name_present', + '_num_failures_value', + '_num_failures_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + num_failures=None, + session_info=None, + display_name=None): + self._session_info_value = None + self._session_info_present = False + self._display_name_value = None + self._display_name_present = False + self._num_failures_value = None + self._num_failures_present = False + if session_info is not None: + self.session_info = session_info + if display_name is not None: + self.display_name = display_name + if num_failures is not None: + self.num_failures = num_failures + + @property + def session_info(self): + """ + Session unique id. Might be missing due to historical data gap. + + :rtype: SessionLogInfo + """ + if self._session_info_present: + return self._session_info_value + else: + return None + + @session_info.setter + def session_info(self, val): + if val is None: + del self.session_info + return + self._session_info_validator.validate_type_only(val) + self._session_info_value = val + self._session_info_present = True + + @session_info.deleter + def session_info(self): + self._session_info_value = None + self._session_info_present = False + + @property + def display_name(self): + """ + The device name. Might be missing due to historical data gap. + + :rtype: str + """ + if self._display_name_present: + return self._display_name_value + else: + return None + + @display_name.setter + def display_name(self, val): + if val is None: + del self.display_name + return + val = self._display_name_validator.validate(val) + self._display_name_value = val + self._display_name_present = True + + @display_name.deleter + def display_name(self): + self._display_name_value = None + self._display_name_present = False + + @property + def num_failures(self): + """ + The number of times that remote file deletion failed. + + :rtype: int + """ + if self._num_failures_present: + return self._num_failures_value + else: + raise AttributeError("missing required field 'num_failures'") + + @num_failures.setter + def num_failures(self, val): + val = self._num_failures_validator.validate(val) + self._num_failures_value = val + self._num_failures_present = True + + @num_failures.deleter + def num_failures(self): + self._num_failures_value = None + self._num_failures_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesSetInviteNewUserPrefToYesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceDeleteOnUnlinkFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesSetInviteNewUserPrefToYesDetails()' + return 'DeviceDeleteOnUnlinkFailDetails(num_failures={!r}, session_info={!r}, display_name={!r})'.format( + self._num_failures_value, + self._session_info_value, + self._display_name_value, + ) -DomainInvitesSetInviteNewUserPrefToYesDetails_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToYesDetails) +DeviceDeleteOnUnlinkFailDetails_validator = bv.Struct(DeviceDeleteOnUnlinkFailDetails) -class DomainInvitesSetInviteNewUserPrefToYesType(bb.Struct): +class DeviceDeleteOnUnlinkFailType(bb.Struct): __slots__ = [ '_description_value', @@ -6205,109 +7305,110 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainInvitesSetInviteNewUserPrefToYesType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceDeleteOnUnlinkFailType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainInvitesSetInviteNewUserPrefToYesType(description={!r})'.format( + return 'DeviceDeleteOnUnlinkFailType(description={!r})'.format( self._description_value, ) -DomainInvitesSetInviteNewUserPrefToYesType_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToYesType) +DeviceDeleteOnUnlinkFailType_validator = bv.Struct(DeviceDeleteOnUnlinkFailType) -class DomainVerificationAddDomainFailDetails(bb.Struct): +class DeviceDeleteOnUnlinkSuccessDetails(bb.Struct): """ - Failed to verify team domain. + Deleted all files from unlinked device. - :ivar team_log.DomainVerificationAddDomainFailDetails.domain_name: Domain - name. - :ivar team_log.DomainVerificationAddDomainFailDetails.verification_method: - Domain name verification method. Might be missing due to historical data - gap. + :ivar team_log.DeviceDeleteOnUnlinkSuccessDetails.session_info: Session + unique id. Might be missing due to historical data gap. + :ivar team_log.DeviceDeleteOnUnlinkSuccessDetails.display_name: The device + name. Might be missing due to historical data gap. """ __slots__ = [ - '_domain_name_value', - '_domain_name_present', - '_verification_method_value', - '_verification_method_present', + '_session_info_value', + '_session_info_present', + '_display_name_value', + '_display_name_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - domain_name=None, - verification_method=None): - self._domain_name_value = None - self._domain_name_present = False - self._verification_method_value = None - self._verification_method_present = False - if domain_name is not None: - self.domain_name = domain_name - if verification_method is not None: - self.verification_method = verification_method + session_info=None, + display_name=None): + self._session_info_value = None + self._session_info_present = False + self._display_name_value = None + self._display_name_present = False + if session_info is not None: + self.session_info = session_info + if display_name is not None: + self.display_name = display_name @property - def domain_name(self): + def session_info(self): """ - Domain name. + Session unique id. Might be missing due to historical data gap. - :rtype: str + :rtype: SessionLogInfo """ - if self._domain_name_present: - return self._domain_name_value + if self._session_info_present: + return self._session_info_value else: - raise AttributeError("missing required field 'domain_name'") + return None - @domain_name.setter - def domain_name(self, val): - val = self._domain_name_validator.validate(val) - self._domain_name_value = val - self._domain_name_present = True + @session_info.setter + def session_info(self, val): + if val is None: + del self.session_info + return + self._session_info_validator.validate_type_only(val) + self._session_info_value = val + self._session_info_present = True - @domain_name.deleter - def domain_name(self): - self._domain_name_value = None - self._domain_name_present = False + @session_info.deleter + def session_info(self): + self._session_info_value = None + self._session_info_present = False @property - def verification_method(self): + def display_name(self): """ - Domain name verification method. Might be missing due to historical data - gap. + The device name. Might be missing due to historical data gap. :rtype: str """ - if self._verification_method_present: - return self._verification_method_value + if self._display_name_present: + return self._display_name_value else: return None - @verification_method.setter - def verification_method(self, val): + @display_name.setter + def display_name(self, val): if val is None: - del self.verification_method + del self.display_name return - val = self._verification_method_validator.validate(val) - self._verification_method_value = val - self._verification_method_present = True + val = self._display_name_validator.validate(val) + self._display_name_value = val + self._display_name_present = True - @verification_method.deleter - def verification_method(self): - self._verification_method_value = None - self._verification_method_present = False + @display_name.deleter + def display_name(self): + self._display_name_value = None + self._display_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainVerificationAddDomainFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceDeleteOnUnlinkSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainVerificationAddDomainFailDetails(domain_name={!r}, verification_method={!r})'.format( - self._domain_name_value, - self._verification_method_value, + return 'DeviceDeleteOnUnlinkSuccessDetails(session_info={!r}, display_name={!r})'.format( + self._session_info_value, + self._display_name_value, ) -DomainVerificationAddDomainFailDetails_validator = bv.Struct(DomainVerificationAddDomainFailDetails) +DeviceDeleteOnUnlinkSuccessDetails_validator = bv.Struct(DeviceDeleteOnUnlinkSuccessDetails) -class DomainVerificationAddDomainFailType(bb.Struct): +class DeviceDeleteOnUnlinkSuccessType(bb.Struct): __slots__ = [ '_description_value', @@ -6345,110 +7446,107 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainVerificationAddDomainFailType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceDeleteOnUnlinkSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainVerificationAddDomainFailType(description={!r})'.format( + return 'DeviceDeleteOnUnlinkSuccessType(description={!r})'.format( self._description_value, ) -DomainVerificationAddDomainFailType_validator = bv.Struct(DomainVerificationAddDomainFailType) +DeviceDeleteOnUnlinkSuccessType_validator = bv.Struct(DeviceDeleteOnUnlinkSuccessType) -class DomainVerificationAddDomainSuccessDetails(bb.Struct): +class DeviceLinkFailDetails(bb.Struct): """ - Verified team domain. + Failed to link device. - :ivar team_log.DomainVerificationAddDomainSuccessDetails.domain_names: - Domain names. - :ivar - team_log.DomainVerificationAddDomainSuccessDetails.verification_method: - Domain name verification method. Might be missing due to historical data - gap. + :ivar team_log.DeviceLinkFailDetails.ip_address: IP address. Might be + missing due to historical data gap. + :ivar team_log.DeviceLinkFailDetails.device_type: A description of the + device used while user approval blocked. """ __slots__ = [ - '_domain_names_value', - '_domain_names_present', - '_verification_method_value', - '_verification_method_present', + '_ip_address_value', + '_ip_address_present', + '_device_type_value', + '_device_type_present', ] _has_required_fields = True def __init__(self, - domain_names=None, - verification_method=None): - self._domain_names_value = None - self._domain_names_present = False - self._verification_method_value = None - self._verification_method_present = False - if domain_names is not None: - self.domain_names = domain_names - if verification_method is not None: - self.verification_method = verification_method + device_type=None, + ip_address=None): + self._ip_address_value = None + self._ip_address_present = False + self._device_type_value = None + self._device_type_present = False + if ip_address is not None: + self.ip_address = ip_address + if device_type is not None: + self.device_type = device_type @property - def domain_names(self): + def ip_address(self): """ - Domain names. + IP address. Might be missing due to historical data gap. - :rtype: list of [str] + :rtype: str """ - if self._domain_names_present: - return self._domain_names_value + if self._ip_address_present: + return self._ip_address_value else: - raise AttributeError("missing required field 'domain_names'") + return None - @domain_names.setter - def domain_names(self, val): - val = self._domain_names_validator.validate(val) - self._domain_names_value = val - self._domain_names_present = True + @ip_address.setter + def ip_address(self, val): + if val is None: + del self.ip_address + return + val = self._ip_address_validator.validate(val) + self._ip_address_value = val + self._ip_address_present = True - @domain_names.deleter - def domain_names(self): - self._domain_names_value = None - self._domain_names_present = False + @ip_address.deleter + def ip_address(self): + self._ip_address_value = None + self._ip_address_present = False @property - def verification_method(self): + def device_type(self): """ - Domain name verification method. Might be missing due to historical data - gap. + A description of the device used while user approval blocked. - :rtype: str + :rtype: DeviceType """ - if self._verification_method_present: - return self._verification_method_value + if self._device_type_present: + return self._device_type_value else: - return None + raise AttributeError("missing required field 'device_type'") - @verification_method.setter - def verification_method(self, val): - if val is None: - del self.verification_method - return - val = self._verification_method_validator.validate(val) - self._verification_method_value = val - self._verification_method_present = True + @device_type.setter + def device_type(self, val): + self._device_type_validator.validate_type_only(val) + self._device_type_value = val + self._device_type_present = True - @verification_method.deleter - def verification_method(self): - self._verification_method_value = None - self._verification_method_present = False + @device_type.deleter + def device_type(self): + self._device_type_value = None + self._device_type_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainVerificationAddDomainSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceLinkFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainVerificationAddDomainSuccessDetails(domain_names={!r}, verification_method={!r})'.format( - self._domain_names_value, - self._verification_method_value, + return 'DeviceLinkFailDetails(device_type={!r}, ip_address={!r})'.format( + self._device_type_value, + self._ip_address_value, ) -DomainVerificationAddDomainSuccessDetails_validator = bv.Struct(DomainVerificationAddDomainSuccessDetails) +DeviceLinkFailDetails_validator = bv.Struct(DeviceLinkFailDetails) -class DomainVerificationAddDomainSuccessType(bb.Struct): +class DeviceLinkFailType(bb.Struct): __slots__ = [ '_description_value', @@ -6486,71 +7584,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainVerificationAddDomainSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceLinkFailType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainVerificationAddDomainSuccessType(description={!r})'.format( + return 'DeviceLinkFailType(description={!r})'.format( self._description_value, ) -DomainVerificationAddDomainSuccessType_validator = bv.Struct(DomainVerificationAddDomainSuccessType) +DeviceLinkFailType_validator = bv.Struct(DeviceLinkFailType) -class DomainVerificationRemoveDomainDetails(bb.Struct): +class DeviceLinkSuccessDetails(bb.Struct): """ - Removed domain from list of verified team domains. + Linked device. - :ivar team_log.DomainVerificationRemoveDomainDetails.domain_names: Domain - names. + :ivar team_log.DeviceLinkSuccessDetails.device_session_info: Device's + session logged information. """ __slots__ = [ - '_domain_names_value', - '_domain_names_present', + '_device_session_info_value', + '_device_session_info_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - domain_names=None): - self._domain_names_value = None - self._domain_names_present = False - if domain_names is not None: - self.domain_names = domain_names + device_session_info=None): + self._device_session_info_value = None + self._device_session_info_present = False + if device_session_info is not None: + self.device_session_info = device_session_info @property - def domain_names(self): + def device_session_info(self): """ - Domain names. + Device's session logged information. - :rtype: list of [str] + :rtype: DeviceSessionLogInfo """ - if self._domain_names_present: - return self._domain_names_value + if self._device_session_info_present: + return self._device_session_info_value else: - raise AttributeError("missing required field 'domain_names'") + return None - @domain_names.setter - def domain_names(self, val): - val = self._domain_names_validator.validate(val) - self._domain_names_value = val - self._domain_names_present = True + @device_session_info.setter + def device_session_info(self, val): + if val is None: + del self.device_session_info + return + self._device_session_info_validator.validate_type_only(val) + self._device_session_info_value = val + self._device_session_info_present = True - @domain_names.deleter - def domain_names(self): - self._domain_names_value = None - self._domain_names_present = False + @device_session_info.deleter + def device_session_info(self): + self._device_session_info_value = None + self._device_session_info_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainVerificationRemoveDomainDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceLinkSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainVerificationRemoveDomainDetails(domain_names={!r})'.format( - self._domain_names_value, + return 'DeviceLinkSuccessDetails(device_session_info={!r})'.format( + self._device_session_info_value, ) -DomainVerificationRemoveDomainDetails_validator = bv.Struct(DomainVerificationRemoveDomainDetails) +DeviceLinkSuccessDetails_validator = bv.Struct(DeviceLinkSuccessDetails) -class DomainVerificationRemoveDomainType(bb.Struct): +class DeviceLinkSuccessType(bb.Struct): __slots__ = [ '_description_value', @@ -6588,153 +7689,86 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DomainVerificationRemoveDomainType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceLinkSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DomainVerificationRemoveDomainType(description={!r})'.format( + return 'DeviceLinkSuccessType(description={!r})'.format( self._description_value, ) -DomainVerificationRemoveDomainType_validator = bv.Struct(DomainVerificationRemoveDomainType) +DeviceLinkSuccessType_validator = bv.Struct(DeviceLinkSuccessType) -class DownloadPolicyType(bb.Union): +class DeviceManagementDisabledDetails(bb.Struct): """ - Shared content downloads policy - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Disabled device management. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - allow = None - # Attribute is overwritten below the class definition - disallow = None - # Attribute is overwritten below the class definition - other = None - - def is_allow(self): - """ - Check if the union tag is ``allow``. - - :rtype: bool - """ - return self._tag == 'allow' - - def is_disallow(self): - """ - Check if the union tag is ``disallow``. - - :rtype: bool - """ - return self._tag == 'disallow' + __slots__ = [ + ] - def is_other(self): - """ - Check if the union tag is ``other``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'other' + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DownloadPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceManagementDisabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DownloadPolicyType(%r, %r)' % (self._tag, self._value) - -DownloadPolicyType_validator = bv.Union(DownloadPolicyType) + return 'DeviceManagementDisabledDetails()' -class DurationLogInfo(bb.Struct): - """ - Represents a time duration: unit and amount +DeviceManagementDisabledDetails_validator = bv.Struct(DeviceManagementDisabledDetails) - :ivar team_log.DurationLogInfo.unit: Time unit. - :ivar team_log.DurationLogInfo.amount: Amount of time. - """ +class DeviceManagementDisabledType(bb.Struct): __slots__ = [ - '_unit_value', - '_unit_present', - '_amount_value', - '_amount_present', + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - unit=None, - amount=None): - self._unit_value = None - self._unit_present = False - self._amount_value = None - self._amount_present = False - if unit is not None: - self.unit = unit - if amount is not None: - self.amount = amount - - @property - def unit(self): - """ - Time unit. - - :rtype: TimeUnit - """ - if self._unit_present: - return self._unit_value - else: - raise AttributeError("missing required field 'unit'") - - @unit.setter - def unit(self, val): - self._unit_validator.validate_type_only(val) - self._unit_value = val - self._unit_present = True - - @unit.deleter - def unit(self): - self._unit_value = None - self._unit_present = False + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def amount(self): + def description(self): """ - Amount of time. - - :rtype: int + :rtype: str """ - if self._amount_present: - return self._amount_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'amount'") + raise AttributeError("missing required field 'description'") - @amount.setter - def amount(self, val): - val = self._amount_validator.validate(val) - self._amount_value = val - self._amount_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @amount.deleter - def amount(self): - self._amount_value = None - self._amount_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(DurationLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceManagementDisabledType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'DurationLogInfo(unit={!r}, amount={!r})'.format( - self._unit_value, - self._amount_value, + return 'DeviceManagementDisabledType(description={!r})'.format( + self._description_value, ) -DurationLogInfo_validator = bv.Struct(DurationLogInfo) +DeviceManagementDisabledType_validator = bv.Struct(DeviceManagementDisabledType) -class EmmAddExceptionDetails(bb.Struct): +class DeviceManagementEnabledDetails(bb.Struct): """ - Added members to EMM exception list. + Enabled device management. """ __slots__ = [ @@ -6746,14 +7780,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmAddExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceManagementEnabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmAddExceptionDetails()' + return 'DeviceManagementEnabledDetails()' -EmmAddExceptionDetails_validator = bv.Struct(EmmAddExceptionDetails) +DeviceManagementEnabledDetails_validator = bv.Struct(DeviceManagementEnabledDetails) -class EmmAddExceptionType(bb.Struct): +class DeviceManagementEnabledType(bb.Struct): __slots__ = [ '_description_value', @@ -6791,108 +7825,237 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmAddExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceManagementEnabledType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmAddExceptionType(description={!r})'.format( + return 'DeviceManagementEnabledType(description={!r})'.format( self._description_value, ) -EmmAddExceptionType_validator = bv.Struct(EmmAddExceptionType) +DeviceManagementEnabledType_validator = bv.Struct(DeviceManagementEnabledType) -class EmmChangePolicyDetails(bb.Struct): +class DeviceType(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - Enabled/disabled enterprise mobility management for members. - :ivar team_log.EmmChangePolicyDetails.new_value: New enterprise mobility - management policy. - :ivar team_log.EmmChangePolicyDetails.previous_value: Previous enterprise - mobility management policy. Might be missing due to historical data gap. + _catch_all = 'other' + # Attribute is overwritten below the class definition + desktop = None + # Attribute is overwritten below the class definition + mobile = None + # Attribute is overwritten below the class definition + other = None + + def is_desktop(self): + """ + Check if the union tag is ``desktop``. + + :rtype: bool + """ + return self._tag == 'desktop' + + def is_mobile(self): + """ + Check if the union tag is ``mobile``. + + :rtype: bool + """ + return self._tag == 'mobile' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DeviceType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'DeviceType(%r, %r)' % (self._tag, self._value) + +DeviceType_validator = bv.Union(DeviceType) + +class DeviceUnlinkDetails(bb.Struct): + """ + Disconnected device. + + :ivar team_log.DeviceUnlinkDetails.session_info: Session unique id. + :ivar team_log.DeviceUnlinkDetails.display_name: The device name. Might be + missing due to historical data gap. + :ivar team_log.DeviceUnlinkDetails.delete_data: True if the user requested + to delete data after device unlink, false otherwise. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_session_info_value', + '_session_info_present', + '_display_name_value', + '_display_name_present', + '_delete_data_value', + '_delete_data_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + delete_data=None, + session_info=None, + display_name=None): + self._session_info_value = None + self._session_info_present = False + self._display_name_value = None + self._display_name_present = False + self._delete_data_value = None + self._delete_data_present = False + if session_info is not None: + self.session_info = session_info + if display_name is not None: + self.display_name = display_name + if delete_data is not None: + self.delete_data = delete_data @property - def new_value(self): + def session_info(self): """ - New enterprise mobility management policy. + Session unique id. - :rtype: team_policies.EmmState + :rtype: SessionLogInfo """ - if self._new_value_present: - return self._new_value_value + if self._session_info_present: + return self._session_info_value else: - raise AttributeError("missing required field 'new_value'") + return None - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @session_info.setter + def session_info(self, val): + if val is None: + del self.session_info + return + self._session_info_validator.validate_type_only(val) + self._session_info_value = val + self._session_info_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @session_info.deleter + def session_info(self): + self._session_info_value = None + self._session_info_present = False @property - def previous_value(self): + def display_name(self): """ - Previous enterprise mobility management policy. Might be missing due to - historical data gap. + The device name. Might be missing due to historical data gap. - :rtype: team_policies.EmmState + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._display_name_present: + return self._display_name_value else: return None - @previous_value.setter - def previous_value(self, val): + @display_name.setter + def display_name(self, val): if val is None: - del self.previous_value + del self.display_name return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + val = self._display_name_validator.validate(val) + self._display_name_value = val + self._display_name_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @display_name.deleter + def display_name(self): + self._display_name_value = None + self._display_name_present = False + + @property + def delete_data(self): + """ + True if the user requested to delete data after device unlink, false + otherwise. + + :rtype: bool + """ + if self._delete_data_present: + return self._delete_data_value + else: + raise AttributeError("missing required field 'delete_data'") + + @delete_data.setter + def delete_data(self, val): + val = self._delete_data_validator.validate(val) + self._delete_data_value = val + self._delete_data_present = True + + @delete_data.deleter + def delete_data(self): + self._delete_data_value = None + self._delete_data_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceUnlinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'DeviceUnlinkDetails(delete_data={!r}, session_info={!r}, display_name={!r})'.format( + self._delete_data_value, + self._session_info_value, + self._display_name_value, ) -EmmChangePolicyDetails_validator = bv.Struct(EmmChangePolicyDetails) +DeviceUnlinkDetails_validator = bv.Struct(DeviceUnlinkDetails) -class EmmChangePolicyType(bb.Struct): +class DeviceUnlinkPolicy(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + remove = None + # Attribute is overwritten below the class definition + keep = None + # Attribute is overwritten below the class definition + other = None + + def is_remove(self): + """ + Check if the union tag is ``remove``. + + :rtype: bool + """ + return self._tag == 'remove' + + def is_keep(self): + """ + Check if the union tag is ``keep``. + + :rtype: bool + """ + return self._tag == 'keep' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DeviceUnlinkPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'DeviceUnlinkPolicy(%r, %r)' % (self._tag, self._value) + +DeviceUnlinkPolicy_validator = bv.Union(DeviceUnlinkPolicy) + +class DeviceUnlinkType(bb.Struct): __slots__ = [ '_description_value', @@ -6930,18 +8093,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DeviceUnlinkType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmChangePolicyType(description={!r})'.format( + return 'DeviceUnlinkType(description={!r})'.format( self._description_value, ) -EmmChangePolicyType_validator = bv.Struct(EmmChangePolicyType) +DeviceUnlinkType_validator = bv.Struct(DeviceUnlinkType) -class EmmCreateExceptionsReportDetails(bb.Struct): +class DirectoryRestrictionsAddMembersDetails(bb.Struct): """ - Created EMM-excluded users report. + Added members to directory restrictions list. """ __slots__ = [ @@ -6953,14 +8116,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmCreateExceptionsReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DirectoryRestrictionsAddMembersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmCreateExceptionsReportDetails()' + return 'DirectoryRestrictionsAddMembersDetails()' -EmmCreateExceptionsReportDetails_validator = bv.Struct(EmmCreateExceptionsReportDetails) +DirectoryRestrictionsAddMembersDetails_validator = bv.Struct(DirectoryRestrictionsAddMembersDetails) -class EmmCreateExceptionsReportType(bb.Struct): +class DirectoryRestrictionsAddMembersType(bb.Struct): __slots__ = [ '_description_value', @@ -6998,18 +8161,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmCreateExceptionsReportType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DirectoryRestrictionsAddMembersType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmCreateExceptionsReportType(description={!r})'.format( + return 'DirectoryRestrictionsAddMembersType(description={!r})'.format( self._description_value, ) -EmmCreateExceptionsReportType_validator = bv.Struct(EmmCreateExceptionsReportType) +DirectoryRestrictionsAddMembersType_validator = bv.Struct(DirectoryRestrictionsAddMembersType) -class EmmCreateUsageReportDetails(bb.Struct): +class DirectoryRestrictionsRemoveMembersDetails(bb.Struct): """ - Created EMM mobile app usage report. + Removed members from directory restrictions list. """ __slots__ = [ @@ -7021,14 +8184,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmCreateUsageReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DirectoryRestrictionsRemoveMembersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmCreateUsageReportDetails()' + return 'DirectoryRestrictionsRemoveMembersDetails()' -EmmCreateUsageReportDetails_validator = bv.Struct(EmmCreateUsageReportDetails) +DirectoryRestrictionsRemoveMembersDetails_validator = bv.Struct(DirectoryRestrictionsRemoveMembersDetails) -class EmmCreateUsageReportType(bb.Struct): +class DirectoryRestrictionsRemoveMembersType(bb.Struct): __slots__ = [ '_description_value', @@ -7066,70 +8229,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmCreateUsageReportType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DirectoryRestrictionsRemoveMembersType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmCreateUsageReportType(description={!r})'.format( + return 'DirectoryRestrictionsRemoveMembersType(description={!r})'.format( self._description_value, ) -EmmCreateUsageReportType_validator = bv.Struct(EmmCreateUsageReportType) +DirectoryRestrictionsRemoveMembersType_validator = bv.Struct(DirectoryRestrictionsRemoveMembersType) -class EmmErrorDetails(bb.Struct): +class DisabledDomainInvitesDetails(bb.Struct): """ - Failed to sign in via EMM. - - :ivar team_log.EmmErrorDetails.error_details: Error details. + Disabled domain invites. """ __slots__ = [ - '_error_details_value', - '_error_details_present', ] - _has_required_fields = True - - def __init__(self, - error_details=None): - self._error_details_value = None - self._error_details_present = False - if error_details is not None: - self.error_details = error_details - - @property - def error_details(self): - """ - Error details. - - :rtype: FailureDetailsLogInfo - """ - if self._error_details_present: - return self._error_details_value - else: - raise AttributeError("missing required field 'error_details'") - - @error_details.setter - def error_details(self, val): - self._error_details_validator.validate_type_only(val) - self._error_details_value = val - self._error_details_present = True + _has_required_fields = False - @error_details.deleter - def error_details(self): - self._error_details_value = None - self._error_details_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmErrorDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DisabledDomainInvitesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmErrorDetails(error_details={!r})'.format( - self._error_details_value, - ) + return 'DisabledDomainInvitesDetails()' -EmmErrorDetails_validator = bv.Struct(EmmErrorDetails) +DisabledDomainInvitesDetails_validator = bv.Struct(DisabledDomainInvitesDetails) -class EmmErrorType(bb.Struct): +class DisabledDomainInvitesType(bb.Struct): __slots__ = [ '_description_value', @@ -7167,18 +8297,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmErrorType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DisabledDomainInvitesType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmErrorType(description={!r})'.format( + return 'DisabledDomainInvitesType(description={!r})'.format( self._description_value, ) -EmmErrorType_validator = bv.Struct(EmmErrorType) +DisabledDomainInvitesType_validator = bv.Struct(DisabledDomainInvitesType) -class EmmRefreshAuthTokenDetails(bb.Struct): +class DomainInvitesApproveRequestToJoinTeamDetails(bb.Struct): """ - Refreshed auth token used for setting up EMM. + Approved user's request to join team. """ __slots__ = [ @@ -7190,14 +8320,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmRefreshAuthTokenDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DomainInvitesApproveRequestToJoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmRefreshAuthTokenDetails()' + return 'DomainInvitesApproveRequestToJoinTeamDetails()' -EmmRefreshAuthTokenDetails_validator = bv.Struct(EmmRefreshAuthTokenDetails) +DomainInvitesApproveRequestToJoinTeamDetails_validator = bv.Struct(DomainInvitesApproveRequestToJoinTeamDetails) -class EmmRefreshAuthTokenType(bb.Struct): +class DomainInvitesApproveRequestToJoinTeamType(bb.Struct): __slots__ = [ '_description_value', @@ -7235,18 +8365,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmRefreshAuthTokenType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DomainInvitesApproveRequestToJoinTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmRefreshAuthTokenType(description={!r})'.format( + return 'DomainInvitesApproveRequestToJoinTeamType(description={!r})'.format( self._description_value, ) -EmmRefreshAuthTokenType_validator = bv.Struct(EmmRefreshAuthTokenType) +DomainInvitesApproveRequestToJoinTeamType_validator = bv.Struct(DomainInvitesApproveRequestToJoinTeamType) -class EmmRemoveExceptionDetails(bb.Struct): +class DomainInvitesDeclineRequestToJoinTeamDetails(bb.Struct): """ - Removed members from EMM exception list. + Declined user's request to join team. """ __slots__ = [ @@ -7258,14 +8388,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmRemoveExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DomainInvitesDeclineRequestToJoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmRemoveExceptionDetails()' + return 'DomainInvitesDeclineRequestToJoinTeamDetails()' -EmmRemoveExceptionDetails_validator = bv.Struct(EmmRemoveExceptionDetails) +DomainInvitesDeclineRequestToJoinTeamDetails_validator = bv.Struct(DomainInvitesDeclineRequestToJoinTeamDetails) -class EmmRemoveExceptionType(bb.Struct): +class DomainInvitesDeclineRequestToJoinTeamType(bb.Struct): __slots__ = [ '_description_value', @@ -7303,37 +8433,104 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EmmRemoveExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DomainInvitesDeclineRequestToJoinTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EmmRemoveExceptionType(description={!r})'.format( + return 'DomainInvitesDeclineRequestToJoinTeamType(description={!r})'.format( self._description_value, ) -EmmRemoveExceptionType_validator = bv.Struct(EmmRemoveExceptionType) +DomainInvitesDeclineRequestToJoinTeamType_validator = bv.Struct(DomainInvitesDeclineRequestToJoinTeamType) -class EnabledDomainInvitesDetails(bb.Struct): +class DomainInvitesEmailExistingUsersDetails(bb.Struct): """ - Enabled domain invites. + Sent domain invites to existing domain accounts. + + :ivar team_log.DomainInvitesEmailExistingUsersDetails.domain_name: Domain + names. + :ivar team_log.DomainInvitesEmailExistingUsersDetails.num_recipients: Number + of recipients. """ __slots__ = [ + '_domain_name_value', + '_domain_name_present', + '_num_recipients_value', + '_num_recipients_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + domain_name=None, + num_recipients=None): + self._domain_name_value = None + self._domain_name_present = False + self._num_recipients_value = None + self._num_recipients_present = False + if domain_name is not None: + self.domain_name = domain_name + if num_recipients is not None: + self.num_recipients = num_recipients + + @property + def domain_name(self): + """ + Domain names. + + :rtype: str + """ + if self._domain_name_present: + return self._domain_name_value + else: + raise AttributeError("missing required field 'domain_name'") + + @domain_name.setter + def domain_name(self, val): + val = self._domain_name_validator.validate(val) + self._domain_name_value = val + self._domain_name_present = True + + @domain_name.deleter + def domain_name(self): + self._domain_name_value = None + self._domain_name_present = False + + @property + def num_recipients(self): + """ + Number of recipients. + + :rtype: int + """ + if self._num_recipients_present: + return self._num_recipients_value + else: + raise AttributeError("missing required field 'num_recipients'") + + @num_recipients.setter + def num_recipients(self, val): + val = self._num_recipients_validator.validate(val) + self._num_recipients_value = val + self._num_recipients_present = True + + @num_recipients.deleter + def num_recipients(self): + self._num_recipients_value = None + self._num_recipients_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EnabledDomainInvitesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DomainInvitesEmailExistingUsersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EnabledDomainInvitesDetails()' + return 'DomainInvitesEmailExistingUsersDetails(domain_name={!r}, num_recipients={!r})'.format( + self._domain_name_value, + self._num_recipients_value, + ) -EnabledDomainInvitesDetails_validator = bv.Struct(EnabledDomainInvitesDetails) +DomainInvitesEmailExistingUsersDetails_validator = bv.Struct(DomainInvitesEmailExistingUsersDetails) -class EnabledDomainInvitesType(bb.Struct): +class DomainInvitesEmailExistingUsersType(bb.Struct): __slots__ = [ '_description_value', @@ -7371,17899 +8568,34757 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EnabledDomainInvitesType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DomainInvitesEmailExistingUsersType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EnabledDomainInvitesType(description={!r})'.format( + return 'DomainInvitesEmailExistingUsersType(description={!r})'.format( self._description_value, ) -EnabledDomainInvitesType_validator = bv.Struct(EnabledDomainInvitesType) +DomainInvitesEmailExistingUsersType_validator = bv.Struct(DomainInvitesEmailExistingUsersType) -class EventCategory(bb.Union): +class DomainInvitesRequestToJoinTeamDetails(bb.Struct): + """ + Requested to join team. """ - Category of events in event audit log. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + __slots__ = [ + ] - :ivar team_log.EventCategory.apps: Events that apply to management of linked - apps. - :ivar team_log.EventCategory.comments: Events that have to do with comments - on files and Paper documents. - :ivar team_log.EventCategory.devices: Events that apply to linked devices on - mobile, desktop and Web platforms. - :ivar team_log.EventCategory.domains: Events that involve domain management - feature: domain verification, invite enforcement and account capture. - :ivar team_log.EventCategory.file_operations: Events that have to do with - filesystem operations on files and folders: copy, move, delete, etc. - :ivar team_log.EventCategory.file_requests: Events that apply to the file - requests feature. - :ivar team_log.EventCategory.groups: Events that involve group management. - :ivar team_log.EventCategory.logins: Events that involve users signing in to - or out of Dropbox. - :ivar team_log.EventCategory.members: Events that involve team member - management. - :ivar team_log.EventCategory.paper: Events that apply to Dropbox Paper. - :ivar team_log.EventCategory.passwords: Events that involve using, changing - or resetting passwords. - :ivar team_log.EventCategory.reports: Events that concern generation of - admin reports, including team activity and device usage. - :ivar team_log.EventCategory.sharing: Events that apply to all types of - sharing and collaboration. - :ivar team_log.EventCategory.showcase: Events that apply to Dropbox - Showcase. - :ivar team_log.EventCategory.sso: Events that involve using or configuring - single sign-on as well as administrative policies concerning single - sign-on. - :ivar team_log.EventCategory.team_folders: Events that involve team folder - management. - :ivar team_log.EventCategory.team_policies: Events that involve a change in - team-wide policies. - :ivar team_log.EventCategory.team_profile: Events that involve a change in - the team profile. - :ivar team_log.EventCategory.tfa: Events that involve using or configuring - two factor authentication as well as administrative policies concerning - two factor authentication. - :ivar team_log.EventCategory.trusted_teams: Events that apply to cross-team - trust establishment. - """ + _has_required_fields = False - _catch_all = 'other' - # Attribute is overwritten below the class definition - apps = None - # Attribute is overwritten below the class definition - comments = None - # Attribute is overwritten below the class definition - devices = None - # Attribute is overwritten below the class definition - domains = None - # Attribute is overwritten below the class definition - file_operations = None - # Attribute is overwritten below the class definition - file_requests = None - # Attribute is overwritten below the class definition - groups = None - # Attribute is overwritten below the class definition - logins = None - # Attribute is overwritten below the class definition - members = None - # Attribute is overwritten below the class definition - paper = None - # Attribute is overwritten below the class definition - passwords = None - # Attribute is overwritten below the class definition - reports = None - # Attribute is overwritten below the class definition - sharing = None - # Attribute is overwritten below the class definition - showcase = None - # Attribute is overwritten below the class definition - sso = None - # Attribute is overwritten below the class definition - team_folders = None - # Attribute is overwritten below the class definition - team_policies = None - # Attribute is overwritten below the class definition - team_profile = None - # Attribute is overwritten below the class definition - tfa = None - # Attribute is overwritten below the class definition - trusted_teams = None - # Attribute is overwritten below the class definition - other = None + def __init__(self): + pass - def is_apps(self): - """ - Check if the union tag is ``apps``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainInvitesRequestToJoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'apps' + def __repr__(self): + return 'DomainInvitesRequestToJoinTeamDetails()' - def is_comments(self): - """ - Check if the union tag is ``comments``. +DomainInvitesRequestToJoinTeamDetails_validator = bv.Struct(DomainInvitesRequestToJoinTeamDetails) - :rtype: bool - """ - return self._tag == 'comments' +class DomainInvitesRequestToJoinTeamType(bb.Struct): - def is_devices(self): - """ - Check if the union tag is ``devices``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: bool - """ - return self._tag == 'devices' + _has_required_fields = True - def is_domains(self): - """ - Check if the union tag is ``domains``. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: bool + @property + def description(self): """ - return self._tag == 'domains' - - def is_file_operations(self): + :rtype: str """ - Check if the union tag is ``file_operations``. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :rtype: bool - """ - return self._tag == 'file_operations' + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - def is_file_requests(self): - """ - Check if the union tag is ``file_requests``. + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - :rtype: bool - """ - return self._tag == 'file_requests' + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainInvitesRequestToJoinTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) - def is_groups(self): - """ - Check if the union tag is ``groups``. + def __repr__(self): + return 'DomainInvitesRequestToJoinTeamType(description={!r})'.format( + self._description_value, + ) - :rtype: bool - """ - return self._tag == 'groups' +DomainInvitesRequestToJoinTeamType_validator = bv.Struct(DomainInvitesRequestToJoinTeamType) - def is_logins(self): - """ - Check if the union tag is ``logins``. +class DomainInvitesSetInviteNewUserPrefToNoDetails(bb.Struct): + """ + Disabled "Automatically invite new users". + """ - :rtype: bool - """ - return self._tag == 'logins' + __slots__ = [ + ] - def is_members(self): - """ - Check if the union tag is ``members``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'members' + def __init__(self): + pass - def is_paper(self): - """ - Check if the union tag is ``paper``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainInvitesSetInviteNewUserPrefToNoDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'paper' + def __repr__(self): + return 'DomainInvitesSetInviteNewUserPrefToNoDetails()' - def is_passwords(self): - """ - Check if the union tag is ``passwords``. +DomainInvitesSetInviteNewUserPrefToNoDetails_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToNoDetails) - :rtype: bool - """ - return self._tag == 'passwords' +class DomainInvitesSetInviteNewUserPrefToNoType(bb.Struct): - def is_reports(self): - """ - Check if the union tag is ``reports``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: bool - """ - return self._tag == 'reports' + _has_required_fields = True - def is_sharing(self): - """ - Check if the union tag is ``sharing``. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: bool + @property + def description(self): """ - return self._tag == 'sharing' - - def is_showcase(self): + :rtype: str """ - Check if the union tag is ``showcase``. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :rtype: bool - """ - return self._tag == 'showcase' + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - def is_sso(self): - """ - Check if the union tag is ``sso``. + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - :rtype: bool - """ - return self._tag == 'sso' + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainInvitesSetInviteNewUserPrefToNoType, self)._process_custom_annotations(annotation_type, field_path, processor) - def is_team_folders(self): - """ - Check if the union tag is ``team_folders``. + def __repr__(self): + return 'DomainInvitesSetInviteNewUserPrefToNoType(description={!r})'.format( + self._description_value, + ) - :rtype: bool - """ - return self._tag == 'team_folders' +DomainInvitesSetInviteNewUserPrefToNoType_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToNoType) - def is_team_policies(self): - """ - Check if the union tag is ``team_policies``. +class DomainInvitesSetInviteNewUserPrefToYesDetails(bb.Struct): + """ + Enabled "Automatically invite new users". + """ - :rtype: bool - """ - return self._tag == 'team_policies' + __slots__ = [ + ] - def is_team_profile(self): - """ - Check if the union tag is ``team_profile``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'team_profile' + def __init__(self): + pass - def is_tfa(self): - """ - Check if the union tag is ``tfa``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainInvitesSetInviteNewUserPrefToYesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'tfa' + def __repr__(self): + return 'DomainInvitesSetInviteNewUserPrefToYesDetails()' - def is_trusted_teams(self): - """ - Check if the union tag is ``trusted_teams``. +DomainInvitesSetInviteNewUserPrefToYesDetails_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToYesDetails) - :rtype: bool - """ - return self._tag == 'trusted_teams' +class DomainInvitesSetInviteNewUserPrefToYesType(bb.Struct): - def is_other(self): - """ - Check if the union tag is ``other``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: bool + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - return self._tag == 'other' + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EventCategory, self)._process_custom_annotations(annotation_type, field_path, processor) + super(DomainInvitesSetInviteNewUserPrefToYesType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EventCategory(%r, %r)' % (self._tag, self._value) + return 'DomainInvitesSetInviteNewUserPrefToYesType(description={!r})'.format( + self._description_value, + ) -EventCategory_validator = bv.Union(EventCategory) +DomainInvitesSetInviteNewUserPrefToYesType_validator = bv.Struct(DomainInvitesSetInviteNewUserPrefToYesType) -class EventDetails(bb.Union): +class DomainVerificationAddDomainFailDetails(bb.Struct): """ - Additional fields depending on the event type. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Failed to verify team domain. - :ivar MissingDetails EventDetails.missing_details: Hints that this event was - returned with missing details due to an internal error. + :ivar team_log.DomainVerificationAddDomainFailDetails.domain_name: Domain + name. + :ivar team_log.DomainVerificationAddDomainFailDetails.verification_method: + Domain name verification method. Might be missing due to historical data + gap. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None - - @classmethod - def app_link_team_details(cls, val): - """ - Create an instance of this class set to the ``app_link_team_details`` - tag with value ``val``. + __slots__ = [ + '_domain_name_value', + '_domain_name_present', + '_verification_method_value', + '_verification_method_present', + ] - :param AppLinkTeamDetails val: - :rtype: EventDetails - """ - return cls('app_link_team_details', val) + _has_required_fields = True - @classmethod - def app_link_user_details(cls, val): - """ - Create an instance of this class set to the ``app_link_user_details`` - tag with value ``val``. + def __init__(self, + domain_name=None, + verification_method=None): + self._domain_name_value = None + self._domain_name_present = False + self._verification_method_value = None + self._verification_method_present = False + if domain_name is not None: + self.domain_name = domain_name + if verification_method is not None: + self.verification_method = verification_method - :param AppLinkUserDetails val: - :rtype: EventDetails + @property + def domain_name(self): """ - return cls('app_link_user_details', val) + Domain name. - @classmethod - def app_unlink_team_details(cls, val): + :rtype: str """ - Create an instance of this class set to the ``app_unlink_team_details`` - tag with value ``val``. + if self._domain_name_present: + return self._domain_name_value + else: + raise AttributeError("missing required field 'domain_name'") - :param AppUnlinkTeamDetails val: - :rtype: EventDetails - """ - return cls('app_unlink_team_details', val) + @domain_name.setter + def domain_name(self, val): + val = self._domain_name_validator.validate(val) + self._domain_name_value = val + self._domain_name_present = True - @classmethod - def app_unlink_user_details(cls, val): - """ - Create an instance of this class set to the ``app_unlink_user_details`` - tag with value ``val``. + @domain_name.deleter + def domain_name(self): + self._domain_name_value = None + self._domain_name_present = False - :param AppUnlinkUserDetails val: - :rtype: EventDetails + @property + def verification_method(self): """ - return cls('app_unlink_user_details', val) + Domain name verification method. Might be missing due to historical data + gap. - @classmethod - def integration_connected_details(cls, val): + :rtype: str """ - Create an instance of this class set to the - ``integration_connected_details`` tag with value ``val``. + if self._verification_method_present: + return self._verification_method_value + else: + return None - :param IntegrationConnectedDetails val: - :rtype: EventDetails - """ - return cls('integration_connected_details', val) + @verification_method.setter + def verification_method(self, val): + if val is None: + del self.verification_method + return + val = self._verification_method_validator.validate(val) + self._verification_method_value = val + self._verification_method_present = True - @classmethod - def integration_disconnected_details(cls, val): - """ - Create an instance of this class set to the - ``integration_disconnected_details`` tag with value ``val``. + @verification_method.deleter + def verification_method(self): + self._verification_method_value = None + self._verification_method_present = False - :param IntegrationDisconnectedDetails val: - :rtype: EventDetails - """ - return cls('integration_disconnected_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainVerificationAddDomainFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def file_add_comment_details(cls, val): - """ - Create an instance of this class set to the ``file_add_comment_details`` - tag with value ``val``. + def __repr__(self): + return 'DomainVerificationAddDomainFailDetails(domain_name={!r}, verification_method={!r})'.format( + self._domain_name_value, + self._verification_method_value, + ) - :param FileAddCommentDetails val: - :rtype: EventDetails - """ - return cls('file_add_comment_details', val) +DomainVerificationAddDomainFailDetails_validator = bv.Struct(DomainVerificationAddDomainFailDetails) - @classmethod - def file_change_comment_subscription_details(cls, val): - """ - Create an instance of this class set to the - ``file_change_comment_subscription_details`` tag with value ``val``. +class DomainVerificationAddDomainFailType(bb.Struct): - :param FileChangeCommentSubscriptionDetails val: - :rtype: EventDetails - """ - return cls('file_change_comment_subscription_details', val) + __slots__ = [ + '_description_value', + '_description_present', + ] - @classmethod - def file_delete_comment_details(cls, val): - """ - Create an instance of this class set to the - ``file_delete_comment_details`` tag with value ``val``. + _has_required_fields = True - :param FileDeleteCommentDetails val: - :rtype: EventDetails - """ - return cls('file_delete_comment_details', val) + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def file_edit_comment_details(cls, val): + @property + def description(self): """ - Create an instance of this class set to the - ``file_edit_comment_details`` tag with value ``val``. - - :param FileEditCommentDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('file_edit_comment_details', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def file_like_comment_details(cls, val): - """ - Create an instance of this class set to the - ``file_like_comment_details`` tag with value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param FileLikeCommentDetails val: - :rtype: EventDetails - """ - return cls('file_like_comment_details', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def file_resolve_comment_details(cls, val): - """ - Create an instance of this class set to the - ``file_resolve_comment_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainVerificationAddDomainFailType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param FileResolveCommentDetails val: - :rtype: EventDetails - """ - return cls('file_resolve_comment_details', val) + def __repr__(self): + return 'DomainVerificationAddDomainFailType(description={!r})'.format( + self._description_value, + ) - @classmethod - def file_unlike_comment_details(cls, val): - """ - Create an instance of this class set to the - ``file_unlike_comment_details`` tag with value ``val``. +DomainVerificationAddDomainFailType_validator = bv.Struct(DomainVerificationAddDomainFailType) - :param FileUnlikeCommentDetails val: - :rtype: EventDetails - """ - return cls('file_unlike_comment_details', val) +class DomainVerificationAddDomainSuccessDetails(bb.Struct): + """ + Verified team domain. - @classmethod - def file_unresolve_comment_details(cls, val): - """ - Create an instance of this class set to the - ``file_unresolve_comment_details`` tag with value ``val``. + :ivar team_log.DomainVerificationAddDomainSuccessDetails.domain_names: + Domain names. + :ivar + team_log.DomainVerificationAddDomainSuccessDetails.verification_method: + Domain name verification method. Might be missing due to historical data + gap. + """ - :param FileUnresolveCommentDetails val: - :rtype: EventDetails - """ - return cls('file_unresolve_comment_details', val) + __slots__ = [ + '_domain_names_value', + '_domain_names_present', + '_verification_method_value', + '_verification_method_present', + ] - @classmethod - def device_change_ip_desktop_details(cls, val): - """ - Create an instance of this class set to the - ``device_change_ip_desktop_details`` tag with value ``val``. + _has_required_fields = True - :param DeviceChangeIpDesktopDetails val: - :rtype: EventDetails - """ - return cls('device_change_ip_desktop_details', val) + def __init__(self, + domain_names=None, + verification_method=None): + self._domain_names_value = None + self._domain_names_present = False + self._verification_method_value = None + self._verification_method_present = False + if domain_names is not None: + self.domain_names = domain_names + if verification_method is not None: + self.verification_method = verification_method - @classmethod - def device_change_ip_mobile_details(cls, val): + @property + def domain_names(self): """ - Create an instance of this class set to the - ``device_change_ip_mobile_details`` tag with value ``val``. + Domain names. - :param DeviceChangeIpMobileDetails val: - :rtype: EventDetails + :rtype: list of [str] """ - return cls('device_change_ip_mobile_details', val) + if self._domain_names_present: + return self._domain_names_value + else: + raise AttributeError("missing required field 'domain_names'") - @classmethod - def device_change_ip_web_details(cls, val): - """ - Create an instance of this class set to the - ``device_change_ip_web_details`` tag with value ``val``. + @domain_names.setter + def domain_names(self, val): + val = self._domain_names_validator.validate(val) + self._domain_names_value = val + self._domain_names_present = True - :param DeviceChangeIpWebDetails val: - :rtype: EventDetails - """ - return cls('device_change_ip_web_details', val) + @domain_names.deleter + def domain_names(self): + self._domain_names_value = None + self._domain_names_present = False - @classmethod - def device_delete_on_unlink_fail_details(cls, val): + @property + def verification_method(self): """ - Create an instance of this class set to the - ``device_delete_on_unlink_fail_details`` tag with value ``val``. + Domain name verification method. Might be missing due to historical data + gap. - :param DeviceDeleteOnUnlinkFailDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('device_delete_on_unlink_fail_details', val) + if self._verification_method_present: + return self._verification_method_value + else: + return None - @classmethod - def device_delete_on_unlink_success_details(cls, val): - """ - Create an instance of this class set to the - ``device_delete_on_unlink_success_details`` tag with value ``val``. + @verification_method.setter + def verification_method(self, val): + if val is None: + del self.verification_method + return + val = self._verification_method_validator.validate(val) + self._verification_method_value = val + self._verification_method_present = True - :param DeviceDeleteOnUnlinkSuccessDetails val: - :rtype: EventDetails - """ - return cls('device_delete_on_unlink_success_details', val) + @verification_method.deleter + def verification_method(self): + self._verification_method_value = None + self._verification_method_present = False - @classmethod - def device_link_fail_details(cls, val): - """ - Create an instance of this class set to the ``device_link_fail_details`` - tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainVerificationAddDomainSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :param DeviceLinkFailDetails val: - :rtype: EventDetails - """ - return cls('device_link_fail_details', val) + def __repr__(self): + return 'DomainVerificationAddDomainSuccessDetails(domain_names={!r}, verification_method={!r})'.format( + self._domain_names_value, + self._verification_method_value, + ) - @classmethod - def device_link_success_details(cls, val): - """ - Create an instance of this class set to the - ``device_link_success_details`` tag with value ``val``. +DomainVerificationAddDomainSuccessDetails_validator = bv.Struct(DomainVerificationAddDomainSuccessDetails) - :param DeviceLinkSuccessDetails val: - :rtype: EventDetails - """ - return cls('device_link_success_details', val) +class DomainVerificationAddDomainSuccessType(bb.Struct): - @classmethod - def device_management_disabled_details(cls, val): - """ - Create an instance of this class set to the - ``device_management_disabled_details`` tag with value ``val``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :param DeviceManagementDisabledDetails val: - :rtype: EventDetails - """ - return cls('device_management_disabled_details', val) + _has_required_fields = True - @classmethod - def device_management_enabled_details(cls, val): - """ - Create an instance of this class set to the - ``device_management_enabled_details`` tag with value ``val``. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :param DeviceManagementEnabledDetails val: - :rtype: EventDetails + @property + def description(self): """ - return cls('device_management_enabled_details', val) - - @classmethod - def device_unlink_details(cls, val): + :rtype: str """ - Create an instance of this class set to the ``device_unlink_details`` - tag with value ``val``. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :param DeviceUnlinkDetails val: - :rtype: EventDetails - """ - return cls('device_unlink_details', val) + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @classmethod - def emm_refresh_auth_token_details(cls, val): - """ - Create an instance of this class set to the - ``emm_refresh_auth_token_details`` tag with value ``val``. + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - :param EmmRefreshAuthTokenDetails val: - :rtype: EventDetails - """ - return cls('emm_refresh_auth_token_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainVerificationAddDomainSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def account_capture_change_availability_details(cls, val): - """ - Create an instance of this class set to the - ``account_capture_change_availability_details`` tag with value ``val``. + def __repr__(self): + return 'DomainVerificationAddDomainSuccessType(description={!r})'.format( + self._description_value, + ) - :param AccountCaptureChangeAvailabilityDetails val: - :rtype: EventDetails - """ - return cls('account_capture_change_availability_details', val) +DomainVerificationAddDomainSuccessType_validator = bv.Struct(DomainVerificationAddDomainSuccessType) - @classmethod - def account_capture_migrate_account_details(cls, val): - """ - Create an instance of this class set to the - ``account_capture_migrate_account_details`` tag with value ``val``. +class DomainVerificationRemoveDomainDetails(bb.Struct): + """ + Removed domain from list of verified team domains. - :param AccountCaptureMigrateAccountDetails val: - :rtype: EventDetails - """ - return cls('account_capture_migrate_account_details', val) + :ivar team_log.DomainVerificationRemoveDomainDetails.domain_names: Domain + names. + """ - @classmethod - def account_capture_notification_emails_sent_details(cls, val): - """ - Create an instance of this class set to the - ``account_capture_notification_emails_sent_details`` tag with value - ``val``. + __slots__ = [ + '_domain_names_value', + '_domain_names_present', + ] - :param AccountCaptureNotificationEmailsSentDetails val: - :rtype: EventDetails - """ - return cls('account_capture_notification_emails_sent_details', val) + _has_required_fields = True - @classmethod - def account_capture_relinquish_account_details(cls, val): - """ - Create an instance of this class set to the - ``account_capture_relinquish_account_details`` tag with value ``val``. + def __init__(self, + domain_names=None): + self._domain_names_value = None + self._domain_names_present = False + if domain_names is not None: + self.domain_names = domain_names - :param AccountCaptureRelinquishAccountDetails val: - :rtype: EventDetails + @property + def domain_names(self): """ - return cls('account_capture_relinquish_account_details', val) + Domain names. - @classmethod - def disabled_domain_invites_details(cls, val): + :rtype: list of [str] """ - Create an instance of this class set to the - ``disabled_domain_invites_details`` tag with value ``val``. + if self._domain_names_present: + return self._domain_names_value + else: + raise AttributeError("missing required field 'domain_names'") - :param DisabledDomainInvitesDetails val: - :rtype: EventDetails - """ - return cls('disabled_domain_invites_details', val) + @domain_names.setter + def domain_names(self, val): + val = self._domain_names_validator.validate(val) + self._domain_names_value = val + self._domain_names_present = True - @classmethod - def domain_invites_approve_request_to_join_team_details(cls, val): - """ - Create an instance of this class set to the - ``domain_invites_approve_request_to_join_team_details`` tag with value - ``val``. + @domain_names.deleter + def domain_names(self): + self._domain_names_value = None + self._domain_names_present = False - :param DomainInvitesApproveRequestToJoinTeamDetails val: - :rtype: EventDetails - """ - return cls('domain_invites_approve_request_to_join_team_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainVerificationRemoveDomainDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def domain_invites_decline_request_to_join_team_details(cls, val): - """ - Create an instance of this class set to the - ``domain_invites_decline_request_to_join_team_details`` tag with value - ``val``. + def __repr__(self): + return 'DomainVerificationRemoveDomainDetails(domain_names={!r})'.format( + self._domain_names_value, + ) - :param DomainInvitesDeclineRequestToJoinTeamDetails val: - :rtype: EventDetails - """ - return cls('domain_invites_decline_request_to_join_team_details', val) +DomainVerificationRemoveDomainDetails_validator = bv.Struct(DomainVerificationRemoveDomainDetails) - @classmethod - def domain_invites_email_existing_users_details(cls, val): - """ - Create an instance of this class set to the - ``domain_invites_email_existing_users_details`` tag with value ``val``. +class DomainVerificationRemoveDomainType(bb.Struct): - :param DomainInvitesEmailExistingUsersDetails val: - :rtype: EventDetails - """ - return cls('domain_invites_email_existing_users_details', val) + __slots__ = [ + '_description_value', + '_description_present', + ] - @classmethod - def domain_invites_request_to_join_team_details(cls, val): - """ - Create an instance of this class set to the - ``domain_invites_request_to_join_team_details`` tag with value ``val``. + _has_required_fields = True - :param DomainInvitesRequestToJoinTeamDetails val: - :rtype: EventDetails - """ - return cls('domain_invites_request_to_join_team_details', val) + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def domain_invites_set_invite_new_user_pref_to_no_details(cls, val): + @property + def description(self): """ - Create an instance of this class set to the - ``domain_invites_set_invite_new_user_pref_to_no_details`` tag with value - ``val``. - - :param DomainInvitesSetInviteNewUserPrefToNoDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('domain_invites_set_invite_new_user_pref_to_no_details', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def domain_invites_set_invite_new_user_pref_to_yes_details(cls, val): - """ - Create an instance of this class set to the - ``domain_invites_set_invite_new_user_pref_to_yes_details`` tag with - value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param DomainInvitesSetInviteNewUserPrefToYesDetails val: - :rtype: EventDetails - """ - return cls('domain_invites_set_invite_new_user_pref_to_yes_details', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def domain_verification_add_domain_fail_details(cls, val): - """ - Create an instance of this class set to the - ``domain_verification_add_domain_fail_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DomainVerificationRemoveDomainType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param DomainVerificationAddDomainFailDetails val: - :rtype: EventDetails - """ - return cls('domain_verification_add_domain_fail_details', val) + def __repr__(self): + return 'DomainVerificationRemoveDomainType(description={!r})'.format( + self._description_value, + ) - @classmethod - def domain_verification_add_domain_success_details(cls, val): - """ - Create an instance of this class set to the - ``domain_verification_add_domain_success_details`` tag with value - ``val``. +DomainVerificationRemoveDomainType_validator = bv.Struct(DomainVerificationRemoveDomainType) - :param DomainVerificationAddDomainSuccessDetails val: - :rtype: EventDetails - """ - return cls('domain_verification_add_domain_success_details', val) +class DownloadPolicyType(bb.Union): + """ + Shared content downloads policy - @classmethod - def domain_verification_remove_domain_details(cls, val): - """ - Create an instance of this class set to the - ``domain_verification_remove_domain_details`` tag with value ``val``. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - :param DomainVerificationRemoveDomainDetails val: - :rtype: EventDetails - """ - return cls('domain_verification_remove_domain_details', val) + _catch_all = 'other' + # Attribute is overwritten below the class definition + allow = None + # Attribute is overwritten below the class definition + disallow = None + # Attribute is overwritten below the class definition + other = None - @classmethod - def enabled_domain_invites_details(cls, val): + def is_allow(self): """ - Create an instance of this class set to the - ``enabled_domain_invites_details`` tag with value ``val``. + Check if the union tag is ``allow``. - :param EnabledDomainInvitesDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('enabled_domain_invites_details', val) + return self._tag == 'allow' - @classmethod - def create_folder_details(cls, val): + def is_disallow(self): """ - Create an instance of this class set to the ``create_folder_details`` - tag with value ``val``. + Check if the union tag is ``disallow``. - :param CreateFolderDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('create_folder_details', val) + return self._tag == 'disallow' - @classmethod - def file_add_details(cls, val): + def is_other(self): """ - Create an instance of this class set to the ``file_add_details`` tag - with value ``val``. + Check if the union tag is ``other``. - :param FileAddDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('file_add_details', val) + return self._tag == 'other' - @classmethod - def file_copy_details(cls, val): - """ - Create an instance of this class set to the ``file_copy_details`` tag - with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DownloadPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param FileCopyDetails val: - :rtype: EventDetails - """ - return cls('file_copy_details', val) + def __repr__(self): + return 'DownloadPolicyType(%r, %r)' % (self._tag, self._value) - @classmethod - def file_delete_details(cls, val): - """ - Create an instance of this class set to the ``file_delete_details`` tag - with value ``val``. +DownloadPolicyType_validator = bv.Union(DownloadPolicyType) - :param FileDeleteDetails val: - :rtype: EventDetails - """ - return cls('file_delete_details', val) +class DurationLogInfo(bb.Struct): + """ + Represents a time duration: unit and amount - @classmethod - def file_download_details(cls, val): - """ - Create an instance of this class set to the ``file_download_details`` - tag with value ``val``. + :ivar team_log.DurationLogInfo.unit: Time unit. + :ivar team_log.DurationLogInfo.amount: Amount of time. + """ - :param FileDownloadDetails val: - :rtype: EventDetails - """ - return cls('file_download_details', val) + __slots__ = [ + '_unit_value', + '_unit_present', + '_amount_value', + '_amount_present', + ] - @classmethod - def file_edit_details(cls, val): - """ - Create an instance of this class set to the ``file_edit_details`` tag - with value ``val``. + _has_required_fields = True - :param FileEditDetails val: - :rtype: EventDetails - """ - return cls('file_edit_details', val) + def __init__(self, + unit=None, + amount=None): + self._unit_value = None + self._unit_present = False + self._amount_value = None + self._amount_present = False + if unit is not None: + self.unit = unit + if amount is not None: + self.amount = amount - @classmethod - def file_get_copy_reference_details(cls, val): + @property + def unit(self): """ - Create an instance of this class set to the - ``file_get_copy_reference_details`` tag with value ``val``. + Time unit. - :param FileGetCopyReferenceDetails val: - :rtype: EventDetails + :rtype: TimeUnit """ - return cls('file_get_copy_reference_details', val) + if self._unit_present: + return self._unit_value + else: + raise AttributeError("missing required field 'unit'") - @classmethod - def file_move_details(cls, val): - """ - Create an instance of this class set to the ``file_move_details`` tag - with value ``val``. + @unit.setter + def unit(self, val): + self._unit_validator.validate_type_only(val) + self._unit_value = val + self._unit_present = True - :param FileMoveDetails val: - :rtype: EventDetails - """ - return cls('file_move_details', val) + @unit.deleter + def unit(self): + self._unit_value = None + self._unit_present = False - @classmethod - def file_permanently_delete_details(cls, val): + @property + def amount(self): """ - Create an instance of this class set to the - ``file_permanently_delete_details`` tag with value ``val``. + Amount of time. - :param FilePermanentlyDeleteDetails val: - :rtype: EventDetails + :rtype: int """ - return cls('file_permanently_delete_details', val) + if self._amount_present: + return self._amount_value + else: + raise AttributeError("missing required field 'amount'") - @classmethod - def file_preview_details(cls, val): - """ - Create an instance of this class set to the ``file_preview_details`` tag - with value ``val``. + @amount.setter + def amount(self, val): + val = self._amount_validator.validate(val) + self._amount_value = val + self._amount_present = True - :param FilePreviewDetails val: - :rtype: EventDetails - """ - return cls('file_preview_details', val) + @amount.deleter + def amount(self): + self._amount_value = None + self._amount_present = False - @classmethod - def file_rename_details(cls, val): - """ - Create an instance of this class set to the ``file_rename_details`` tag - with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(DurationLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - :param FileRenameDetails val: - :rtype: EventDetails - """ - return cls('file_rename_details', val) + def __repr__(self): + return 'DurationLogInfo(unit={!r}, amount={!r})'.format( + self._unit_value, + self._amount_value, + ) - @classmethod - def file_restore_details(cls, val): - """ - Create an instance of this class set to the ``file_restore_details`` tag - with value ``val``. +DurationLogInfo_validator = bv.Struct(DurationLogInfo) - :param FileRestoreDetails val: - :rtype: EventDetails - """ - return cls('file_restore_details', val) +class EmmAddExceptionDetails(bb.Struct): + """ + Added members to EMM exception list. + """ - @classmethod - def file_revert_details(cls, val): - """ - Create an instance of this class set to the ``file_revert_details`` tag - with value ``val``. + __slots__ = [ + ] - :param FileRevertDetails val: - :rtype: EventDetails - """ - return cls('file_revert_details', val) + _has_required_fields = False - @classmethod - def file_rollback_changes_details(cls, val): - """ - Create an instance of this class set to the - ``file_rollback_changes_details`` tag with value ``val``. + def __init__(self): + pass - :param FileRollbackChangesDetails val: - :rtype: EventDetails - """ - return cls('file_rollback_changes_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmAddExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def file_save_copy_reference_details(cls, val): - """ - Create an instance of this class set to the - ``file_save_copy_reference_details`` tag with value ``val``. + def __repr__(self): + return 'EmmAddExceptionDetails()' - :param FileSaveCopyReferenceDetails val: - :rtype: EventDetails - """ - return cls('file_save_copy_reference_details', val) +EmmAddExceptionDetails_validator = bv.Struct(EmmAddExceptionDetails) - @classmethod - def file_request_change_details(cls, val): - """ - Create an instance of this class set to the - ``file_request_change_details`` tag with value ``val``. +class EmmAddExceptionType(bb.Struct): - :param FileRequestChangeDetails val: - :rtype: EventDetails - """ - return cls('file_request_change_details', val) + __slots__ = [ + '_description_value', + '_description_present', + ] - @classmethod - def file_request_close_details(cls, val): - """ - Create an instance of this class set to the - ``file_request_close_details`` tag with value ``val``. + _has_required_fields = True - :param FileRequestCloseDetails val: - :rtype: EventDetails - """ - return cls('file_request_close_details', val) + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def file_request_create_details(cls, val): + @property + def description(self): """ - Create an instance of this class set to the - ``file_request_create_details`` tag with value ``val``. - - :param FileRequestCreateDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('file_request_create_details', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def file_request_delete_details(cls, val): - """ - Create an instance of this class set to the - ``file_request_delete_details`` tag with value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param FileRequestDeleteDetails val: - :rtype: EventDetails - """ - return cls('file_request_delete_details', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def file_request_receive_file_details(cls, val): - """ - Create an instance of this class set to the - ``file_request_receive_file_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmAddExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param FileRequestReceiveFileDetails val: - :rtype: EventDetails - """ - return cls('file_request_receive_file_details', val) + def __repr__(self): + return 'EmmAddExceptionType(description={!r})'.format( + self._description_value, + ) - @classmethod - def group_add_external_id_details(cls, val): - """ - Create an instance of this class set to the - ``group_add_external_id_details`` tag with value ``val``. +EmmAddExceptionType_validator = bv.Struct(EmmAddExceptionType) - :param GroupAddExternalIdDetails val: - :rtype: EventDetails - """ - return cls('group_add_external_id_details', val) +class EmmChangePolicyDetails(bb.Struct): + """ + Enabled/disabled enterprise mobility management for members. - @classmethod - def group_add_member_details(cls, val): - """ - Create an instance of this class set to the ``group_add_member_details`` - tag with value ``val``. + :ivar team_log.EmmChangePolicyDetails.new_value: New enterprise mobility + management policy. + :ivar team_log.EmmChangePolicyDetails.previous_value: Previous enterprise + mobility management policy. Might be missing due to historical data gap. + """ - :param GroupAddMemberDetails val: - :rtype: EventDetails - """ - return cls('group_add_member_details', val) + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] - @classmethod - def group_change_external_id_details(cls, val): - """ - Create an instance of this class set to the - ``group_change_external_id_details`` tag with value ``val``. + _has_required_fields = True - :param GroupChangeExternalIdDetails val: - :rtype: EventDetails - """ - return cls('group_change_external_id_details', val) + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value - @classmethod - def group_change_management_type_details(cls, val): + @property + def new_value(self): """ - Create an instance of this class set to the - ``group_change_management_type_details`` tag with value ``val``. + New enterprise mobility management policy. - :param GroupChangeManagementTypeDetails val: - :rtype: EventDetails + :rtype: team_policies.EmmState """ - return cls('group_change_management_type_details', val) + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - @classmethod - def group_change_member_role_details(cls, val): - """ - Create an instance of this class set to the - ``group_change_member_role_details`` tag with value ``val``. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - :param GroupChangeMemberRoleDetails val: - :rtype: EventDetails - """ - return cls('group_change_member_role_details', val) + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - @classmethod - def group_create_details(cls, val): - """ - Create an instance of this class set to the ``group_create_details`` tag - with value ``val``. - - :param GroupCreateDetails val: - :rtype: EventDetails - """ - return cls('group_create_details', val) - - @classmethod - def group_delete_details(cls, val): + @property + def previous_value(self): """ - Create an instance of this class set to the ``group_delete_details`` tag - with value ``val``. + Previous enterprise mobility management policy. Might be missing due to + historical data gap. - :param GroupDeleteDetails val: - :rtype: EventDetails + :rtype: team_policies.EmmState """ - return cls('group_delete_details', val) + if self._previous_value_present: + return self._previous_value_value + else: + return None - @classmethod - def group_description_updated_details(cls, val): - """ - Create an instance of this class set to the - ``group_description_updated_details`` tag with value ``val``. + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - :param GroupDescriptionUpdatedDetails val: - :rtype: EventDetails - """ - return cls('group_description_updated_details', val) + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - @classmethod - def group_join_policy_updated_details(cls, val): - """ - Create an instance of this class set to the - ``group_join_policy_updated_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :param GroupJoinPolicyUpdatedDetails val: - :rtype: EventDetails - """ - return cls('group_join_policy_updated_details', val) + def __repr__(self): + return 'EmmChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) - @classmethod - def group_moved_details(cls, val): - """ - Create an instance of this class set to the ``group_moved_details`` tag - with value ``val``. +EmmChangePolicyDetails_validator = bv.Struct(EmmChangePolicyDetails) - :param GroupMovedDetails val: - :rtype: EventDetails - """ - return cls('group_moved_details', val) +class EmmChangePolicyType(bb.Struct): - @classmethod - def group_remove_external_id_details(cls, val): - """ - Create an instance of this class set to the - ``group_remove_external_id_details`` tag with value ``val``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :param GroupRemoveExternalIdDetails val: - :rtype: EventDetails - """ - return cls('group_remove_external_id_details', val) + _has_required_fields = True - @classmethod - def group_remove_member_details(cls, val): - """ - Create an instance of this class set to the - ``group_remove_member_details`` tag with value ``val``. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :param GroupRemoveMemberDetails val: - :rtype: EventDetails + @property + def description(self): """ - return cls('group_remove_member_details', val) - - @classmethod - def group_rename_details(cls, val): + :rtype: str """ - Create an instance of this class set to the ``group_rename_details`` tag - with value ``val``. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :param GroupRenameDetails val: - :rtype: EventDetails - """ - return cls('group_rename_details', val) + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @classmethod - def emm_error_details(cls, val): - """ - Create an instance of this class set to the ``emm_error_details`` tag - with value ``val``. + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - :param EmmErrorDetails val: - :rtype: EventDetails - """ - return cls('emm_error_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def guest_admin_signed_in_via_trusted_teams_details(cls, val): - """ - Create an instance of this class set to the - ``guest_admin_signed_in_via_trusted_teams_details`` tag with value - ``val``. + def __repr__(self): + return 'EmmChangePolicyType(description={!r})'.format( + self._description_value, + ) - :param GuestAdminSignedInViaTrustedTeamsDetails val: - :rtype: EventDetails - """ - return cls('guest_admin_signed_in_via_trusted_teams_details', val) +EmmChangePolicyType_validator = bv.Struct(EmmChangePolicyType) - @classmethod - def guest_admin_signed_out_via_trusted_teams_details(cls, val): - """ - Create an instance of this class set to the - ``guest_admin_signed_out_via_trusted_teams_details`` tag with value - ``val``. +class EmmCreateExceptionsReportDetails(bb.Struct): + """ + Created EMM-excluded users report. + """ - :param GuestAdminSignedOutViaTrustedTeamsDetails val: - :rtype: EventDetails - """ - return cls('guest_admin_signed_out_via_trusted_teams_details', val) + __slots__ = [ + ] - @classmethod - def login_fail_details(cls, val): - """ - Create an instance of this class set to the ``login_fail_details`` tag - with value ``val``. + _has_required_fields = False - :param LoginFailDetails val: - :rtype: EventDetails - """ - return cls('login_fail_details', val) + def __init__(self): + pass - @classmethod - def login_success_details(cls, val): - """ - Create an instance of this class set to the ``login_success_details`` - tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmCreateExceptionsReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :param LoginSuccessDetails val: - :rtype: EventDetails - """ - return cls('login_success_details', val) + def __repr__(self): + return 'EmmCreateExceptionsReportDetails()' - @classmethod - def logout_details(cls, val): - """ - Create an instance of this class set to the ``logout_details`` tag with - value ``val``. +EmmCreateExceptionsReportDetails_validator = bv.Struct(EmmCreateExceptionsReportDetails) - :param LogoutDetails val: - :rtype: EventDetails - """ - return cls('logout_details', val) +class EmmCreateExceptionsReportType(bb.Struct): - @classmethod - def reseller_support_session_end_details(cls, val): - """ - Create an instance of this class set to the - ``reseller_support_session_end_details`` tag with value ``val``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :param ResellerSupportSessionEndDetails val: - :rtype: EventDetails - """ - return cls('reseller_support_session_end_details', val) + _has_required_fields = True - @classmethod - def reseller_support_session_start_details(cls, val): - """ - Create an instance of this class set to the - ``reseller_support_session_start_details`` tag with value ``val``. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :param ResellerSupportSessionStartDetails val: - :rtype: EventDetails + @property + def description(self): """ - return cls('reseller_support_session_start_details', val) - - @classmethod - def sign_in_as_session_end_details(cls, val): + :rtype: str """ - Create an instance of this class set to the - ``sign_in_as_session_end_details`` tag with value ``val``. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :param SignInAsSessionEndDetails val: - :rtype: EventDetails - """ - return cls('sign_in_as_session_end_details', val) + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @classmethod - def sign_in_as_session_start_details(cls, val): - """ - Create an instance of this class set to the - ``sign_in_as_session_start_details`` tag with value ``val``. + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - :param SignInAsSessionStartDetails val: - :rtype: EventDetails - """ - return cls('sign_in_as_session_start_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmCreateExceptionsReportType, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def sso_error_details(cls, val): - """ - Create an instance of this class set to the ``sso_error_details`` tag - with value ``val``. + def __repr__(self): + return 'EmmCreateExceptionsReportType(description={!r})'.format( + self._description_value, + ) - :param SsoErrorDetails val: - :rtype: EventDetails - """ - return cls('sso_error_details', val) +EmmCreateExceptionsReportType_validator = bv.Struct(EmmCreateExceptionsReportType) - @classmethod - def member_add_external_id_details(cls, val): - """ - Create an instance of this class set to the - ``member_add_external_id_details`` tag with value ``val``. +class EmmCreateUsageReportDetails(bb.Struct): + """ + Created EMM mobile app usage report. + """ - :param MemberAddExternalIdDetails val: - :rtype: EventDetails - """ - return cls('member_add_external_id_details', val) + __slots__ = [ + ] - @classmethod - def member_add_name_details(cls, val): - """ - Create an instance of this class set to the ``member_add_name_details`` - tag with value ``val``. + _has_required_fields = False - :param MemberAddNameDetails val: - :rtype: EventDetails - """ - return cls('member_add_name_details', val) + def __init__(self): + pass - @classmethod - def member_change_admin_role_details(cls, val): - """ - Create an instance of this class set to the - ``member_change_admin_role_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmCreateUsageReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :param MemberChangeAdminRoleDetails val: - :rtype: EventDetails - """ - return cls('member_change_admin_role_details', val) + def __repr__(self): + return 'EmmCreateUsageReportDetails()' - @classmethod - def member_change_email_details(cls, val): - """ - Create an instance of this class set to the - ``member_change_email_details`` tag with value ``val``. +EmmCreateUsageReportDetails_validator = bv.Struct(EmmCreateUsageReportDetails) - :param MemberChangeEmailDetails val: - :rtype: EventDetails - """ - return cls('member_change_email_details', val) +class EmmCreateUsageReportType(bb.Struct): - @classmethod - def member_change_external_id_details(cls, val): - """ - Create an instance of this class set to the - ``member_change_external_id_details`` tag with value ``val``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :param MemberChangeExternalIdDetails val: - :rtype: EventDetails - """ - return cls('member_change_external_id_details', val) + _has_required_fields = True - @classmethod - def member_change_membership_type_details(cls, val): - """ - Create an instance of this class set to the - ``member_change_membership_type_details`` tag with value ``val``. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :param MemberChangeMembershipTypeDetails val: - :rtype: EventDetails + @property + def description(self): """ - return cls('member_change_membership_type_details', val) - - @classmethod - def member_change_name_details(cls, val): + :rtype: str """ - Create an instance of this class set to the - ``member_change_name_details`` tag with value ``val``. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :param MemberChangeNameDetails val: - :rtype: EventDetails - """ - return cls('member_change_name_details', val) + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @classmethod - def member_change_status_details(cls, val): - """ - Create an instance of this class set to the - ``member_change_status_details`` tag with value ``val``. + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - :param MemberChangeStatusDetails val: - :rtype: EventDetails - """ - return cls('member_change_status_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmCreateUsageReportType, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def member_delete_manual_contacts_details(cls, val): - """ - Create an instance of this class set to the - ``member_delete_manual_contacts_details`` tag with value ``val``. + def __repr__(self): + return 'EmmCreateUsageReportType(description={!r})'.format( + self._description_value, + ) - :param MemberDeleteManualContactsDetails val: - :rtype: EventDetails - """ - return cls('member_delete_manual_contacts_details', val) +EmmCreateUsageReportType_validator = bv.Struct(EmmCreateUsageReportType) - @classmethod - def member_permanently_delete_account_contents_details(cls, val): - """ - Create an instance of this class set to the - ``member_permanently_delete_account_contents_details`` tag with value - ``val``. +class EmmErrorDetails(bb.Struct): + """ + Failed to sign in via EMM. - :param MemberPermanentlyDeleteAccountContentsDetails val: - :rtype: EventDetails - """ - return cls('member_permanently_delete_account_contents_details', val) + :ivar team_log.EmmErrorDetails.error_details: Error details. + """ - @classmethod - def member_remove_external_id_details(cls, val): - """ - Create an instance of this class set to the - ``member_remove_external_id_details`` tag with value ``val``. + __slots__ = [ + '_error_details_value', + '_error_details_present', + ] - :param MemberRemoveExternalIdDetails val: - :rtype: EventDetails - """ - return cls('member_remove_external_id_details', val) + _has_required_fields = True - @classmethod - def member_space_limits_add_custom_quota_details(cls, val): - """ - Create an instance of this class set to the - ``member_space_limits_add_custom_quota_details`` tag with value ``val``. + def __init__(self, + error_details=None): + self._error_details_value = None + self._error_details_present = False + if error_details is not None: + self.error_details = error_details - :param MemberSpaceLimitsAddCustomQuotaDetails val: - :rtype: EventDetails + @property + def error_details(self): """ - return cls('member_space_limits_add_custom_quota_details', val) + Error details. - @classmethod - def member_space_limits_change_custom_quota_details(cls, val): + :rtype: FailureDetailsLogInfo """ - Create an instance of this class set to the - ``member_space_limits_change_custom_quota_details`` tag with value - ``val``. + if self._error_details_present: + return self._error_details_value + else: + raise AttributeError("missing required field 'error_details'") - :param MemberSpaceLimitsChangeCustomQuotaDetails val: - :rtype: EventDetails - """ - return cls('member_space_limits_change_custom_quota_details', val) + @error_details.setter + def error_details(self, val): + self._error_details_validator.validate_type_only(val) + self._error_details_value = val + self._error_details_present = True - @classmethod - def member_space_limits_change_status_details(cls, val): - """ - Create an instance of this class set to the - ``member_space_limits_change_status_details`` tag with value ``val``. + @error_details.deleter + def error_details(self): + self._error_details_value = None + self._error_details_present = False - :param MemberSpaceLimitsChangeStatusDetails val: - :rtype: EventDetails - """ - return cls('member_space_limits_change_status_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmErrorDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def member_space_limits_remove_custom_quota_details(cls, val): - """ - Create an instance of this class set to the - ``member_space_limits_remove_custom_quota_details`` tag with value - ``val``. + def __repr__(self): + return 'EmmErrorDetails(error_details={!r})'.format( + self._error_details_value, + ) - :param MemberSpaceLimitsRemoveCustomQuotaDetails val: - :rtype: EventDetails - """ - return cls('member_space_limits_remove_custom_quota_details', val) +EmmErrorDetails_validator = bv.Struct(EmmErrorDetails) - @classmethod - def member_suggest_details(cls, val): - """ - Create an instance of this class set to the ``member_suggest_details`` - tag with value ``val``. +class EmmErrorType(bb.Struct): - :param MemberSuggestDetails val: - :rtype: EventDetails - """ - return cls('member_suggest_details', val) + __slots__ = [ + '_description_value', + '_description_present', + ] - @classmethod - def member_transfer_account_contents_details(cls, val): - """ - Create an instance of this class set to the - ``member_transfer_account_contents_details`` tag with value ``val``. + _has_required_fields = True - :param MemberTransferAccountContentsDetails val: - :rtype: EventDetails - """ - return cls('member_transfer_account_contents_details', val) + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def secondary_mails_policy_changed_details(cls, val): + @property + def description(self): """ - Create an instance of this class set to the - ``secondary_mails_policy_changed_details`` tag with value ``val``. - - :param SecondaryMailsPolicyChangedDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('secondary_mails_policy_changed_details', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def paper_content_add_member_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_add_member_details`` tag with value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param PaperContentAddMemberDetails val: - :rtype: EventDetails - """ - return cls('paper_content_add_member_details', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def paper_content_add_to_folder_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_add_to_folder_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmErrorType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param PaperContentAddToFolderDetails val: - :rtype: EventDetails - """ - return cls('paper_content_add_to_folder_details', val) + def __repr__(self): + return 'EmmErrorType(description={!r})'.format( + self._description_value, + ) - @classmethod - def paper_content_archive_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_archive_details`` tag with value ``val``. +EmmErrorType_validator = bv.Struct(EmmErrorType) - :param PaperContentArchiveDetails val: - :rtype: EventDetails - """ - return cls('paper_content_archive_details', val) +class EmmRefreshAuthTokenDetails(bb.Struct): + """ + Refreshed auth token used for setting up EMM. + """ - @classmethod - def paper_content_create_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_create_details`` tag with value ``val``. + __slots__ = [ + ] - :param PaperContentCreateDetails val: - :rtype: EventDetails - """ - return cls('paper_content_create_details', val) + _has_required_fields = False - @classmethod - def paper_content_permanently_delete_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_permanently_delete_details`` tag with value ``val``. + def __init__(self): + pass - :param PaperContentPermanentlyDeleteDetails val: - :rtype: EventDetails - """ - return cls('paper_content_permanently_delete_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmRefreshAuthTokenDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def paper_content_remove_from_folder_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_remove_from_folder_details`` tag with value ``val``. + def __repr__(self): + return 'EmmRefreshAuthTokenDetails()' - :param PaperContentRemoveFromFolderDetails val: - :rtype: EventDetails - """ - return cls('paper_content_remove_from_folder_details', val) +EmmRefreshAuthTokenDetails_validator = bv.Struct(EmmRefreshAuthTokenDetails) - @classmethod - def paper_content_remove_member_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_remove_member_details`` tag with value ``val``. +class EmmRefreshAuthTokenType(bb.Struct): - :param PaperContentRemoveMemberDetails val: - :rtype: EventDetails - """ - return cls('paper_content_remove_member_details', val) + __slots__ = [ + '_description_value', + '_description_present', + ] - @classmethod - def paper_content_rename_details(cls, val): - """ - Create an instance of this class set to the - ``paper_content_rename_details`` tag with value ``val``. + _has_required_fields = True - :param PaperContentRenameDetails val: - :rtype: EventDetails - """ - return cls('paper_content_rename_details', val) + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def paper_content_restore_details(cls, val): + @property + def description(self): """ - Create an instance of this class set to the - ``paper_content_restore_details`` tag with value ``val``. - - :param PaperContentRestoreDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('paper_content_restore_details', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def paper_doc_add_comment_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_add_comment_details`` tag with value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param PaperDocAddCommentDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_add_comment_details', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def paper_doc_change_member_role_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_change_member_role_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmRefreshAuthTokenType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param PaperDocChangeMemberRoleDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_change_member_role_details', val) + def __repr__(self): + return 'EmmRefreshAuthTokenType(description={!r})'.format( + self._description_value, + ) - @classmethod - def paper_doc_change_sharing_policy_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_change_sharing_policy_details`` tag with value ``val``. +EmmRefreshAuthTokenType_validator = bv.Struct(EmmRefreshAuthTokenType) - :param PaperDocChangeSharingPolicyDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_change_sharing_policy_details', val) +class EmmRemoveExceptionDetails(bb.Struct): + """ + Removed members from EMM exception list. + """ - @classmethod - def paper_doc_change_subscription_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_change_subscription_details`` tag with value ``val``. + __slots__ = [ + ] - :param PaperDocChangeSubscriptionDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_change_subscription_details', val) + _has_required_fields = False - @classmethod - def paper_doc_deleted_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_deleted_details`` tag with value ``val``. + def __init__(self): + pass - :param PaperDocDeletedDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_deleted_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmRemoveExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def paper_doc_delete_comment_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_delete_comment_details`` tag with value ``val``. + def __repr__(self): + return 'EmmRemoveExceptionDetails()' - :param PaperDocDeleteCommentDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_delete_comment_details', val) +EmmRemoveExceptionDetails_validator = bv.Struct(EmmRemoveExceptionDetails) - @classmethod - def paper_doc_download_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_download_details`` tag with value ``val``. +class EmmRemoveExceptionType(bb.Struct): - :param PaperDocDownloadDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_download_details', val) + __slots__ = [ + '_description_value', + '_description_present', + ] - @classmethod - def paper_doc_edit_details(cls, val): - """ - Create an instance of this class set to the ``paper_doc_edit_details`` - tag with value ``val``. + _has_required_fields = True - :param PaperDocEditDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_edit_details', val) + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def paper_doc_edit_comment_details(cls, val): + @property + def description(self): """ - Create an instance of this class set to the - ``paper_doc_edit_comment_details`` tag with value ``val``. - - :param PaperDocEditCommentDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('paper_doc_edit_comment_details', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def paper_doc_followed_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_followed_details`` tag with value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param PaperDocFollowedDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_followed_details', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def paper_doc_mention_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_mention_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EmmRemoveExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param PaperDocMentionDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_mention_details', val) + def __repr__(self): + return 'EmmRemoveExceptionType(description={!r})'.format( + self._description_value, + ) - @classmethod - def paper_doc_ownership_changed_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_ownership_changed_details`` tag with value ``val``. +EmmRemoveExceptionType_validator = bv.Struct(EmmRemoveExceptionType) - :param PaperDocOwnershipChangedDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_ownership_changed_details', val) +class EnabledDomainInvitesDetails(bb.Struct): + """ + Enabled domain invites. + """ - @classmethod - def paper_doc_request_access_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_request_access_details`` tag with value ``val``. + __slots__ = [ + ] - :param PaperDocRequestAccessDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_request_access_details', val) + _has_required_fields = False - @classmethod - def paper_doc_resolve_comment_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_resolve_comment_details`` tag with value ``val``. + def __init__(self): + pass - :param PaperDocResolveCommentDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_resolve_comment_details', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EnabledDomainInvitesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def paper_doc_revert_details(cls, val): - """ - Create an instance of this class set to the ``paper_doc_revert_details`` - tag with value ``val``. + def __repr__(self): + return 'EnabledDomainInvitesDetails()' - :param PaperDocRevertDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_revert_details', val) +EnabledDomainInvitesDetails_validator = bv.Struct(EnabledDomainInvitesDetails) - @classmethod - def paper_doc_slack_share_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_slack_share_details`` tag with value ``val``. +class EnabledDomainInvitesType(bb.Struct): - :param PaperDocSlackShareDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_slack_share_details', val) + __slots__ = [ + '_description_value', + '_description_present', + ] - @classmethod - def paper_doc_team_invite_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_team_invite_details`` tag with value ``val``. + _has_required_fields = True - :param PaperDocTeamInviteDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_team_invite_details', val) + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def paper_doc_trashed_details(cls, val): + @property + def description(self): """ - Create an instance of this class set to the - ``paper_doc_trashed_details`` tag with value ``val``. - - :param PaperDocTrashedDetails val: - :rtype: EventDetails + :rtype: str """ - return cls('paper_doc_trashed_details', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def paper_doc_unresolve_comment_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_unresolve_comment_details`` tag with value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param PaperDocUnresolveCommentDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_unresolve_comment_details', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def paper_doc_untrashed_details(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_untrashed_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EnabledDomainInvitesType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param PaperDocUntrashedDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_untrashed_details', val) + def __repr__(self): + return 'EnabledDomainInvitesType(description={!r})'.format( + self._description_value, + ) - @classmethod - def paper_doc_view_details(cls, val): - """ - Create an instance of this class set to the ``paper_doc_view_details`` - tag with value ``val``. +EnabledDomainInvitesType_validator = bv.Struct(EnabledDomainInvitesType) - :param PaperDocViewDetails val: - :rtype: EventDetails - """ - return cls('paper_doc_view_details', val) +class EndedEnterpriseAdminSessionDeprecatedDetails(bb.Struct): + """ + Ended enterprise admin session. - @classmethod - def paper_external_view_allow_details(cls, val): - """ - Create an instance of this class set to the - ``paper_external_view_allow_details`` tag with value ``val``. + :ivar + team_log.EndedEnterpriseAdminSessionDeprecatedDetails.federation_extra_details: + More information about the organization or team. + """ - :param PaperExternalViewAllowDetails val: - :rtype: EventDetails - """ - return cls('paper_external_view_allow_details', val) + __slots__ = [ + '_federation_extra_details_value', + '_federation_extra_details_present', + ] - @classmethod - def paper_external_view_default_team_details(cls, val): - """ - Create an instance of this class set to the - ``paper_external_view_default_team_details`` tag with value ``val``. + _has_required_fields = True - :param PaperExternalViewDefaultTeamDetails val: - :rtype: EventDetails - """ - return cls('paper_external_view_default_team_details', val) + def __init__(self, + federation_extra_details=None): + self._federation_extra_details_value = None + self._federation_extra_details_present = False + if federation_extra_details is not None: + self.federation_extra_details = federation_extra_details - @classmethod - def paper_external_view_forbid_details(cls, val): + @property + def federation_extra_details(self): """ - Create an instance of this class set to the - ``paper_external_view_forbid_details`` tag with value ``val``. + More information about the organization or team. - :param PaperExternalViewForbidDetails val: - :rtype: EventDetails + :rtype: FedExtraDetails """ - return cls('paper_external_view_forbid_details', val) + if self._federation_extra_details_present: + return self._federation_extra_details_value + else: + raise AttributeError("missing required field 'federation_extra_details'") - @classmethod - def paper_folder_change_subscription_details(cls, val): - """ - Create an instance of this class set to the - ``paper_folder_change_subscription_details`` tag with value ``val``. + @federation_extra_details.setter + def federation_extra_details(self, val): + self._federation_extra_details_validator.validate_type_only(val) + self._federation_extra_details_value = val + self._federation_extra_details_present = True - :param PaperFolderChangeSubscriptionDetails val: - :rtype: EventDetails - """ - return cls('paper_folder_change_subscription_details', val) + @federation_extra_details.deleter + def federation_extra_details(self): + self._federation_extra_details_value = None + self._federation_extra_details_present = False - @classmethod - def paper_folder_deleted_details(cls, val): - """ - Create an instance of this class set to the - ``paper_folder_deleted_details`` tag with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EndedEnterpriseAdminSessionDeprecatedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :param PaperFolderDeletedDetails val: - :rtype: EventDetails + def __repr__(self): + return 'EndedEnterpriseAdminSessionDeprecatedDetails(federation_extra_details={!r})'.format( + self._federation_extra_details_value, + ) + +EndedEnterpriseAdminSessionDeprecatedDetails_validator = bv.Struct(EndedEnterpriseAdminSessionDeprecatedDetails) + +class EndedEnterpriseAdminSessionDeprecatedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - return cls('paper_folder_deleted_details', val) + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def paper_folder_followed_details(cls, val): + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EndedEnterpriseAdminSessionDeprecatedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EndedEnterpriseAdminSessionDeprecatedType(description={!r})'.format( + self._description_value, + ) + +EndedEnterpriseAdminSessionDeprecatedType_validator = bv.Struct(EndedEnterpriseAdminSessionDeprecatedType) + +class EndedEnterpriseAdminSessionDetails(bb.Struct): + """ + Ended enterprise admin session. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EndedEnterpriseAdminSessionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EndedEnterpriseAdminSessionDetails()' + +EndedEnterpriseAdminSessionDetails_validator = bv.Struct(EndedEnterpriseAdminSessionDetails) + +class EndedEnterpriseAdminSessionType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - Create an instance of this class set to the - ``paper_folder_followed_details`` tag with value ``val``. + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :param PaperFolderFollowedDetails val: - :rtype: EventDetails + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EndedEnterpriseAdminSessionType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EndedEnterpriseAdminSessionType(description={!r})'.format( + self._description_value, + ) + +EndedEnterpriseAdminSessionType_validator = bv.Struct(EndedEnterpriseAdminSessionType) + +class EnterpriseSettingsLockingDetails(bb.Struct): + """ + Changed who can update a setting. + + :ivar team_log.EnterpriseSettingsLockingDetails.team_name: The secondary + team name. + :ivar team_log.EnterpriseSettingsLockingDetails.settings_page_name: Settings + page name. + :ivar + team_log.EnterpriseSettingsLockingDetails.previous_settings_page_locking_state: + Previous locked settings page state. + :ivar + team_log.EnterpriseSettingsLockingDetails.new_settings_page_locking_state: + New locked settings page state. + """ + + __slots__ = [ + '_team_name_value', + '_team_name_present', + '_settings_page_name_value', + '_settings_page_name_present', + '_previous_settings_page_locking_state_value', + '_previous_settings_page_locking_state_present', + '_new_settings_page_locking_state_value', + '_new_settings_page_locking_state_present', + ] + + _has_required_fields = True + + def __init__(self, + team_name=None, + settings_page_name=None, + previous_settings_page_locking_state=None, + new_settings_page_locking_state=None): + self._team_name_value = None + self._team_name_present = False + self._settings_page_name_value = None + self._settings_page_name_present = False + self._previous_settings_page_locking_state_value = None + self._previous_settings_page_locking_state_present = False + self._new_settings_page_locking_state_value = None + self._new_settings_page_locking_state_present = False + if team_name is not None: + self.team_name = team_name + if settings_page_name is not None: + self.settings_page_name = settings_page_name + if previous_settings_page_locking_state is not None: + self.previous_settings_page_locking_state = previous_settings_page_locking_state + if new_settings_page_locking_state is not None: + self.new_settings_page_locking_state = new_settings_page_locking_state + + @property + def team_name(self): """ - return cls('paper_folder_followed_details', val) + The secondary team name. - @classmethod - def paper_folder_team_invite_details(cls, val): + :rtype: str """ - Create an instance of this class set to the - ``paper_folder_team_invite_details`` tag with value ``val``. + if self._team_name_present: + return self._team_name_value + else: + raise AttributeError("missing required field 'team_name'") - :param PaperFolderTeamInviteDetails val: - :rtype: EventDetails + @team_name.setter + def team_name(self, val): + val = self._team_name_validator.validate(val) + self._team_name_value = val + self._team_name_present = True + + @team_name.deleter + def team_name(self): + self._team_name_value = None + self._team_name_present = False + + @property + def settings_page_name(self): """ - return cls('paper_folder_team_invite_details', val) + Settings page name. - @classmethod - def paper_published_link_create_details(cls, val): + :rtype: str """ - Create an instance of this class set to the - ``paper_published_link_create_details`` tag with value ``val``. + if self._settings_page_name_present: + return self._settings_page_name_value + else: + raise AttributeError("missing required field 'settings_page_name'") - :param PaperPublishedLinkCreateDetails val: - :rtype: EventDetails + @settings_page_name.setter + def settings_page_name(self, val): + val = self._settings_page_name_validator.validate(val) + self._settings_page_name_value = val + self._settings_page_name_present = True + + @settings_page_name.deleter + def settings_page_name(self): + self._settings_page_name_value = None + self._settings_page_name_present = False + + @property + def previous_settings_page_locking_state(self): """ - return cls('paper_published_link_create_details', val) + Previous locked settings page state. - @classmethod - def paper_published_link_disabled_details(cls, val): + :rtype: str """ - Create an instance of this class set to the - ``paper_published_link_disabled_details`` tag with value ``val``. + if self._previous_settings_page_locking_state_present: + return self._previous_settings_page_locking_state_value + else: + raise AttributeError("missing required field 'previous_settings_page_locking_state'") - :param PaperPublishedLinkDisabledDetails val: - :rtype: EventDetails + @previous_settings_page_locking_state.setter + def previous_settings_page_locking_state(self, val): + val = self._previous_settings_page_locking_state_validator.validate(val) + self._previous_settings_page_locking_state_value = val + self._previous_settings_page_locking_state_present = True + + @previous_settings_page_locking_state.deleter + def previous_settings_page_locking_state(self): + self._previous_settings_page_locking_state_value = None + self._previous_settings_page_locking_state_present = False + + @property + def new_settings_page_locking_state(self): """ - return cls('paper_published_link_disabled_details', val) + New locked settings page state. - @classmethod - def paper_published_link_view_details(cls, val): + :rtype: str """ - Create an instance of this class set to the - ``paper_published_link_view_details`` tag with value ``val``. + if self._new_settings_page_locking_state_present: + return self._new_settings_page_locking_state_value + else: + raise AttributeError("missing required field 'new_settings_page_locking_state'") - :param PaperPublishedLinkViewDetails val: - :rtype: EventDetails + @new_settings_page_locking_state.setter + def new_settings_page_locking_state(self, val): + val = self._new_settings_page_locking_state_validator.validate(val) + self._new_settings_page_locking_state_value = val + self._new_settings_page_locking_state_present = True + + @new_settings_page_locking_state.deleter + def new_settings_page_locking_state(self): + self._new_settings_page_locking_state_value = None + self._new_settings_page_locking_state_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EnterpriseSettingsLockingDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EnterpriseSettingsLockingDetails(team_name={!r}, settings_page_name={!r}, previous_settings_page_locking_state={!r}, new_settings_page_locking_state={!r})'.format( + self._team_name_value, + self._settings_page_name_value, + self._previous_settings_page_locking_state_value, + self._new_settings_page_locking_state_value, + ) + +EnterpriseSettingsLockingDetails_validator = bv.Struct(EnterpriseSettingsLockingDetails) + +class EnterpriseSettingsLockingType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - return cls('paper_published_link_view_details', val) + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def password_change_details(cls, val): + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EnterpriseSettingsLockingType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EnterpriseSettingsLockingType(description={!r})'.format( + self._description_value, + ) + +EnterpriseSettingsLockingType_validator = bv.Struct(EnterpriseSettingsLockingType) + +class EventCategory(bb.Union): + """ + Category of events in event audit log. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team_log.EventCategory.apps: Events that apply to management of linked + apps. + :ivar team_log.EventCategory.comments: Events that have to do with comments + on files and Paper documents. + :ivar team_log.EventCategory.devices: Events that apply to linked devices on + mobile, desktop and Web platforms. + :ivar team_log.EventCategory.domains: Events that involve domain management + feature: domain verification, invite enforcement and account capture. + :ivar team_log.EventCategory.file_operations: Events that have to do with + filesystem operations on files and folders: copy, move, delete, etc. + :ivar team_log.EventCategory.file_requests: Events that apply to the file + requests feature. + :ivar team_log.EventCategory.groups: Events that involve group management. + :ivar team_log.EventCategory.legal_holds: Events that involve placing holds + on content for litigation reasons + :ivar team_log.EventCategory.logins: Events that involve users signing in to + or out of Dropbox. + :ivar team_log.EventCategory.members: Events that involve team member + management. + :ivar team_log.EventCategory.paper: Events that apply to Dropbox Paper. + :ivar team_log.EventCategory.passwords: Events that involve using, changing + or resetting passwords. + :ivar team_log.EventCategory.reports: Events that concern generation of + admin reports, including team activity and device usage. + :ivar team_log.EventCategory.sharing: Events that apply to all types of + sharing and collaboration. + :ivar team_log.EventCategory.showcase: Events that apply to Dropbox + Showcase. + :ivar team_log.EventCategory.sso: Events that involve using or configuring + single sign-on as well as administrative policies concerning single + sign-on. + :ivar team_log.EventCategory.team_folders: Events that involve team folder + management. + :ivar team_log.EventCategory.team_policies: Events that involve a change in + team-wide policies. + :ivar team_log.EventCategory.team_profile: Events that involve a change in + the team profile. + :ivar team_log.EventCategory.tfa: Events that involve using or configuring + two factor authentication as well as administrative policies concerning + two factor authentication. + :ivar team_log.EventCategory.trusted_teams: Events that apply to cross-team + trust establishment. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + apps = None + # Attribute is overwritten below the class definition + comments = None + # Attribute is overwritten below the class definition + devices = None + # Attribute is overwritten below the class definition + domains = None + # Attribute is overwritten below the class definition + file_operations = None + # Attribute is overwritten below the class definition + file_requests = None + # Attribute is overwritten below the class definition + groups = None + # Attribute is overwritten below the class definition + legal_holds = None + # Attribute is overwritten below the class definition + logins = None + # Attribute is overwritten below the class definition + members = None + # Attribute is overwritten below the class definition + paper = None + # Attribute is overwritten below the class definition + passwords = None + # Attribute is overwritten below the class definition + reports = None + # Attribute is overwritten below the class definition + sharing = None + # Attribute is overwritten below the class definition + showcase = None + # Attribute is overwritten below the class definition + sso = None + # Attribute is overwritten below the class definition + team_folders = None + # Attribute is overwritten below the class definition + team_policies = None + # Attribute is overwritten below the class definition + team_profile = None + # Attribute is overwritten below the class definition + tfa = None + # Attribute is overwritten below the class definition + trusted_teams = None + # Attribute is overwritten below the class definition + other = None + + def is_apps(self): """ - Create an instance of this class set to the ``password_change_details`` - tag with value ``val``. + Check if the union tag is ``apps``. - :param PasswordChangeDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('password_change_details', val) + return self._tag == 'apps' - @classmethod - def password_reset_details(cls, val): + def is_comments(self): """ - Create an instance of this class set to the ``password_reset_details`` - tag with value ``val``. + Check if the union tag is ``comments``. - :param PasswordResetDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('password_reset_details', val) + return self._tag == 'comments' - @classmethod - def password_reset_all_details(cls, val): + def is_devices(self): """ - Create an instance of this class set to the - ``password_reset_all_details`` tag with value ``val``. + Check if the union tag is ``devices``. - :param PasswordResetAllDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('password_reset_all_details', val) + return self._tag == 'devices' - @classmethod - def emm_create_exceptions_report_details(cls, val): + def is_domains(self): """ - Create an instance of this class set to the - ``emm_create_exceptions_report_details`` tag with value ``val``. + Check if the union tag is ``domains``. - :param EmmCreateExceptionsReportDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('emm_create_exceptions_report_details', val) + return self._tag == 'domains' - @classmethod - def emm_create_usage_report_details(cls, val): + def is_file_operations(self): """ - Create an instance of this class set to the - ``emm_create_usage_report_details`` tag with value ``val``. + Check if the union tag is ``file_operations``. - :param EmmCreateUsageReportDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('emm_create_usage_report_details', val) + return self._tag == 'file_operations' - @classmethod - def export_members_report_details(cls, val): + def is_file_requests(self): """ - Create an instance of this class set to the - ``export_members_report_details`` tag with value ``val``. + Check if the union tag is ``file_requests``. - :param ExportMembersReportDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('export_members_report_details', val) + return self._tag == 'file_requests' - @classmethod - def paper_admin_export_start_details(cls, val): + def is_groups(self): """ - Create an instance of this class set to the - ``paper_admin_export_start_details`` tag with value ``val``. + Check if the union tag is ``groups``. - :param PaperAdminExportStartDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('paper_admin_export_start_details', val) + return self._tag == 'groups' - @classmethod - def smart_sync_create_admin_privilege_report_details(cls, val): + def is_legal_holds(self): """ - Create an instance of this class set to the - ``smart_sync_create_admin_privilege_report_details`` tag with value - ``val``. + Check if the union tag is ``legal_holds``. - :param SmartSyncCreateAdminPrivilegeReportDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('smart_sync_create_admin_privilege_report_details', val) + return self._tag == 'legal_holds' - @classmethod - def team_activity_create_report_details(cls, val): + def is_logins(self): """ - Create an instance of this class set to the - ``team_activity_create_report_details`` tag with value ``val``. + Check if the union tag is ``logins``. - :param TeamActivityCreateReportDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('team_activity_create_report_details', val) + return self._tag == 'logins' - @classmethod - def team_activity_create_report_fail_details(cls, val): + def is_members(self): """ - Create an instance of this class set to the - ``team_activity_create_report_fail_details`` tag with value ``val``. + Check if the union tag is ``members``. - :param TeamActivityCreateReportFailDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('team_activity_create_report_fail_details', val) + return self._tag == 'members' - @classmethod - def collection_share_details(cls, val): + def is_paper(self): """ - Create an instance of this class set to the ``collection_share_details`` - tag with value ``val``. + Check if the union tag is ``paper``. - :param CollectionShareDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('collection_share_details', val) + return self._tag == 'paper' - @classmethod - def note_acl_invite_only_details(cls, val): + def is_passwords(self): """ - Create an instance of this class set to the - ``note_acl_invite_only_details`` tag with value ``val``. + Check if the union tag is ``passwords``. - :param NoteAclInviteOnlyDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('note_acl_invite_only_details', val) + return self._tag == 'passwords' - @classmethod - def note_acl_link_details(cls, val): + def is_reports(self): """ - Create an instance of this class set to the ``note_acl_link_details`` - tag with value ``val``. + Check if the union tag is ``reports``. - :param NoteAclLinkDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('note_acl_link_details', val) + return self._tag == 'reports' - @classmethod - def note_acl_team_link_details(cls, val): + def is_sharing(self): """ - Create an instance of this class set to the - ``note_acl_team_link_details`` tag with value ``val``. + Check if the union tag is ``sharing``. - :param NoteAclTeamLinkDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('note_acl_team_link_details', val) + return self._tag == 'sharing' - @classmethod - def note_shared_details(cls, val): + def is_showcase(self): """ - Create an instance of this class set to the ``note_shared_details`` tag - with value ``val``. + Check if the union tag is ``showcase``. - :param NoteSharedDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('note_shared_details', val) + return self._tag == 'showcase' - @classmethod - def note_share_receive_details(cls, val): + def is_sso(self): """ - Create an instance of this class set to the - ``note_share_receive_details`` tag with value ``val``. + Check if the union tag is ``sso``. - :param NoteShareReceiveDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('note_share_receive_details', val) + return self._tag == 'sso' - @classmethod - def open_note_shared_details(cls, val): + def is_team_folders(self): """ - Create an instance of this class set to the ``open_note_shared_details`` - tag with value ``val``. + Check if the union tag is ``team_folders``. - :param OpenNoteSharedDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('open_note_shared_details', val) + return self._tag == 'team_folders' - @classmethod - def sf_add_group_details(cls, val): + def is_team_policies(self): """ - Create an instance of this class set to the ``sf_add_group_details`` tag - with value ``val``. + Check if the union tag is ``team_policies``. - :param SfAddGroupDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('sf_add_group_details', val) + return self._tag == 'team_policies' - @classmethod - def sf_allow_non_members_to_view_shared_links_details(cls, val): + def is_team_profile(self): """ - Create an instance of this class set to the - ``sf_allow_non_members_to_view_shared_links_details`` tag with value - ``val``. + Check if the union tag is ``team_profile``. - :param SfAllowNonMembersToViewSharedLinksDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('sf_allow_non_members_to_view_shared_links_details', val) + return self._tag == 'team_profile' - @classmethod - def sf_external_invite_warn_details(cls, val): + def is_tfa(self): """ - Create an instance of this class set to the - ``sf_external_invite_warn_details`` tag with value ``val``. + Check if the union tag is ``tfa``. - :param SfExternalInviteWarnDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('sf_external_invite_warn_details', val) + return self._tag == 'tfa' - @classmethod - def sf_fb_invite_details(cls, val): + def is_trusted_teams(self): """ - Create an instance of this class set to the ``sf_fb_invite_details`` tag - with value ``val``. + Check if the union tag is ``trusted_teams``. - :param SfFbInviteDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('sf_fb_invite_details', val) + return self._tag == 'trusted_teams' - @classmethod - def sf_fb_invite_change_role_details(cls, val): + def is_other(self): """ - Create an instance of this class set to the - ``sf_fb_invite_change_role_details`` tag with value ``val``. + Check if the union tag is ``other``. - :param SfFbInviteChangeRoleDetails val: - :rtype: EventDetails + :rtype: bool """ - return cls('sf_fb_invite_change_role_details', val) + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EventCategory, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EventCategory(%r, %r)' % (self._tag, self._value) + +EventCategory_validator = bv.Union(EventCategory) + +class EventDetails(bb.Union): + """ + Additional fields depending on the event type. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar MissingDetails EventDetails.missing_details: Hints that this event was + returned with missing details due to an internal error. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None @classmethod - def sf_fb_uninvite_details(cls, val): + def app_link_team_details(cls, val): """ - Create an instance of this class set to the ``sf_fb_uninvite_details`` + Create an instance of this class set to the ``app_link_team_details`` tag with value ``val``. - :param SfFbUninviteDetails val: + :param AppLinkTeamDetails val: :rtype: EventDetails """ - return cls('sf_fb_uninvite_details', val) + return cls('app_link_team_details', val) @classmethod - def sf_invite_group_details(cls, val): + def app_link_user_details(cls, val): """ - Create an instance of this class set to the ``sf_invite_group_details`` + Create an instance of this class set to the ``app_link_user_details`` tag with value ``val``. - :param SfInviteGroupDetails val: + :param AppLinkUserDetails val: :rtype: EventDetails """ - return cls('sf_invite_group_details', val) + return cls('app_link_user_details', val) @classmethod - def sf_team_grant_access_details(cls, val): + def app_unlink_team_details(cls, val): """ - Create an instance of this class set to the - ``sf_team_grant_access_details`` tag with value ``val``. + Create an instance of this class set to the ``app_unlink_team_details`` + tag with value ``val``. - :param SfTeamGrantAccessDetails val: + :param AppUnlinkTeamDetails val: :rtype: EventDetails """ - return cls('sf_team_grant_access_details', val) + return cls('app_unlink_team_details', val) @classmethod - def sf_team_invite_details(cls, val): + def app_unlink_user_details(cls, val): """ - Create an instance of this class set to the ``sf_team_invite_details`` + Create an instance of this class set to the ``app_unlink_user_details`` tag with value ``val``. - :param SfTeamInviteDetails val: + :param AppUnlinkUserDetails val: :rtype: EventDetails """ - return cls('sf_team_invite_details', val) + return cls('app_unlink_user_details', val) @classmethod - def sf_team_invite_change_role_details(cls, val): + def integration_connected_details(cls, val): """ Create an instance of this class set to the - ``sf_team_invite_change_role_details`` tag with value ``val``. + ``integration_connected_details`` tag with value ``val``. - :param SfTeamInviteChangeRoleDetails val: + :param IntegrationConnectedDetails val: :rtype: EventDetails """ - return cls('sf_team_invite_change_role_details', val) + return cls('integration_connected_details', val) @classmethod - def sf_team_join_details(cls, val): + def integration_disconnected_details(cls, val): """ - Create an instance of this class set to the ``sf_team_join_details`` tag - with value ``val``. + Create an instance of this class set to the + ``integration_disconnected_details`` tag with value ``val``. - :param SfTeamJoinDetails val: + :param IntegrationDisconnectedDetails val: :rtype: EventDetails """ - return cls('sf_team_join_details', val) + return cls('integration_disconnected_details', val) @classmethod - def sf_team_join_from_oob_link_details(cls, val): + def file_add_comment_details(cls, val): """ - Create an instance of this class set to the - ``sf_team_join_from_oob_link_details`` tag with value ``val``. + Create an instance of this class set to the ``file_add_comment_details`` + tag with value ``val``. - :param SfTeamJoinFromOobLinkDetails val: + :param FileAddCommentDetails val: :rtype: EventDetails """ - return cls('sf_team_join_from_oob_link_details', val) + return cls('file_add_comment_details', val) @classmethod - def sf_team_uninvite_details(cls, val): + def file_change_comment_subscription_details(cls, val): """ - Create an instance of this class set to the ``sf_team_uninvite_details`` - tag with value ``val``. + Create an instance of this class set to the + ``file_change_comment_subscription_details`` tag with value ``val``. - :param SfTeamUninviteDetails val: + :param FileChangeCommentSubscriptionDetails val: :rtype: EventDetails """ - return cls('sf_team_uninvite_details', val) + return cls('file_change_comment_subscription_details', val) @classmethod - def shared_content_add_invitees_details(cls, val): + def file_delete_comment_details(cls, val): """ Create an instance of this class set to the - ``shared_content_add_invitees_details`` tag with value ``val``. + ``file_delete_comment_details`` tag with value ``val``. - :param SharedContentAddInviteesDetails val: + :param FileDeleteCommentDetails val: :rtype: EventDetails """ - return cls('shared_content_add_invitees_details', val) + return cls('file_delete_comment_details', val) @classmethod - def shared_content_add_link_expiry_details(cls, val): + def file_edit_comment_details(cls, val): """ Create an instance of this class set to the - ``shared_content_add_link_expiry_details`` tag with value ``val``. + ``file_edit_comment_details`` tag with value ``val``. - :param SharedContentAddLinkExpiryDetails val: + :param FileEditCommentDetails val: :rtype: EventDetails """ - return cls('shared_content_add_link_expiry_details', val) + return cls('file_edit_comment_details', val) @classmethod - def shared_content_add_link_password_details(cls, val): + def file_like_comment_details(cls, val): """ Create an instance of this class set to the - ``shared_content_add_link_password_details`` tag with value ``val``. + ``file_like_comment_details`` tag with value ``val``. - :param SharedContentAddLinkPasswordDetails val: + :param FileLikeCommentDetails val: :rtype: EventDetails """ - return cls('shared_content_add_link_password_details', val) + return cls('file_like_comment_details', val) @classmethod - def shared_content_add_member_details(cls, val): + def file_resolve_comment_details(cls, val): """ Create an instance of this class set to the - ``shared_content_add_member_details`` tag with value ``val``. + ``file_resolve_comment_details`` tag with value ``val``. - :param SharedContentAddMemberDetails val: + :param FileResolveCommentDetails val: :rtype: EventDetails """ - return cls('shared_content_add_member_details', val) + return cls('file_resolve_comment_details', val) @classmethod - def shared_content_change_downloads_policy_details(cls, val): + def file_unlike_comment_details(cls, val): """ Create an instance of this class set to the - ``shared_content_change_downloads_policy_details`` tag with value - ``val``. + ``file_unlike_comment_details`` tag with value ``val``. - :param SharedContentChangeDownloadsPolicyDetails val: + :param FileUnlikeCommentDetails val: :rtype: EventDetails """ - return cls('shared_content_change_downloads_policy_details', val) + return cls('file_unlike_comment_details', val) @classmethod - def shared_content_change_invitee_role_details(cls, val): + def file_unresolve_comment_details(cls, val): """ Create an instance of this class set to the - ``shared_content_change_invitee_role_details`` tag with value ``val``. + ``file_unresolve_comment_details`` tag with value ``val``. - :param SharedContentChangeInviteeRoleDetails val: + :param FileUnresolveCommentDetails val: :rtype: EventDetails """ - return cls('shared_content_change_invitee_role_details', val) + return cls('file_unresolve_comment_details', val) @classmethod - def shared_content_change_link_audience_details(cls, val): + def device_change_ip_desktop_details(cls, val): """ Create an instance of this class set to the - ``shared_content_change_link_audience_details`` tag with value ``val``. + ``device_change_ip_desktop_details`` tag with value ``val``. - :param SharedContentChangeLinkAudienceDetails val: + :param DeviceChangeIpDesktopDetails val: :rtype: EventDetails """ - return cls('shared_content_change_link_audience_details', val) + return cls('device_change_ip_desktop_details', val) @classmethod - def shared_content_change_link_expiry_details(cls, val): + def device_change_ip_mobile_details(cls, val): """ Create an instance of this class set to the - ``shared_content_change_link_expiry_details`` tag with value ``val``. + ``device_change_ip_mobile_details`` tag with value ``val``. - :param SharedContentChangeLinkExpiryDetails val: + :param DeviceChangeIpMobileDetails val: :rtype: EventDetails """ - return cls('shared_content_change_link_expiry_details', val) + return cls('device_change_ip_mobile_details', val) @classmethod - def shared_content_change_link_password_details(cls, val): + def device_change_ip_web_details(cls, val): """ Create an instance of this class set to the - ``shared_content_change_link_password_details`` tag with value ``val``. + ``device_change_ip_web_details`` tag with value ``val``. - :param SharedContentChangeLinkPasswordDetails val: + :param DeviceChangeIpWebDetails val: :rtype: EventDetails """ - return cls('shared_content_change_link_password_details', val) + return cls('device_change_ip_web_details', val) @classmethod - def shared_content_change_member_role_details(cls, val): + def device_delete_on_unlink_fail_details(cls, val): """ Create an instance of this class set to the - ``shared_content_change_member_role_details`` tag with value ``val``. + ``device_delete_on_unlink_fail_details`` tag with value ``val``. - :param SharedContentChangeMemberRoleDetails val: + :param DeviceDeleteOnUnlinkFailDetails val: :rtype: EventDetails """ - return cls('shared_content_change_member_role_details', val) + return cls('device_delete_on_unlink_fail_details', val) @classmethod - def shared_content_change_viewer_info_policy_details(cls, val): + def device_delete_on_unlink_success_details(cls, val): """ Create an instance of this class set to the - ``shared_content_change_viewer_info_policy_details`` tag with value - ``val``. + ``device_delete_on_unlink_success_details`` tag with value ``val``. - :param SharedContentChangeViewerInfoPolicyDetails val: + :param DeviceDeleteOnUnlinkSuccessDetails val: :rtype: EventDetails """ - return cls('shared_content_change_viewer_info_policy_details', val) + return cls('device_delete_on_unlink_success_details', val) @classmethod - def shared_content_claim_invitation_details(cls, val): + def device_link_fail_details(cls, val): """ - Create an instance of this class set to the - ``shared_content_claim_invitation_details`` tag with value ``val``. + Create an instance of this class set to the ``device_link_fail_details`` + tag with value ``val``. - :param SharedContentClaimInvitationDetails val: + :param DeviceLinkFailDetails val: :rtype: EventDetails """ - return cls('shared_content_claim_invitation_details', val) + return cls('device_link_fail_details', val) @classmethod - def shared_content_copy_details(cls, val): + def device_link_success_details(cls, val): """ Create an instance of this class set to the - ``shared_content_copy_details`` tag with value ``val``. + ``device_link_success_details`` tag with value ``val``. - :param SharedContentCopyDetails val: + :param DeviceLinkSuccessDetails val: :rtype: EventDetails """ - return cls('shared_content_copy_details', val) + return cls('device_link_success_details', val) @classmethod - def shared_content_download_details(cls, val): + def device_management_disabled_details(cls, val): """ Create an instance of this class set to the - ``shared_content_download_details`` tag with value ``val``. + ``device_management_disabled_details`` tag with value ``val``. - :param SharedContentDownloadDetails val: + :param DeviceManagementDisabledDetails val: :rtype: EventDetails """ - return cls('shared_content_download_details', val) + return cls('device_management_disabled_details', val) @classmethod - def shared_content_relinquish_membership_details(cls, val): + def device_management_enabled_details(cls, val): """ Create an instance of this class set to the - ``shared_content_relinquish_membership_details`` tag with value ``val``. + ``device_management_enabled_details`` tag with value ``val``. - :param SharedContentRelinquishMembershipDetails val: + :param DeviceManagementEnabledDetails val: :rtype: EventDetails """ - return cls('shared_content_relinquish_membership_details', val) + return cls('device_management_enabled_details', val) @classmethod - def shared_content_remove_invitees_details(cls, val): + def device_unlink_details(cls, val): """ - Create an instance of this class set to the - ``shared_content_remove_invitees_details`` tag with value ``val``. + Create an instance of this class set to the ``device_unlink_details`` + tag with value ``val``. - :param SharedContentRemoveInviteesDetails val: + :param DeviceUnlinkDetails val: :rtype: EventDetails """ - return cls('shared_content_remove_invitees_details', val) + return cls('device_unlink_details', val) @classmethod - def shared_content_remove_link_expiry_details(cls, val): + def emm_refresh_auth_token_details(cls, val): """ Create an instance of this class set to the - ``shared_content_remove_link_expiry_details`` tag with value ``val``. + ``emm_refresh_auth_token_details`` tag with value ``val``. - :param SharedContentRemoveLinkExpiryDetails val: + :param EmmRefreshAuthTokenDetails val: :rtype: EventDetails """ - return cls('shared_content_remove_link_expiry_details', val) + return cls('emm_refresh_auth_token_details', val) @classmethod - def shared_content_remove_link_password_details(cls, val): + def account_capture_change_availability_details(cls, val): """ Create an instance of this class set to the - ``shared_content_remove_link_password_details`` tag with value ``val``. + ``account_capture_change_availability_details`` tag with value ``val``. - :param SharedContentRemoveLinkPasswordDetails val: + :param AccountCaptureChangeAvailabilityDetails val: :rtype: EventDetails """ - return cls('shared_content_remove_link_password_details', val) + return cls('account_capture_change_availability_details', val) @classmethod - def shared_content_remove_member_details(cls, val): + def account_capture_migrate_account_details(cls, val): """ Create an instance of this class set to the - ``shared_content_remove_member_details`` tag with value ``val``. + ``account_capture_migrate_account_details`` tag with value ``val``. - :param SharedContentRemoveMemberDetails val: + :param AccountCaptureMigrateAccountDetails val: :rtype: EventDetails """ - return cls('shared_content_remove_member_details', val) + return cls('account_capture_migrate_account_details', val) @classmethod - def shared_content_request_access_details(cls, val): + def account_capture_notification_emails_sent_details(cls, val): """ Create an instance of this class set to the - ``shared_content_request_access_details`` tag with value ``val``. + ``account_capture_notification_emails_sent_details`` tag with value + ``val``. - :param SharedContentRequestAccessDetails val: + :param AccountCaptureNotificationEmailsSentDetails val: :rtype: EventDetails """ - return cls('shared_content_request_access_details', val) + return cls('account_capture_notification_emails_sent_details', val) @classmethod - def shared_content_unshare_details(cls, val): + def account_capture_relinquish_account_details(cls, val): """ Create an instance of this class set to the - ``shared_content_unshare_details`` tag with value ``val``. + ``account_capture_relinquish_account_details`` tag with value ``val``. - :param SharedContentUnshareDetails val: + :param AccountCaptureRelinquishAccountDetails val: :rtype: EventDetails """ - return cls('shared_content_unshare_details', val) + return cls('account_capture_relinquish_account_details', val) @classmethod - def shared_content_view_details(cls, val): + def disabled_domain_invites_details(cls, val): """ Create an instance of this class set to the - ``shared_content_view_details`` tag with value ``val``. + ``disabled_domain_invites_details`` tag with value ``val``. - :param SharedContentViewDetails val: + :param DisabledDomainInvitesDetails val: :rtype: EventDetails """ - return cls('shared_content_view_details', val) + return cls('disabled_domain_invites_details', val) @classmethod - def shared_folder_change_link_policy_details(cls, val): + def domain_invites_approve_request_to_join_team_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_change_link_policy_details`` tag with value ``val``. + ``domain_invites_approve_request_to_join_team_details`` tag with value + ``val``. - :param SharedFolderChangeLinkPolicyDetails val: + :param DomainInvitesApproveRequestToJoinTeamDetails val: :rtype: EventDetails """ - return cls('shared_folder_change_link_policy_details', val) + return cls('domain_invites_approve_request_to_join_team_details', val) @classmethod - def shared_folder_change_members_inheritance_policy_details(cls, val): + def domain_invites_decline_request_to_join_team_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_change_members_inheritance_policy_details`` tag with - value ``val``. + ``domain_invites_decline_request_to_join_team_details`` tag with value + ``val``. - :param SharedFolderChangeMembersInheritancePolicyDetails val: + :param DomainInvitesDeclineRequestToJoinTeamDetails val: :rtype: EventDetails """ - return cls('shared_folder_change_members_inheritance_policy_details', val) + return cls('domain_invites_decline_request_to_join_team_details', val) @classmethod - def shared_folder_change_members_management_policy_details(cls, val): + def domain_invites_email_existing_users_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_change_members_management_policy_details`` tag with - value ``val``. + ``domain_invites_email_existing_users_details`` tag with value ``val``. - :param SharedFolderChangeMembersManagementPolicyDetails val: + :param DomainInvitesEmailExistingUsersDetails val: :rtype: EventDetails """ - return cls('shared_folder_change_members_management_policy_details', val) + return cls('domain_invites_email_existing_users_details', val) @classmethod - def shared_folder_change_members_policy_details(cls, val): + def domain_invites_request_to_join_team_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_change_members_policy_details`` tag with value ``val``. + ``domain_invites_request_to_join_team_details`` tag with value ``val``. - :param SharedFolderChangeMembersPolicyDetails val: + :param DomainInvitesRequestToJoinTeamDetails val: :rtype: EventDetails """ - return cls('shared_folder_change_members_policy_details', val) + return cls('domain_invites_request_to_join_team_details', val) @classmethod - def shared_folder_create_details(cls, val): + def domain_invites_set_invite_new_user_pref_to_no_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_create_details`` tag with value ``val``. + ``domain_invites_set_invite_new_user_pref_to_no_details`` tag with value + ``val``. - :param SharedFolderCreateDetails val: + :param DomainInvitesSetInviteNewUserPrefToNoDetails val: :rtype: EventDetails """ - return cls('shared_folder_create_details', val) + return cls('domain_invites_set_invite_new_user_pref_to_no_details', val) @classmethod - def shared_folder_decline_invitation_details(cls, val): + def domain_invites_set_invite_new_user_pref_to_yes_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_decline_invitation_details`` tag with value ``val``. + ``domain_invites_set_invite_new_user_pref_to_yes_details`` tag with + value ``val``. - :param SharedFolderDeclineInvitationDetails val: + :param DomainInvitesSetInviteNewUserPrefToYesDetails val: :rtype: EventDetails """ - return cls('shared_folder_decline_invitation_details', val) + return cls('domain_invites_set_invite_new_user_pref_to_yes_details', val) @classmethod - def shared_folder_mount_details(cls, val): + def domain_verification_add_domain_fail_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_mount_details`` tag with value ``val``. + ``domain_verification_add_domain_fail_details`` tag with value ``val``. - :param SharedFolderMountDetails val: + :param DomainVerificationAddDomainFailDetails val: :rtype: EventDetails """ - return cls('shared_folder_mount_details', val) + return cls('domain_verification_add_domain_fail_details', val) @classmethod - def shared_folder_nest_details(cls, val): + def domain_verification_add_domain_success_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_nest_details`` tag with value ``val``. + ``domain_verification_add_domain_success_details`` tag with value + ``val``. - :param SharedFolderNestDetails val: + :param DomainVerificationAddDomainSuccessDetails val: :rtype: EventDetails """ - return cls('shared_folder_nest_details', val) + return cls('domain_verification_add_domain_success_details', val) @classmethod - def shared_folder_transfer_ownership_details(cls, val): + def domain_verification_remove_domain_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_transfer_ownership_details`` tag with value ``val``. + ``domain_verification_remove_domain_details`` tag with value ``val``. - :param SharedFolderTransferOwnershipDetails val: + :param DomainVerificationRemoveDomainDetails val: :rtype: EventDetails """ - return cls('shared_folder_transfer_ownership_details', val) + return cls('domain_verification_remove_domain_details', val) @classmethod - def shared_folder_unmount_details(cls, val): + def enabled_domain_invites_details(cls, val): """ Create an instance of this class set to the - ``shared_folder_unmount_details`` tag with value ``val``. + ``enabled_domain_invites_details`` tag with value ``val``. - :param SharedFolderUnmountDetails val: + :param EnabledDomainInvitesDetails val: :rtype: EventDetails """ - return cls('shared_folder_unmount_details', val) + return cls('enabled_domain_invites_details', val) @classmethod - def shared_link_add_expiry_details(cls, val): + def create_folder_details(cls, val): """ - Create an instance of this class set to the - ``shared_link_add_expiry_details`` tag with value ``val``. + Create an instance of this class set to the ``create_folder_details`` + tag with value ``val``. - :param SharedLinkAddExpiryDetails val: + :param CreateFolderDetails val: :rtype: EventDetails """ - return cls('shared_link_add_expiry_details', val) + return cls('create_folder_details', val) @classmethod - def shared_link_change_expiry_details(cls, val): + def file_add_details(cls, val): """ - Create an instance of this class set to the - ``shared_link_change_expiry_details`` tag with value ``val``. + Create an instance of this class set to the ``file_add_details`` tag + with value ``val``. - :param SharedLinkChangeExpiryDetails val: + :param FileAddDetails val: :rtype: EventDetails """ - return cls('shared_link_change_expiry_details', val) + return cls('file_add_details', val) @classmethod - def shared_link_change_visibility_details(cls, val): + def file_copy_details(cls, val): """ - Create an instance of this class set to the - ``shared_link_change_visibility_details`` tag with value ``val``. + Create an instance of this class set to the ``file_copy_details`` tag + with value ``val``. - :param SharedLinkChangeVisibilityDetails val: + :param FileCopyDetails val: :rtype: EventDetails """ - return cls('shared_link_change_visibility_details', val) + return cls('file_copy_details', val) @classmethod - def shared_link_copy_details(cls, val): + def file_delete_details(cls, val): """ - Create an instance of this class set to the ``shared_link_copy_details`` - tag with value ``val``. + Create an instance of this class set to the ``file_delete_details`` tag + with value ``val``. - :param SharedLinkCopyDetails val: + :param FileDeleteDetails val: :rtype: EventDetails """ - return cls('shared_link_copy_details', val) + return cls('file_delete_details', val) @classmethod - def shared_link_create_details(cls, val): + def file_download_details(cls, val): """ - Create an instance of this class set to the - ``shared_link_create_details`` tag with value ``val``. + Create an instance of this class set to the ``file_download_details`` + tag with value ``val``. - :param SharedLinkCreateDetails val: + :param FileDownloadDetails val: :rtype: EventDetails """ - return cls('shared_link_create_details', val) + return cls('file_download_details', val) @classmethod - def shared_link_disable_details(cls, val): + def file_edit_details(cls, val): """ - Create an instance of this class set to the - ``shared_link_disable_details`` tag with value ``val``. + Create an instance of this class set to the ``file_edit_details`` tag + with value ``val``. - :param SharedLinkDisableDetails val: + :param FileEditDetails val: :rtype: EventDetails """ - return cls('shared_link_disable_details', val) + return cls('file_edit_details', val) @classmethod - def shared_link_download_details(cls, val): + def file_get_copy_reference_details(cls, val): """ Create an instance of this class set to the - ``shared_link_download_details`` tag with value ``val``. + ``file_get_copy_reference_details`` tag with value ``val``. - :param SharedLinkDownloadDetails val: + :param FileGetCopyReferenceDetails val: :rtype: EventDetails """ - return cls('shared_link_download_details', val) + return cls('file_get_copy_reference_details', val) @classmethod - def shared_link_remove_expiry_details(cls, val): + def file_locking_lock_status_changed_details(cls, val): """ Create an instance of this class set to the - ``shared_link_remove_expiry_details`` tag with value ``val``. + ``file_locking_lock_status_changed_details`` tag with value ``val``. - :param SharedLinkRemoveExpiryDetails val: + :param FileLockingLockStatusChangedDetails val: :rtype: EventDetails """ - return cls('shared_link_remove_expiry_details', val) + return cls('file_locking_lock_status_changed_details', val) @classmethod - def shared_link_share_details(cls, val): + def file_move_details(cls, val): """ - Create an instance of this class set to the - ``shared_link_share_details`` tag with value ``val``. + Create an instance of this class set to the ``file_move_details`` tag + with value ``val``. - :param SharedLinkShareDetails val: + :param FileMoveDetails val: :rtype: EventDetails """ - return cls('shared_link_share_details', val) + return cls('file_move_details', val) @classmethod - def shared_link_view_details(cls, val): + def file_permanently_delete_details(cls, val): """ - Create an instance of this class set to the ``shared_link_view_details`` - tag with value ``val``. + Create an instance of this class set to the + ``file_permanently_delete_details`` tag with value ``val``. - :param SharedLinkViewDetails val: + :param FilePermanentlyDeleteDetails val: :rtype: EventDetails """ - return cls('shared_link_view_details', val) + return cls('file_permanently_delete_details', val) @classmethod - def shared_note_opened_details(cls, val): + def file_preview_details(cls, val): """ - Create an instance of this class set to the - ``shared_note_opened_details`` tag with value ``val``. + Create an instance of this class set to the ``file_preview_details`` tag + with value ``val``. - :param SharedNoteOpenedDetails val: + :param FilePreviewDetails val: :rtype: EventDetails """ - return cls('shared_note_opened_details', val) + return cls('file_preview_details', val) @classmethod - def shmodel_group_share_details(cls, val): + def file_rename_details(cls, val): """ - Create an instance of this class set to the - ``shmodel_group_share_details`` tag with value ``val``. + Create an instance of this class set to the ``file_rename_details`` tag + with value ``val``. - :param ShmodelGroupShareDetails val: + :param FileRenameDetails val: :rtype: EventDetails """ - return cls('shmodel_group_share_details', val) + return cls('file_rename_details', val) @classmethod - def showcase_access_granted_details(cls, val): + def file_restore_details(cls, val): """ - Create an instance of this class set to the - ``showcase_access_granted_details`` tag with value ``val``. + Create an instance of this class set to the ``file_restore_details`` tag + with value ``val``. - :param ShowcaseAccessGrantedDetails val: + :param FileRestoreDetails val: :rtype: EventDetails """ - return cls('showcase_access_granted_details', val) + return cls('file_restore_details', val) @classmethod - def showcase_add_member_details(cls, val): + def file_revert_details(cls, val): """ - Create an instance of this class set to the - ``showcase_add_member_details`` tag with value ``val``. + Create an instance of this class set to the ``file_revert_details`` tag + with value ``val``. - :param ShowcaseAddMemberDetails val: + :param FileRevertDetails val: :rtype: EventDetails """ - return cls('showcase_add_member_details', val) + return cls('file_revert_details', val) @classmethod - def showcase_archived_details(cls, val): + def file_rollback_changes_details(cls, val): """ Create an instance of this class set to the - ``showcase_archived_details`` tag with value ``val``. + ``file_rollback_changes_details`` tag with value ``val``. - :param ShowcaseArchivedDetails val: + :param FileRollbackChangesDetails val: :rtype: EventDetails """ - return cls('showcase_archived_details', val) + return cls('file_rollback_changes_details', val) @classmethod - def showcase_created_details(cls, val): + def file_save_copy_reference_details(cls, val): """ - Create an instance of this class set to the ``showcase_created_details`` - tag with value ``val``. + Create an instance of this class set to the + ``file_save_copy_reference_details`` tag with value ``val``. - :param ShowcaseCreatedDetails val: + :param FileSaveCopyReferenceDetails val: :rtype: EventDetails """ - return cls('showcase_created_details', val) + return cls('file_save_copy_reference_details', val) @classmethod - def showcase_delete_comment_details(cls, val): + def folder_overview_description_changed_details(cls, val): """ Create an instance of this class set to the - ``showcase_delete_comment_details`` tag with value ``val``. + ``folder_overview_description_changed_details`` tag with value ``val``. - :param ShowcaseDeleteCommentDetails val: + :param FolderOverviewDescriptionChangedDetails val: :rtype: EventDetails """ - return cls('showcase_delete_comment_details', val) + return cls('folder_overview_description_changed_details', val) @classmethod - def showcase_edited_details(cls, val): + def folder_overview_item_pinned_details(cls, val): """ - Create an instance of this class set to the ``showcase_edited_details`` - tag with value ``val``. + Create an instance of this class set to the + ``folder_overview_item_pinned_details`` tag with value ``val``. - :param ShowcaseEditedDetails val: + :param FolderOverviewItemPinnedDetails val: :rtype: EventDetails """ - return cls('showcase_edited_details', val) + return cls('folder_overview_item_pinned_details', val) @classmethod - def showcase_edit_comment_details(cls, val): + def folder_overview_item_unpinned_details(cls, val): """ Create an instance of this class set to the - ``showcase_edit_comment_details`` tag with value ``val``. + ``folder_overview_item_unpinned_details`` tag with value ``val``. - :param ShowcaseEditCommentDetails val: + :param FolderOverviewItemUnpinnedDetails val: :rtype: EventDetails """ - return cls('showcase_edit_comment_details', val) + return cls('folder_overview_item_unpinned_details', val) @classmethod - def showcase_file_added_details(cls, val): + def rewind_folder_details(cls, val): """ - Create an instance of this class set to the - ``showcase_file_added_details`` tag with value ``val``. + Create an instance of this class set to the ``rewind_folder_details`` + tag with value ``val``. - :param ShowcaseFileAddedDetails val: + :param RewindFolderDetails val: :rtype: EventDetails """ - return cls('showcase_file_added_details', val) + return cls('rewind_folder_details', val) @classmethod - def showcase_file_download_details(cls, val): + def file_request_change_details(cls, val): """ Create an instance of this class set to the - ``showcase_file_download_details`` tag with value ``val``. + ``file_request_change_details`` tag with value ``val``. - :param ShowcaseFileDownloadDetails val: + :param FileRequestChangeDetails val: :rtype: EventDetails """ - return cls('showcase_file_download_details', val) + return cls('file_request_change_details', val) @classmethod - def showcase_file_removed_details(cls, val): + def file_request_close_details(cls, val): """ Create an instance of this class set to the - ``showcase_file_removed_details`` tag with value ``val``. + ``file_request_close_details`` tag with value ``val``. - :param ShowcaseFileRemovedDetails val: + :param FileRequestCloseDetails val: :rtype: EventDetails """ - return cls('showcase_file_removed_details', val) + return cls('file_request_close_details', val) @classmethod - def showcase_file_view_details(cls, val): + def file_request_create_details(cls, val): """ Create an instance of this class set to the - ``showcase_file_view_details`` tag with value ``val``. + ``file_request_create_details`` tag with value ``val``. - :param ShowcaseFileViewDetails val: + :param FileRequestCreateDetails val: :rtype: EventDetails """ - return cls('showcase_file_view_details', val) + return cls('file_request_create_details', val) @classmethod - def showcase_permanently_deleted_details(cls, val): + def file_request_delete_details(cls, val): """ Create an instance of this class set to the - ``showcase_permanently_deleted_details`` tag with value ``val``. + ``file_request_delete_details`` tag with value ``val``. - :param ShowcasePermanentlyDeletedDetails val: + :param FileRequestDeleteDetails val: :rtype: EventDetails """ - return cls('showcase_permanently_deleted_details', val) + return cls('file_request_delete_details', val) @classmethod - def showcase_post_comment_details(cls, val): + def file_request_receive_file_details(cls, val): """ Create an instance of this class set to the - ``showcase_post_comment_details`` tag with value ``val``. + ``file_request_receive_file_details`` tag with value ``val``. - :param ShowcasePostCommentDetails val: + :param FileRequestReceiveFileDetails val: :rtype: EventDetails """ - return cls('showcase_post_comment_details', val) + return cls('file_request_receive_file_details', val) @classmethod - def showcase_remove_member_details(cls, val): + def group_add_external_id_details(cls, val): """ Create an instance of this class set to the - ``showcase_remove_member_details`` tag with value ``val``. + ``group_add_external_id_details`` tag with value ``val``. - :param ShowcaseRemoveMemberDetails val: + :param GroupAddExternalIdDetails val: :rtype: EventDetails """ - return cls('showcase_remove_member_details', val) + return cls('group_add_external_id_details', val) @classmethod - def showcase_renamed_details(cls, val): + def group_add_member_details(cls, val): """ - Create an instance of this class set to the ``showcase_renamed_details`` + Create an instance of this class set to the ``group_add_member_details`` tag with value ``val``. - :param ShowcaseRenamedDetails val: + :param GroupAddMemberDetails val: :rtype: EventDetails """ - return cls('showcase_renamed_details', val) + return cls('group_add_member_details', val) @classmethod - def showcase_request_access_details(cls, val): + def group_change_external_id_details(cls, val): """ Create an instance of this class set to the - ``showcase_request_access_details`` tag with value ``val``. + ``group_change_external_id_details`` tag with value ``val``. - :param ShowcaseRequestAccessDetails val: + :param GroupChangeExternalIdDetails val: :rtype: EventDetails """ - return cls('showcase_request_access_details', val) + return cls('group_change_external_id_details', val) @classmethod - def showcase_resolve_comment_details(cls, val): + def group_change_management_type_details(cls, val): """ Create an instance of this class set to the - ``showcase_resolve_comment_details`` tag with value ``val``. + ``group_change_management_type_details`` tag with value ``val``. - :param ShowcaseResolveCommentDetails val: + :param GroupChangeManagementTypeDetails val: :rtype: EventDetails """ - return cls('showcase_resolve_comment_details', val) + return cls('group_change_management_type_details', val) @classmethod - def showcase_restored_details(cls, val): + def group_change_member_role_details(cls, val): """ Create an instance of this class set to the - ``showcase_restored_details`` tag with value ``val``. + ``group_change_member_role_details`` tag with value ``val``. - :param ShowcaseRestoredDetails val: + :param GroupChangeMemberRoleDetails val: :rtype: EventDetails """ - return cls('showcase_restored_details', val) + return cls('group_change_member_role_details', val) @classmethod - def showcase_trashed_details(cls, val): + def group_create_details(cls, val): """ - Create an instance of this class set to the ``showcase_trashed_details`` - tag with value ``val``. + Create an instance of this class set to the ``group_create_details`` tag + with value ``val``. - :param ShowcaseTrashedDetails val: + :param GroupCreateDetails val: :rtype: EventDetails """ - return cls('showcase_trashed_details', val) + return cls('group_create_details', val) @classmethod - def showcase_trashed_deprecated_details(cls, val): + def group_delete_details(cls, val): """ - Create an instance of this class set to the - ``showcase_trashed_deprecated_details`` tag with value ``val``. + Create an instance of this class set to the ``group_delete_details`` tag + with value ``val``. - :param ShowcaseTrashedDeprecatedDetails val: + :param GroupDeleteDetails val: :rtype: EventDetails """ - return cls('showcase_trashed_deprecated_details', val) + return cls('group_delete_details', val) @classmethod - def showcase_unresolve_comment_details(cls, val): + def group_description_updated_details(cls, val): """ Create an instance of this class set to the - ``showcase_unresolve_comment_details`` tag with value ``val``. + ``group_description_updated_details`` tag with value ``val``. - :param ShowcaseUnresolveCommentDetails val: + :param GroupDescriptionUpdatedDetails val: :rtype: EventDetails """ - return cls('showcase_unresolve_comment_details', val) + return cls('group_description_updated_details', val) @classmethod - def showcase_untrashed_details(cls, val): + def group_join_policy_updated_details(cls, val): """ Create an instance of this class set to the - ``showcase_untrashed_details`` tag with value ``val``. + ``group_join_policy_updated_details`` tag with value ``val``. - :param ShowcaseUntrashedDetails val: + :param GroupJoinPolicyUpdatedDetails val: :rtype: EventDetails """ - return cls('showcase_untrashed_details', val) + return cls('group_join_policy_updated_details', val) @classmethod - def showcase_untrashed_deprecated_details(cls, val): + def group_moved_details(cls, val): """ - Create an instance of this class set to the - ``showcase_untrashed_deprecated_details`` tag with value ``val``. + Create an instance of this class set to the ``group_moved_details`` tag + with value ``val``. - :param ShowcaseUntrashedDeprecatedDetails val: + :param GroupMovedDetails val: :rtype: EventDetails """ - return cls('showcase_untrashed_deprecated_details', val) + return cls('group_moved_details', val) @classmethod - def showcase_view_details(cls, val): + def group_remove_external_id_details(cls, val): """ - Create an instance of this class set to the ``showcase_view_details`` - tag with value ``val``. + Create an instance of this class set to the + ``group_remove_external_id_details`` tag with value ``val``. - :param ShowcaseViewDetails val: + :param GroupRemoveExternalIdDetails val: :rtype: EventDetails """ - return cls('showcase_view_details', val) + return cls('group_remove_external_id_details', val) @classmethod - def sso_add_cert_details(cls, val): + def group_remove_member_details(cls, val): """ - Create an instance of this class set to the ``sso_add_cert_details`` tag - with value ``val``. + Create an instance of this class set to the + ``group_remove_member_details`` tag with value ``val``. - :param SsoAddCertDetails val: + :param GroupRemoveMemberDetails val: :rtype: EventDetails """ - return cls('sso_add_cert_details', val) + return cls('group_remove_member_details', val) @classmethod - def sso_add_login_url_details(cls, val): + def group_rename_details(cls, val): """ - Create an instance of this class set to the - ``sso_add_login_url_details`` tag with value ``val``. + Create an instance of this class set to the ``group_rename_details`` tag + with value ``val``. - :param SsoAddLoginUrlDetails val: + :param GroupRenameDetails val: :rtype: EventDetails """ - return cls('sso_add_login_url_details', val) + return cls('group_rename_details', val) @classmethod - def sso_add_logout_url_details(cls, val): + def legal_holds_activate_a_hold_details(cls, val): """ Create an instance of this class set to the - ``sso_add_logout_url_details`` tag with value ``val``. + ``legal_holds_activate_a_hold_details`` tag with value ``val``. - :param SsoAddLogoutUrlDetails val: + :param LegalHoldsActivateAHoldDetails val: :rtype: EventDetails """ - return cls('sso_add_logout_url_details', val) + return cls('legal_holds_activate_a_hold_details', val) @classmethod - def sso_change_cert_details(cls, val): + def legal_holds_add_members_details(cls, val): """ - Create an instance of this class set to the ``sso_change_cert_details`` - tag with value ``val``. + Create an instance of this class set to the + ``legal_holds_add_members_details`` tag with value ``val``. - :param SsoChangeCertDetails val: + :param LegalHoldsAddMembersDetails val: :rtype: EventDetails """ - return cls('sso_change_cert_details', val) + return cls('legal_holds_add_members_details', val) @classmethod - def sso_change_login_url_details(cls, val): + def legal_holds_change_hold_details_details(cls, val): """ Create an instance of this class set to the - ``sso_change_login_url_details`` tag with value ``val``. + ``legal_holds_change_hold_details_details`` tag with value ``val``. - :param SsoChangeLoginUrlDetails val: + :param LegalHoldsChangeHoldDetailsDetails val: :rtype: EventDetails """ - return cls('sso_change_login_url_details', val) + return cls('legal_holds_change_hold_details_details', val) @classmethod - def sso_change_logout_url_details(cls, val): + def legal_holds_change_hold_name_details(cls, val): """ Create an instance of this class set to the - ``sso_change_logout_url_details`` tag with value ``val``. + ``legal_holds_change_hold_name_details`` tag with value ``val``. - :param SsoChangeLogoutUrlDetails val: + :param LegalHoldsChangeHoldNameDetails val: :rtype: EventDetails """ - return cls('sso_change_logout_url_details', val) + return cls('legal_holds_change_hold_name_details', val) @classmethod - def sso_change_saml_identity_mode_details(cls, val): + def legal_holds_export_a_hold_details(cls, val): """ Create an instance of this class set to the - ``sso_change_saml_identity_mode_details`` tag with value ``val``. + ``legal_holds_export_a_hold_details`` tag with value ``val``. - :param SsoChangeSamlIdentityModeDetails val: + :param LegalHoldsExportAHoldDetails val: :rtype: EventDetails """ - return cls('sso_change_saml_identity_mode_details', val) + return cls('legal_holds_export_a_hold_details', val) @classmethod - def sso_remove_cert_details(cls, val): + def legal_holds_export_cancelled_details(cls, val): """ - Create an instance of this class set to the ``sso_remove_cert_details`` - tag with value ``val``. + Create an instance of this class set to the + ``legal_holds_export_cancelled_details`` tag with value ``val``. - :param SsoRemoveCertDetails val: + :param LegalHoldsExportCancelledDetails val: :rtype: EventDetails """ - return cls('sso_remove_cert_details', val) + return cls('legal_holds_export_cancelled_details', val) @classmethod - def sso_remove_login_url_details(cls, val): + def legal_holds_export_downloaded_details(cls, val): """ Create an instance of this class set to the - ``sso_remove_login_url_details`` tag with value ``val``. + ``legal_holds_export_downloaded_details`` tag with value ``val``. - :param SsoRemoveLoginUrlDetails val: + :param LegalHoldsExportDownloadedDetails val: :rtype: EventDetails """ - return cls('sso_remove_login_url_details', val) + return cls('legal_holds_export_downloaded_details', val) @classmethod - def sso_remove_logout_url_details(cls, val): + def legal_holds_export_removed_details(cls, val): """ Create an instance of this class set to the - ``sso_remove_logout_url_details`` tag with value ``val``. + ``legal_holds_export_removed_details`` tag with value ``val``. - :param SsoRemoveLogoutUrlDetails val: + :param LegalHoldsExportRemovedDetails val: :rtype: EventDetails """ - return cls('sso_remove_logout_url_details', val) + return cls('legal_holds_export_removed_details', val) @classmethod - def team_folder_change_status_details(cls, val): + def legal_holds_release_a_hold_details(cls, val): """ Create an instance of this class set to the - ``team_folder_change_status_details`` tag with value ``val``. + ``legal_holds_release_a_hold_details`` tag with value ``val``. - :param TeamFolderChangeStatusDetails val: + :param LegalHoldsReleaseAHoldDetails val: :rtype: EventDetails """ - return cls('team_folder_change_status_details', val) + return cls('legal_holds_release_a_hold_details', val) @classmethod - def team_folder_create_details(cls, val): + def legal_holds_remove_members_details(cls, val): """ Create an instance of this class set to the - ``team_folder_create_details`` tag with value ``val``. + ``legal_holds_remove_members_details`` tag with value ``val``. - :param TeamFolderCreateDetails val: + :param LegalHoldsRemoveMembersDetails val: :rtype: EventDetails """ - return cls('team_folder_create_details', val) + return cls('legal_holds_remove_members_details', val) @classmethod - def team_folder_downgrade_details(cls, val): + def legal_holds_report_a_hold_details(cls, val): """ Create an instance of this class set to the - ``team_folder_downgrade_details`` tag with value ``val``. + ``legal_holds_report_a_hold_details`` tag with value ``val``. - :param TeamFolderDowngradeDetails val: + :param LegalHoldsReportAHoldDetails val: :rtype: EventDetails """ - return cls('team_folder_downgrade_details', val) + return cls('legal_holds_report_a_hold_details', val) @classmethod - def team_folder_permanently_delete_details(cls, val): + def account_lock_or_unlocked_details(cls, val): """ Create an instance of this class set to the - ``team_folder_permanently_delete_details`` tag with value ``val``. + ``account_lock_or_unlocked_details`` tag with value ``val``. - :param TeamFolderPermanentlyDeleteDetails val: + :param AccountLockOrUnlockedDetails val: :rtype: EventDetails """ - return cls('team_folder_permanently_delete_details', val) + return cls('account_lock_or_unlocked_details', val) @classmethod - def team_folder_rename_details(cls, val): + def emm_error_details(cls, val): """ - Create an instance of this class set to the - ``team_folder_rename_details`` tag with value ``val``. + Create an instance of this class set to the ``emm_error_details`` tag + with value ``val``. - :param TeamFolderRenameDetails val: + :param EmmErrorDetails val: :rtype: EventDetails """ - return cls('team_folder_rename_details', val) + return cls('emm_error_details', val) @classmethod - def team_selective_sync_settings_changed_details(cls, val): + def guest_admin_signed_in_via_trusted_teams_details(cls, val): """ Create an instance of this class set to the - ``team_selective_sync_settings_changed_details`` tag with value ``val``. + ``guest_admin_signed_in_via_trusted_teams_details`` tag with value + ``val``. - :param TeamSelectiveSyncSettingsChangedDetails val: + :param GuestAdminSignedInViaTrustedTeamsDetails val: :rtype: EventDetails """ - return cls('team_selective_sync_settings_changed_details', val) + return cls('guest_admin_signed_in_via_trusted_teams_details', val) @classmethod - def account_capture_change_policy_details(cls, val): + def guest_admin_signed_out_via_trusted_teams_details(cls, val): """ Create an instance of this class set to the - ``account_capture_change_policy_details`` tag with value ``val``. + ``guest_admin_signed_out_via_trusted_teams_details`` tag with value + ``val``. - :param AccountCaptureChangePolicyDetails val: + :param GuestAdminSignedOutViaTrustedTeamsDetails val: :rtype: EventDetails """ - return cls('account_capture_change_policy_details', val) + return cls('guest_admin_signed_out_via_trusted_teams_details', val) @classmethod - def allow_download_disabled_details(cls, val): + def login_fail_details(cls, val): """ - Create an instance of this class set to the - ``allow_download_disabled_details`` tag with value ``val``. + Create an instance of this class set to the ``login_fail_details`` tag + with value ``val``. - :param AllowDownloadDisabledDetails val: + :param LoginFailDetails val: :rtype: EventDetails """ - return cls('allow_download_disabled_details', val) + return cls('login_fail_details', val) @classmethod - def allow_download_enabled_details(cls, val): + def login_success_details(cls, val): """ - Create an instance of this class set to the - ``allow_download_enabled_details`` tag with value ``val``. + Create an instance of this class set to the ``login_success_details`` + tag with value ``val``. - :param AllowDownloadEnabledDetails val: + :param LoginSuccessDetails val: :rtype: EventDetails """ - return cls('allow_download_enabled_details', val) + return cls('login_success_details', val) @classmethod - def camera_uploads_policy_changed_details(cls, val): + def logout_details(cls, val): """ - Create an instance of this class set to the - ``camera_uploads_policy_changed_details`` tag with value ``val``. + Create an instance of this class set to the ``logout_details`` tag with + value ``val``. - :param CameraUploadsPolicyChangedDetails val: + :param LogoutDetails val: :rtype: EventDetails """ - return cls('camera_uploads_policy_changed_details', val) + return cls('logout_details', val) @classmethod - def data_placement_restriction_change_policy_details(cls, val): + def reseller_support_session_end_details(cls, val): """ Create an instance of this class set to the - ``data_placement_restriction_change_policy_details`` tag with value - ``val``. + ``reseller_support_session_end_details`` tag with value ``val``. - :param DataPlacementRestrictionChangePolicyDetails val: + :param ResellerSupportSessionEndDetails val: :rtype: EventDetails """ - return cls('data_placement_restriction_change_policy_details', val) + return cls('reseller_support_session_end_details', val) @classmethod - def data_placement_restriction_satisfy_policy_details(cls, val): + def reseller_support_session_start_details(cls, val): """ Create an instance of this class set to the - ``data_placement_restriction_satisfy_policy_details`` tag with value - ``val``. + ``reseller_support_session_start_details`` tag with value ``val``. - :param DataPlacementRestrictionSatisfyPolicyDetails val: + :param ResellerSupportSessionStartDetails val: :rtype: EventDetails """ - return cls('data_placement_restriction_satisfy_policy_details', val) + return cls('reseller_support_session_start_details', val) @classmethod - def device_approvals_change_desktop_policy_details(cls, val): + def sign_in_as_session_end_details(cls, val): """ Create an instance of this class set to the - ``device_approvals_change_desktop_policy_details`` tag with value - ``val``. + ``sign_in_as_session_end_details`` tag with value ``val``. - :param DeviceApprovalsChangeDesktopPolicyDetails val: + :param SignInAsSessionEndDetails val: :rtype: EventDetails """ - return cls('device_approvals_change_desktop_policy_details', val) + return cls('sign_in_as_session_end_details', val) @classmethod - def device_approvals_change_mobile_policy_details(cls, val): + def sign_in_as_session_start_details(cls, val): """ Create an instance of this class set to the - ``device_approvals_change_mobile_policy_details`` tag with value - ``val``. + ``sign_in_as_session_start_details`` tag with value ``val``. - :param DeviceApprovalsChangeMobilePolicyDetails val: + :param SignInAsSessionStartDetails val: :rtype: EventDetails """ - return cls('device_approvals_change_mobile_policy_details', val) + return cls('sign_in_as_session_start_details', val) @classmethod - def device_approvals_change_overage_action_details(cls, val): + def sso_error_details(cls, val): """ - Create an instance of this class set to the - ``device_approvals_change_overage_action_details`` tag with value - ``val``. + Create an instance of this class set to the ``sso_error_details`` tag + with value ``val``. - :param DeviceApprovalsChangeOverageActionDetails val: + :param SsoErrorDetails val: :rtype: EventDetails """ - return cls('device_approvals_change_overage_action_details', val) + return cls('sso_error_details', val) @classmethod - def device_approvals_change_unlink_action_details(cls, val): + def create_team_invite_link_details(cls, val): """ Create an instance of this class set to the - ``device_approvals_change_unlink_action_details`` tag with value - ``val``. + ``create_team_invite_link_details`` tag with value ``val``. - :param DeviceApprovalsChangeUnlinkActionDetails val: + :param CreateTeamInviteLinkDetails val: :rtype: EventDetails """ - return cls('device_approvals_change_unlink_action_details', val) + return cls('create_team_invite_link_details', val) @classmethod - def directory_restrictions_add_members_details(cls, val): + def delete_team_invite_link_details(cls, val): """ Create an instance of this class set to the - ``directory_restrictions_add_members_details`` tag with value ``val``. + ``delete_team_invite_link_details`` tag with value ``val``. - :param DirectoryRestrictionsAddMembersDetails val: + :param DeleteTeamInviteLinkDetails val: :rtype: EventDetails """ - return cls('directory_restrictions_add_members_details', val) + return cls('delete_team_invite_link_details', val) @classmethod - def directory_restrictions_remove_members_details(cls, val): + def member_add_external_id_details(cls, val): """ Create an instance of this class set to the - ``directory_restrictions_remove_members_details`` tag with value - ``val``. + ``member_add_external_id_details`` tag with value ``val``. - :param DirectoryRestrictionsRemoveMembersDetails val: + :param MemberAddExternalIdDetails val: :rtype: EventDetails """ - return cls('directory_restrictions_remove_members_details', val) + return cls('member_add_external_id_details', val) @classmethod - def emm_add_exception_details(cls, val): + def member_add_name_details(cls, val): """ - Create an instance of this class set to the - ``emm_add_exception_details`` tag with value ``val``. + Create an instance of this class set to the ``member_add_name_details`` + tag with value ``val``. - :param EmmAddExceptionDetails val: + :param MemberAddNameDetails val: :rtype: EventDetails """ - return cls('emm_add_exception_details', val) + return cls('member_add_name_details', val) @classmethod - def emm_change_policy_details(cls, val): + def member_change_admin_role_details(cls, val): """ Create an instance of this class set to the - ``emm_change_policy_details`` tag with value ``val``. + ``member_change_admin_role_details`` tag with value ``val``. - :param EmmChangePolicyDetails val: + :param MemberChangeAdminRoleDetails val: :rtype: EventDetails """ - return cls('emm_change_policy_details', val) + return cls('member_change_admin_role_details', val) @classmethod - def emm_remove_exception_details(cls, val): + def member_change_email_details(cls, val): """ Create an instance of this class set to the - ``emm_remove_exception_details`` tag with value ``val``. + ``member_change_email_details`` tag with value ``val``. - :param EmmRemoveExceptionDetails val: + :param MemberChangeEmailDetails val: :rtype: EventDetails """ - return cls('emm_remove_exception_details', val) + return cls('member_change_email_details', val) @classmethod - def extended_version_history_change_policy_details(cls, val): + def member_change_external_id_details(cls, val): """ Create an instance of this class set to the - ``extended_version_history_change_policy_details`` tag with value - ``val``. + ``member_change_external_id_details`` tag with value ``val``. - :param ExtendedVersionHistoryChangePolicyDetails val: + :param MemberChangeExternalIdDetails val: :rtype: EventDetails """ - return cls('extended_version_history_change_policy_details', val) + return cls('member_change_external_id_details', val) @classmethod - def file_comments_change_policy_details(cls, val): + def member_change_membership_type_details(cls, val): """ Create an instance of this class set to the - ``file_comments_change_policy_details`` tag with value ``val``. + ``member_change_membership_type_details`` tag with value ``val``. - :param FileCommentsChangePolicyDetails val: + :param MemberChangeMembershipTypeDetails val: :rtype: EventDetails """ - return cls('file_comments_change_policy_details', val) + return cls('member_change_membership_type_details', val) @classmethod - def file_requests_change_policy_details(cls, val): + def member_change_name_details(cls, val): """ Create an instance of this class set to the - ``file_requests_change_policy_details`` tag with value ``val``. + ``member_change_name_details`` tag with value ``val``. - :param FileRequestsChangePolicyDetails val: + :param MemberChangeNameDetails val: :rtype: EventDetails """ - return cls('file_requests_change_policy_details', val) + return cls('member_change_name_details', val) @classmethod - def file_requests_emails_enabled_details(cls, val): + def member_change_status_details(cls, val): """ Create an instance of this class set to the - ``file_requests_emails_enabled_details`` tag with value ``val``. + ``member_change_status_details`` tag with value ``val``. - :param FileRequestsEmailsEnabledDetails val: + :param MemberChangeStatusDetails val: :rtype: EventDetails """ - return cls('file_requests_emails_enabled_details', val) + return cls('member_change_status_details', val) @classmethod - def file_requests_emails_restricted_to_team_only_details(cls, val): + def member_delete_manual_contacts_details(cls, val): """ Create an instance of this class set to the - ``file_requests_emails_restricted_to_team_only_details`` tag with value - ``val``. + ``member_delete_manual_contacts_details`` tag with value ``val``. - :param FileRequestsEmailsRestrictedToTeamOnlyDetails val: + :param MemberDeleteManualContactsDetails val: :rtype: EventDetails """ - return cls('file_requests_emails_restricted_to_team_only_details', val) + return cls('member_delete_manual_contacts_details', val) @classmethod - def google_sso_change_policy_details(cls, val): + def member_delete_profile_photo_details(cls, val): """ Create an instance of this class set to the - ``google_sso_change_policy_details`` tag with value ``val``. + ``member_delete_profile_photo_details`` tag with value ``val``. - :param GoogleSsoChangePolicyDetails val: + :param MemberDeleteProfilePhotoDetails val: :rtype: EventDetails """ - return cls('google_sso_change_policy_details', val) + return cls('member_delete_profile_photo_details', val) @classmethod - def group_user_management_change_policy_details(cls, val): + def member_permanently_delete_account_contents_details(cls, val): """ Create an instance of this class set to the - ``group_user_management_change_policy_details`` tag with value ``val``. + ``member_permanently_delete_account_contents_details`` tag with value + ``val``. - :param GroupUserManagementChangePolicyDetails val: + :param MemberPermanentlyDeleteAccountContentsDetails val: :rtype: EventDetails """ - return cls('group_user_management_change_policy_details', val) + return cls('member_permanently_delete_account_contents_details', val) @classmethod - def integration_policy_changed_details(cls, val): + def member_remove_external_id_details(cls, val): """ Create an instance of this class set to the - ``integration_policy_changed_details`` tag with value ``val``. + ``member_remove_external_id_details`` tag with value ``val``. - :param IntegrationPolicyChangedDetails val: + :param MemberRemoveExternalIdDetails val: :rtype: EventDetails """ - return cls('integration_policy_changed_details', val) + return cls('member_remove_external_id_details', val) @classmethod - def member_requests_change_policy_details(cls, val): + def member_set_profile_photo_details(cls, val): """ Create an instance of this class set to the - ``member_requests_change_policy_details`` tag with value ``val``. + ``member_set_profile_photo_details`` tag with value ``val``. - :param MemberRequestsChangePolicyDetails val: + :param MemberSetProfilePhotoDetails val: :rtype: EventDetails """ - return cls('member_requests_change_policy_details', val) + return cls('member_set_profile_photo_details', val) @classmethod - def member_space_limits_add_exception_details(cls, val): + def member_space_limits_add_custom_quota_details(cls, val): """ Create an instance of this class set to the - ``member_space_limits_add_exception_details`` tag with value ``val``. + ``member_space_limits_add_custom_quota_details`` tag with value ``val``. - :param MemberSpaceLimitsAddExceptionDetails val: + :param MemberSpaceLimitsAddCustomQuotaDetails val: :rtype: EventDetails """ - return cls('member_space_limits_add_exception_details', val) + return cls('member_space_limits_add_custom_quota_details', val) @classmethod - def member_space_limits_change_caps_type_policy_details(cls, val): + def member_space_limits_change_custom_quota_details(cls, val): """ Create an instance of this class set to the - ``member_space_limits_change_caps_type_policy_details`` tag with value + ``member_space_limits_change_custom_quota_details`` tag with value ``val``. - :param MemberSpaceLimitsChangeCapsTypePolicyDetails val: + :param MemberSpaceLimitsChangeCustomQuotaDetails val: :rtype: EventDetails """ - return cls('member_space_limits_change_caps_type_policy_details', val) + return cls('member_space_limits_change_custom_quota_details', val) @classmethod - def member_space_limits_change_policy_details(cls, val): + def member_space_limits_change_status_details(cls, val): """ Create an instance of this class set to the - ``member_space_limits_change_policy_details`` tag with value ``val``. + ``member_space_limits_change_status_details`` tag with value ``val``. - :param MemberSpaceLimitsChangePolicyDetails val: + :param MemberSpaceLimitsChangeStatusDetails val: :rtype: EventDetails """ - return cls('member_space_limits_change_policy_details', val) + return cls('member_space_limits_change_status_details', val) @classmethod - def member_space_limits_remove_exception_details(cls, val): + def member_space_limits_remove_custom_quota_details(cls, val): """ Create an instance of this class set to the - ``member_space_limits_remove_exception_details`` tag with value ``val``. + ``member_space_limits_remove_custom_quota_details`` tag with value + ``val``. - :param MemberSpaceLimitsRemoveExceptionDetails val: + :param MemberSpaceLimitsRemoveCustomQuotaDetails val: :rtype: EventDetails """ - return cls('member_space_limits_remove_exception_details', val) + return cls('member_space_limits_remove_custom_quota_details', val) @classmethod - def member_suggestions_change_policy_details(cls, val): + def member_suggest_details(cls, val): """ - Create an instance of this class set to the - ``member_suggestions_change_policy_details`` tag with value ``val``. + Create an instance of this class set to the ``member_suggest_details`` + tag with value ``val``. - :param MemberSuggestionsChangePolicyDetails val: + :param MemberSuggestDetails val: :rtype: EventDetails """ - return cls('member_suggestions_change_policy_details', val) + return cls('member_suggest_details', val) @classmethod - def microsoft_office_addin_change_policy_details(cls, val): + def member_transfer_account_contents_details(cls, val): """ Create an instance of this class set to the - ``microsoft_office_addin_change_policy_details`` tag with value ``val``. + ``member_transfer_account_contents_details`` tag with value ``val``. - :param MicrosoftOfficeAddinChangePolicyDetails val: + :param MemberTransferAccountContentsDetails val: :rtype: EventDetails """ - return cls('microsoft_office_addin_change_policy_details', val) + return cls('member_transfer_account_contents_details', val) @classmethod - def network_control_change_policy_details(cls, val): + def pending_secondary_email_added_details(cls, val): """ Create an instance of this class set to the - ``network_control_change_policy_details`` tag with value ``val``. + ``pending_secondary_email_added_details`` tag with value ``val``. - :param NetworkControlChangePolicyDetails val: + :param PendingSecondaryEmailAddedDetails val: :rtype: EventDetails """ - return cls('network_control_change_policy_details', val) + return cls('pending_secondary_email_added_details', val) @classmethod - def paper_change_deployment_policy_details(cls, val): + def secondary_email_deleted_details(cls, val): """ Create an instance of this class set to the - ``paper_change_deployment_policy_details`` tag with value ``val``. + ``secondary_email_deleted_details`` tag with value ``val``. - :param PaperChangeDeploymentPolicyDetails val: + :param SecondaryEmailDeletedDetails val: :rtype: EventDetails """ - return cls('paper_change_deployment_policy_details', val) + return cls('secondary_email_deleted_details', val) @classmethod - def paper_change_member_link_policy_details(cls, val): + def secondary_email_verified_details(cls, val): """ Create an instance of this class set to the - ``paper_change_member_link_policy_details`` tag with value ``val``. + ``secondary_email_verified_details`` tag with value ``val``. - :param PaperChangeMemberLinkPolicyDetails val: + :param SecondaryEmailVerifiedDetails val: :rtype: EventDetails """ - return cls('paper_change_member_link_policy_details', val) + return cls('secondary_email_verified_details', val) @classmethod - def paper_change_member_policy_details(cls, val): + def secondary_mails_policy_changed_details(cls, val): """ Create an instance of this class set to the - ``paper_change_member_policy_details`` tag with value ``val``. + ``secondary_mails_policy_changed_details`` tag with value ``val``. - :param PaperChangeMemberPolicyDetails val: + :param SecondaryMailsPolicyChangedDetails val: :rtype: EventDetails """ - return cls('paper_change_member_policy_details', val) + return cls('secondary_mails_policy_changed_details', val) @classmethod - def paper_change_policy_details(cls, val): + def binder_add_page_details(cls, val): """ - Create an instance of this class set to the - ``paper_change_policy_details`` tag with value ``val``. + Create an instance of this class set to the ``binder_add_page_details`` + tag with value ``val``. - :param PaperChangePolicyDetails val: + :param BinderAddPageDetails val: :rtype: EventDetails """ - return cls('paper_change_policy_details', val) + return cls('binder_add_page_details', val) @classmethod - def paper_default_folder_policy_changed_details(cls, val): + def binder_add_section_details(cls, val): """ Create an instance of this class set to the - ``paper_default_folder_policy_changed_details`` tag with value ``val``. + ``binder_add_section_details`` tag with value ``val``. - :param PaperDefaultFolderPolicyChangedDetails val: + :param BinderAddSectionDetails val: :rtype: EventDetails """ - return cls('paper_default_folder_policy_changed_details', val) + return cls('binder_add_section_details', val) @classmethod - def paper_desktop_policy_changed_details(cls, val): + def binder_remove_page_details(cls, val): """ Create an instance of this class set to the - ``paper_desktop_policy_changed_details`` tag with value ``val``. + ``binder_remove_page_details`` tag with value ``val``. - :param PaperDesktopPolicyChangedDetails val: + :param BinderRemovePageDetails val: :rtype: EventDetails """ - return cls('paper_desktop_policy_changed_details', val) + return cls('binder_remove_page_details', val) @classmethod - def paper_enabled_users_group_addition_details(cls, val): + def binder_remove_section_details(cls, val): """ Create an instance of this class set to the - ``paper_enabled_users_group_addition_details`` tag with value ``val``. + ``binder_remove_section_details`` tag with value ``val``. - :param PaperEnabledUsersGroupAdditionDetails val: + :param BinderRemoveSectionDetails val: :rtype: EventDetails """ - return cls('paper_enabled_users_group_addition_details', val) + return cls('binder_remove_section_details', val) @classmethod - def paper_enabled_users_group_removal_details(cls, val): + def binder_rename_page_details(cls, val): """ Create an instance of this class set to the - ``paper_enabled_users_group_removal_details`` tag with value ``val``. + ``binder_rename_page_details`` tag with value ``val``. - :param PaperEnabledUsersGroupRemovalDetails val: + :param BinderRenamePageDetails val: :rtype: EventDetails """ - return cls('paper_enabled_users_group_removal_details', val) + return cls('binder_rename_page_details', val) @classmethod - def permanent_delete_change_policy_details(cls, val): + def binder_rename_section_details(cls, val): """ Create an instance of this class set to the - ``permanent_delete_change_policy_details`` tag with value ``val``. + ``binder_rename_section_details`` tag with value ``val``. - :param PermanentDeleteChangePolicyDetails val: + :param BinderRenameSectionDetails val: :rtype: EventDetails """ - return cls('permanent_delete_change_policy_details', val) + return cls('binder_rename_section_details', val) @classmethod - def reseller_support_change_policy_details(cls, val): + def binder_reorder_page_details(cls, val): """ Create an instance of this class set to the - ``reseller_support_change_policy_details`` tag with value ``val``. + ``binder_reorder_page_details`` tag with value ``val``. - :param ResellerSupportChangePolicyDetails val: + :param BinderReorderPageDetails val: :rtype: EventDetails """ - return cls('reseller_support_change_policy_details', val) + return cls('binder_reorder_page_details', val) @classmethod - def sharing_change_folder_join_policy_details(cls, val): + def binder_reorder_section_details(cls, val): """ Create an instance of this class set to the - ``sharing_change_folder_join_policy_details`` tag with value ``val``. + ``binder_reorder_section_details`` tag with value ``val``. - :param SharingChangeFolderJoinPolicyDetails val: + :param BinderReorderSectionDetails val: :rtype: EventDetails """ - return cls('sharing_change_folder_join_policy_details', val) + return cls('binder_reorder_section_details', val) @classmethod - def sharing_change_link_policy_details(cls, val): + def paper_content_add_member_details(cls, val): """ Create an instance of this class set to the - ``sharing_change_link_policy_details`` tag with value ``val``. + ``paper_content_add_member_details`` tag with value ``val``. - :param SharingChangeLinkPolicyDetails val: + :param PaperContentAddMemberDetails val: :rtype: EventDetails """ - return cls('sharing_change_link_policy_details', val) + return cls('paper_content_add_member_details', val) @classmethod - def sharing_change_member_policy_details(cls, val): + def paper_content_add_to_folder_details(cls, val): """ Create an instance of this class set to the - ``sharing_change_member_policy_details`` tag with value ``val``. + ``paper_content_add_to_folder_details`` tag with value ``val``. - :param SharingChangeMemberPolicyDetails val: + :param PaperContentAddToFolderDetails val: :rtype: EventDetails """ - return cls('sharing_change_member_policy_details', val) + return cls('paper_content_add_to_folder_details', val) @classmethod - def showcase_change_download_policy_details(cls, val): + def paper_content_archive_details(cls, val): """ Create an instance of this class set to the - ``showcase_change_download_policy_details`` tag with value ``val``. + ``paper_content_archive_details`` tag with value ``val``. - :param ShowcaseChangeDownloadPolicyDetails val: + :param PaperContentArchiveDetails val: :rtype: EventDetails """ - return cls('showcase_change_download_policy_details', val) + return cls('paper_content_archive_details', val) @classmethod - def showcase_change_enabled_policy_details(cls, val): + def paper_content_create_details(cls, val): """ Create an instance of this class set to the - ``showcase_change_enabled_policy_details`` tag with value ``val``. + ``paper_content_create_details`` tag with value ``val``. - :param ShowcaseChangeEnabledPolicyDetails val: + :param PaperContentCreateDetails val: :rtype: EventDetails """ - return cls('showcase_change_enabled_policy_details', val) + return cls('paper_content_create_details', val) @classmethod - def showcase_change_external_sharing_policy_details(cls, val): + def paper_content_permanently_delete_details(cls, val): """ Create an instance of this class set to the - ``showcase_change_external_sharing_policy_details`` tag with value - ``val``. + ``paper_content_permanently_delete_details`` tag with value ``val``. - :param ShowcaseChangeExternalSharingPolicyDetails val: + :param PaperContentPermanentlyDeleteDetails val: :rtype: EventDetails """ - return cls('showcase_change_external_sharing_policy_details', val) + return cls('paper_content_permanently_delete_details', val) @classmethod - def smart_sync_change_policy_details(cls, val): + def paper_content_remove_from_folder_details(cls, val): """ Create an instance of this class set to the - ``smart_sync_change_policy_details`` tag with value ``val``. + ``paper_content_remove_from_folder_details`` tag with value ``val``. - :param SmartSyncChangePolicyDetails val: + :param PaperContentRemoveFromFolderDetails val: :rtype: EventDetails """ - return cls('smart_sync_change_policy_details', val) + return cls('paper_content_remove_from_folder_details', val) @classmethod - def smart_sync_not_opt_out_details(cls, val): + def paper_content_remove_member_details(cls, val): """ Create an instance of this class set to the - ``smart_sync_not_opt_out_details`` tag with value ``val``. + ``paper_content_remove_member_details`` tag with value ``val``. - :param SmartSyncNotOptOutDetails val: + :param PaperContentRemoveMemberDetails val: :rtype: EventDetails """ - return cls('smart_sync_not_opt_out_details', val) + return cls('paper_content_remove_member_details', val) @classmethod - def smart_sync_opt_out_details(cls, val): + def paper_content_rename_details(cls, val): """ Create an instance of this class set to the - ``smart_sync_opt_out_details`` tag with value ``val``. + ``paper_content_rename_details`` tag with value ``val``. - :param SmartSyncOptOutDetails val: + :param PaperContentRenameDetails val: :rtype: EventDetails """ - return cls('smart_sync_opt_out_details', val) + return cls('paper_content_rename_details', val) @classmethod - def sso_change_policy_details(cls, val): + def paper_content_restore_details(cls, val): """ Create an instance of this class set to the - ``sso_change_policy_details`` tag with value ``val``. + ``paper_content_restore_details`` tag with value ``val``. - :param SsoChangePolicyDetails val: + :param PaperContentRestoreDetails val: :rtype: EventDetails """ - return cls('sso_change_policy_details', val) + return cls('paper_content_restore_details', val) @classmethod - def team_extensions_policy_changed_details(cls, val): + def paper_doc_add_comment_details(cls, val): """ Create an instance of this class set to the - ``team_extensions_policy_changed_details`` tag with value ``val``. + ``paper_doc_add_comment_details`` tag with value ``val``. - :param TeamExtensionsPolicyChangedDetails val: + :param PaperDocAddCommentDetails val: :rtype: EventDetails """ - return cls('team_extensions_policy_changed_details', val) + return cls('paper_doc_add_comment_details', val) @classmethod - def team_selective_sync_policy_changed_details(cls, val): + def paper_doc_change_member_role_details(cls, val): """ Create an instance of this class set to the - ``team_selective_sync_policy_changed_details`` tag with value ``val``. + ``paper_doc_change_member_role_details`` tag with value ``val``. - :param TeamSelectiveSyncPolicyChangedDetails val: + :param PaperDocChangeMemberRoleDetails val: :rtype: EventDetails """ - return cls('team_selective_sync_policy_changed_details', val) + return cls('paper_doc_change_member_role_details', val) @classmethod - def tfa_change_policy_details(cls, val): + def paper_doc_change_sharing_policy_details(cls, val): """ Create an instance of this class set to the - ``tfa_change_policy_details`` tag with value ``val``. + ``paper_doc_change_sharing_policy_details`` tag with value ``val``. - :param TfaChangePolicyDetails val: + :param PaperDocChangeSharingPolicyDetails val: :rtype: EventDetails """ - return cls('tfa_change_policy_details', val) + return cls('paper_doc_change_sharing_policy_details', val) @classmethod - def two_account_change_policy_details(cls, val): + def paper_doc_change_subscription_details(cls, val): """ Create an instance of this class set to the - ``two_account_change_policy_details`` tag with value ``val``. + ``paper_doc_change_subscription_details`` tag with value ``val``. - :param TwoAccountChangePolicyDetails val: + :param PaperDocChangeSubscriptionDetails val: :rtype: EventDetails """ - return cls('two_account_change_policy_details', val) + return cls('paper_doc_change_subscription_details', val) @classmethod - def viewer_info_policy_changed_details(cls, val): + def paper_doc_deleted_details(cls, val): """ Create an instance of this class set to the - ``viewer_info_policy_changed_details`` tag with value ``val``. + ``paper_doc_deleted_details`` tag with value ``val``. - :param ViewerInfoPolicyChangedDetails val: + :param PaperDocDeletedDetails val: :rtype: EventDetails """ - return cls('viewer_info_policy_changed_details', val) + return cls('paper_doc_deleted_details', val) @classmethod - def web_sessions_change_fixed_length_policy_details(cls, val): + def paper_doc_delete_comment_details(cls, val): """ Create an instance of this class set to the - ``web_sessions_change_fixed_length_policy_details`` tag with value - ``val``. + ``paper_doc_delete_comment_details`` tag with value ``val``. - :param WebSessionsChangeFixedLengthPolicyDetails val: + :param PaperDocDeleteCommentDetails val: :rtype: EventDetails """ - return cls('web_sessions_change_fixed_length_policy_details', val) + return cls('paper_doc_delete_comment_details', val) @classmethod - def web_sessions_change_idle_length_policy_details(cls, val): + def paper_doc_download_details(cls, val): """ Create an instance of this class set to the - ``web_sessions_change_idle_length_policy_details`` tag with value - ``val``. + ``paper_doc_download_details`` tag with value ``val``. - :param WebSessionsChangeIdleLengthPolicyDetails val: + :param PaperDocDownloadDetails val: :rtype: EventDetails """ - return cls('web_sessions_change_idle_length_policy_details', val) + return cls('paper_doc_download_details', val) @classmethod - def team_merge_from_details(cls, val): + def paper_doc_edit_details(cls, val): """ - Create an instance of this class set to the ``team_merge_from_details`` + Create an instance of this class set to the ``paper_doc_edit_details`` tag with value ``val``. - :param TeamMergeFromDetails val: + :param PaperDocEditDetails val: :rtype: EventDetails """ - return cls('team_merge_from_details', val) + return cls('paper_doc_edit_details', val) @classmethod - def team_merge_to_details(cls, val): + def paper_doc_edit_comment_details(cls, val): """ - Create an instance of this class set to the ``team_merge_to_details`` - tag with value ``val``. + Create an instance of this class set to the + ``paper_doc_edit_comment_details`` tag with value ``val``. - :param TeamMergeToDetails val: + :param PaperDocEditCommentDetails val: :rtype: EventDetails """ - return cls('team_merge_to_details', val) + return cls('paper_doc_edit_comment_details', val) @classmethod - def team_profile_add_logo_details(cls, val): + def paper_doc_followed_details(cls, val): """ Create an instance of this class set to the - ``team_profile_add_logo_details`` tag with value ``val``. + ``paper_doc_followed_details`` tag with value ``val``. - :param TeamProfileAddLogoDetails val: + :param PaperDocFollowedDetails val: :rtype: EventDetails """ - return cls('team_profile_add_logo_details', val) + return cls('paper_doc_followed_details', val) @classmethod - def team_profile_change_default_language_details(cls, val): + def paper_doc_mention_details(cls, val): """ Create an instance of this class set to the - ``team_profile_change_default_language_details`` tag with value ``val``. + ``paper_doc_mention_details`` tag with value ``val``. - :param TeamProfileChangeDefaultLanguageDetails val: + :param PaperDocMentionDetails val: :rtype: EventDetails """ - return cls('team_profile_change_default_language_details', val) + return cls('paper_doc_mention_details', val) @classmethod - def team_profile_change_logo_details(cls, val): + def paper_doc_ownership_changed_details(cls, val): """ Create an instance of this class set to the - ``team_profile_change_logo_details`` tag with value ``val``. + ``paper_doc_ownership_changed_details`` tag with value ``val``. - :param TeamProfileChangeLogoDetails val: + :param PaperDocOwnershipChangedDetails val: :rtype: EventDetails """ - return cls('team_profile_change_logo_details', val) + return cls('paper_doc_ownership_changed_details', val) @classmethod - def team_profile_change_name_details(cls, val): + def paper_doc_request_access_details(cls, val): """ Create an instance of this class set to the - ``team_profile_change_name_details`` tag with value ``val``. + ``paper_doc_request_access_details`` tag with value ``val``. - :param TeamProfileChangeNameDetails val: + :param PaperDocRequestAccessDetails val: :rtype: EventDetails """ - return cls('team_profile_change_name_details', val) + return cls('paper_doc_request_access_details', val) @classmethod - def team_profile_remove_logo_details(cls, val): + def paper_doc_resolve_comment_details(cls, val): """ Create an instance of this class set to the - ``team_profile_remove_logo_details`` tag with value ``val``. + ``paper_doc_resolve_comment_details`` tag with value ``val``. - :param TeamProfileRemoveLogoDetails val: + :param PaperDocResolveCommentDetails val: :rtype: EventDetails """ - return cls('team_profile_remove_logo_details', val) + return cls('paper_doc_resolve_comment_details', val) @classmethod - def tfa_add_backup_phone_details(cls, val): + def paper_doc_revert_details(cls, val): """ - Create an instance of this class set to the - ``tfa_add_backup_phone_details`` tag with value ``val``. + Create an instance of this class set to the ``paper_doc_revert_details`` + tag with value ``val``. - :param TfaAddBackupPhoneDetails val: + :param PaperDocRevertDetails val: :rtype: EventDetails """ - return cls('tfa_add_backup_phone_details', val) + return cls('paper_doc_revert_details', val) @classmethod - def tfa_add_security_key_details(cls, val): + def paper_doc_slack_share_details(cls, val): """ Create an instance of this class set to the - ``tfa_add_security_key_details`` tag with value ``val``. + ``paper_doc_slack_share_details`` tag with value ``val``. - :param TfaAddSecurityKeyDetails val: + :param PaperDocSlackShareDetails val: :rtype: EventDetails """ - return cls('tfa_add_security_key_details', val) + return cls('paper_doc_slack_share_details', val) @classmethod - def tfa_change_backup_phone_details(cls, val): + def paper_doc_team_invite_details(cls, val): """ Create an instance of this class set to the - ``tfa_change_backup_phone_details`` tag with value ``val``. + ``paper_doc_team_invite_details`` tag with value ``val``. - :param TfaChangeBackupPhoneDetails val: + :param PaperDocTeamInviteDetails val: :rtype: EventDetails """ - return cls('tfa_change_backup_phone_details', val) + return cls('paper_doc_team_invite_details', val) @classmethod - def tfa_change_status_details(cls, val): + def paper_doc_trashed_details(cls, val): """ Create an instance of this class set to the - ``tfa_change_status_details`` tag with value ``val``. + ``paper_doc_trashed_details`` tag with value ``val``. - :param TfaChangeStatusDetails val: + :param PaperDocTrashedDetails val: :rtype: EventDetails """ - return cls('tfa_change_status_details', val) + return cls('paper_doc_trashed_details', val) @classmethod - def tfa_remove_backup_phone_details(cls, val): + def paper_doc_unresolve_comment_details(cls, val): """ Create an instance of this class set to the - ``tfa_remove_backup_phone_details`` tag with value ``val``. + ``paper_doc_unresolve_comment_details`` tag with value ``val``. - :param TfaRemoveBackupPhoneDetails val: + :param PaperDocUnresolveCommentDetails val: :rtype: EventDetails """ - return cls('tfa_remove_backup_phone_details', val) + return cls('paper_doc_unresolve_comment_details', val) @classmethod - def tfa_remove_security_key_details(cls, val): + def paper_doc_untrashed_details(cls, val): """ Create an instance of this class set to the - ``tfa_remove_security_key_details`` tag with value ``val``. + ``paper_doc_untrashed_details`` tag with value ``val``. - :param TfaRemoveSecurityKeyDetails val: + :param PaperDocUntrashedDetails val: :rtype: EventDetails """ - return cls('tfa_remove_security_key_details', val) + return cls('paper_doc_untrashed_details', val) @classmethod - def tfa_reset_details(cls, val): + def paper_doc_view_details(cls, val): """ - Create an instance of this class set to the ``tfa_reset_details`` tag - with value ``val``. + Create an instance of this class set to the ``paper_doc_view_details`` + tag with value ``val``. - :param TfaResetDetails val: + :param PaperDocViewDetails val: :rtype: EventDetails """ - return cls('tfa_reset_details', val) + return cls('paper_doc_view_details', val) @classmethod - def guest_admin_change_status_details(cls, val): + def paper_external_view_allow_details(cls, val): """ Create an instance of this class set to the - ``guest_admin_change_status_details`` tag with value ``val``. + ``paper_external_view_allow_details`` tag with value ``val``. - :param GuestAdminChangeStatusDetails val: + :param PaperExternalViewAllowDetails val: :rtype: EventDetails """ - return cls('guest_admin_change_status_details', val) + return cls('paper_external_view_allow_details', val) @classmethod - def team_merge_request_accepted_details(cls, val): + def paper_external_view_default_team_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_accepted_details`` tag with value ``val``. + ``paper_external_view_default_team_details`` tag with value ``val``. - :param TeamMergeRequestAcceptedDetails val: + :param PaperExternalViewDefaultTeamDetails val: :rtype: EventDetails """ - return cls('team_merge_request_accepted_details', val) + return cls('paper_external_view_default_team_details', val) @classmethod - def team_merge_request_accepted_shown_to_primary_team_details(cls, val): + def paper_external_view_forbid_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_accepted_shown_to_primary_team_details`` tag with - value ``val``. + ``paper_external_view_forbid_details`` tag with value ``val``. - :param TeamMergeRequestAcceptedShownToPrimaryTeamDetails val: + :param PaperExternalViewForbidDetails val: :rtype: EventDetails """ - return cls('team_merge_request_accepted_shown_to_primary_team_details', val) + return cls('paper_external_view_forbid_details', val) @classmethod - def team_merge_request_accepted_shown_to_secondary_team_details(cls, val): + def paper_folder_change_subscription_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_accepted_shown_to_secondary_team_details`` tag with - value ``val``. + ``paper_folder_change_subscription_details`` tag with value ``val``. - :param TeamMergeRequestAcceptedShownToSecondaryTeamDetails val: + :param PaperFolderChangeSubscriptionDetails val: :rtype: EventDetails """ - return cls('team_merge_request_accepted_shown_to_secondary_team_details', val) + return cls('paper_folder_change_subscription_details', val) @classmethod - def team_merge_request_auto_canceled_details(cls, val): + def paper_folder_deleted_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_auto_canceled_details`` tag with value ``val``. + ``paper_folder_deleted_details`` tag with value ``val``. - :param TeamMergeRequestAutoCanceledDetails val: + :param PaperFolderDeletedDetails val: :rtype: EventDetails """ - return cls('team_merge_request_auto_canceled_details', val) + return cls('paper_folder_deleted_details', val) @classmethod - def team_merge_request_canceled_details(cls, val): + def paper_folder_followed_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_canceled_details`` tag with value ``val``. + ``paper_folder_followed_details`` tag with value ``val``. - :param TeamMergeRequestCanceledDetails val: + :param PaperFolderFollowedDetails val: :rtype: EventDetails """ - return cls('team_merge_request_canceled_details', val) + return cls('paper_folder_followed_details', val) @classmethod - def team_merge_request_canceled_shown_to_primary_team_details(cls, val): + def paper_folder_team_invite_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_canceled_shown_to_primary_team_details`` tag with - value ``val``. + ``paper_folder_team_invite_details`` tag with value ``val``. - :param TeamMergeRequestCanceledShownToPrimaryTeamDetails val: + :param PaperFolderTeamInviteDetails val: :rtype: EventDetails """ - return cls('team_merge_request_canceled_shown_to_primary_team_details', val) + return cls('paper_folder_team_invite_details', val) @classmethod - def team_merge_request_canceled_shown_to_secondary_team_details(cls, val): + def paper_published_link_change_permission_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_canceled_shown_to_secondary_team_details`` tag with - value ``val``. + ``paper_published_link_change_permission_details`` tag with value + ``val``. - :param TeamMergeRequestCanceledShownToSecondaryTeamDetails val: + :param PaperPublishedLinkChangePermissionDetails val: :rtype: EventDetails """ - return cls('team_merge_request_canceled_shown_to_secondary_team_details', val) + return cls('paper_published_link_change_permission_details', val) @classmethod - def team_merge_request_expired_details(cls, val): + def paper_published_link_create_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_expired_details`` tag with value ``val``. + ``paper_published_link_create_details`` tag with value ``val``. - :param TeamMergeRequestExpiredDetails val: + :param PaperPublishedLinkCreateDetails val: :rtype: EventDetails """ - return cls('team_merge_request_expired_details', val) + return cls('paper_published_link_create_details', val) @classmethod - def team_merge_request_expired_shown_to_primary_team_details(cls, val): + def paper_published_link_disabled_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_expired_shown_to_primary_team_details`` tag with - value ``val``. + ``paper_published_link_disabled_details`` tag with value ``val``. - :param TeamMergeRequestExpiredShownToPrimaryTeamDetails val: + :param PaperPublishedLinkDisabledDetails val: :rtype: EventDetails """ - return cls('team_merge_request_expired_shown_to_primary_team_details', val) + return cls('paper_published_link_disabled_details', val) @classmethod - def team_merge_request_expired_shown_to_secondary_team_details(cls, val): + def paper_published_link_view_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_expired_shown_to_secondary_team_details`` tag with - value ``val``. + ``paper_published_link_view_details`` tag with value ``val``. - :param TeamMergeRequestExpiredShownToSecondaryTeamDetails val: + :param PaperPublishedLinkViewDetails val: :rtype: EventDetails """ - return cls('team_merge_request_expired_shown_to_secondary_team_details', val) + return cls('paper_published_link_view_details', val) @classmethod - def team_merge_request_rejected_shown_to_primary_team_details(cls, val): + def password_change_details(cls, val): """ - Create an instance of this class set to the - ``team_merge_request_rejected_shown_to_primary_team_details`` tag with - value ``val``. + Create an instance of this class set to the ``password_change_details`` + tag with value ``val``. - :param TeamMergeRequestRejectedShownToPrimaryTeamDetails val: + :param PasswordChangeDetails val: :rtype: EventDetails """ - return cls('team_merge_request_rejected_shown_to_primary_team_details', val) + return cls('password_change_details', val) @classmethod - def team_merge_request_rejected_shown_to_secondary_team_details(cls, val): + def password_reset_details(cls, val): """ - Create an instance of this class set to the - ``team_merge_request_rejected_shown_to_secondary_team_details`` tag with - value ``val``. + Create an instance of this class set to the ``password_reset_details`` + tag with value ``val``. - :param TeamMergeRequestRejectedShownToSecondaryTeamDetails val: + :param PasswordResetDetails val: :rtype: EventDetails """ - return cls('team_merge_request_rejected_shown_to_secondary_team_details', val) + return cls('password_reset_details', val) @classmethod - def team_merge_request_reminder_details(cls, val): + def password_reset_all_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_reminder_details`` tag with value ``val``. + ``password_reset_all_details`` tag with value ``val``. - :param TeamMergeRequestReminderDetails val: + :param PasswordResetAllDetails val: :rtype: EventDetails """ - return cls('team_merge_request_reminder_details', val) + return cls('password_reset_all_details', val) @classmethod - def team_merge_request_reminder_shown_to_primary_team_details(cls, val): + def emm_create_exceptions_report_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_reminder_shown_to_primary_team_details`` tag with - value ``val``. + ``emm_create_exceptions_report_details`` tag with value ``val``. - :param TeamMergeRequestReminderShownToPrimaryTeamDetails val: + :param EmmCreateExceptionsReportDetails val: :rtype: EventDetails """ - return cls('team_merge_request_reminder_shown_to_primary_team_details', val) + return cls('emm_create_exceptions_report_details', val) @classmethod - def team_merge_request_reminder_shown_to_secondary_team_details(cls, val): + def emm_create_usage_report_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_reminder_shown_to_secondary_team_details`` tag with - value ``val``. + ``emm_create_usage_report_details`` tag with value ``val``. - :param TeamMergeRequestReminderShownToSecondaryTeamDetails val: + :param EmmCreateUsageReportDetails val: :rtype: EventDetails """ - return cls('team_merge_request_reminder_shown_to_secondary_team_details', val) + return cls('emm_create_usage_report_details', val) @classmethod - def team_merge_request_revoked_details(cls, val): + def export_members_report_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_revoked_details`` tag with value ``val``. + ``export_members_report_details`` tag with value ``val``. - :param TeamMergeRequestRevokedDetails val: + :param ExportMembersReportDetails val: :rtype: EventDetails """ - return cls('team_merge_request_revoked_details', val) + return cls('export_members_report_details', val) @classmethod - def team_merge_request_sent_shown_to_primary_team_details(cls, val): + def export_members_report_fail_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_sent_shown_to_primary_team_details`` tag with value - ``val``. + ``export_members_report_fail_details`` tag with value ``val``. - :param TeamMergeRequestSentShownToPrimaryTeamDetails val: + :param ExportMembersReportFailDetails val: :rtype: EventDetails """ - return cls('team_merge_request_sent_shown_to_primary_team_details', val) + return cls('export_members_report_fail_details', val) @classmethod - def team_merge_request_sent_shown_to_secondary_team_details(cls, val): + def no_expiration_link_gen_create_report_details(cls, val): """ Create an instance of this class set to the - ``team_merge_request_sent_shown_to_secondary_team_details`` tag with - value ``val``. + ``no_expiration_link_gen_create_report_details`` tag with value ``val``. - :param TeamMergeRequestSentShownToSecondaryTeamDetails val: + :param NoExpirationLinkGenCreateReportDetails val: :rtype: EventDetails """ - return cls('team_merge_request_sent_shown_to_secondary_team_details', val) + return cls('no_expiration_link_gen_create_report_details', val) @classmethod - def missing_details(cls, val): + def no_expiration_link_gen_report_failed_details(cls, val): """ - Create an instance of this class set to the ``missing_details`` tag with - value ``val``. + Create an instance of this class set to the + ``no_expiration_link_gen_report_failed_details`` tag with value ``val``. - :param MissingDetails val: + :param NoExpirationLinkGenReportFailedDetails val: :rtype: EventDetails """ - return cls('missing_details', val) + return cls('no_expiration_link_gen_report_failed_details', val) - def is_app_link_team_details(self): + @classmethod + def no_password_link_gen_create_report_details(cls, val): """ - Check if the union tag is ``app_link_team_details``. + Create an instance of this class set to the + ``no_password_link_gen_create_report_details`` tag with value ``val``. - :rtype: bool + :param NoPasswordLinkGenCreateReportDetails val: + :rtype: EventDetails """ - return self._tag == 'app_link_team_details' + return cls('no_password_link_gen_create_report_details', val) - def is_app_link_user_details(self): + @classmethod + def no_password_link_gen_report_failed_details(cls, val): """ - Check if the union tag is ``app_link_user_details``. + Create an instance of this class set to the + ``no_password_link_gen_report_failed_details`` tag with value ``val``. - :rtype: bool + :param NoPasswordLinkGenReportFailedDetails val: + :rtype: EventDetails """ - return self._tag == 'app_link_user_details' + return cls('no_password_link_gen_report_failed_details', val) - def is_app_unlink_team_details(self): + @classmethod + def no_password_link_view_create_report_details(cls, val): """ - Check if the union tag is ``app_unlink_team_details``. + Create an instance of this class set to the + ``no_password_link_view_create_report_details`` tag with value ``val``. - :rtype: bool + :param NoPasswordLinkViewCreateReportDetails val: + :rtype: EventDetails """ - return self._tag == 'app_unlink_team_details' + return cls('no_password_link_view_create_report_details', val) - def is_app_unlink_user_details(self): + @classmethod + def no_password_link_view_report_failed_details(cls, val): """ - Check if the union tag is ``app_unlink_user_details``. + Create an instance of this class set to the + ``no_password_link_view_report_failed_details`` tag with value ``val``. - :rtype: bool + :param NoPasswordLinkViewReportFailedDetails val: + :rtype: EventDetails """ - return self._tag == 'app_unlink_user_details' + return cls('no_password_link_view_report_failed_details', val) - def is_integration_connected_details(self): + @classmethod + def outdated_link_view_create_report_details(cls, val): """ - Check if the union tag is ``integration_connected_details``. + Create an instance of this class set to the + ``outdated_link_view_create_report_details`` tag with value ``val``. - :rtype: bool + :param OutdatedLinkViewCreateReportDetails val: + :rtype: EventDetails """ - return self._tag == 'integration_connected_details' + return cls('outdated_link_view_create_report_details', val) - def is_integration_disconnected_details(self): + @classmethod + def outdated_link_view_report_failed_details(cls, val): """ - Check if the union tag is ``integration_disconnected_details``. + Create an instance of this class set to the + ``outdated_link_view_report_failed_details`` tag with value ``val``. - :rtype: bool + :param OutdatedLinkViewReportFailedDetails val: + :rtype: EventDetails """ - return self._tag == 'integration_disconnected_details' + return cls('outdated_link_view_report_failed_details', val) - def is_file_add_comment_details(self): + @classmethod + def paper_admin_export_start_details(cls, val): """ - Check if the union tag is ``file_add_comment_details``. + Create an instance of this class set to the + ``paper_admin_export_start_details`` tag with value ``val``. - :rtype: bool + :param PaperAdminExportStartDetails val: + :rtype: EventDetails """ - return self._tag == 'file_add_comment_details' + return cls('paper_admin_export_start_details', val) - def is_file_change_comment_subscription_details(self): + @classmethod + def smart_sync_create_admin_privilege_report_details(cls, val): """ - Check if the union tag is ``file_change_comment_subscription_details``. + Create an instance of this class set to the + ``smart_sync_create_admin_privilege_report_details`` tag with value + ``val``. - :rtype: bool + :param SmartSyncCreateAdminPrivilegeReportDetails val: + :rtype: EventDetails """ - return self._tag == 'file_change_comment_subscription_details' + return cls('smart_sync_create_admin_privilege_report_details', val) - def is_file_delete_comment_details(self): + @classmethod + def team_activity_create_report_details(cls, val): """ - Check if the union tag is ``file_delete_comment_details``. + Create an instance of this class set to the + ``team_activity_create_report_details`` tag with value ``val``. - :rtype: bool + :param TeamActivityCreateReportDetails val: + :rtype: EventDetails """ - return self._tag == 'file_delete_comment_details' + return cls('team_activity_create_report_details', val) - def is_file_edit_comment_details(self): + @classmethod + def team_activity_create_report_fail_details(cls, val): """ - Check if the union tag is ``file_edit_comment_details``. + Create an instance of this class set to the + ``team_activity_create_report_fail_details`` tag with value ``val``. - :rtype: bool + :param TeamActivityCreateReportFailDetails val: + :rtype: EventDetails """ - return self._tag == 'file_edit_comment_details' + return cls('team_activity_create_report_fail_details', val) - def is_file_like_comment_details(self): + @classmethod + def collection_share_details(cls, val): """ - Check if the union tag is ``file_like_comment_details``. + Create an instance of this class set to the ``collection_share_details`` + tag with value ``val``. - :rtype: bool + :param CollectionShareDetails val: + :rtype: EventDetails """ - return self._tag == 'file_like_comment_details' + return cls('collection_share_details', val) - def is_file_resolve_comment_details(self): + @classmethod + def file_transfers_file_add_details(cls, val): """ - Check if the union tag is ``file_resolve_comment_details``. + Create an instance of this class set to the + ``file_transfers_file_add_details`` tag with value ``val``. - :rtype: bool + :param FileTransfersFileAddDetails val: + :rtype: EventDetails """ - return self._tag == 'file_resolve_comment_details' + return cls('file_transfers_file_add_details', val) - def is_file_unlike_comment_details(self): + @classmethod + def file_transfers_transfer_delete_details(cls, val): """ - Check if the union tag is ``file_unlike_comment_details``. + Create an instance of this class set to the + ``file_transfers_transfer_delete_details`` tag with value ``val``. - :rtype: bool + :param FileTransfersTransferDeleteDetails val: + :rtype: EventDetails """ - return self._tag == 'file_unlike_comment_details' + return cls('file_transfers_transfer_delete_details', val) - def is_file_unresolve_comment_details(self): + @classmethod + def file_transfers_transfer_download_details(cls, val): """ - Check if the union tag is ``file_unresolve_comment_details``. + Create an instance of this class set to the + ``file_transfers_transfer_download_details`` tag with value ``val``. - :rtype: bool + :param FileTransfersTransferDownloadDetails val: + :rtype: EventDetails """ - return self._tag == 'file_unresolve_comment_details' + return cls('file_transfers_transfer_download_details', val) - def is_device_change_ip_desktop_details(self): + @classmethod + def file_transfers_transfer_send_details(cls, val): """ - Check if the union tag is ``device_change_ip_desktop_details``. + Create an instance of this class set to the + ``file_transfers_transfer_send_details`` tag with value ``val``. - :rtype: bool + :param FileTransfersTransferSendDetails val: + :rtype: EventDetails """ - return self._tag == 'device_change_ip_desktop_details' + return cls('file_transfers_transfer_send_details', val) - def is_device_change_ip_mobile_details(self): + @classmethod + def file_transfers_transfer_view_details(cls, val): """ - Check if the union tag is ``device_change_ip_mobile_details``. + Create an instance of this class set to the + ``file_transfers_transfer_view_details`` tag with value ``val``. - :rtype: bool + :param FileTransfersTransferViewDetails val: + :rtype: EventDetails """ - return self._tag == 'device_change_ip_mobile_details' + return cls('file_transfers_transfer_view_details', val) - def is_device_change_ip_web_details(self): + @classmethod + def note_acl_invite_only_details(cls, val): """ - Check if the union tag is ``device_change_ip_web_details``. + Create an instance of this class set to the + ``note_acl_invite_only_details`` tag with value ``val``. - :rtype: bool + :param NoteAclInviteOnlyDetails val: + :rtype: EventDetails """ - return self._tag == 'device_change_ip_web_details' + return cls('note_acl_invite_only_details', val) - def is_device_delete_on_unlink_fail_details(self): + @classmethod + def note_acl_link_details(cls, val): """ - Check if the union tag is ``device_delete_on_unlink_fail_details``. + Create an instance of this class set to the ``note_acl_link_details`` + tag with value ``val``. - :rtype: bool + :param NoteAclLinkDetails val: + :rtype: EventDetails """ - return self._tag == 'device_delete_on_unlink_fail_details' + return cls('note_acl_link_details', val) - def is_device_delete_on_unlink_success_details(self): + @classmethod + def note_acl_team_link_details(cls, val): """ - Check if the union tag is ``device_delete_on_unlink_success_details``. + Create an instance of this class set to the + ``note_acl_team_link_details`` tag with value ``val``. - :rtype: bool + :param NoteAclTeamLinkDetails val: + :rtype: EventDetails """ - return self._tag == 'device_delete_on_unlink_success_details' + return cls('note_acl_team_link_details', val) - def is_device_link_fail_details(self): + @classmethod + def note_shared_details(cls, val): """ - Check if the union tag is ``device_link_fail_details``. + Create an instance of this class set to the ``note_shared_details`` tag + with value ``val``. - :rtype: bool + :param NoteSharedDetails val: + :rtype: EventDetails """ - return self._tag == 'device_link_fail_details' + return cls('note_shared_details', val) - def is_device_link_success_details(self): + @classmethod + def note_share_receive_details(cls, val): """ - Check if the union tag is ``device_link_success_details``. + Create an instance of this class set to the + ``note_share_receive_details`` tag with value ``val``. - :rtype: bool + :param NoteShareReceiveDetails val: + :rtype: EventDetails """ - return self._tag == 'device_link_success_details' + return cls('note_share_receive_details', val) - def is_device_management_disabled_details(self): + @classmethod + def open_note_shared_details(cls, val): """ - Check if the union tag is ``device_management_disabled_details``. + Create an instance of this class set to the ``open_note_shared_details`` + tag with value ``val``. - :rtype: bool + :param OpenNoteSharedDetails val: + :rtype: EventDetails """ - return self._tag == 'device_management_disabled_details' + return cls('open_note_shared_details', val) - def is_device_management_enabled_details(self): + @classmethod + def sf_add_group_details(cls, val): """ - Check if the union tag is ``device_management_enabled_details``. + Create an instance of this class set to the ``sf_add_group_details`` tag + with value ``val``. - :rtype: bool + :param SfAddGroupDetails val: + :rtype: EventDetails """ - return self._tag == 'device_management_enabled_details' + return cls('sf_add_group_details', val) - def is_device_unlink_details(self): + @classmethod + def sf_allow_non_members_to_view_shared_links_details(cls, val): """ - Check if the union tag is ``device_unlink_details``. + Create an instance of this class set to the + ``sf_allow_non_members_to_view_shared_links_details`` tag with value + ``val``. - :rtype: bool + :param SfAllowNonMembersToViewSharedLinksDetails val: + :rtype: EventDetails """ - return self._tag == 'device_unlink_details' + return cls('sf_allow_non_members_to_view_shared_links_details', val) - def is_emm_refresh_auth_token_details(self): + @classmethod + def sf_external_invite_warn_details(cls, val): """ - Check if the union tag is ``emm_refresh_auth_token_details``. + Create an instance of this class set to the + ``sf_external_invite_warn_details`` tag with value ``val``. - :rtype: bool + :param SfExternalInviteWarnDetails val: + :rtype: EventDetails """ - return self._tag == 'emm_refresh_auth_token_details' + return cls('sf_external_invite_warn_details', val) - def is_account_capture_change_availability_details(self): + @classmethod + def sf_fb_invite_details(cls, val): """ - Check if the union tag is ``account_capture_change_availability_details``. + Create an instance of this class set to the ``sf_fb_invite_details`` tag + with value ``val``. - :rtype: bool + :param SfFbInviteDetails val: + :rtype: EventDetails """ - return self._tag == 'account_capture_change_availability_details' + return cls('sf_fb_invite_details', val) - def is_account_capture_migrate_account_details(self): + @classmethod + def sf_fb_invite_change_role_details(cls, val): """ - Check if the union tag is ``account_capture_migrate_account_details``. + Create an instance of this class set to the + ``sf_fb_invite_change_role_details`` tag with value ``val``. - :rtype: bool + :param SfFbInviteChangeRoleDetails val: + :rtype: EventDetails """ - return self._tag == 'account_capture_migrate_account_details' + return cls('sf_fb_invite_change_role_details', val) - def is_account_capture_notification_emails_sent_details(self): + @classmethod + def sf_fb_uninvite_details(cls, val): """ - Check if the union tag is ``account_capture_notification_emails_sent_details``. + Create an instance of this class set to the ``sf_fb_uninvite_details`` + tag with value ``val``. - :rtype: bool + :param SfFbUninviteDetails val: + :rtype: EventDetails """ - return self._tag == 'account_capture_notification_emails_sent_details' + return cls('sf_fb_uninvite_details', val) - def is_account_capture_relinquish_account_details(self): + @classmethod + def sf_invite_group_details(cls, val): """ - Check if the union tag is ``account_capture_relinquish_account_details``. + Create an instance of this class set to the ``sf_invite_group_details`` + tag with value ``val``. - :rtype: bool + :param SfInviteGroupDetails val: + :rtype: EventDetails """ - return self._tag == 'account_capture_relinquish_account_details' + return cls('sf_invite_group_details', val) - def is_disabled_domain_invites_details(self): + @classmethod + def sf_team_grant_access_details(cls, val): """ - Check if the union tag is ``disabled_domain_invites_details``. + Create an instance of this class set to the + ``sf_team_grant_access_details`` tag with value ``val``. - :rtype: bool + :param SfTeamGrantAccessDetails val: + :rtype: EventDetails """ - return self._tag == 'disabled_domain_invites_details' + return cls('sf_team_grant_access_details', val) - def is_domain_invites_approve_request_to_join_team_details(self): + @classmethod + def sf_team_invite_details(cls, val): """ - Check if the union tag is ``domain_invites_approve_request_to_join_team_details``. + Create an instance of this class set to the ``sf_team_invite_details`` + tag with value ``val``. - :rtype: bool + :param SfTeamInviteDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_invites_approve_request_to_join_team_details' + return cls('sf_team_invite_details', val) - def is_domain_invites_decline_request_to_join_team_details(self): + @classmethod + def sf_team_invite_change_role_details(cls, val): """ - Check if the union tag is ``domain_invites_decline_request_to_join_team_details``. + Create an instance of this class set to the + ``sf_team_invite_change_role_details`` tag with value ``val``. - :rtype: bool + :param SfTeamInviteChangeRoleDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_invites_decline_request_to_join_team_details' + return cls('sf_team_invite_change_role_details', val) - def is_domain_invites_email_existing_users_details(self): + @classmethod + def sf_team_join_details(cls, val): """ - Check if the union tag is ``domain_invites_email_existing_users_details``. + Create an instance of this class set to the ``sf_team_join_details`` tag + with value ``val``. - :rtype: bool + :param SfTeamJoinDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_invites_email_existing_users_details' + return cls('sf_team_join_details', val) - def is_domain_invites_request_to_join_team_details(self): + @classmethod + def sf_team_join_from_oob_link_details(cls, val): """ - Check if the union tag is ``domain_invites_request_to_join_team_details``. + Create an instance of this class set to the + ``sf_team_join_from_oob_link_details`` tag with value ``val``. - :rtype: bool + :param SfTeamJoinFromOobLinkDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_invites_request_to_join_team_details' + return cls('sf_team_join_from_oob_link_details', val) - def is_domain_invites_set_invite_new_user_pref_to_no_details(self): + @classmethod + def sf_team_uninvite_details(cls, val): """ - Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_no_details``. + Create an instance of this class set to the ``sf_team_uninvite_details`` + tag with value ``val``. - :rtype: bool + :param SfTeamUninviteDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_invites_set_invite_new_user_pref_to_no_details' + return cls('sf_team_uninvite_details', val) - def is_domain_invites_set_invite_new_user_pref_to_yes_details(self): + @classmethod + def shared_content_add_invitees_details(cls, val): """ - Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_yes_details``. + Create an instance of this class set to the + ``shared_content_add_invitees_details`` tag with value ``val``. - :rtype: bool + :param SharedContentAddInviteesDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_invites_set_invite_new_user_pref_to_yes_details' + return cls('shared_content_add_invitees_details', val) - def is_domain_verification_add_domain_fail_details(self): + @classmethod + def shared_content_add_link_expiry_details(cls, val): """ - Check if the union tag is ``domain_verification_add_domain_fail_details``. + Create an instance of this class set to the + ``shared_content_add_link_expiry_details`` tag with value ``val``. - :rtype: bool + :param SharedContentAddLinkExpiryDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_verification_add_domain_fail_details' + return cls('shared_content_add_link_expiry_details', val) - def is_domain_verification_add_domain_success_details(self): + @classmethod + def shared_content_add_link_password_details(cls, val): """ - Check if the union tag is ``domain_verification_add_domain_success_details``. + Create an instance of this class set to the + ``shared_content_add_link_password_details`` tag with value ``val``. - :rtype: bool + :param SharedContentAddLinkPasswordDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_verification_add_domain_success_details' + return cls('shared_content_add_link_password_details', val) - def is_domain_verification_remove_domain_details(self): + @classmethod + def shared_content_add_member_details(cls, val): """ - Check if the union tag is ``domain_verification_remove_domain_details``. + Create an instance of this class set to the + ``shared_content_add_member_details`` tag with value ``val``. - :rtype: bool + :param SharedContentAddMemberDetails val: + :rtype: EventDetails """ - return self._tag == 'domain_verification_remove_domain_details' + return cls('shared_content_add_member_details', val) - def is_enabled_domain_invites_details(self): + @classmethod + def shared_content_change_downloads_policy_details(cls, val): """ - Check if the union tag is ``enabled_domain_invites_details``. + Create an instance of this class set to the + ``shared_content_change_downloads_policy_details`` tag with value + ``val``. - :rtype: bool + :param SharedContentChangeDownloadsPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'enabled_domain_invites_details' + return cls('shared_content_change_downloads_policy_details', val) - def is_create_folder_details(self): + @classmethod + def shared_content_change_invitee_role_details(cls, val): """ - Check if the union tag is ``create_folder_details``. + Create an instance of this class set to the + ``shared_content_change_invitee_role_details`` tag with value ``val``. - :rtype: bool + :param SharedContentChangeInviteeRoleDetails val: + :rtype: EventDetails """ - return self._tag == 'create_folder_details' + return cls('shared_content_change_invitee_role_details', val) - def is_file_add_details(self): + @classmethod + def shared_content_change_link_audience_details(cls, val): """ - Check if the union tag is ``file_add_details``. + Create an instance of this class set to the + ``shared_content_change_link_audience_details`` tag with value ``val``. - :rtype: bool + :param SharedContentChangeLinkAudienceDetails val: + :rtype: EventDetails """ - return self._tag == 'file_add_details' + return cls('shared_content_change_link_audience_details', val) - def is_file_copy_details(self): + @classmethod + def shared_content_change_link_expiry_details(cls, val): """ - Check if the union tag is ``file_copy_details``. + Create an instance of this class set to the + ``shared_content_change_link_expiry_details`` tag with value ``val``. - :rtype: bool + :param SharedContentChangeLinkExpiryDetails val: + :rtype: EventDetails """ - return self._tag == 'file_copy_details' + return cls('shared_content_change_link_expiry_details', val) - def is_file_delete_details(self): + @classmethod + def shared_content_change_link_password_details(cls, val): """ - Check if the union tag is ``file_delete_details``. + Create an instance of this class set to the + ``shared_content_change_link_password_details`` tag with value ``val``. - :rtype: bool + :param SharedContentChangeLinkPasswordDetails val: + :rtype: EventDetails """ - return self._tag == 'file_delete_details' + return cls('shared_content_change_link_password_details', val) - def is_file_download_details(self): + @classmethod + def shared_content_change_member_role_details(cls, val): """ - Check if the union tag is ``file_download_details``. + Create an instance of this class set to the + ``shared_content_change_member_role_details`` tag with value ``val``. - :rtype: bool + :param SharedContentChangeMemberRoleDetails val: + :rtype: EventDetails """ - return self._tag == 'file_download_details' + return cls('shared_content_change_member_role_details', val) - def is_file_edit_details(self): + @classmethod + def shared_content_change_viewer_info_policy_details(cls, val): """ - Check if the union tag is ``file_edit_details``. + Create an instance of this class set to the + ``shared_content_change_viewer_info_policy_details`` tag with value + ``val``. - :rtype: bool + :param SharedContentChangeViewerInfoPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'file_edit_details' + return cls('shared_content_change_viewer_info_policy_details', val) - def is_file_get_copy_reference_details(self): + @classmethod + def shared_content_claim_invitation_details(cls, val): """ - Check if the union tag is ``file_get_copy_reference_details``. + Create an instance of this class set to the + ``shared_content_claim_invitation_details`` tag with value ``val``. - :rtype: bool + :param SharedContentClaimInvitationDetails val: + :rtype: EventDetails """ - return self._tag == 'file_get_copy_reference_details' + return cls('shared_content_claim_invitation_details', val) - def is_file_move_details(self): + @classmethod + def shared_content_copy_details(cls, val): """ - Check if the union tag is ``file_move_details``. + Create an instance of this class set to the + ``shared_content_copy_details`` tag with value ``val``. - :rtype: bool + :param SharedContentCopyDetails val: + :rtype: EventDetails """ - return self._tag == 'file_move_details' + return cls('shared_content_copy_details', val) - def is_file_permanently_delete_details(self): + @classmethod + def shared_content_download_details(cls, val): """ - Check if the union tag is ``file_permanently_delete_details``. + Create an instance of this class set to the + ``shared_content_download_details`` tag with value ``val``. - :rtype: bool + :param SharedContentDownloadDetails val: + :rtype: EventDetails """ - return self._tag == 'file_permanently_delete_details' + return cls('shared_content_download_details', val) - def is_file_preview_details(self): + @classmethod + def shared_content_relinquish_membership_details(cls, val): """ - Check if the union tag is ``file_preview_details``. + Create an instance of this class set to the + ``shared_content_relinquish_membership_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRelinquishMembershipDetails val: + :rtype: EventDetails """ - return self._tag == 'file_preview_details' + return cls('shared_content_relinquish_membership_details', val) - def is_file_rename_details(self): + @classmethod + def shared_content_remove_invitees_details(cls, val): """ - Check if the union tag is ``file_rename_details``. + Create an instance of this class set to the + ``shared_content_remove_invitees_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRemoveInviteesDetails val: + :rtype: EventDetails """ - return self._tag == 'file_rename_details' + return cls('shared_content_remove_invitees_details', val) - def is_file_restore_details(self): + @classmethod + def shared_content_remove_link_expiry_details(cls, val): """ - Check if the union tag is ``file_restore_details``. + Create an instance of this class set to the + ``shared_content_remove_link_expiry_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRemoveLinkExpiryDetails val: + :rtype: EventDetails """ - return self._tag == 'file_restore_details' + return cls('shared_content_remove_link_expiry_details', val) - def is_file_revert_details(self): + @classmethod + def shared_content_remove_link_password_details(cls, val): """ - Check if the union tag is ``file_revert_details``. + Create an instance of this class set to the + ``shared_content_remove_link_password_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRemoveLinkPasswordDetails val: + :rtype: EventDetails """ - return self._tag == 'file_revert_details' + return cls('shared_content_remove_link_password_details', val) - def is_file_rollback_changes_details(self): + @classmethod + def shared_content_remove_member_details(cls, val): """ - Check if the union tag is ``file_rollback_changes_details``. + Create an instance of this class set to the + ``shared_content_remove_member_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRemoveMemberDetails val: + :rtype: EventDetails """ - return self._tag == 'file_rollback_changes_details' + return cls('shared_content_remove_member_details', val) - def is_file_save_copy_reference_details(self): + @classmethod + def shared_content_request_access_details(cls, val): """ - Check if the union tag is ``file_save_copy_reference_details``. + Create an instance of this class set to the + ``shared_content_request_access_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRequestAccessDetails val: + :rtype: EventDetails """ - return self._tag == 'file_save_copy_reference_details' + return cls('shared_content_request_access_details', val) - def is_file_request_change_details(self): + @classmethod + def shared_content_restore_invitees_details(cls, val): """ - Check if the union tag is ``file_request_change_details``. + Create an instance of this class set to the + ``shared_content_restore_invitees_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRestoreInviteesDetails val: + :rtype: EventDetails """ - return self._tag == 'file_request_change_details' + return cls('shared_content_restore_invitees_details', val) - def is_file_request_close_details(self): + @classmethod + def shared_content_restore_member_details(cls, val): """ - Check if the union tag is ``file_request_close_details``. + Create an instance of this class set to the + ``shared_content_restore_member_details`` tag with value ``val``. - :rtype: bool + :param SharedContentRestoreMemberDetails val: + :rtype: EventDetails """ - return self._tag == 'file_request_close_details' + return cls('shared_content_restore_member_details', val) - def is_file_request_create_details(self): + @classmethod + def shared_content_unshare_details(cls, val): """ - Check if the union tag is ``file_request_create_details``. + Create an instance of this class set to the + ``shared_content_unshare_details`` tag with value ``val``. - :rtype: bool + :param SharedContentUnshareDetails val: + :rtype: EventDetails """ - return self._tag == 'file_request_create_details' + return cls('shared_content_unshare_details', val) - def is_file_request_delete_details(self): + @classmethod + def shared_content_view_details(cls, val): """ - Check if the union tag is ``file_request_delete_details``. + Create an instance of this class set to the + ``shared_content_view_details`` tag with value ``val``. - :rtype: bool + :param SharedContentViewDetails val: + :rtype: EventDetails """ - return self._tag == 'file_request_delete_details' + return cls('shared_content_view_details', val) - def is_file_request_receive_file_details(self): + @classmethod + def shared_folder_change_link_policy_details(cls, val): """ - Check if the union tag is ``file_request_receive_file_details``. + Create an instance of this class set to the + ``shared_folder_change_link_policy_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderChangeLinkPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'file_request_receive_file_details' + return cls('shared_folder_change_link_policy_details', val) - def is_group_add_external_id_details(self): + @classmethod + def shared_folder_change_members_inheritance_policy_details(cls, val): """ - Check if the union tag is ``group_add_external_id_details``. + Create an instance of this class set to the + ``shared_folder_change_members_inheritance_policy_details`` tag with + value ``val``. - :rtype: bool + :param SharedFolderChangeMembersInheritancePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'group_add_external_id_details' + return cls('shared_folder_change_members_inheritance_policy_details', val) - def is_group_add_member_details(self): + @classmethod + def shared_folder_change_members_management_policy_details(cls, val): """ - Check if the union tag is ``group_add_member_details``. + Create an instance of this class set to the + ``shared_folder_change_members_management_policy_details`` tag with + value ``val``. - :rtype: bool + :param SharedFolderChangeMembersManagementPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'group_add_member_details' + return cls('shared_folder_change_members_management_policy_details', val) - def is_group_change_external_id_details(self): + @classmethod + def shared_folder_change_members_policy_details(cls, val): """ - Check if the union tag is ``group_change_external_id_details``. + Create an instance of this class set to the + ``shared_folder_change_members_policy_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderChangeMembersPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'group_change_external_id_details' + return cls('shared_folder_change_members_policy_details', val) - def is_group_change_management_type_details(self): + @classmethod + def shared_folder_create_details(cls, val): """ - Check if the union tag is ``group_change_management_type_details``. + Create an instance of this class set to the + ``shared_folder_create_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderCreateDetails val: + :rtype: EventDetails """ - return self._tag == 'group_change_management_type_details' + return cls('shared_folder_create_details', val) - def is_group_change_member_role_details(self): + @classmethod + def shared_folder_decline_invitation_details(cls, val): """ - Check if the union tag is ``group_change_member_role_details``. + Create an instance of this class set to the + ``shared_folder_decline_invitation_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderDeclineInvitationDetails val: + :rtype: EventDetails """ - return self._tag == 'group_change_member_role_details' + return cls('shared_folder_decline_invitation_details', val) - def is_group_create_details(self): + @classmethod + def shared_folder_mount_details(cls, val): """ - Check if the union tag is ``group_create_details``. + Create an instance of this class set to the + ``shared_folder_mount_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderMountDetails val: + :rtype: EventDetails """ - return self._tag == 'group_create_details' + return cls('shared_folder_mount_details', val) - def is_group_delete_details(self): + @classmethod + def shared_folder_nest_details(cls, val): """ - Check if the union tag is ``group_delete_details``. + Create an instance of this class set to the + ``shared_folder_nest_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderNestDetails val: + :rtype: EventDetails """ - return self._tag == 'group_delete_details' + return cls('shared_folder_nest_details', val) - def is_group_description_updated_details(self): + @classmethod + def shared_folder_transfer_ownership_details(cls, val): """ - Check if the union tag is ``group_description_updated_details``. + Create an instance of this class set to the + ``shared_folder_transfer_ownership_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderTransferOwnershipDetails val: + :rtype: EventDetails """ - return self._tag == 'group_description_updated_details' + return cls('shared_folder_transfer_ownership_details', val) - def is_group_join_policy_updated_details(self): + @classmethod + def shared_folder_unmount_details(cls, val): """ - Check if the union tag is ``group_join_policy_updated_details``. + Create an instance of this class set to the + ``shared_folder_unmount_details`` tag with value ``val``. - :rtype: bool + :param SharedFolderUnmountDetails val: + :rtype: EventDetails """ - return self._tag == 'group_join_policy_updated_details' + return cls('shared_folder_unmount_details', val) - def is_group_moved_details(self): + @classmethod + def shared_link_add_expiry_details(cls, val): """ - Check if the union tag is ``group_moved_details``. + Create an instance of this class set to the + ``shared_link_add_expiry_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkAddExpiryDetails val: + :rtype: EventDetails """ - return self._tag == 'group_moved_details' + return cls('shared_link_add_expiry_details', val) - def is_group_remove_external_id_details(self): + @classmethod + def shared_link_change_expiry_details(cls, val): """ - Check if the union tag is ``group_remove_external_id_details``. + Create an instance of this class set to the + ``shared_link_change_expiry_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkChangeExpiryDetails val: + :rtype: EventDetails """ - return self._tag == 'group_remove_external_id_details' + return cls('shared_link_change_expiry_details', val) - def is_group_remove_member_details(self): + @classmethod + def shared_link_change_visibility_details(cls, val): """ - Check if the union tag is ``group_remove_member_details``. + Create an instance of this class set to the + ``shared_link_change_visibility_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkChangeVisibilityDetails val: + :rtype: EventDetails """ - return self._tag == 'group_remove_member_details' + return cls('shared_link_change_visibility_details', val) - def is_group_rename_details(self): + @classmethod + def shared_link_copy_details(cls, val): """ - Check if the union tag is ``group_rename_details``. + Create an instance of this class set to the ``shared_link_copy_details`` + tag with value ``val``. - :rtype: bool + :param SharedLinkCopyDetails val: + :rtype: EventDetails """ - return self._tag == 'group_rename_details' + return cls('shared_link_copy_details', val) - def is_emm_error_details(self): + @classmethod + def shared_link_create_details(cls, val): """ - Check if the union tag is ``emm_error_details``. + Create an instance of this class set to the + ``shared_link_create_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkCreateDetails val: + :rtype: EventDetails """ - return self._tag == 'emm_error_details' + return cls('shared_link_create_details', val) - def is_guest_admin_signed_in_via_trusted_teams_details(self): + @classmethod + def shared_link_disable_details(cls, val): """ - Check if the union tag is ``guest_admin_signed_in_via_trusted_teams_details``. + Create an instance of this class set to the + ``shared_link_disable_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkDisableDetails val: + :rtype: EventDetails """ - return self._tag == 'guest_admin_signed_in_via_trusted_teams_details' + return cls('shared_link_disable_details', val) - def is_guest_admin_signed_out_via_trusted_teams_details(self): + @classmethod + def shared_link_download_details(cls, val): """ - Check if the union tag is ``guest_admin_signed_out_via_trusted_teams_details``. + Create an instance of this class set to the + ``shared_link_download_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkDownloadDetails val: + :rtype: EventDetails """ - return self._tag == 'guest_admin_signed_out_via_trusted_teams_details' + return cls('shared_link_download_details', val) - def is_login_fail_details(self): + @classmethod + def shared_link_remove_expiry_details(cls, val): """ - Check if the union tag is ``login_fail_details``. + Create an instance of this class set to the + ``shared_link_remove_expiry_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkRemoveExpiryDetails val: + :rtype: EventDetails """ - return self._tag == 'login_fail_details' + return cls('shared_link_remove_expiry_details', val) - def is_login_success_details(self): + @classmethod + def shared_link_settings_add_expiration_details(cls, val): """ - Check if the union tag is ``login_success_details``. + Create an instance of this class set to the + ``shared_link_settings_add_expiration_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkSettingsAddExpirationDetails val: + :rtype: EventDetails """ - return self._tag == 'login_success_details' + return cls('shared_link_settings_add_expiration_details', val) - def is_logout_details(self): + @classmethod + def shared_link_settings_add_password_details(cls, val): """ - Check if the union tag is ``logout_details``. + Create an instance of this class set to the + ``shared_link_settings_add_password_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkSettingsAddPasswordDetails val: + :rtype: EventDetails """ - return self._tag == 'logout_details' + return cls('shared_link_settings_add_password_details', val) - def is_reseller_support_session_end_details(self): + @classmethod + def shared_link_settings_allow_download_disabled_details(cls, val): """ - Check if the union tag is ``reseller_support_session_end_details``. + Create an instance of this class set to the + ``shared_link_settings_allow_download_disabled_details`` tag with value + ``val``. - :rtype: bool + :param SharedLinkSettingsAllowDownloadDisabledDetails val: + :rtype: EventDetails """ - return self._tag == 'reseller_support_session_end_details' + return cls('shared_link_settings_allow_download_disabled_details', val) - def is_reseller_support_session_start_details(self): + @classmethod + def shared_link_settings_allow_download_enabled_details(cls, val): """ - Check if the union tag is ``reseller_support_session_start_details``. + Create an instance of this class set to the + ``shared_link_settings_allow_download_enabled_details`` tag with value + ``val``. - :rtype: bool + :param SharedLinkSettingsAllowDownloadEnabledDetails val: + :rtype: EventDetails """ - return self._tag == 'reseller_support_session_start_details' + return cls('shared_link_settings_allow_download_enabled_details', val) - def is_sign_in_as_session_end_details(self): + @classmethod + def shared_link_settings_change_audience_details(cls, val): """ - Check if the union tag is ``sign_in_as_session_end_details``. + Create an instance of this class set to the + ``shared_link_settings_change_audience_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkSettingsChangeAudienceDetails val: + :rtype: EventDetails """ - return self._tag == 'sign_in_as_session_end_details' + return cls('shared_link_settings_change_audience_details', val) - def is_sign_in_as_session_start_details(self): + @classmethod + def shared_link_settings_change_expiration_details(cls, val): """ - Check if the union tag is ``sign_in_as_session_start_details``. + Create an instance of this class set to the + ``shared_link_settings_change_expiration_details`` tag with value + ``val``. - :rtype: bool + :param SharedLinkSettingsChangeExpirationDetails val: + :rtype: EventDetails """ - return self._tag == 'sign_in_as_session_start_details' + return cls('shared_link_settings_change_expiration_details', val) - def is_sso_error_details(self): + @classmethod + def shared_link_settings_change_password_details(cls, val): """ - Check if the union tag is ``sso_error_details``. + Create an instance of this class set to the + ``shared_link_settings_change_password_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkSettingsChangePasswordDetails val: + :rtype: EventDetails """ - return self._tag == 'sso_error_details' + return cls('shared_link_settings_change_password_details', val) - def is_member_add_external_id_details(self): + @classmethod + def shared_link_settings_remove_expiration_details(cls, val): """ - Check if the union tag is ``member_add_external_id_details``. + Create an instance of this class set to the + ``shared_link_settings_remove_expiration_details`` tag with value + ``val``. - :rtype: bool + :param SharedLinkSettingsRemoveExpirationDetails val: + :rtype: EventDetails """ - return self._tag == 'member_add_external_id_details' + return cls('shared_link_settings_remove_expiration_details', val) - def is_member_add_name_details(self): + @classmethod + def shared_link_settings_remove_password_details(cls, val): """ - Check if the union tag is ``member_add_name_details``. + Create an instance of this class set to the + ``shared_link_settings_remove_password_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkSettingsRemovePasswordDetails val: + :rtype: EventDetails """ - return self._tag == 'member_add_name_details' + return cls('shared_link_settings_remove_password_details', val) - def is_member_change_admin_role_details(self): + @classmethod + def shared_link_share_details(cls, val): """ - Check if the union tag is ``member_change_admin_role_details``. + Create an instance of this class set to the + ``shared_link_share_details`` tag with value ``val``. - :rtype: bool + :param SharedLinkShareDetails val: + :rtype: EventDetails """ - return self._tag == 'member_change_admin_role_details' + return cls('shared_link_share_details', val) - def is_member_change_email_details(self): + @classmethod + def shared_link_view_details(cls, val): """ - Check if the union tag is ``member_change_email_details``. + Create an instance of this class set to the ``shared_link_view_details`` + tag with value ``val``. - :rtype: bool + :param SharedLinkViewDetails val: + :rtype: EventDetails """ - return self._tag == 'member_change_email_details' + return cls('shared_link_view_details', val) - def is_member_change_external_id_details(self): + @classmethod + def shared_note_opened_details(cls, val): """ - Check if the union tag is ``member_change_external_id_details``. + Create an instance of this class set to the + ``shared_note_opened_details`` tag with value ``val``. - :rtype: bool + :param SharedNoteOpenedDetails val: + :rtype: EventDetails """ - return self._tag == 'member_change_external_id_details' + return cls('shared_note_opened_details', val) - def is_member_change_membership_type_details(self): + @classmethod + def shmodel_group_share_details(cls, val): """ - Check if the union tag is ``member_change_membership_type_details``. + Create an instance of this class set to the + ``shmodel_group_share_details`` tag with value ``val``. - :rtype: bool + :param ShmodelGroupShareDetails val: + :rtype: EventDetails """ - return self._tag == 'member_change_membership_type_details' + return cls('shmodel_group_share_details', val) - def is_member_change_name_details(self): + @classmethod + def showcase_access_granted_details(cls, val): """ - Check if the union tag is ``member_change_name_details``. + Create an instance of this class set to the + ``showcase_access_granted_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseAccessGrantedDetails val: + :rtype: EventDetails """ - return self._tag == 'member_change_name_details' + return cls('showcase_access_granted_details', val) - def is_member_change_status_details(self): + @classmethod + def showcase_add_member_details(cls, val): """ - Check if the union tag is ``member_change_status_details``. + Create an instance of this class set to the + ``showcase_add_member_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseAddMemberDetails val: + :rtype: EventDetails """ - return self._tag == 'member_change_status_details' + return cls('showcase_add_member_details', val) - def is_member_delete_manual_contacts_details(self): + @classmethod + def showcase_archived_details(cls, val): """ - Check if the union tag is ``member_delete_manual_contacts_details``. + Create an instance of this class set to the + ``showcase_archived_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseArchivedDetails val: + :rtype: EventDetails """ - return self._tag == 'member_delete_manual_contacts_details' + return cls('showcase_archived_details', val) - def is_member_permanently_delete_account_contents_details(self): + @classmethod + def showcase_created_details(cls, val): """ - Check if the union tag is ``member_permanently_delete_account_contents_details``. + Create an instance of this class set to the ``showcase_created_details`` + tag with value ``val``. - :rtype: bool + :param ShowcaseCreatedDetails val: + :rtype: EventDetails """ - return self._tag == 'member_permanently_delete_account_contents_details' + return cls('showcase_created_details', val) - def is_member_remove_external_id_details(self): + @classmethod + def showcase_delete_comment_details(cls, val): """ - Check if the union tag is ``member_remove_external_id_details``. + Create an instance of this class set to the + ``showcase_delete_comment_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseDeleteCommentDetails val: + :rtype: EventDetails """ - return self._tag == 'member_remove_external_id_details' + return cls('showcase_delete_comment_details', val) - def is_member_space_limits_add_custom_quota_details(self): + @classmethod + def showcase_edited_details(cls, val): """ - Check if the union tag is ``member_space_limits_add_custom_quota_details``. + Create an instance of this class set to the ``showcase_edited_details`` + tag with value ``val``. - :rtype: bool + :param ShowcaseEditedDetails val: + :rtype: EventDetails """ - return self._tag == 'member_space_limits_add_custom_quota_details' + return cls('showcase_edited_details', val) - def is_member_space_limits_change_custom_quota_details(self): + @classmethod + def showcase_edit_comment_details(cls, val): """ - Check if the union tag is ``member_space_limits_change_custom_quota_details``. + Create an instance of this class set to the + ``showcase_edit_comment_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseEditCommentDetails val: + :rtype: EventDetails """ - return self._tag == 'member_space_limits_change_custom_quota_details' + return cls('showcase_edit_comment_details', val) - def is_member_space_limits_change_status_details(self): + @classmethod + def showcase_file_added_details(cls, val): """ - Check if the union tag is ``member_space_limits_change_status_details``. + Create an instance of this class set to the + ``showcase_file_added_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseFileAddedDetails val: + :rtype: EventDetails """ - return self._tag == 'member_space_limits_change_status_details' + return cls('showcase_file_added_details', val) - def is_member_space_limits_remove_custom_quota_details(self): + @classmethod + def showcase_file_download_details(cls, val): """ - Check if the union tag is ``member_space_limits_remove_custom_quota_details``. + Create an instance of this class set to the + ``showcase_file_download_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseFileDownloadDetails val: + :rtype: EventDetails """ - return self._tag == 'member_space_limits_remove_custom_quota_details' + return cls('showcase_file_download_details', val) - def is_member_suggest_details(self): + @classmethod + def showcase_file_removed_details(cls, val): """ - Check if the union tag is ``member_suggest_details``. + Create an instance of this class set to the + ``showcase_file_removed_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseFileRemovedDetails val: + :rtype: EventDetails """ - return self._tag == 'member_suggest_details' + return cls('showcase_file_removed_details', val) - def is_member_transfer_account_contents_details(self): + @classmethod + def showcase_file_view_details(cls, val): """ - Check if the union tag is ``member_transfer_account_contents_details``. + Create an instance of this class set to the + ``showcase_file_view_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseFileViewDetails val: + :rtype: EventDetails """ - return self._tag == 'member_transfer_account_contents_details' + return cls('showcase_file_view_details', val) - def is_secondary_mails_policy_changed_details(self): + @classmethod + def showcase_permanently_deleted_details(cls, val): """ - Check if the union tag is ``secondary_mails_policy_changed_details``. + Create an instance of this class set to the + ``showcase_permanently_deleted_details`` tag with value ``val``. - :rtype: bool + :param ShowcasePermanentlyDeletedDetails val: + :rtype: EventDetails """ - return self._tag == 'secondary_mails_policy_changed_details' + return cls('showcase_permanently_deleted_details', val) - def is_paper_content_add_member_details(self): + @classmethod + def showcase_post_comment_details(cls, val): """ - Check if the union tag is ``paper_content_add_member_details``. + Create an instance of this class set to the + ``showcase_post_comment_details`` tag with value ``val``. - :rtype: bool + :param ShowcasePostCommentDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_add_member_details' + return cls('showcase_post_comment_details', val) - def is_paper_content_add_to_folder_details(self): + @classmethod + def showcase_remove_member_details(cls, val): """ - Check if the union tag is ``paper_content_add_to_folder_details``. + Create an instance of this class set to the + ``showcase_remove_member_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseRemoveMemberDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_add_to_folder_details' + return cls('showcase_remove_member_details', val) - def is_paper_content_archive_details(self): + @classmethod + def showcase_renamed_details(cls, val): """ - Check if the union tag is ``paper_content_archive_details``. + Create an instance of this class set to the ``showcase_renamed_details`` + tag with value ``val``. - :rtype: bool + :param ShowcaseRenamedDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_archive_details' + return cls('showcase_renamed_details', val) - def is_paper_content_create_details(self): + @classmethod + def showcase_request_access_details(cls, val): """ - Check if the union tag is ``paper_content_create_details``. + Create an instance of this class set to the + ``showcase_request_access_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseRequestAccessDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_create_details' + return cls('showcase_request_access_details', val) - def is_paper_content_permanently_delete_details(self): + @classmethod + def showcase_resolve_comment_details(cls, val): """ - Check if the union tag is ``paper_content_permanently_delete_details``. + Create an instance of this class set to the + ``showcase_resolve_comment_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseResolveCommentDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_permanently_delete_details' + return cls('showcase_resolve_comment_details', val) - def is_paper_content_remove_from_folder_details(self): + @classmethod + def showcase_restored_details(cls, val): """ - Check if the union tag is ``paper_content_remove_from_folder_details``. + Create an instance of this class set to the + ``showcase_restored_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseRestoredDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_remove_from_folder_details' + return cls('showcase_restored_details', val) - def is_paper_content_remove_member_details(self): + @classmethod + def showcase_trashed_details(cls, val): """ - Check if the union tag is ``paper_content_remove_member_details``. + Create an instance of this class set to the ``showcase_trashed_details`` + tag with value ``val``. - :rtype: bool + :param ShowcaseTrashedDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_remove_member_details' + return cls('showcase_trashed_details', val) - def is_paper_content_rename_details(self): + @classmethod + def showcase_trashed_deprecated_details(cls, val): """ - Check if the union tag is ``paper_content_rename_details``. + Create an instance of this class set to the + ``showcase_trashed_deprecated_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseTrashedDeprecatedDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_rename_details' + return cls('showcase_trashed_deprecated_details', val) - def is_paper_content_restore_details(self): + @classmethod + def showcase_unresolve_comment_details(cls, val): """ - Check if the union tag is ``paper_content_restore_details``. + Create an instance of this class set to the + ``showcase_unresolve_comment_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseUnresolveCommentDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_content_restore_details' + return cls('showcase_unresolve_comment_details', val) - def is_paper_doc_add_comment_details(self): + @classmethod + def showcase_untrashed_details(cls, val): """ - Check if the union tag is ``paper_doc_add_comment_details``. + Create an instance of this class set to the + ``showcase_untrashed_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseUntrashedDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_add_comment_details' + return cls('showcase_untrashed_details', val) - def is_paper_doc_change_member_role_details(self): + @classmethod + def showcase_untrashed_deprecated_details(cls, val): """ - Check if the union tag is ``paper_doc_change_member_role_details``. + Create an instance of this class set to the + ``showcase_untrashed_deprecated_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseUntrashedDeprecatedDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_change_member_role_details' + return cls('showcase_untrashed_deprecated_details', val) - def is_paper_doc_change_sharing_policy_details(self): + @classmethod + def showcase_view_details(cls, val): """ - Check if the union tag is ``paper_doc_change_sharing_policy_details``. + Create an instance of this class set to the ``showcase_view_details`` + tag with value ``val``. - :rtype: bool + :param ShowcaseViewDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_change_sharing_policy_details' + return cls('showcase_view_details', val) - def is_paper_doc_change_subscription_details(self): + @classmethod + def sso_add_cert_details(cls, val): """ - Check if the union tag is ``paper_doc_change_subscription_details``. + Create an instance of this class set to the ``sso_add_cert_details`` tag + with value ``val``. - :rtype: bool + :param SsoAddCertDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_change_subscription_details' + return cls('sso_add_cert_details', val) - def is_paper_doc_deleted_details(self): + @classmethod + def sso_add_login_url_details(cls, val): """ - Check if the union tag is ``paper_doc_deleted_details``. + Create an instance of this class set to the + ``sso_add_login_url_details`` tag with value ``val``. - :rtype: bool + :param SsoAddLoginUrlDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_deleted_details' + return cls('sso_add_login_url_details', val) - def is_paper_doc_delete_comment_details(self): + @classmethod + def sso_add_logout_url_details(cls, val): """ - Check if the union tag is ``paper_doc_delete_comment_details``. + Create an instance of this class set to the + ``sso_add_logout_url_details`` tag with value ``val``. - :rtype: bool + :param SsoAddLogoutUrlDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_delete_comment_details' + return cls('sso_add_logout_url_details', val) - def is_paper_doc_download_details(self): + @classmethod + def sso_change_cert_details(cls, val): """ - Check if the union tag is ``paper_doc_download_details``. + Create an instance of this class set to the ``sso_change_cert_details`` + tag with value ``val``. - :rtype: bool + :param SsoChangeCertDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_download_details' + return cls('sso_change_cert_details', val) - def is_paper_doc_edit_details(self): + @classmethod + def sso_change_login_url_details(cls, val): """ - Check if the union tag is ``paper_doc_edit_details``. + Create an instance of this class set to the + ``sso_change_login_url_details`` tag with value ``val``. - :rtype: bool + :param SsoChangeLoginUrlDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_edit_details' + return cls('sso_change_login_url_details', val) - def is_paper_doc_edit_comment_details(self): + @classmethod + def sso_change_logout_url_details(cls, val): """ - Check if the union tag is ``paper_doc_edit_comment_details``. + Create an instance of this class set to the + ``sso_change_logout_url_details`` tag with value ``val``. - :rtype: bool + :param SsoChangeLogoutUrlDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_edit_comment_details' + return cls('sso_change_logout_url_details', val) - def is_paper_doc_followed_details(self): + @classmethod + def sso_change_saml_identity_mode_details(cls, val): """ - Check if the union tag is ``paper_doc_followed_details``. + Create an instance of this class set to the + ``sso_change_saml_identity_mode_details`` tag with value ``val``. - :rtype: bool + :param SsoChangeSamlIdentityModeDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_followed_details' + return cls('sso_change_saml_identity_mode_details', val) - def is_paper_doc_mention_details(self): + @classmethod + def sso_remove_cert_details(cls, val): """ - Check if the union tag is ``paper_doc_mention_details``. + Create an instance of this class set to the ``sso_remove_cert_details`` + tag with value ``val``. - :rtype: bool + :param SsoRemoveCertDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_mention_details' + return cls('sso_remove_cert_details', val) - def is_paper_doc_ownership_changed_details(self): + @classmethod + def sso_remove_login_url_details(cls, val): """ - Check if the union tag is ``paper_doc_ownership_changed_details``. + Create an instance of this class set to the + ``sso_remove_login_url_details`` tag with value ``val``. - :rtype: bool + :param SsoRemoveLoginUrlDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_ownership_changed_details' + return cls('sso_remove_login_url_details', val) - def is_paper_doc_request_access_details(self): + @classmethod + def sso_remove_logout_url_details(cls, val): """ - Check if the union tag is ``paper_doc_request_access_details``. + Create an instance of this class set to the + ``sso_remove_logout_url_details`` tag with value ``val``. - :rtype: bool + :param SsoRemoveLogoutUrlDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_request_access_details' + return cls('sso_remove_logout_url_details', val) - def is_paper_doc_resolve_comment_details(self): + @classmethod + def team_folder_change_status_details(cls, val): """ - Check if the union tag is ``paper_doc_resolve_comment_details``. + Create an instance of this class set to the + ``team_folder_change_status_details`` tag with value ``val``. - :rtype: bool + :param TeamFolderChangeStatusDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_resolve_comment_details' + return cls('team_folder_change_status_details', val) - def is_paper_doc_revert_details(self): + @classmethod + def team_folder_create_details(cls, val): """ - Check if the union tag is ``paper_doc_revert_details``. + Create an instance of this class set to the + ``team_folder_create_details`` tag with value ``val``. - :rtype: bool + :param TeamFolderCreateDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_revert_details' + return cls('team_folder_create_details', val) - def is_paper_doc_slack_share_details(self): + @classmethod + def team_folder_downgrade_details(cls, val): """ - Check if the union tag is ``paper_doc_slack_share_details``. + Create an instance of this class set to the + ``team_folder_downgrade_details`` tag with value ``val``. - :rtype: bool + :param TeamFolderDowngradeDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_slack_share_details' + return cls('team_folder_downgrade_details', val) - def is_paper_doc_team_invite_details(self): + @classmethod + def team_folder_permanently_delete_details(cls, val): """ - Check if the union tag is ``paper_doc_team_invite_details``. + Create an instance of this class set to the + ``team_folder_permanently_delete_details`` tag with value ``val``. - :rtype: bool + :param TeamFolderPermanentlyDeleteDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_team_invite_details' + return cls('team_folder_permanently_delete_details', val) - def is_paper_doc_trashed_details(self): + @classmethod + def team_folder_rename_details(cls, val): """ - Check if the union tag is ``paper_doc_trashed_details``. + Create an instance of this class set to the + ``team_folder_rename_details`` tag with value ``val``. - :rtype: bool + :param TeamFolderRenameDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_trashed_details' + return cls('team_folder_rename_details', val) - def is_paper_doc_unresolve_comment_details(self): + @classmethod + def team_selective_sync_settings_changed_details(cls, val): """ - Check if the union tag is ``paper_doc_unresolve_comment_details``. + Create an instance of this class set to the + ``team_selective_sync_settings_changed_details`` tag with value ``val``. - :rtype: bool + :param TeamSelectiveSyncSettingsChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_unresolve_comment_details' + return cls('team_selective_sync_settings_changed_details', val) - def is_paper_doc_untrashed_details(self): + @classmethod + def account_capture_change_policy_details(cls, val): """ - Check if the union tag is ``paper_doc_untrashed_details``. + Create an instance of this class set to the + ``account_capture_change_policy_details`` tag with value ``val``. - :rtype: bool + :param AccountCaptureChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_untrashed_details' + return cls('account_capture_change_policy_details', val) - def is_paper_doc_view_details(self): + @classmethod + def allow_download_disabled_details(cls, val): """ - Check if the union tag is ``paper_doc_view_details``. + Create an instance of this class set to the + ``allow_download_disabled_details`` tag with value ``val``. - :rtype: bool + :param AllowDownloadDisabledDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_doc_view_details' + return cls('allow_download_disabled_details', val) - def is_paper_external_view_allow_details(self): + @classmethod + def allow_download_enabled_details(cls, val): """ - Check if the union tag is ``paper_external_view_allow_details``. + Create an instance of this class set to the + ``allow_download_enabled_details`` tag with value ``val``. - :rtype: bool + :param AllowDownloadEnabledDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_external_view_allow_details' + return cls('allow_download_enabled_details', val) - def is_paper_external_view_default_team_details(self): + @classmethod + def camera_uploads_policy_changed_details(cls, val): """ - Check if the union tag is ``paper_external_view_default_team_details``. + Create an instance of this class set to the + ``camera_uploads_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param CameraUploadsPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_external_view_default_team_details' + return cls('camera_uploads_policy_changed_details', val) - def is_paper_external_view_forbid_details(self): + @classmethod + def data_placement_restriction_change_policy_details(cls, val): """ - Check if the union tag is ``paper_external_view_forbid_details``. + Create an instance of this class set to the + ``data_placement_restriction_change_policy_details`` tag with value + ``val``. - :rtype: bool + :param DataPlacementRestrictionChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_external_view_forbid_details' + return cls('data_placement_restriction_change_policy_details', val) - def is_paper_folder_change_subscription_details(self): + @classmethod + def data_placement_restriction_satisfy_policy_details(cls, val): """ - Check if the union tag is ``paper_folder_change_subscription_details``. + Create an instance of this class set to the + ``data_placement_restriction_satisfy_policy_details`` tag with value + ``val``. - :rtype: bool + :param DataPlacementRestrictionSatisfyPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_folder_change_subscription_details' + return cls('data_placement_restriction_satisfy_policy_details', val) - def is_paper_folder_deleted_details(self): + @classmethod + def device_approvals_add_exception_details(cls, val): """ - Check if the union tag is ``paper_folder_deleted_details``. + Create an instance of this class set to the + ``device_approvals_add_exception_details`` tag with value ``val``. - :rtype: bool + :param DeviceApprovalsAddExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_folder_deleted_details' + return cls('device_approvals_add_exception_details', val) - def is_paper_folder_followed_details(self): + @classmethod + def device_approvals_change_desktop_policy_details(cls, val): """ - Check if the union tag is ``paper_folder_followed_details``. + Create an instance of this class set to the + ``device_approvals_change_desktop_policy_details`` tag with value + ``val``. - :rtype: bool + :param DeviceApprovalsChangeDesktopPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_folder_followed_details' + return cls('device_approvals_change_desktop_policy_details', val) - def is_paper_folder_team_invite_details(self): + @classmethod + def device_approvals_change_mobile_policy_details(cls, val): """ - Check if the union tag is ``paper_folder_team_invite_details``. + Create an instance of this class set to the + ``device_approvals_change_mobile_policy_details`` tag with value + ``val``. - :rtype: bool + :param DeviceApprovalsChangeMobilePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_folder_team_invite_details' + return cls('device_approvals_change_mobile_policy_details', val) - def is_paper_published_link_create_details(self): + @classmethod + def device_approvals_change_overage_action_details(cls, val): """ - Check if the union tag is ``paper_published_link_create_details``. + Create an instance of this class set to the + ``device_approvals_change_overage_action_details`` tag with value + ``val``. - :rtype: bool + :param DeviceApprovalsChangeOverageActionDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_published_link_create_details' + return cls('device_approvals_change_overage_action_details', val) - def is_paper_published_link_disabled_details(self): + @classmethod + def device_approvals_change_unlink_action_details(cls, val): """ - Check if the union tag is ``paper_published_link_disabled_details``. + Create an instance of this class set to the + ``device_approvals_change_unlink_action_details`` tag with value + ``val``. - :rtype: bool + :param DeviceApprovalsChangeUnlinkActionDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_published_link_disabled_details' + return cls('device_approvals_change_unlink_action_details', val) - def is_paper_published_link_view_details(self): + @classmethod + def device_approvals_remove_exception_details(cls, val): """ - Check if the union tag is ``paper_published_link_view_details``. + Create an instance of this class set to the + ``device_approvals_remove_exception_details`` tag with value ``val``. - :rtype: bool + :param DeviceApprovalsRemoveExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_published_link_view_details' + return cls('device_approvals_remove_exception_details', val) - def is_password_change_details(self): + @classmethod + def directory_restrictions_add_members_details(cls, val): """ - Check if the union tag is ``password_change_details``. + Create an instance of this class set to the + ``directory_restrictions_add_members_details`` tag with value ``val``. - :rtype: bool + :param DirectoryRestrictionsAddMembersDetails val: + :rtype: EventDetails """ - return self._tag == 'password_change_details' + return cls('directory_restrictions_add_members_details', val) - def is_password_reset_details(self): + @classmethod + def directory_restrictions_remove_members_details(cls, val): """ - Check if the union tag is ``password_reset_details``. + Create an instance of this class set to the + ``directory_restrictions_remove_members_details`` tag with value + ``val``. - :rtype: bool + :param DirectoryRestrictionsRemoveMembersDetails val: + :rtype: EventDetails """ - return self._tag == 'password_reset_details' + return cls('directory_restrictions_remove_members_details', val) - def is_password_reset_all_details(self): + @classmethod + def emm_add_exception_details(cls, val): """ - Check if the union tag is ``password_reset_all_details``. + Create an instance of this class set to the + ``emm_add_exception_details`` tag with value ``val``. - :rtype: bool + :param EmmAddExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'password_reset_all_details' + return cls('emm_add_exception_details', val) - def is_emm_create_exceptions_report_details(self): + @classmethod + def emm_change_policy_details(cls, val): """ - Check if the union tag is ``emm_create_exceptions_report_details``. + Create an instance of this class set to the + ``emm_change_policy_details`` tag with value ``val``. - :rtype: bool + :param EmmChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'emm_create_exceptions_report_details' + return cls('emm_change_policy_details', val) - def is_emm_create_usage_report_details(self): + @classmethod + def emm_remove_exception_details(cls, val): """ - Check if the union tag is ``emm_create_usage_report_details``. + Create an instance of this class set to the + ``emm_remove_exception_details`` tag with value ``val``. - :rtype: bool + :param EmmRemoveExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'emm_create_usage_report_details' + return cls('emm_remove_exception_details', val) - def is_export_members_report_details(self): + @classmethod + def extended_version_history_change_policy_details(cls, val): """ - Check if the union tag is ``export_members_report_details``. + Create an instance of this class set to the + ``extended_version_history_change_policy_details`` tag with value + ``val``. - :rtype: bool + :param ExtendedVersionHistoryChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'export_members_report_details' + return cls('extended_version_history_change_policy_details', val) - def is_paper_admin_export_start_details(self): + @classmethod + def file_comments_change_policy_details(cls, val): """ - Check if the union tag is ``paper_admin_export_start_details``. + Create an instance of this class set to the + ``file_comments_change_policy_details`` tag with value ``val``. - :rtype: bool + :param FileCommentsChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'paper_admin_export_start_details' + return cls('file_comments_change_policy_details', val) - def is_smart_sync_create_admin_privilege_report_details(self): + @classmethod + def file_locking_policy_changed_details(cls, val): """ - Check if the union tag is ``smart_sync_create_admin_privilege_report_details``. + Create an instance of this class set to the + ``file_locking_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param FileLockingPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'smart_sync_create_admin_privilege_report_details' + return cls('file_locking_policy_changed_details', val) - def is_team_activity_create_report_details(self): + @classmethod + def file_requests_change_policy_details(cls, val): """ - Check if the union tag is ``team_activity_create_report_details``. + Create an instance of this class set to the + ``file_requests_change_policy_details`` tag with value ``val``. - :rtype: bool + :param FileRequestsChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'team_activity_create_report_details' + return cls('file_requests_change_policy_details', val) - def is_team_activity_create_report_fail_details(self): + @classmethod + def file_requests_emails_enabled_details(cls, val): """ - Check if the union tag is ``team_activity_create_report_fail_details``. + Create an instance of this class set to the + ``file_requests_emails_enabled_details`` tag with value ``val``. - :rtype: bool + :param FileRequestsEmailsEnabledDetails val: + :rtype: EventDetails """ - return self._tag == 'team_activity_create_report_fail_details' + return cls('file_requests_emails_enabled_details', val) - def is_collection_share_details(self): + @classmethod + def file_requests_emails_restricted_to_team_only_details(cls, val): """ - Check if the union tag is ``collection_share_details``. + Create an instance of this class set to the + ``file_requests_emails_restricted_to_team_only_details`` tag with value + ``val``. - :rtype: bool + :param FileRequestsEmailsRestrictedToTeamOnlyDetails val: + :rtype: EventDetails """ - return self._tag == 'collection_share_details' + return cls('file_requests_emails_restricted_to_team_only_details', val) - def is_note_acl_invite_only_details(self): + @classmethod + def file_transfers_policy_changed_details(cls, val): """ - Check if the union tag is ``note_acl_invite_only_details``. + Create an instance of this class set to the + ``file_transfers_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param FileTransfersPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'note_acl_invite_only_details' + return cls('file_transfers_policy_changed_details', val) - def is_note_acl_link_details(self): + @classmethod + def google_sso_change_policy_details(cls, val): """ - Check if the union tag is ``note_acl_link_details``. + Create an instance of this class set to the + ``google_sso_change_policy_details`` tag with value ``val``. - :rtype: bool + :param GoogleSsoChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'note_acl_link_details' + return cls('google_sso_change_policy_details', val) - def is_note_acl_team_link_details(self): + @classmethod + def group_user_management_change_policy_details(cls, val): """ - Check if the union tag is ``note_acl_team_link_details``. + Create an instance of this class set to the + ``group_user_management_change_policy_details`` tag with value ``val``. - :rtype: bool + :param GroupUserManagementChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'note_acl_team_link_details' + return cls('group_user_management_change_policy_details', val) - def is_note_shared_details(self): + @classmethod + def integration_policy_changed_details(cls, val): """ - Check if the union tag is ``note_shared_details``. + Create an instance of this class set to the + ``integration_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param IntegrationPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'note_shared_details' + return cls('integration_policy_changed_details', val) - def is_note_share_receive_details(self): + @classmethod + def member_requests_change_policy_details(cls, val): """ - Check if the union tag is ``note_share_receive_details``. + Create an instance of this class set to the + ``member_requests_change_policy_details`` tag with value ``val``. - :rtype: bool + :param MemberRequestsChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'note_share_receive_details' + return cls('member_requests_change_policy_details', val) - def is_open_note_shared_details(self): + @classmethod + def member_send_invite_policy_changed_details(cls, val): """ - Check if the union tag is ``open_note_shared_details``. + Create an instance of this class set to the + ``member_send_invite_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param MemberSendInvitePolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'open_note_shared_details' + return cls('member_send_invite_policy_changed_details', val) - def is_sf_add_group_details(self): + @classmethod + def member_space_limits_add_exception_details(cls, val): """ - Check if the union tag is ``sf_add_group_details``. + Create an instance of this class set to the + ``member_space_limits_add_exception_details`` tag with value ``val``. - :rtype: bool + :param MemberSpaceLimitsAddExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_add_group_details' + return cls('member_space_limits_add_exception_details', val) - def is_sf_allow_non_members_to_view_shared_links_details(self): + @classmethod + def member_space_limits_change_caps_type_policy_details(cls, val): """ - Check if the union tag is ``sf_allow_non_members_to_view_shared_links_details``. + Create an instance of this class set to the + ``member_space_limits_change_caps_type_policy_details`` tag with value + ``val``. - :rtype: bool + :param MemberSpaceLimitsChangeCapsTypePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_allow_non_members_to_view_shared_links_details' + return cls('member_space_limits_change_caps_type_policy_details', val) - def is_sf_external_invite_warn_details(self): + @classmethod + def member_space_limits_change_policy_details(cls, val): """ - Check if the union tag is ``sf_external_invite_warn_details``. + Create an instance of this class set to the + ``member_space_limits_change_policy_details`` tag with value ``val``. - :rtype: bool + :param MemberSpaceLimitsChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_external_invite_warn_details' + return cls('member_space_limits_change_policy_details', val) - def is_sf_fb_invite_details(self): + @classmethod + def member_space_limits_remove_exception_details(cls, val): """ - Check if the union tag is ``sf_fb_invite_details``. + Create an instance of this class set to the + ``member_space_limits_remove_exception_details`` tag with value ``val``. - :rtype: bool + :param MemberSpaceLimitsRemoveExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_fb_invite_details' + return cls('member_space_limits_remove_exception_details', val) - def is_sf_fb_invite_change_role_details(self): + @classmethod + def member_suggestions_change_policy_details(cls, val): """ - Check if the union tag is ``sf_fb_invite_change_role_details``. + Create an instance of this class set to the + ``member_suggestions_change_policy_details`` tag with value ``val``. - :rtype: bool + :param MemberSuggestionsChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_fb_invite_change_role_details' + return cls('member_suggestions_change_policy_details', val) - def is_sf_fb_uninvite_details(self): + @classmethod + def microsoft_office_addin_change_policy_details(cls, val): """ - Check if the union tag is ``sf_fb_uninvite_details``. + Create an instance of this class set to the + ``microsoft_office_addin_change_policy_details`` tag with value ``val``. - :rtype: bool + :param MicrosoftOfficeAddinChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_fb_uninvite_details' + return cls('microsoft_office_addin_change_policy_details', val) - def is_sf_invite_group_details(self): + @classmethod + def network_control_change_policy_details(cls, val): """ - Check if the union tag is ``sf_invite_group_details``. + Create an instance of this class set to the + ``network_control_change_policy_details`` tag with value ``val``. - :rtype: bool + :param NetworkControlChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_invite_group_details' + return cls('network_control_change_policy_details', val) - def is_sf_team_grant_access_details(self): + @classmethod + def paper_change_deployment_policy_details(cls, val): """ - Check if the union tag is ``sf_team_grant_access_details``. + Create an instance of this class set to the + ``paper_change_deployment_policy_details`` tag with value ``val``. - :rtype: bool + :param PaperChangeDeploymentPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_team_grant_access_details' + return cls('paper_change_deployment_policy_details', val) - def is_sf_team_invite_details(self): + @classmethod + def paper_change_member_link_policy_details(cls, val): """ - Check if the union tag is ``sf_team_invite_details``. + Create an instance of this class set to the + ``paper_change_member_link_policy_details`` tag with value ``val``. - :rtype: bool + :param PaperChangeMemberLinkPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_team_invite_details' + return cls('paper_change_member_link_policy_details', val) - def is_sf_team_invite_change_role_details(self): + @classmethod + def paper_change_member_policy_details(cls, val): """ - Check if the union tag is ``sf_team_invite_change_role_details``. + Create an instance of this class set to the + ``paper_change_member_policy_details`` tag with value ``val``. - :rtype: bool + :param PaperChangeMemberPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_team_invite_change_role_details' + return cls('paper_change_member_policy_details', val) - def is_sf_team_join_details(self): + @classmethod + def paper_change_policy_details(cls, val): """ - Check if the union tag is ``sf_team_join_details``. + Create an instance of this class set to the + ``paper_change_policy_details`` tag with value ``val``. - :rtype: bool + :param PaperChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_team_join_details' + return cls('paper_change_policy_details', val) - def is_sf_team_join_from_oob_link_details(self): + @classmethod + def paper_default_folder_policy_changed_details(cls, val): """ - Check if the union tag is ``sf_team_join_from_oob_link_details``. + Create an instance of this class set to the + ``paper_default_folder_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param PaperDefaultFolderPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_team_join_from_oob_link_details' + return cls('paper_default_folder_policy_changed_details', val) - def is_sf_team_uninvite_details(self): + @classmethod + def paper_desktop_policy_changed_details(cls, val): """ - Check if the union tag is ``sf_team_uninvite_details``. + Create an instance of this class set to the + ``paper_desktop_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param PaperDesktopPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'sf_team_uninvite_details' + return cls('paper_desktop_policy_changed_details', val) - def is_shared_content_add_invitees_details(self): + @classmethod + def paper_enabled_users_group_addition_details(cls, val): """ - Check if the union tag is ``shared_content_add_invitees_details``. + Create an instance of this class set to the + ``paper_enabled_users_group_addition_details`` tag with value ``val``. - :rtype: bool + :param PaperEnabledUsersGroupAdditionDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_add_invitees_details' + return cls('paper_enabled_users_group_addition_details', val) - def is_shared_content_add_link_expiry_details(self): + @classmethod + def paper_enabled_users_group_removal_details(cls, val): """ - Check if the union tag is ``shared_content_add_link_expiry_details``. + Create an instance of this class set to the + ``paper_enabled_users_group_removal_details`` tag with value ``val``. - :rtype: bool + :param PaperEnabledUsersGroupRemovalDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_add_link_expiry_details' + return cls('paper_enabled_users_group_removal_details', val) - def is_shared_content_add_link_password_details(self): + @classmethod + def password_strength_requirements_change_policy_details(cls, val): """ - Check if the union tag is ``shared_content_add_link_password_details``. + Create an instance of this class set to the + ``password_strength_requirements_change_policy_details`` tag with value + ``val``. - :rtype: bool + :param PasswordStrengthRequirementsChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_add_link_password_details' + return cls('password_strength_requirements_change_policy_details', val) - def is_shared_content_add_member_details(self): + @classmethod + def permanent_delete_change_policy_details(cls, val): """ - Check if the union tag is ``shared_content_add_member_details``. + Create an instance of this class set to the + ``permanent_delete_change_policy_details`` tag with value ``val``. - :rtype: bool + :param PermanentDeleteChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_add_member_details' + return cls('permanent_delete_change_policy_details', val) - def is_shared_content_change_downloads_policy_details(self): + @classmethod + def reseller_support_change_policy_details(cls, val): """ - Check if the union tag is ``shared_content_change_downloads_policy_details``. + Create an instance of this class set to the + ``reseller_support_change_policy_details`` tag with value ``val``. - :rtype: bool + :param ResellerSupportChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_change_downloads_policy_details' + return cls('reseller_support_change_policy_details', val) - def is_shared_content_change_invitee_role_details(self): + @classmethod + def rewind_policy_changed_details(cls, val): """ - Check if the union tag is ``shared_content_change_invitee_role_details``. + Create an instance of this class set to the + ``rewind_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param RewindPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_change_invitee_role_details' + return cls('rewind_policy_changed_details', val) - def is_shared_content_change_link_audience_details(self): + @classmethod + def sharing_change_folder_join_policy_details(cls, val): """ - Check if the union tag is ``shared_content_change_link_audience_details``. + Create an instance of this class set to the + ``sharing_change_folder_join_policy_details`` tag with value ``val``. - :rtype: bool + :param SharingChangeFolderJoinPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_change_link_audience_details' + return cls('sharing_change_folder_join_policy_details', val) - def is_shared_content_change_link_expiry_details(self): + @classmethod + def sharing_change_link_policy_details(cls, val): """ - Check if the union tag is ``shared_content_change_link_expiry_details``. + Create an instance of this class set to the + ``sharing_change_link_policy_details`` tag with value ``val``. - :rtype: bool + :param SharingChangeLinkPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_change_link_expiry_details' + return cls('sharing_change_link_policy_details', val) - def is_shared_content_change_link_password_details(self): + @classmethod + def sharing_change_member_policy_details(cls, val): """ - Check if the union tag is ``shared_content_change_link_password_details``. + Create an instance of this class set to the + ``sharing_change_member_policy_details`` tag with value ``val``. - :rtype: bool + :param SharingChangeMemberPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_change_link_password_details' + return cls('sharing_change_member_policy_details', val) - def is_shared_content_change_member_role_details(self): + @classmethod + def showcase_change_download_policy_details(cls, val): """ - Check if the union tag is ``shared_content_change_member_role_details``. + Create an instance of this class set to the + ``showcase_change_download_policy_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseChangeDownloadPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_change_member_role_details' + return cls('showcase_change_download_policy_details', val) - def is_shared_content_change_viewer_info_policy_details(self): + @classmethod + def showcase_change_enabled_policy_details(cls, val): """ - Check if the union tag is ``shared_content_change_viewer_info_policy_details``. + Create an instance of this class set to the + ``showcase_change_enabled_policy_details`` tag with value ``val``. - :rtype: bool + :param ShowcaseChangeEnabledPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_change_viewer_info_policy_details' + return cls('showcase_change_enabled_policy_details', val) - def is_shared_content_claim_invitation_details(self): + @classmethod + def showcase_change_external_sharing_policy_details(cls, val): """ - Check if the union tag is ``shared_content_claim_invitation_details``. + Create an instance of this class set to the + ``showcase_change_external_sharing_policy_details`` tag with value + ``val``. - :rtype: bool + :param ShowcaseChangeExternalSharingPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_claim_invitation_details' + return cls('showcase_change_external_sharing_policy_details', val) - def is_shared_content_copy_details(self): + @classmethod + def smarter_smart_sync_policy_changed_details(cls, val): """ - Check if the union tag is ``shared_content_copy_details``. + Create an instance of this class set to the + ``smarter_smart_sync_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param SmarterSmartSyncPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_copy_details' + return cls('smarter_smart_sync_policy_changed_details', val) - def is_shared_content_download_details(self): + @classmethod + def smart_sync_change_policy_details(cls, val): """ - Check if the union tag is ``shared_content_download_details``. + Create an instance of this class set to the + ``smart_sync_change_policy_details`` tag with value ``val``. - :rtype: bool + :param SmartSyncChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_download_details' + return cls('smart_sync_change_policy_details', val) - def is_shared_content_relinquish_membership_details(self): + @classmethod + def smart_sync_not_opt_out_details(cls, val): """ - Check if the union tag is ``shared_content_relinquish_membership_details``. + Create an instance of this class set to the + ``smart_sync_not_opt_out_details`` tag with value ``val``. - :rtype: bool + :param SmartSyncNotOptOutDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_relinquish_membership_details' + return cls('smart_sync_not_opt_out_details', val) - def is_shared_content_remove_invitees_details(self): + @classmethod + def smart_sync_opt_out_details(cls, val): """ - Check if the union tag is ``shared_content_remove_invitees_details``. + Create an instance of this class set to the + ``smart_sync_opt_out_details`` tag with value ``val``. - :rtype: bool + :param SmartSyncOptOutDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_remove_invitees_details' + return cls('smart_sync_opt_out_details', val) - def is_shared_content_remove_link_expiry_details(self): + @classmethod + def sso_change_policy_details(cls, val): """ - Check if the union tag is ``shared_content_remove_link_expiry_details``. + Create an instance of this class set to the + ``sso_change_policy_details`` tag with value ``val``. - :rtype: bool + :param SsoChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_remove_link_expiry_details' + return cls('sso_change_policy_details', val) - def is_shared_content_remove_link_password_details(self): + @classmethod + def team_extensions_policy_changed_details(cls, val): """ - Check if the union tag is ``shared_content_remove_link_password_details``. + Create an instance of this class set to the + ``team_extensions_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param TeamExtensionsPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_remove_link_password_details' + return cls('team_extensions_policy_changed_details', val) - def is_shared_content_remove_member_details(self): + @classmethod + def team_selective_sync_policy_changed_details(cls, val): """ - Check if the union tag is ``shared_content_remove_member_details``. + Create an instance of this class set to the + ``team_selective_sync_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param TeamSelectiveSyncPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_remove_member_details' + return cls('team_selective_sync_policy_changed_details', val) - def is_shared_content_request_access_details(self): + @classmethod + def team_sharing_whitelist_subjects_changed_details(cls, val): """ - Check if the union tag is ``shared_content_request_access_details``. + Create an instance of this class set to the + ``team_sharing_whitelist_subjects_changed_details`` tag with value + ``val``. - :rtype: bool + :param TeamSharingWhitelistSubjectsChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_request_access_details' + return cls('team_sharing_whitelist_subjects_changed_details', val) - def is_shared_content_unshare_details(self): + @classmethod + def tfa_add_exception_details(cls, val): """ - Check if the union tag is ``shared_content_unshare_details``. + Create an instance of this class set to the + ``tfa_add_exception_details`` tag with value ``val``. - :rtype: bool + :param TfaAddExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_unshare_details' + return cls('tfa_add_exception_details', val) - def is_shared_content_view_details(self): + @classmethod + def tfa_change_policy_details(cls, val): """ - Check if the union tag is ``shared_content_view_details``. + Create an instance of this class set to the + ``tfa_change_policy_details`` tag with value ``val``. - :rtype: bool + :param TfaChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_content_view_details' + return cls('tfa_change_policy_details', val) - def is_shared_folder_change_link_policy_details(self): + @classmethod + def tfa_remove_exception_details(cls, val): """ - Check if the union tag is ``shared_folder_change_link_policy_details``. + Create an instance of this class set to the + ``tfa_remove_exception_details`` tag with value ``val``. - :rtype: bool + :param TfaRemoveExceptionDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_change_link_policy_details' + return cls('tfa_remove_exception_details', val) - def is_shared_folder_change_members_inheritance_policy_details(self): + @classmethod + def two_account_change_policy_details(cls, val): """ - Check if the union tag is ``shared_folder_change_members_inheritance_policy_details``. + Create an instance of this class set to the + ``two_account_change_policy_details`` tag with value ``val``. - :rtype: bool + :param TwoAccountChangePolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_change_members_inheritance_policy_details' + return cls('two_account_change_policy_details', val) - def is_shared_folder_change_members_management_policy_details(self): + @classmethod + def viewer_info_policy_changed_details(cls, val): """ - Check if the union tag is ``shared_folder_change_members_management_policy_details``. + Create an instance of this class set to the + ``viewer_info_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param ViewerInfoPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_change_members_management_policy_details' + return cls('viewer_info_policy_changed_details', val) - def is_shared_folder_change_members_policy_details(self): + @classmethod + def watermarking_policy_changed_details(cls, val): """ - Check if the union tag is ``shared_folder_change_members_policy_details``. + Create an instance of this class set to the + ``watermarking_policy_changed_details`` tag with value ``val``. - :rtype: bool + :param WatermarkingPolicyChangedDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_change_members_policy_details' + return cls('watermarking_policy_changed_details', val) - def is_shared_folder_create_details(self): + @classmethod + def web_sessions_change_active_session_limit_details(cls, val): """ - Check if the union tag is ``shared_folder_create_details``. + Create an instance of this class set to the + ``web_sessions_change_active_session_limit_details`` tag with value + ``val``. - :rtype: bool + :param WebSessionsChangeActiveSessionLimitDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_create_details' + return cls('web_sessions_change_active_session_limit_details', val) - def is_shared_folder_decline_invitation_details(self): + @classmethod + def web_sessions_change_fixed_length_policy_details(cls, val): """ - Check if the union tag is ``shared_folder_decline_invitation_details``. + Create an instance of this class set to the + ``web_sessions_change_fixed_length_policy_details`` tag with value + ``val``. - :rtype: bool + :param WebSessionsChangeFixedLengthPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_decline_invitation_details' + return cls('web_sessions_change_fixed_length_policy_details', val) - def is_shared_folder_mount_details(self): + @classmethod + def web_sessions_change_idle_length_policy_details(cls, val): """ - Check if the union tag is ``shared_folder_mount_details``. + Create an instance of this class set to the + ``web_sessions_change_idle_length_policy_details`` tag with value + ``val``. - :rtype: bool + :param WebSessionsChangeIdleLengthPolicyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_mount_details' + return cls('web_sessions_change_idle_length_policy_details', val) - def is_shared_folder_nest_details(self): + @classmethod + def team_merge_from_details(cls, val): """ - Check if the union tag is ``shared_folder_nest_details``. + Create an instance of this class set to the ``team_merge_from_details`` + tag with value ``val``. - :rtype: bool + :param TeamMergeFromDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_nest_details' + return cls('team_merge_from_details', val) - def is_shared_folder_transfer_ownership_details(self): + @classmethod + def team_merge_to_details(cls, val): """ - Check if the union tag is ``shared_folder_transfer_ownership_details``. + Create an instance of this class set to the ``team_merge_to_details`` + tag with value ``val``. - :rtype: bool + :param TeamMergeToDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_transfer_ownership_details' + return cls('team_merge_to_details', val) - def is_shared_folder_unmount_details(self): + @classmethod + def team_profile_add_logo_details(cls, val): """ - Check if the union tag is ``shared_folder_unmount_details``. + Create an instance of this class set to the + ``team_profile_add_logo_details`` tag with value ``val``. - :rtype: bool + :param TeamProfileAddLogoDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_folder_unmount_details' + return cls('team_profile_add_logo_details', val) - def is_shared_link_add_expiry_details(self): + @classmethod + def team_profile_change_default_language_details(cls, val): """ - Check if the union tag is ``shared_link_add_expiry_details``. + Create an instance of this class set to the + ``team_profile_change_default_language_details`` tag with value ``val``. - :rtype: bool + :param TeamProfileChangeDefaultLanguageDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_add_expiry_details' + return cls('team_profile_change_default_language_details', val) - def is_shared_link_change_expiry_details(self): + @classmethod + def team_profile_change_logo_details(cls, val): """ - Check if the union tag is ``shared_link_change_expiry_details``. + Create an instance of this class set to the + ``team_profile_change_logo_details`` tag with value ``val``. - :rtype: bool + :param TeamProfileChangeLogoDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_change_expiry_details' + return cls('team_profile_change_logo_details', val) - def is_shared_link_change_visibility_details(self): + @classmethod + def team_profile_change_name_details(cls, val): """ - Check if the union tag is ``shared_link_change_visibility_details``. + Create an instance of this class set to the + ``team_profile_change_name_details`` tag with value ``val``. - :rtype: bool + :param TeamProfileChangeNameDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_change_visibility_details' + return cls('team_profile_change_name_details', val) - def is_shared_link_copy_details(self): + @classmethod + def team_profile_remove_logo_details(cls, val): """ - Check if the union tag is ``shared_link_copy_details``. + Create an instance of this class set to the + ``team_profile_remove_logo_details`` tag with value ``val``. - :rtype: bool + :param TeamProfileRemoveLogoDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_copy_details' + return cls('team_profile_remove_logo_details', val) - def is_shared_link_create_details(self): + @classmethod + def tfa_add_backup_phone_details(cls, val): """ - Check if the union tag is ``shared_link_create_details``. + Create an instance of this class set to the + ``tfa_add_backup_phone_details`` tag with value ``val``. - :rtype: bool + :param TfaAddBackupPhoneDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_create_details' + return cls('tfa_add_backup_phone_details', val) - def is_shared_link_disable_details(self): + @classmethod + def tfa_add_security_key_details(cls, val): """ - Check if the union tag is ``shared_link_disable_details``. + Create an instance of this class set to the + ``tfa_add_security_key_details`` tag with value ``val``. - :rtype: bool + :param TfaAddSecurityKeyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_disable_details' + return cls('tfa_add_security_key_details', val) - def is_shared_link_download_details(self): + @classmethod + def tfa_change_backup_phone_details(cls, val): """ - Check if the union tag is ``shared_link_download_details``. + Create an instance of this class set to the + ``tfa_change_backup_phone_details`` tag with value ``val``. - :rtype: bool + :param TfaChangeBackupPhoneDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_download_details' + return cls('tfa_change_backup_phone_details', val) - def is_shared_link_remove_expiry_details(self): + @classmethod + def tfa_change_status_details(cls, val): """ - Check if the union tag is ``shared_link_remove_expiry_details``. + Create an instance of this class set to the + ``tfa_change_status_details`` tag with value ``val``. - :rtype: bool + :param TfaChangeStatusDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_remove_expiry_details' + return cls('tfa_change_status_details', val) - def is_shared_link_share_details(self): + @classmethod + def tfa_remove_backup_phone_details(cls, val): """ - Check if the union tag is ``shared_link_share_details``. + Create an instance of this class set to the + ``tfa_remove_backup_phone_details`` tag with value ``val``. - :rtype: bool + :param TfaRemoveBackupPhoneDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_share_details' + return cls('tfa_remove_backup_phone_details', val) - def is_shared_link_view_details(self): + @classmethod + def tfa_remove_security_key_details(cls, val): """ - Check if the union tag is ``shared_link_view_details``. + Create an instance of this class set to the + ``tfa_remove_security_key_details`` tag with value ``val``. - :rtype: bool + :param TfaRemoveSecurityKeyDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_link_view_details' + return cls('tfa_remove_security_key_details', val) - def is_shared_note_opened_details(self): + @classmethod + def tfa_reset_details(cls, val): """ - Check if the union tag is ``shared_note_opened_details``. + Create an instance of this class set to the ``tfa_reset_details`` tag + with value ``val``. - :rtype: bool + :param TfaResetDetails val: + :rtype: EventDetails """ - return self._tag == 'shared_note_opened_details' + return cls('tfa_reset_details', val) - def is_shmodel_group_share_details(self): + @classmethod + def changed_enterprise_admin_role_details(cls, val): """ - Check if the union tag is ``shmodel_group_share_details``. + Create an instance of this class set to the + ``changed_enterprise_admin_role_details`` tag with value ``val``. - :rtype: bool + :param ChangedEnterpriseAdminRoleDetails val: + :rtype: EventDetails """ - return self._tag == 'shmodel_group_share_details' + return cls('changed_enterprise_admin_role_details', val) - def is_showcase_access_granted_details(self): + @classmethod + def changed_enterprise_connected_team_status_details(cls, val): """ - Check if the union tag is ``showcase_access_granted_details``. + Create an instance of this class set to the + ``changed_enterprise_connected_team_status_details`` tag with value + ``val``. - :rtype: bool + :param ChangedEnterpriseConnectedTeamStatusDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_access_granted_details' + return cls('changed_enterprise_connected_team_status_details', val) - def is_showcase_add_member_details(self): + @classmethod + def ended_enterprise_admin_session_details(cls, val): """ - Check if the union tag is ``showcase_add_member_details``. + Create an instance of this class set to the + ``ended_enterprise_admin_session_details`` tag with value ``val``. - :rtype: bool + :param EndedEnterpriseAdminSessionDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_add_member_details' + return cls('ended_enterprise_admin_session_details', val) - def is_showcase_archived_details(self): + @classmethod + def ended_enterprise_admin_session_deprecated_details(cls, val): """ - Check if the union tag is ``showcase_archived_details``. + Create an instance of this class set to the + ``ended_enterprise_admin_session_deprecated_details`` tag with value + ``val``. - :rtype: bool + :param EndedEnterpriseAdminSessionDeprecatedDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_archived_details' + return cls('ended_enterprise_admin_session_deprecated_details', val) - def is_showcase_created_details(self): + @classmethod + def enterprise_settings_locking_details(cls, val): """ - Check if the union tag is ``showcase_created_details``. + Create an instance of this class set to the + ``enterprise_settings_locking_details`` tag with value ``val``. - :rtype: bool + :param EnterpriseSettingsLockingDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_created_details' + return cls('enterprise_settings_locking_details', val) - def is_showcase_delete_comment_details(self): + @classmethod + def guest_admin_change_status_details(cls, val): """ - Check if the union tag is ``showcase_delete_comment_details``. + Create an instance of this class set to the + ``guest_admin_change_status_details`` tag with value ``val``. - :rtype: bool + :param GuestAdminChangeStatusDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_delete_comment_details' + return cls('guest_admin_change_status_details', val) - def is_showcase_edited_details(self): + @classmethod + def started_enterprise_admin_session_details(cls, val): """ - Check if the union tag is ``showcase_edited_details``. + Create an instance of this class set to the + ``started_enterprise_admin_session_details`` tag with value ``val``. - :rtype: bool + :param StartedEnterpriseAdminSessionDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_edited_details' + return cls('started_enterprise_admin_session_details', val) - def is_showcase_edit_comment_details(self): + @classmethod + def team_merge_request_accepted_details(cls, val): """ - Check if the union tag is ``showcase_edit_comment_details``. + Create an instance of this class set to the + ``team_merge_request_accepted_details`` tag with value ``val``. - :rtype: bool + :param TeamMergeRequestAcceptedDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_edit_comment_details' + return cls('team_merge_request_accepted_details', val) - def is_showcase_file_added_details(self): + @classmethod + def team_merge_request_accepted_shown_to_primary_team_details(cls, val): """ - Check if the union tag is ``showcase_file_added_details``. + Create an instance of this class set to the + ``team_merge_request_accepted_shown_to_primary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestAcceptedShownToPrimaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_file_added_details' + return cls('team_merge_request_accepted_shown_to_primary_team_details', val) - def is_showcase_file_download_details(self): + @classmethod + def team_merge_request_accepted_shown_to_secondary_team_details(cls, val): """ - Check if the union tag is ``showcase_file_download_details``. + Create an instance of this class set to the + ``team_merge_request_accepted_shown_to_secondary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestAcceptedShownToSecondaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_file_download_details' + return cls('team_merge_request_accepted_shown_to_secondary_team_details', val) - def is_showcase_file_removed_details(self): + @classmethod + def team_merge_request_auto_canceled_details(cls, val): """ - Check if the union tag is ``showcase_file_removed_details``. + Create an instance of this class set to the + ``team_merge_request_auto_canceled_details`` tag with value ``val``. - :rtype: bool + :param TeamMergeRequestAutoCanceledDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_file_removed_details' + return cls('team_merge_request_auto_canceled_details', val) - def is_showcase_file_view_details(self): + @classmethod + def team_merge_request_canceled_details(cls, val): """ - Check if the union tag is ``showcase_file_view_details``. + Create an instance of this class set to the + ``team_merge_request_canceled_details`` tag with value ``val``. - :rtype: bool + :param TeamMergeRequestCanceledDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_file_view_details' + return cls('team_merge_request_canceled_details', val) - def is_showcase_permanently_deleted_details(self): + @classmethod + def team_merge_request_canceled_shown_to_primary_team_details(cls, val): """ - Check if the union tag is ``showcase_permanently_deleted_details``. + Create an instance of this class set to the + ``team_merge_request_canceled_shown_to_primary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestCanceledShownToPrimaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_permanently_deleted_details' + return cls('team_merge_request_canceled_shown_to_primary_team_details', val) - def is_showcase_post_comment_details(self): + @classmethod + def team_merge_request_canceled_shown_to_secondary_team_details(cls, val): """ - Check if the union tag is ``showcase_post_comment_details``. + Create an instance of this class set to the + ``team_merge_request_canceled_shown_to_secondary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestCanceledShownToSecondaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_post_comment_details' + return cls('team_merge_request_canceled_shown_to_secondary_team_details', val) - def is_showcase_remove_member_details(self): + @classmethod + def team_merge_request_expired_details(cls, val): """ - Check if the union tag is ``showcase_remove_member_details``. + Create an instance of this class set to the + ``team_merge_request_expired_details`` tag with value ``val``. - :rtype: bool + :param TeamMergeRequestExpiredDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_remove_member_details' + return cls('team_merge_request_expired_details', val) - def is_showcase_renamed_details(self): + @classmethod + def team_merge_request_expired_shown_to_primary_team_details(cls, val): """ - Check if the union tag is ``showcase_renamed_details``. + Create an instance of this class set to the + ``team_merge_request_expired_shown_to_primary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestExpiredShownToPrimaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_renamed_details' + return cls('team_merge_request_expired_shown_to_primary_team_details', val) - def is_showcase_request_access_details(self): + @classmethod + def team_merge_request_expired_shown_to_secondary_team_details(cls, val): """ - Check if the union tag is ``showcase_request_access_details``. + Create an instance of this class set to the + ``team_merge_request_expired_shown_to_secondary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestExpiredShownToSecondaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_request_access_details' + return cls('team_merge_request_expired_shown_to_secondary_team_details', val) - def is_showcase_resolve_comment_details(self): + @classmethod + def team_merge_request_rejected_shown_to_primary_team_details(cls, val): """ - Check if the union tag is ``showcase_resolve_comment_details``. + Create an instance of this class set to the + ``team_merge_request_rejected_shown_to_primary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestRejectedShownToPrimaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_resolve_comment_details' + return cls('team_merge_request_rejected_shown_to_primary_team_details', val) - def is_showcase_restored_details(self): + @classmethod + def team_merge_request_rejected_shown_to_secondary_team_details(cls, val): """ - Check if the union tag is ``showcase_restored_details``. + Create an instance of this class set to the + ``team_merge_request_rejected_shown_to_secondary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestRejectedShownToSecondaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_restored_details' + return cls('team_merge_request_rejected_shown_to_secondary_team_details', val) - def is_showcase_trashed_details(self): + @classmethod + def team_merge_request_reminder_details(cls, val): """ - Check if the union tag is ``showcase_trashed_details``. + Create an instance of this class set to the + ``team_merge_request_reminder_details`` tag with value ``val``. - :rtype: bool + :param TeamMergeRequestReminderDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_trashed_details' + return cls('team_merge_request_reminder_details', val) - def is_showcase_trashed_deprecated_details(self): + @classmethod + def team_merge_request_reminder_shown_to_primary_team_details(cls, val): """ - Check if the union tag is ``showcase_trashed_deprecated_details``. + Create an instance of this class set to the + ``team_merge_request_reminder_shown_to_primary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestReminderShownToPrimaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_trashed_deprecated_details' + return cls('team_merge_request_reminder_shown_to_primary_team_details', val) - def is_showcase_unresolve_comment_details(self): + @classmethod + def team_merge_request_reminder_shown_to_secondary_team_details(cls, val): """ - Check if the union tag is ``showcase_unresolve_comment_details``. + Create an instance of this class set to the + ``team_merge_request_reminder_shown_to_secondary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestReminderShownToSecondaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_unresolve_comment_details' + return cls('team_merge_request_reminder_shown_to_secondary_team_details', val) - def is_showcase_untrashed_details(self): + @classmethod + def team_merge_request_revoked_details(cls, val): """ - Check if the union tag is ``showcase_untrashed_details``. + Create an instance of this class set to the + ``team_merge_request_revoked_details`` tag with value ``val``. - :rtype: bool + :param TeamMergeRequestRevokedDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_untrashed_details' + return cls('team_merge_request_revoked_details', val) - def is_showcase_untrashed_deprecated_details(self): + @classmethod + def team_merge_request_sent_shown_to_primary_team_details(cls, val): """ - Check if the union tag is ``showcase_untrashed_deprecated_details``. + Create an instance of this class set to the + ``team_merge_request_sent_shown_to_primary_team_details`` tag with value + ``val``. - :rtype: bool + :param TeamMergeRequestSentShownToPrimaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_untrashed_deprecated_details' + return cls('team_merge_request_sent_shown_to_primary_team_details', val) - def is_showcase_view_details(self): + @classmethod + def team_merge_request_sent_shown_to_secondary_team_details(cls, val): """ - Check if the union tag is ``showcase_view_details``. + Create an instance of this class set to the + ``team_merge_request_sent_shown_to_secondary_team_details`` tag with + value ``val``. - :rtype: bool + :param TeamMergeRequestSentShownToSecondaryTeamDetails val: + :rtype: EventDetails """ - return self._tag == 'showcase_view_details' + return cls('team_merge_request_sent_shown_to_secondary_team_details', val) - def is_sso_add_cert_details(self): + @classmethod + def missing_details(cls, val): """ - Check if the union tag is ``sso_add_cert_details``. + Create an instance of this class set to the ``missing_details`` tag with + value ``val``. - :rtype: bool + :param MissingDetails val: + :rtype: EventDetails """ - return self._tag == 'sso_add_cert_details' + return cls('missing_details', val) - def is_sso_add_login_url_details(self): + def is_app_link_team_details(self): """ - Check if the union tag is ``sso_add_login_url_details``. + Check if the union tag is ``app_link_team_details``. :rtype: bool """ - return self._tag == 'sso_add_login_url_details' + return self._tag == 'app_link_team_details' - def is_sso_add_logout_url_details(self): + def is_app_link_user_details(self): """ - Check if the union tag is ``sso_add_logout_url_details``. + Check if the union tag is ``app_link_user_details``. :rtype: bool """ - return self._tag == 'sso_add_logout_url_details' + return self._tag == 'app_link_user_details' - def is_sso_change_cert_details(self): + def is_app_unlink_team_details(self): """ - Check if the union tag is ``sso_change_cert_details``. + Check if the union tag is ``app_unlink_team_details``. :rtype: bool """ - return self._tag == 'sso_change_cert_details' + return self._tag == 'app_unlink_team_details' - def is_sso_change_login_url_details(self): + def is_app_unlink_user_details(self): """ - Check if the union tag is ``sso_change_login_url_details``. + Check if the union tag is ``app_unlink_user_details``. :rtype: bool """ - return self._tag == 'sso_change_login_url_details' + return self._tag == 'app_unlink_user_details' - def is_sso_change_logout_url_details(self): + def is_integration_connected_details(self): """ - Check if the union tag is ``sso_change_logout_url_details``. + Check if the union tag is ``integration_connected_details``. :rtype: bool """ - return self._tag == 'sso_change_logout_url_details' + return self._tag == 'integration_connected_details' - def is_sso_change_saml_identity_mode_details(self): + def is_integration_disconnected_details(self): """ - Check if the union tag is ``sso_change_saml_identity_mode_details``. + Check if the union tag is ``integration_disconnected_details``. :rtype: bool """ - return self._tag == 'sso_change_saml_identity_mode_details' + return self._tag == 'integration_disconnected_details' - def is_sso_remove_cert_details(self): + def is_file_add_comment_details(self): """ - Check if the union tag is ``sso_remove_cert_details``. + Check if the union tag is ``file_add_comment_details``. :rtype: bool """ - return self._tag == 'sso_remove_cert_details' + return self._tag == 'file_add_comment_details' - def is_sso_remove_login_url_details(self): + def is_file_change_comment_subscription_details(self): """ - Check if the union tag is ``sso_remove_login_url_details``. + Check if the union tag is ``file_change_comment_subscription_details``. :rtype: bool """ - return self._tag == 'sso_remove_login_url_details' + return self._tag == 'file_change_comment_subscription_details' - def is_sso_remove_logout_url_details(self): + def is_file_delete_comment_details(self): """ - Check if the union tag is ``sso_remove_logout_url_details``. + Check if the union tag is ``file_delete_comment_details``. :rtype: bool """ - return self._tag == 'sso_remove_logout_url_details' + return self._tag == 'file_delete_comment_details' - def is_team_folder_change_status_details(self): + def is_file_edit_comment_details(self): """ - Check if the union tag is ``team_folder_change_status_details``. + Check if the union tag is ``file_edit_comment_details``. :rtype: bool """ - return self._tag == 'team_folder_change_status_details' + return self._tag == 'file_edit_comment_details' - def is_team_folder_create_details(self): + def is_file_like_comment_details(self): """ - Check if the union tag is ``team_folder_create_details``. + Check if the union tag is ``file_like_comment_details``. :rtype: bool """ - return self._tag == 'team_folder_create_details' + return self._tag == 'file_like_comment_details' - def is_team_folder_downgrade_details(self): + def is_file_resolve_comment_details(self): """ - Check if the union tag is ``team_folder_downgrade_details``. + Check if the union tag is ``file_resolve_comment_details``. :rtype: bool """ - return self._tag == 'team_folder_downgrade_details' + return self._tag == 'file_resolve_comment_details' - def is_team_folder_permanently_delete_details(self): + def is_file_unlike_comment_details(self): """ - Check if the union tag is ``team_folder_permanently_delete_details``. + Check if the union tag is ``file_unlike_comment_details``. :rtype: bool """ - return self._tag == 'team_folder_permanently_delete_details' + return self._tag == 'file_unlike_comment_details' - def is_team_folder_rename_details(self): + def is_file_unresolve_comment_details(self): """ - Check if the union tag is ``team_folder_rename_details``. + Check if the union tag is ``file_unresolve_comment_details``. :rtype: bool """ - return self._tag == 'team_folder_rename_details' + return self._tag == 'file_unresolve_comment_details' - def is_team_selective_sync_settings_changed_details(self): + def is_device_change_ip_desktop_details(self): """ - Check if the union tag is ``team_selective_sync_settings_changed_details``. + Check if the union tag is ``device_change_ip_desktop_details``. :rtype: bool """ - return self._tag == 'team_selective_sync_settings_changed_details' + return self._tag == 'device_change_ip_desktop_details' - def is_account_capture_change_policy_details(self): + def is_device_change_ip_mobile_details(self): """ - Check if the union tag is ``account_capture_change_policy_details``. + Check if the union tag is ``device_change_ip_mobile_details``. :rtype: bool """ - return self._tag == 'account_capture_change_policy_details' + return self._tag == 'device_change_ip_mobile_details' - def is_allow_download_disabled_details(self): + def is_device_change_ip_web_details(self): """ - Check if the union tag is ``allow_download_disabled_details``. + Check if the union tag is ``device_change_ip_web_details``. :rtype: bool """ - return self._tag == 'allow_download_disabled_details' + return self._tag == 'device_change_ip_web_details' - def is_allow_download_enabled_details(self): + def is_device_delete_on_unlink_fail_details(self): """ - Check if the union tag is ``allow_download_enabled_details``. + Check if the union tag is ``device_delete_on_unlink_fail_details``. :rtype: bool """ - return self._tag == 'allow_download_enabled_details' + return self._tag == 'device_delete_on_unlink_fail_details' - def is_camera_uploads_policy_changed_details(self): + def is_device_delete_on_unlink_success_details(self): """ - Check if the union tag is ``camera_uploads_policy_changed_details``. + Check if the union tag is ``device_delete_on_unlink_success_details``. :rtype: bool """ - return self._tag == 'camera_uploads_policy_changed_details' + return self._tag == 'device_delete_on_unlink_success_details' - def is_data_placement_restriction_change_policy_details(self): + def is_device_link_fail_details(self): """ - Check if the union tag is ``data_placement_restriction_change_policy_details``. + Check if the union tag is ``device_link_fail_details``. :rtype: bool """ - return self._tag == 'data_placement_restriction_change_policy_details' + return self._tag == 'device_link_fail_details' - def is_data_placement_restriction_satisfy_policy_details(self): + def is_device_link_success_details(self): """ - Check if the union tag is ``data_placement_restriction_satisfy_policy_details``. + Check if the union tag is ``device_link_success_details``. :rtype: bool """ - return self._tag == 'data_placement_restriction_satisfy_policy_details' + return self._tag == 'device_link_success_details' - def is_device_approvals_change_desktop_policy_details(self): + def is_device_management_disabled_details(self): """ - Check if the union tag is ``device_approvals_change_desktop_policy_details``. + Check if the union tag is ``device_management_disabled_details``. :rtype: bool """ - return self._tag == 'device_approvals_change_desktop_policy_details' + return self._tag == 'device_management_disabled_details' - def is_device_approvals_change_mobile_policy_details(self): + def is_device_management_enabled_details(self): """ - Check if the union tag is ``device_approvals_change_mobile_policy_details``. + Check if the union tag is ``device_management_enabled_details``. :rtype: bool """ - return self._tag == 'device_approvals_change_mobile_policy_details' + return self._tag == 'device_management_enabled_details' - def is_device_approvals_change_overage_action_details(self): + def is_device_unlink_details(self): """ - Check if the union tag is ``device_approvals_change_overage_action_details``. + Check if the union tag is ``device_unlink_details``. :rtype: bool """ - return self._tag == 'device_approvals_change_overage_action_details' + return self._tag == 'device_unlink_details' - def is_device_approvals_change_unlink_action_details(self): + def is_emm_refresh_auth_token_details(self): """ - Check if the union tag is ``device_approvals_change_unlink_action_details``. + Check if the union tag is ``emm_refresh_auth_token_details``. :rtype: bool """ - return self._tag == 'device_approvals_change_unlink_action_details' + return self._tag == 'emm_refresh_auth_token_details' - def is_directory_restrictions_add_members_details(self): + def is_account_capture_change_availability_details(self): """ - Check if the union tag is ``directory_restrictions_add_members_details``. + Check if the union tag is ``account_capture_change_availability_details``. :rtype: bool """ - return self._tag == 'directory_restrictions_add_members_details' + return self._tag == 'account_capture_change_availability_details' - def is_directory_restrictions_remove_members_details(self): + def is_account_capture_migrate_account_details(self): """ - Check if the union tag is ``directory_restrictions_remove_members_details``. + Check if the union tag is ``account_capture_migrate_account_details``. :rtype: bool """ - return self._tag == 'directory_restrictions_remove_members_details' + return self._tag == 'account_capture_migrate_account_details' - def is_emm_add_exception_details(self): + def is_account_capture_notification_emails_sent_details(self): """ - Check if the union tag is ``emm_add_exception_details``. + Check if the union tag is ``account_capture_notification_emails_sent_details``. :rtype: bool """ - return self._tag == 'emm_add_exception_details' + return self._tag == 'account_capture_notification_emails_sent_details' - def is_emm_change_policy_details(self): + def is_account_capture_relinquish_account_details(self): """ - Check if the union tag is ``emm_change_policy_details``. + Check if the union tag is ``account_capture_relinquish_account_details``. :rtype: bool """ - return self._tag == 'emm_change_policy_details' + return self._tag == 'account_capture_relinquish_account_details' - def is_emm_remove_exception_details(self): + def is_disabled_domain_invites_details(self): """ - Check if the union tag is ``emm_remove_exception_details``. + Check if the union tag is ``disabled_domain_invites_details``. :rtype: bool """ - return self._tag == 'emm_remove_exception_details' + return self._tag == 'disabled_domain_invites_details' - def is_extended_version_history_change_policy_details(self): + def is_domain_invites_approve_request_to_join_team_details(self): """ - Check if the union tag is ``extended_version_history_change_policy_details``. + Check if the union tag is ``domain_invites_approve_request_to_join_team_details``. :rtype: bool """ - return self._tag == 'extended_version_history_change_policy_details' + return self._tag == 'domain_invites_approve_request_to_join_team_details' - def is_file_comments_change_policy_details(self): + def is_domain_invites_decline_request_to_join_team_details(self): """ - Check if the union tag is ``file_comments_change_policy_details``. + Check if the union tag is ``domain_invites_decline_request_to_join_team_details``. :rtype: bool """ - return self._tag == 'file_comments_change_policy_details' + return self._tag == 'domain_invites_decline_request_to_join_team_details' - def is_file_requests_change_policy_details(self): + def is_domain_invites_email_existing_users_details(self): """ - Check if the union tag is ``file_requests_change_policy_details``. + Check if the union tag is ``domain_invites_email_existing_users_details``. :rtype: bool """ - return self._tag == 'file_requests_change_policy_details' + return self._tag == 'domain_invites_email_existing_users_details' - def is_file_requests_emails_enabled_details(self): + def is_domain_invites_request_to_join_team_details(self): """ - Check if the union tag is ``file_requests_emails_enabled_details``. + Check if the union tag is ``domain_invites_request_to_join_team_details``. :rtype: bool """ - return self._tag == 'file_requests_emails_enabled_details' + return self._tag == 'domain_invites_request_to_join_team_details' - def is_file_requests_emails_restricted_to_team_only_details(self): + def is_domain_invites_set_invite_new_user_pref_to_no_details(self): """ - Check if the union tag is ``file_requests_emails_restricted_to_team_only_details``. + Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_no_details``. :rtype: bool """ - return self._tag == 'file_requests_emails_restricted_to_team_only_details' + return self._tag == 'domain_invites_set_invite_new_user_pref_to_no_details' - def is_google_sso_change_policy_details(self): + def is_domain_invites_set_invite_new_user_pref_to_yes_details(self): """ - Check if the union tag is ``google_sso_change_policy_details``. + Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_yes_details``. :rtype: bool """ - return self._tag == 'google_sso_change_policy_details' + return self._tag == 'domain_invites_set_invite_new_user_pref_to_yes_details' - def is_group_user_management_change_policy_details(self): + def is_domain_verification_add_domain_fail_details(self): """ - Check if the union tag is ``group_user_management_change_policy_details``. + Check if the union tag is ``domain_verification_add_domain_fail_details``. :rtype: bool """ - return self._tag == 'group_user_management_change_policy_details' + return self._tag == 'domain_verification_add_domain_fail_details' - def is_integration_policy_changed_details(self): + def is_domain_verification_add_domain_success_details(self): """ - Check if the union tag is ``integration_policy_changed_details``. + Check if the union tag is ``domain_verification_add_domain_success_details``. :rtype: bool """ - return self._tag == 'integration_policy_changed_details' + return self._tag == 'domain_verification_add_domain_success_details' - def is_member_requests_change_policy_details(self): + def is_domain_verification_remove_domain_details(self): """ - Check if the union tag is ``member_requests_change_policy_details``. + Check if the union tag is ``domain_verification_remove_domain_details``. :rtype: bool """ - return self._tag == 'member_requests_change_policy_details' + return self._tag == 'domain_verification_remove_domain_details' - def is_member_space_limits_add_exception_details(self): + def is_enabled_domain_invites_details(self): """ - Check if the union tag is ``member_space_limits_add_exception_details``. + Check if the union tag is ``enabled_domain_invites_details``. :rtype: bool """ - return self._tag == 'member_space_limits_add_exception_details' + return self._tag == 'enabled_domain_invites_details' - def is_member_space_limits_change_caps_type_policy_details(self): + def is_create_folder_details(self): """ - Check if the union tag is ``member_space_limits_change_caps_type_policy_details``. + Check if the union tag is ``create_folder_details``. :rtype: bool """ - return self._tag == 'member_space_limits_change_caps_type_policy_details' + return self._tag == 'create_folder_details' - def is_member_space_limits_change_policy_details(self): + def is_file_add_details(self): """ - Check if the union tag is ``member_space_limits_change_policy_details``. + Check if the union tag is ``file_add_details``. :rtype: bool """ - return self._tag == 'member_space_limits_change_policy_details' + return self._tag == 'file_add_details' - def is_member_space_limits_remove_exception_details(self): + def is_file_copy_details(self): """ - Check if the union tag is ``member_space_limits_remove_exception_details``. + Check if the union tag is ``file_copy_details``. :rtype: bool """ - return self._tag == 'member_space_limits_remove_exception_details' + return self._tag == 'file_copy_details' - def is_member_suggestions_change_policy_details(self): + def is_file_delete_details(self): """ - Check if the union tag is ``member_suggestions_change_policy_details``. + Check if the union tag is ``file_delete_details``. :rtype: bool """ - return self._tag == 'member_suggestions_change_policy_details' + return self._tag == 'file_delete_details' - def is_microsoft_office_addin_change_policy_details(self): + def is_file_download_details(self): """ - Check if the union tag is ``microsoft_office_addin_change_policy_details``. + Check if the union tag is ``file_download_details``. :rtype: bool """ - return self._tag == 'microsoft_office_addin_change_policy_details' + return self._tag == 'file_download_details' - def is_network_control_change_policy_details(self): + def is_file_edit_details(self): """ - Check if the union tag is ``network_control_change_policy_details``. + Check if the union tag is ``file_edit_details``. :rtype: bool """ - return self._tag == 'network_control_change_policy_details' + return self._tag == 'file_edit_details' - def is_paper_change_deployment_policy_details(self): + def is_file_get_copy_reference_details(self): """ - Check if the union tag is ``paper_change_deployment_policy_details``. + Check if the union tag is ``file_get_copy_reference_details``. :rtype: bool """ - return self._tag == 'paper_change_deployment_policy_details' + return self._tag == 'file_get_copy_reference_details' - def is_paper_change_member_link_policy_details(self): + def is_file_locking_lock_status_changed_details(self): """ - Check if the union tag is ``paper_change_member_link_policy_details``. + Check if the union tag is ``file_locking_lock_status_changed_details``. :rtype: bool """ - return self._tag == 'paper_change_member_link_policy_details' + return self._tag == 'file_locking_lock_status_changed_details' - def is_paper_change_member_policy_details(self): + def is_file_move_details(self): """ - Check if the union tag is ``paper_change_member_policy_details``. + Check if the union tag is ``file_move_details``. :rtype: bool """ - return self._tag == 'paper_change_member_policy_details' + return self._tag == 'file_move_details' - def is_paper_change_policy_details(self): + def is_file_permanently_delete_details(self): """ - Check if the union tag is ``paper_change_policy_details``. + Check if the union tag is ``file_permanently_delete_details``. :rtype: bool """ - return self._tag == 'paper_change_policy_details' + return self._tag == 'file_permanently_delete_details' - def is_paper_default_folder_policy_changed_details(self): + def is_file_preview_details(self): """ - Check if the union tag is ``paper_default_folder_policy_changed_details``. + Check if the union tag is ``file_preview_details``. :rtype: bool """ - return self._tag == 'paper_default_folder_policy_changed_details' + return self._tag == 'file_preview_details' - def is_paper_desktop_policy_changed_details(self): + def is_file_rename_details(self): """ - Check if the union tag is ``paper_desktop_policy_changed_details``. + Check if the union tag is ``file_rename_details``. :rtype: bool """ - return self._tag == 'paper_desktop_policy_changed_details' + return self._tag == 'file_rename_details' - def is_paper_enabled_users_group_addition_details(self): + def is_file_restore_details(self): """ - Check if the union tag is ``paper_enabled_users_group_addition_details``. + Check if the union tag is ``file_restore_details``. :rtype: bool """ - return self._tag == 'paper_enabled_users_group_addition_details' + return self._tag == 'file_restore_details' - def is_paper_enabled_users_group_removal_details(self): + def is_file_revert_details(self): """ - Check if the union tag is ``paper_enabled_users_group_removal_details``. + Check if the union tag is ``file_revert_details``. :rtype: bool """ - return self._tag == 'paper_enabled_users_group_removal_details' + return self._tag == 'file_revert_details' - def is_permanent_delete_change_policy_details(self): + def is_file_rollback_changes_details(self): """ - Check if the union tag is ``permanent_delete_change_policy_details``. + Check if the union tag is ``file_rollback_changes_details``. :rtype: bool """ - return self._tag == 'permanent_delete_change_policy_details' + return self._tag == 'file_rollback_changes_details' - def is_reseller_support_change_policy_details(self): + def is_file_save_copy_reference_details(self): """ - Check if the union tag is ``reseller_support_change_policy_details``. + Check if the union tag is ``file_save_copy_reference_details``. :rtype: bool """ - return self._tag == 'reseller_support_change_policy_details' + return self._tag == 'file_save_copy_reference_details' - def is_sharing_change_folder_join_policy_details(self): + def is_folder_overview_description_changed_details(self): """ - Check if the union tag is ``sharing_change_folder_join_policy_details``. + Check if the union tag is ``folder_overview_description_changed_details``. :rtype: bool """ - return self._tag == 'sharing_change_folder_join_policy_details' + return self._tag == 'folder_overview_description_changed_details' - def is_sharing_change_link_policy_details(self): + def is_folder_overview_item_pinned_details(self): """ - Check if the union tag is ``sharing_change_link_policy_details``. + Check if the union tag is ``folder_overview_item_pinned_details``. :rtype: bool """ - return self._tag == 'sharing_change_link_policy_details' + return self._tag == 'folder_overview_item_pinned_details' - def is_sharing_change_member_policy_details(self): + def is_folder_overview_item_unpinned_details(self): """ - Check if the union tag is ``sharing_change_member_policy_details``. + Check if the union tag is ``folder_overview_item_unpinned_details``. :rtype: bool """ - return self._tag == 'sharing_change_member_policy_details' + return self._tag == 'folder_overview_item_unpinned_details' - def is_showcase_change_download_policy_details(self): + def is_rewind_folder_details(self): """ - Check if the union tag is ``showcase_change_download_policy_details``. + Check if the union tag is ``rewind_folder_details``. :rtype: bool """ - return self._tag == 'showcase_change_download_policy_details' + return self._tag == 'rewind_folder_details' - def is_showcase_change_enabled_policy_details(self): + def is_file_request_change_details(self): """ - Check if the union tag is ``showcase_change_enabled_policy_details``. + Check if the union tag is ``file_request_change_details``. :rtype: bool """ - return self._tag == 'showcase_change_enabled_policy_details' + return self._tag == 'file_request_change_details' - def is_showcase_change_external_sharing_policy_details(self): + def is_file_request_close_details(self): """ - Check if the union tag is ``showcase_change_external_sharing_policy_details``. + Check if the union tag is ``file_request_close_details``. :rtype: bool """ - return self._tag == 'showcase_change_external_sharing_policy_details' + return self._tag == 'file_request_close_details' - def is_smart_sync_change_policy_details(self): + def is_file_request_create_details(self): """ - Check if the union tag is ``smart_sync_change_policy_details``. + Check if the union tag is ``file_request_create_details``. :rtype: bool """ - return self._tag == 'smart_sync_change_policy_details' + return self._tag == 'file_request_create_details' - def is_smart_sync_not_opt_out_details(self): + def is_file_request_delete_details(self): """ - Check if the union tag is ``smart_sync_not_opt_out_details``. + Check if the union tag is ``file_request_delete_details``. :rtype: bool """ - return self._tag == 'smart_sync_not_opt_out_details' + return self._tag == 'file_request_delete_details' - def is_smart_sync_opt_out_details(self): + def is_file_request_receive_file_details(self): """ - Check if the union tag is ``smart_sync_opt_out_details``. + Check if the union tag is ``file_request_receive_file_details``. :rtype: bool """ - return self._tag == 'smart_sync_opt_out_details' + return self._tag == 'file_request_receive_file_details' - def is_sso_change_policy_details(self): + def is_group_add_external_id_details(self): """ - Check if the union tag is ``sso_change_policy_details``. + Check if the union tag is ``group_add_external_id_details``. :rtype: bool """ - return self._tag == 'sso_change_policy_details' + return self._tag == 'group_add_external_id_details' - def is_team_extensions_policy_changed_details(self): + def is_group_add_member_details(self): """ - Check if the union tag is ``team_extensions_policy_changed_details``. + Check if the union tag is ``group_add_member_details``. :rtype: bool """ - return self._tag == 'team_extensions_policy_changed_details' + return self._tag == 'group_add_member_details' - def is_team_selective_sync_policy_changed_details(self): + def is_group_change_external_id_details(self): """ - Check if the union tag is ``team_selective_sync_policy_changed_details``. + Check if the union tag is ``group_change_external_id_details``. :rtype: bool """ - return self._tag == 'team_selective_sync_policy_changed_details' + return self._tag == 'group_change_external_id_details' - def is_tfa_change_policy_details(self): + def is_group_change_management_type_details(self): """ - Check if the union tag is ``tfa_change_policy_details``. + Check if the union tag is ``group_change_management_type_details``. :rtype: bool """ - return self._tag == 'tfa_change_policy_details' + return self._tag == 'group_change_management_type_details' - def is_two_account_change_policy_details(self): + def is_group_change_member_role_details(self): """ - Check if the union tag is ``two_account_change_policy_details``. + Check if the union tag is ``group_change_member_role_details``. :rtype: bool """ - return self._tag == 'two_account_change_policy_details' + return self._tag == 'group_change_member_role_details' - def is_viewer_info_policy_changed_details(self): + def is_group_create_details(self): """ - Check if the union tag is ``viewer_info_policy_changed_details``. + Check if the union tag is ``group_create_details``. :rtype: bool """ - return self._tag == 'viewer_info_policy_changed_details' + return self._tag == 'group_create_details' - def is_web_sessions_change_fixed_length_policy_details(self): + def is_group_delete_details(self): """ - Check if the union tag is ``web_sessions_change_fixed_length_policy_details``. + Check if the union tag is ``group_delete_details``. :rtype: bool """ - return self._tag == 'web_sessions_change_fixed_length_policy_details' + return self._tag == 'group_delete_details' - def is_web_sessions_change_idle_length_policy_details(self): + def is_group_description_updated_details(self): """ - Check if the union tag is ``web_sessions_change_idle_length_policy_details``. + Check if the union tag is ``group_description_updated_details``. :rtype: bool """ - return self._tag == 'web_sessions_change_idle_length_policy_details' + return self._tag == 'group_description_updated_details' - def is_team_merge_from_details(self): + def is_group_join_policy_updated_details(self): """ - Check if the union tag is ``team_merge_from_details``. + Check if the union tag is ``group_join_policy_updated_details``. :rtype: bool """ - return self._tag == 'team_merge_from_details' + return self._tag == 'group_join_policy_updated_details' - def is_team_merge_to_details(self): + def is_group_moved_details(self): """ - Check if the union tag is ``team_merge_to_details``. + Check if the union tag is ``group_moved_details``. :rtype: bool """ - return self._tag == 'team_merge_to_details' + return self._tag == 'group_moved_details' - def is_team_profile_add_logo_details(self): + def is_group_remove_external_id_details(self): """ - Check if the union tag is ``team_profile_add_logo_details``. + Check if the union tag is ``group_remove_external_id_details``. :rtype: bool """ - return self._tag == 'team_profile_add_logo_details' + return self._tag == 'group_remove_external_id_details' - def is_team_profile_change_default_language_details(self): + def is_group_remove_member_details(self): """ - Check if the union tag is ``team_profile_change_default_language_details``. + Check if the union tag is ``group_remove_member_details``. :rtype: bool """ - return self._tag == 'team_profile_change_default_language_details' + return self._tag == 'group_remove_member_details' - def is_team_profile_change_logo_details(self): + def is_group_rename_details(self): """ - Check if the union tag is ``team_profile_change_logo_details``. + Check if the union tag is ``group_rename_details``. :rtype: bool """ - return self._tag == 'team_profile_change_logo_details' + return self._tag == 'group_rename_details' - def is_team_profile_change_name_details(self): + def is_legal_holds_activate_a_hold_details(self): """ - Check if the union tag is ``team_profile_change_name_details``. + Check if the union tag is ``legal_holds_activate_a_hold_details``. :rtype: bool """ - return self._tag == 'team_profile_change_name_details' + return self._tag == 'legal_holds_activate_a_hold_details' - def is_team_profile_remove_logo_details(self): + def is_legal_holds_add_members_details(self): """ - Check if the union tag is ``team_profile_remove_logo_details``. + Check if the union tag is ``legal_holds_add_members_details``. :rtype: bool """ - return self._tag == 'team_profile_remove_logo_details' + return self._tag == 'legal_holds_add_members_details' - def is_tfa_add_backup_phone_details(self): + def is_legal_holds_change_hold_details_details(self): """ - Check if the union tag is ``tfa_add_backup_phone_details``. + Check if the union tag is ``legal_holds_change_hold_details_details``. :rtype: bool """ - return self._tag == 'tfa_add_backup_phone_details' + return self._tag == 'legal_holds_change_hold_details_details' - def is_tfa_add_security_key_details(self): + def is_legal_holds_change_hold_name_details(self): """ - Check if the union tag is ``tfa_add_security_key_details``. + Check if the union tag is ``legal_holds_change_hold_name_details``. :rtype: bool """ - return self._tag == 'tfa_add_security_key_details' + return self._tag == 'legal_holds_change_hold_name_details' - def is_tfa_change_backup_phone_details(self): + def is_legal_holds_export_a_hold_details(self): """ - Check if the union tag is ``tfa_change_backup_phone_details``. + Check if the union tag is ``legal_holds_export_a_hold_details``. :rtype: bool """ - return self._tag == 'tfa_change_backup_phone_details' + return self._tag == 'legal_holds_export_a_hold_details' - def is_tfa_change_status_details(self): + def is_legal_holds_export_cancelled_details(self): """ - Check if the union tag is ``tfa_change_status_details``. + Check if the union tag is ``legal_holds_export_cancelled_details``. :rtype: bool """ - return self._tag == 'tfa_change_status_details' + return self._tag == 'legal_holds_export_cancelled_details' - def is_tfa_remove_backup_phone_details(self): + def is_legal_holds_export_downloaded_details(self): """ - Check if the union tag is ``tfa_remove_backup_phone_details``. + Check if the union tag is ``legal_holds_export_downloaded_details``. :rtype: bool """ - return self._tag == 'tfa_remove_backup_phone_details' + return self._tag == 'legal_holds_export_downloaded_details' - def is_tfa_remove_security_key_details(self): + def is_legal_holds_export_removed_details(self): """ - Check if the union tag is ``tfa_remove_security_key_details``. + Check if the union tag is ``legal_holds_export_removed_details``. :rtype: bool """ - return self._tag == 'tfa_remove_security_key_details' + return self._tag == 'legal_holds_export_removed_details' - def is_tfa_reset_details(self): + def is_legal_holds_release_a_hold_details(self): """ - Check if the union tag is ``tfa_reset_details``. + Check if the union tag is ``legal_holds_release_a_hold_details``. :rtype: bool """ - return self._tag == 'tfa_reset_details' + return self._tag == 'legal_holds_release_a_hold_details' - def is_guest_admin_change_status_details(self): + def is_legal_holds_remove_members_details(self): """ - Check if the union tag is ``guest_admin_change_status_details``. + Check if the union tag is ``legal_holds_remove_members_details``. :rtype: bool """ - return self._tag == 'guest_admin_change_status_details' + return self._tag == 'legal_holds_remove_members_details' - def is_team_merge_request_accepted_details(self): + def is_legal_holds_report_a_hold_details(self): """ - Check if the union tag is ``team_merge_request_accepted_details``. + Check if the union tag is ``legal_holds_report_a_hold_details``. :rtype: bool """ - return self._tag == 'team_merge_request_accepted_details' + return self._tag == 'legal_holds_report_a_hold_details' - def is_team_merge_request_accepted_shown_to_primary_team_details(self): + def is_account_lock_or_unlocked_details(self): """ - Check if the union tag is ``team_merge_request_accepted_shown_to_primary_team_details``. + Check if the union tag is ``account_lock_or_unlocked_details``. :rtype: bool """ - return self._tag == 'team_merge_request_accepted_shown_to_primary_team_details' + return self._tag == 'account_lock_or_unlocked_details' - def is_team_merge_request_accepted_shown_to_secondary_team_details(self): + def is_emm_error_details(self): """ - Check if the union tag is ``team_merge_request_accepted_shown_to_secondary_team_details``. + Check if the union tag is ``emm_error_details``. :rtype: bool """ - return self._tag == 'team_merge_request_accepted_shown_to_secondary_team_details' + return self._tag == 'emm_error_details' - def is_team_merge_request_auto_canceled_details(self): + def is_guest_admin_signed_in_via_trusted_teams_details(self): """ - Check if the union tag is ``team_merge_request_auto_canceled_details``. + Check if the union tag is ``guest_admin_signed_in_via_trusted_teams_details``. :rtype: bool """ - return self._tag == 'team_merge_request_auto_canceled_details' + return self._tag == 'guest_admin_signed_in_via_trusted_teams_details' - def is_team_merge_request_canceled_details(self): + def is_guest_admin_signed_out_via_trusted_teams_details(self): """ - Check if the union tag is ``team_merge_request_canceled_details``. + Check if the union tag is ``guest_admin_signed_out_via_trusted_teams_details``. :rtype: bool """ - return self._tag == 'team_merge_request_canceled_details' + return self._tag == 'guest_admin_signed_out_via_trusted_teams_details' - def is_team_merge_request_canceled_shown_to_primary_team_details(self): + def is_login_fail_details(self): """ - Check if the union tag is ``team_merge_request_canceled_shown_to_primary_team_details``. + Check if the union tag is ``login_fail_details``. :rtype: bool """ - return self._tag == 'team_merge_request_canceled_shown_to_primary_team_details' + return self._tag == 'login_fail_details' - def is_team_merge_request_canceled_shown_to_secondary_team_details(self): + def is_login_success_details(self): """ - Check if the union tag is ``team_merge_request_canceled_shown_to_secondary_team_details``. + Check if the union tag is ``login_success_details``. :rtype: bool """ - return self._tag == 'team_merge_request_canceled_shown_to_secondary_team_details' + return self._tag == 'login_success_details' - def is_team_merge_request_expired_details(self): + def is_logout_details(self): """ - Check if the union tag is ``team_merge_request_expired_details``. + Check if the union tag is ``logout_details``. :rtype: bool """ - return self._tag == 'team_merge_request_expired_details' + return self._tag == 'logout_details' - def is_team_merge_request_expired_shown_to_primary_team_details(self): + def is_reseller_support_session_end_details(self): """ - Check if the union tag is ``team_merge_request_expired_shown_to_primary_team_details``. + Check if the union tag is ``reseller_support_session_end_details``. :rtype: bool """ - return self._tag == 'team_merge_request_expired_shown_to_primary_team_details' + return self._tag == 'reseller_support_session_end_details' - def is_team_merge_request_expired_shown_to_secondary_team_details(self): + def is_reseller_support_session_start_details(self): """ - Check if the union tag is ``team_merge_request_expired_shown_to_secondary_team_details``. + Check if the union tag is ``reseller_support_session_start_details``. :rtype: bool """ - return self._tag == 'team_merge_request_expired_shown_to_secondary_team_details' + return self._tag == 'reseller_support_session_start_details' - def is_team_merge_request_rejected_shown_to_primary_team_details(self): + def is_sign_in_as_session_end_details(self): """ - Check if the union tag is ``team_merge_request_rejected_shown_to_primary_team_details``. + Check if the union tag is ``sign_in_as_session_end_details``. :rtype: bool """ - return self._tag == 'team_merge_request_rejected_shown_to_primary_team_details' + return self._tag == 'sign_in_as_session_end_details' - def is_team_merge_request_rejected_shown_to_secondary_team_details(self): + def is_sign_in_as_session_start_details(self): """ - Check if the union tag is ``team_merge_request_rejected_shown_to_secondary_team_details``. + Check if the union tag is ``sign_in_as_session_start_details``. :rtype: bool """ - return self._tag == 'team_merge_request_rejected_shown_to_secondary_team_details' + return self._tag == 'sign_in_as_session_start_details' - def is_team_merge_request_reminder_details(self): + def is_sso_error_details(self): """ - Check if the union tag is ``team_merge_request_reminder_details``. + Check if the union tag is ``sso_error_details``. :rtype: bool """ - return self._tag == 'team_merge_request_reminder_details' + return self._tag == 'sso_error_details' - def is_team_merge_request_reminder_shown_to_primary_team_details(self): + def is_create_team_invite_link_details(self): """ - Check if the union tag is ``team_merge_request_reminder_shown_to_primary_team_details``. + Check if the union tag is ``create_team_invite_link_details``. :rtype: bool """ - return self._tag == 'team_merge_request_reminder_shown_to_primary_team_details' + return self._tag == 'create_team_invite_link_details' - def is_team_merge_request_reminder_shown_to_secondary_team_details(self): + def is_delete_team_invite_link_details(self): """ - Check if the union tag is ``team_merge_request_reminder_shown_to_secondary_team_details``. + Check if the union tag is ``delete_team_invite_link_details``. :rtype: bool """ - return self._tag == 'team_merge_request_reminder_shown_to_secondary_team_details' + return self._tag == 'delete_team_invite_link_details' - def is_team_merge_request_revoked_details(self): + def is_member_add_external_id_details(self): """ - Check if the union tag is ``team_merge_request_revoked_details``. + Check if the union tag is ``member_add_external_id_details``. :rtype: bool """ - return self._tag == 'team_merge_request_revoked_details' + return self._tag == 'member_add_external_id_details' - def is_team_merge_request_sent_shown_to_primary_team_details(self): + def is_member_add_name_details(self): """ - Check if the union tag is ``team_merge_request_sent_shown_to_primary_team_details``. + Check if the union tag is ``member_add_name_details``. :rtype: bool """ - return self._tag == 'team_merge_request_sent_shown_to_primary_team_details' + return self._tag == 'member_add_name_details' - def is_team_merge_request_sent_shown_to_secondary_team_details(self): + def is_member_change_admin_role_details(self): """ - Check if the union tag is ``team_merge_request_sent_shown_to_secondary_team_details``. + Check if the union tag is ``member_change_admin_role_details``. :rtype: bool """ - return self._tag == 'team_merge_request_sent_shown_to_secondary_team_details' + return self._tag == 'member_change_admin_role_details' - def is_missing_details(self): + def is_member_change_email_details(self): """ - Check if the union tag is ``missing_details``. + Check if the union tag is ``member_change_email_details``. :rtype: bool """ - return self._tag == 'missing_details' + return self._tag == 'member_change_email_details' - def is_other(self): + def is_member_change_external_id_details(self): """ - Check if the union tag is ``other``. + Check if the union tag is ``member_change_external_id_details``. :rtype: bool """ - return self._tag == 'other' + return self._tag == 'member_change_external_id_details' - def get_app_link_team_details(self): + def is_member_change_membership_type_details(self): """ - Only call this if :meth:`is_app_link_team_details` is true. + Check if the union tag is ``member_change_membership_type_details``. - :rtype: AppLinkTeamDetails + :rtype: bool """ - if not self.is_app_link_team_details(): - raise AttributeError("tag 'app_link_team_details' not set") - return self._value + return self._tag == 'member_change_membership_type_details' - def get_app_link_user_details(self): + def is_member_change_name_details(self): """ - Only call this if :meth:`is_app_link_user_details` is true. + Check if the union tag is ``member_change_name_details``. - :rtype: AppLinkUserDetails + :rtype: bool """ - if not self.is_app_link_user_details(): - raise AttributeError("tag 'app_link_user_details' not set") - return self._value + return self._tag == 'member_change_name_details' - def get_app_unlink_team_details(self): + def is_member_change_status_details(self): """ - Only call this if :meth:`is_app_unlink_team_details` is true. + Check if the union tag is ``member_change_status_details``. - :rtype: AppUnlinkTeamDetails + :rtype: bool """ - if not self.is_app_unlink_team_details(): - raise AttributeError("tag 'app_unlink_team_details' not set") - return self._value + return self._tag == 'member_change_status_details' - def get_app_unlink_user_details(self): + def is_member_delete_manual_contacts_details(self): """ - Only call this if :meth:`is_app_unlink_user_details` is true. + Check if the union tag is ``member_delete_manual_contacts_details``. - :rtype: AppUnlinkUserDetails + :rtype: bool """ - if not self.is_app_unlink_user_details(): - raise AttributeError("tag 'app_unlink_user_details' not set") - return self._value + return self._tag == 'member_delete_manual_contacts_details' - def get_integration_connected_details(self): + def is_member_delete_profile_photo_details(self): """ - Only call this if :meth:`is_integration_connected_details` is true. + Check if the union tag is ``member_delete_profile_photo_details``. - :rtype: IntegrationConnectedDetails + :rtype: bool """ - if not self.is_integration_connected_details(): - raise AttributeError("tag 'integration_connected_details' not set") - return self._value + return self._tag == 'member_delete_profile_photo_details' - def get_integration_disconnected_details(self): + def is_member_permanently_delete_account_contents_details(self): """ - Only call this if :meth:`is_integration_disconnected_details` is true. + Check if the union tag is ``member_permanently_delete_account_contents_details``. - :rtype: IntegrationDisconnectedDetails + :rtype: bool """ - if not self.is_integration_disconnected_details(): - raise AttributeError("tag 'integration_disconnected_details' not set") - return self._value + return self._tag == 'member_permanently_delete_account_contents_details' - def get_file_add_comment_details(self): + def is_member_remove_external_id_details(self): """ - Only call this if :meth:`is_file_add_comment_details` is true. + Check if the union tag is ``member_remove_external_id_details``. - :rtype: FileAddCommentDetails + :rtype: bool """ - if not self.is_file_add_comment_details(): - raise AttributeError("tag 'file_add_comment_details' not set") - return self._value + return self._tag == 'member_remove_external_id_details' - def get_file_change_comment_subscription_details(self): + def is_member_set_profile_photo_details(self): """ - Only call this if :meth:`is_file_change_comment_subscription_details` is true. + Check if the union tag is ``member_set_profile_photo_details``. - :rtype: FileChangeCommentSubscriptionDetails + :rtype: bool """ - if not self.is_file_change_comment_subscription_details(): - raise AttributeError("tag 'file_change_comment_subscription_details' not set") - return self._value + return self._tag == 'member_set_profile_photo_details' - def get_file_delete_comment_details(self): + def is_member_space_limits_add_custom_quota_details(self): """ - Only call this if :meth:`is_file_delete_comment_details` is true. + Check if the union tag is ``member_space_limits_add_custom_quota_details``. - :rtype: FileDeleteCommentDetails + :rtype: bool """ - if not self.is_file_delete_comment_details(): - raise AttributeError("tag 'file_delete_comment_details' not set") - return self._value + return self._tag == 'member_space_limits_add_custom_quota_details' - def get_file_edit_comment_details(self): + def is_member_space_limits_change_custom_quota_details(self): """ - Only call this if :meth:`is_file_edit_comment_details` is true. + Check if the union tag is ``member_space_limits_change_custom_quota_details``. - :rtype: FileEditCommentDetails + :rtype: bool """ - if not self.is_file_edit_comment_details(): - raise AttributeError("tag 'file_edit_comment_details' not set") - return self._value + return self._tag == 'member_space_limits_change_custom_quota_details' - def get_file_like_comment_details(self): + def is_member_space_limits_change_status_details(self): """ - Only call this if :meth:`is_file_like_comment_details` is true. + Check if the union tag is ``member_space_limits_change_status_details``. - :rtype: FileLikeCommentDetails + :rtype: bool """ - if not self.is_file_like_comment_details(): - raise AttributeError("tag 'file_like_comment_details' not set") - return self._value + return self._tag == 'member_space_limits_change_status_details' - def get_file_resolve_comment_details(self): + def is_member_space_limits_remove_custom_quota_details(self): """ - Only call this if :meth:`is_file_resolve_comment_details` is true. + Check if the union tag is ``member_space_limits_remove_custom_quota_details``. - :rtype: FileResolveCommentDetails + :rtype: bool """ - if not self.is_file_resolve_comment_details(): - raise AttributeError("tag 'file_resolve_comment_details' not set") - return self._value + return self._tag == 'member_space_limits_remove_custom_quota_details' - def get_file_unlike_comment_details(self): + def is_member_suggest_details(self): """ - Only call this if :meth:`is_file_unlike_comment_details` is true. + Check if the union tag is ``member_suggest_details``. - :rtype: FileUnlikeCommentDetails + :rtype: bool """ - if not self.is_file_unlike_comment_details(): - raise AttributeError("tag 'file_unlike_comment_details' not set") - return self._value + return self._tag == 'member_suggest_details' - def get_file_unresolve_comment_details(self): + def is_member_transfer_account_contents_details(self): """ - Only call this if :meth:`is_file_unresolve_comment_details` is true. + Check if the union tag is ``member_transfer_account_contents_details``. - :rtype: FileUnresolveCommentDetails + :rtype: bool """ - if not self.is_file_unresolve_comment_details(): - raise AttributeError("tag 'file_unresolve_comment_details' not set") - return self._value + return self._tag == 'member_transfer_account_contents_details' - def get_device_change_ip_desktop_details(self): + def is_pending_secondary_email_added_details(self): """ - Only call this if :meth:`is_device_change_ip_desktop_details` is true. + Check if the union tag is ``pending_secondary_email_added_details``. - :rtype: DeviceChangeIpDesktopDetails + :rtype: bool """ - if not self.is_device_change_ip_desktop_details(): - raise AttributeError("tag 'device_change_ip_desktop_details' not set") - return self._value + return self._tag == 'pending_secondary_email_added_details' - def get_device_change_ip_mobile_details(self): + def is_secondary_email_deleted_details(self): """ - Only call this if :meth:`is_device_change_ip_mobile_details` is true. + Check if the union tag is ``secondary_email_deleted_details``. - :rtype: DeviceChangeIpMobileDetails + :rtype: bool """ - if not self.is_device_change_ip_mobile_details(): - raise AttributeError("tag 'device_change_ip_mobile_details' not set") - return self._value + return self._tag == 'secondary_email_deleted_details' - def get_device_change_ip_web_details(self): + def is_secondary_email_verified_details(self): """ - Only call this if :meth:`is_device_change_ip_web_details` is true. + Check if the union tag is ``secondary_email_verified_details``. - :rtype: DeviceChangeIpWebDetails + :rtype: bool """ - if not self.is_device_change_ip_web_details(): - raise AttributeError("tag 'device_change_ip_web_details' not set") - return self._value + return self._tag == 'secondary_email_verified_details' - def get_device_delete_on_unlink_fail_details(self): + def is_secondary_mails_policy_changed_details(self): """ - Only call this if :meth:`is_device_delete_on_unlink_fail_details` is true. + Check if the union tag is ``secondary_mails_policy_changed_details``. - :rtype: DeviceDeleteOnUnlinkFailDetails + :rtype: bool """ - if not self.is_device_delete_on_unlink_fail_details(): - raise AttributeError("tag 'device_delete_on_unlink_fail_details' not set") - return self._value + return self._tag == 'secondary_mails_policy_changed_details' - def get_device_delete_on_unlink_success_details(self): + def is_binder_add_page_details(self): """ - Only call this if :meth:`is_device_delete_on_unlink_success_details` is true. + Check if the union tag is ``binder_add_page_details``. - :rtype: DeviceDeleteOnUnlinkSuccessDetails + :rtype: bool """ - if not self.is_device_delete_on_unlink_success_details(): - raise AttributeError("tag 'device_delete_on_unlink_success_details' not set") - return self._value + return self._tag == 'binder_add_page_details' - def get_device_link_fail_details(self): + def is_binder_add_section_details(self): """ - Only call this if :meth:`is_device_link_fail_details` is true. + Check if the union tag is ``binder_add_section_details``. - :rtype: DeviceLinkFailDetails + :rtype: bool """ - if not self.is_device_link_fail_details(): - raise AttributeError("tag 'device_link_fail_details' not set") - return self._value + return self._tag == 'binder_add_section_details' - def get_device_link_success_details(self): + def is_binder_remove_page_details(self): """ - Only call this if :meth:`is_device_link_success_details` is true. + Check if the union tag is ``binder_remove_page_details``. - :rtype: DeviceLinkSuccessDetails + :rtype: bool """ - if not self.is_device_link_success_details(): - raise AttributeError("tag 'device_link_success_details' not set") - return self._value + return self._tag == 'binder_remove_page_details' - def get_device_management_disabled_details(self): + def is_binder_remove_section_details(self): """ - Only call this if :meth:`is_device_management_disabled_details` is true. + Check if the union tag is ``binder_remove_section_details``. - :rtype: DeviceManagementDisabledDetails + :rtype: bool """ - if not self.is_device_management_disabled_details(): - raise AttributeError("tag 'device_management_disabled_details' not set") - return self._value + return self._tag == 'binder_remove_section_details' - def get_device_management_enabled_details(self): + def is_binder_rename_page_details(self): """ - Only call this if :meth:`is_device_management_enabled_details` is true. + Check if the union tag is ``binder_rename_page_details``. - :rtype: DeviceManagementEnabledDetails + :rtype: bool """ - if not self.is_device_management_enabled_details(): - raise AttributeError("tag 'device_management_enabled_details' not set") - return self._value + return self._tag == 'binder_rename_page_details' - def get_device_unlink_details(self): + def is_binder_rename_section_details(self): """ - Only call this if :meth:`is_device_unlink_details` is true. + Check if the union tag is ``binder_rename_section_details``. - :rtype: DeviceUnlinkDetails + :rtype: bool """ - if not self.is_device_unlink_details(): - raise AttributeError("tag 'device_unlink_details' not set") - return self._value + return self._tag == 'binder_rename_section_details' - def get_emm_refresh_auth_token_details(self): + def is_binder_reorder_page_details(self): """ - Only call this if :meth:`is_emm_refresh_auth_token_details` is true. + Check if the union tag is ``binder_reorder_page_details``. - :rtype: EmmRefreshAuthTokenDetails + :rtype: bool """ - if not self.is_emm_refresh_auth_token_details(): - raise AttributeError("tag 'emm_refresh_auth_token_details' not set") - return self._value + return self._tag == 'binder_reorder_page_details' - def get_account_capture_change_availability_details(self): + def is_binder_reorder_section_details(self): """ - Only call this if :meth:`is_account_capture_change_availability_details` is true. + Check if the union tag is ``binder_reorder_section_details``. - :rtype: AccountCaptureChangeAvailabilityDetails + :rtype: bool """ - if not self.is_account_capture_change_availability_details(): - raise AttributeError("tag 'account_capture_change_availability_details' not set") - return self._value + return self._tag == 'binder_reorder_section_details' - def get_account_capture_migrate_account_details(self): + def is_paper_content_add_member_details(self): """ - Only call this if :meth:`is_account_capture_migrate_account_details` is true. + Check if the union tag is ``paper_content_add_member_details``. - :rtype: AccountCaptureMigrateAccountDetails + :rtype: bool """ - if not self.is_account_capture_migrate_account_details(): - raise AttributeError("tag 'account_capture_migrate_account_details' not set") - return self._value + return self._tag == 'paper_content_add_member_details' - def get_account_capture_notification_emails_sent_details(self): + def is_paper_content_add_to_folder_details(self): """ - Only call this if :meth:`is_account_capture_notification_emails_sent_details` is true. + Check if the union tag is ``paper_content_add_to_folder_details``. - :rtype: AccountCaptureNotificationEmailsSentDetails + :rtype: bool """ - if not self.is_account_capture_notification_emails_sent_details(): - raise AttributeError("tag 'account_capture_notification_emails_sent_details' not set") - return self._value + return self._tag == 'paper_content_add_to_folder_details' - def get_account_capture_relinquish_account_details(self): + def is_paper_content_archive_details(self): """ - Only call this if :meth:`is_account_capture_relinquish_account_details` is true. + Check if the union tag is ``paper_content_archive_details``. - :rtype: AccountCaptureRelinquishAccountDetails + :rtype: bool """ - if not self.is_account_capture_relinquish_account_details(): - raise AttributeError("tag 'account_capture_relinquish_account_details' not set") - return self._value + return self._tag == 'paper_content_archive_details' - def get_disabled_domain_invites_details(self): + def is_paper_content_create_details(self): """ - Only call this if :meth:`is_disabled_domain_invites_details` is true. + Check if the union tag is ``paper_content_create_details``. - :rtype: DisabledDomainInvitesDetails + :rtype: bool """ - if not self.is_disabled_domain_invites_details(): - raise AttributeError("tag 'disabled_domain_invites_details' not set") - return self._value + return self._tag == 'paper_content_create_details' - def get_domain_invites_approve_request_to_join_team_details(self): + def is_paper_content_permanently_delete_details(self): """ - Only call this if :meth:`is_domain_invites_approve_request_to_join_team_details` is true. + Check if the union tag is ``paper_content_permanently_delete_details``. - :rtype: DomainInvitesApproveRequestToJoinTeamDetails + :rtype: bool """ - if not self.is_domain_invites_approve_request_to_join_team_details(): - raise AttributeError("tag 'domain_invites_approve_request_to_join_team_details' not set") - return self._value + return self._tag == 'paper_content_permanently_delete_details' - def get_domain_invites_decline_request_to_join_team_details(self): + def is_paper_content_remove_from_folder_details(self): """ - Only call this if :meth:`is_domain_invites_decline_request_to_join_team_details` is true. + Check if the union tag is ``paper_content_remove_from_folder_details``. - :rtype: DomainInvitesDeclineRequestToJoinTeamDetails + :rtype: bool """ - if not self.is_domain_invites_decline_request_to_join_team_details(): - raise AttributeError("tag 'domain_invites_decline_request_to_join_team_details' not set") - return self._value + return self._tag == 'paper_content_remove_from_folder_details' - def get_domain_invites_email_existing_users_details(self): + def is_paper_content_remove_member_details(self): """ - Only call this if :meth:`is_domain_invites_email_existing_users_details` is true. + Check if the union tag is ``paper_content_remove_member_details``. - :rtype: DomainInvitesEmailExistingUsersDetails + :rtype: bool """ - if not self.is_domain_invites_email_existing_users_details(): - raise AttributeError("tag 'domain_invites_email_existing_users_details' not set") - return self._value + return self._tag == 'paper_content_remove_member_details' - def get_domain_invites_request_to_join_team_details(self): + def is_paper_content_rename_details(self): """ - Only call this if :meth:`is_domain_invites_request_to_join_team_details` is true. + Check if the union tag is ``paper_content_rename_details``. - :rtype: DomainInvitesRequestToJoinTeamDetails + :rtype: bool """ - if not self.is_domain_invites_request_to_join_team_details(): - raise AttributeError("tag 'domain_invites_request_to_join_team_details' not set") - return self._value + return self._tag == 'paper_content_rename_details' - def get_domain_invites_set_invite_new_user_pref_to_no_details(self): + def is_paper_content_restore_details(self): """ - Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_no_details` is true. + Check if the union tag is ``paper_content_restore_details``. - :rtype: DomainInvitesSetInviteNewUserPrefToNoDetails + :rtype: bool """ - if not self.is_domain_invites_set_invite_new_user_pref_to_no_details(): - raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_no_details' not set") - return self._value + return self._tag == 'paper_content_restore_details' - def get_domain_invites_set_invite_new_user_pref_to_yes_details(self): + def is_paper_doc_add_comment_details(self): """ - Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_yes_details` is true. + Check if the union tag is ``paper_doc_add_comment_details``. - :rtype: DomainInvitesSetInviteNewUserPrefToYesDetails + :rtype: bool """ - if not self.is_domain_invites_set_invite_new_user_pref_to_yes_details(): - raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_yes_details' not set") - return self._value + return self._tag == 'paper_doc_add_comment_details' - def get_domain_verification_add_domain_fail_details(self): + def is_paper_doc_change_member_role_details(self): """ - Only call this if :meth:`is_domain_verification_add_domain_fail_details` is true. + Check if the union tag is ``paper_doc_change_member_role_details``. - :rtype: DomainVerificationAddDomainFailDetails + :rtype: bool """ - if not self.is_domain_verification_add_domain_fail_details(): - raise AttributeError("tag 'domain_verification_add_domain_fail_details' not set") - return self._value + return self._tag == 'paper_doc_change_member_role_details' - def get_domain_verification_add_domain_success_details(self): + def is_paper_doc_change_sharing_policy_details(self): """ - Only call this if :meth:`is_domain_verification_add_domain_success_details` is true. + Check if the union tag is ``paper_doc_change_sharing_policy_details``. - :rtype: DomainVerificationAddDomainSuccessDetails + :rtype: bool """ - if not self.is_domain_verification_add_domain_success_details(): - raise AttributeError("tag 'domain_verification_add_domain_success_details' not set") - return self._value + return self._tag == 'paper_doc_change_sharing_policy_details' - def get_domain_verification_remove_domain_details(self): + def is_paper_doc_change_subscription_details(self): """ - Only call this if :meth:`is_domain_verification_remove_domain_details` is true. + Check if the union tag is ``paper_doc_change_subscription_details``. - :rtype: DomainVerificationRemoveDomainDetails + :rtype: bool """ - if not self.is_domain_verification_remove_domain_details(): - raise AttributeError("tag 'domain_verification_remove_domain_details' not set") - return self._value + return self._tag == 'paper_doc_change_subscription_details' - def get_enabled_domain_invites_details(self): + def is_paper_doc_deleted_details(self): """ - Only call this if :meth:`is_enabled_domain_invites_details` is true. + Check if the union tag is ``paper_doc_deleted_details``. - :rtype: EnabledDomainInvitesDetails + :rtype: bool """ - if not self.is_enabled_domain_invites_details(): - raise AttributeError("tag 'enabled_domain_invites_details' not set") - return self._value + return self._tag == 'paper_doc_deleted_details' - def get_create_folder_details(self): + def is_paper_doc_delete_comment_details(self): """ - Only call this if :meth:`is_create_folder_details` is true. + Check if the union tag is ``paper_doc_delete_comment_details``. - :rtype: CreateFolderDetails + :rtype: bool """ - if not self.is_create_folder_details(): - raise AttributeError("tag 'create_folder_details' not set") - return self._value + return self._tag == 'paper_doc_delete_comment_details' - def get_file_add_details(self): + def is_paper_doc_download_details(self): """ - Only call this if :meth:`is_file_add_details` is true. + Check if the union tag is ``paper_doc_download_details``. - :rtype: FileAddDetails + :rtype: bool """ - if not self.is_file_add_details(): - raise AttributeError("tag 'file_add_details' not set") - return self._value + return self._tag == 'paper_doc_download_details' - def get_file_copy_details(self): + def is_paper_doc_edit_details(self): """ - Only call this if :meth:`is_file_copy_details` is true. + Check if the union tag is ``paper_doc_edit_details``. - :rtype: FileCopyDetails + :rtype: bool """ - if not self.is_file_copy_details(): - raise AttributeError("tag 'file_copy_details' not set") - return self._value + return self._tag == 'paper_doc_edit_details' - def get_file_delete_details(self): + def is_paper_doc_edit_comment_details(self): """ - Only call this if :meth:`is_file_delete_details` is true. + Check if the union tag is ``paper_doc_edit_comment_details``. - :rtype: FileDeleteDetails + :rtype: bool """ - if not self.is_file_delete_details(): - raise AttributeError("tag 'file_delete_details' not set") - return self._value + return self._tag == 'paper_doc_edit_comment_details' - def get_file_download_details(self): + def is_paper_doc_followed_details(self): """ - Only call this if :meth:`is_file_download_details` is true. + Check if the union tag is ``paper_doc_followed_details``. - :rtype: FileDownloadDetails + :rtype: bool """ - if not self.is_file_download_details(): - raise AttributeError("tag 'file_download_details' not set") - return self._value + return self._tag == 'paper_doc_followed_details' - def get_file_edit_details(self): + def is_paper_doc_mention_details(self): """ - Only call this if :meth:`is_file_edit_details` is true. + Check if the union tag is ``paper_doc_mention_details``. - :rtype: FileEditDetails + :rtype: bool """ - if not self.is_file_edit_details(): - raise AttributeError("tag 'file_edit_details' not set") - return self._value + return self._tag == 'paper_doc_mention_details' - def get_file_get_copy_reference_details(self): + def is_paper_doc_ownership_changed_details(self): """ - Only call this if :meth:`is_file_get_copy_reference_details` is true. + Check if the union tag is ``paper_doc_ownership_changed_details``. - :rtype: FileGetCopyReferenceDetails + :rtype: bool """ - if not self.is_file_get_copy_reference_details(): - raise AttributeError("tag 'file_get_copy_reference_details' not set") - return self._value + return self._tag == 'paper_doc_ownership_changed_details' - def get_file_move_details(self): + def is_paper_doc_request_access_details(self): """ - Only call this if :meth:`is_file_move_details` is true. + Check if the union tag is ``paper_doc_request_access_details``. - :rtype: FileMoveDetails + :rtype: bool """ - if not self.is_file_move_details(): - raise AttributeError("tag 'file_move_details' not set") - return self._value + return self._tag == 'paper_doc_request_access_details' - def get_file_permanently_delete_details(self): + def is_paper_doc_resolve_comment_details(self): """ - Only call this if :meth:`is_file_permanently_delete_details` is true. + Check if the union tag is ``paper_doc_resolve_comment_details``. - :rtype: FilePermanentlyDeleteDetails + :rtype: bool """ - if not self.is_file_permanently_delete_details(): - raise AttributeError("tag 'file_permanently_delete_details' not set") - return self._value + return self._tag == 'paper_doc_resolve_comment_details' - def get_file_preview_details(self): + def is_paper_doc_revert_details(self): """ - Only call this if :meth:`is_file_preview_details` is true. + Check if the union tag is ``paper_doc_revert_details``. - :rtype: FilePreviewDetails + :rtype: bool """ - if not self.is_file_preview_details(): - raise AttributeError("tag 'file_preview_details' not set") - return self._value + return self._tag == 'paper_doc_revert_details' - def get_file_rename_details(self): + def is_paper_doc_slack_share_details(self): """ - Only call this if :meth:`is_file_rename_details` is true. + Check if the union tag is ``paper_doc_slack_share_details``. - :rtype: FileRenameDetails + :rtype: bool """ - if not self.is_file_rename_details(): - raise AttributeError("tag 'file_rename_details' not set") - return self._value + return self._tag == 'paper_doc_slack_share_details' - def get_file_restore_details(self): + def is_paper_doc_team_invite_details(self): """ - Only call this if :meth:`is_file_restore_details` is true. + Check if the union tag is ``paper_doc_team_invite_details``. - :rtype: FileRestoreDetails + :rtype: bool """ - if not self.is_file_restore_details(): - raise AttributeError("tag 'file_restore_details' not set") - return self._value + return self._tag == 'paper_doc_team_invite_details' - def get_file_revert_details(self): + def is_paper_doc_trashed_details(self): """ - Only call this if :meth:`is_file_revert_details` is true. + Check if the union tag is ``paper_doc_trashed_details``. - :rtype: FileRevertDetails + :rtype: bool """ - if not self.is_file_revert_details(): - raise AttributeError("tag 'file_revert_details' not set") - return self._value + return self._tag == 'paper_doc_trashed_details' - def get_file_rollback_changes_details(self): + def is_paper_doc_unresolve_comment_details(self): """ - Only call this if :meth:`is_file_rollback_changes_details` is true. + Check if the union tag is ``paper_doc_unresolve_comment_details``. - :rtype: FileRollbackChangesDetails + :rtype: bool """ - if not self.is_file_rollback_changes_details(): - raise AttributeError("tag 'file_rollback_changes_details' not set") - return self._value + return self._tag == 'paper_doc_unresolve_comment_details' - def get_file_save_copy_reference_details(self): + def is_paper_doc_untrashed_details(self): """ - Only call this if :meth:`is_file_save_copy_reference_details` is true. + Check if the union tag is ``paper_doc_untrashed_details``. - :rtype: FileSaveCopyReferenceDetails + :rtype: bool """ - if not self.is_file_save_copy_reference_details(): - raise AttributeError("tag 'file_save_copy_reference_details' not set") - return self._value + return self._tag == 'paper_doc_untrashed_details' - def get_file_request_change_details(self): + def is_paper_doc_view_details(self): """ - Only call this if :meth:`is_file_request_change_details` is true. + Check if the union tag is ``paper_doc_view_details``. - :rtype: FileRequestChangeDetails + :rtype: bool """ - if not self.is_file_request_change_details(): - raise AttributeError("tag 'file_request_change_details' not set") - return self._value + return self._tag == 'paper_doc_view_details' - def get_file_request_close_details(self): + def is_paper_external_view_allow_details(self): """ - Only call this if :meth:`is_file_request_close_details` is true. + Check if the union tag is ``paper_external_view_allow_details``. - :rtype: FileRequestCloseDetails + :rtype: bool """ - if not self.is_file_request_close_details(): - raise AttributeError("tag 'file_request_close_details' not set") - return self._value + return self._tag == 'paper_external_view_allow_details' - def get_file_request_create_details(self): + def is_paper_external_view_default_team_details(self): """ - Only call this if :meth:`is_file_request_create_details` is true. + Check if the union tag is ``paper_external_view_default_team_details``. - :rtype: FileRequestCreateDetails + :rtype: bool """ - if not self.is_file_request_create_details(): - raise AttributeError("tag 'file_request_create_details' not set") - return self._value + return self._tag == 'paper_external_view_default_team_details' - def get_file_request_delete_details(self): + def is_paper_external_view_forbid_details(self): """ - Only call this if :meth:`is_file_request_delete_details` is true. + Check if the union tag is ``paper_external_view_forbid_details``. - :rtype: FileRequestDeleteDetails + :rtype: bool """ - if not self.is_file_request_delete_details(): - raise AttributeError("tag 'file_request_delete_details' not set") - return self._value + return self._tag == 'paper_external_view_forbid_details' - def get_file_request_receive_file_details(self): + def is_paper_folder_change_subscription_details(self): """ - Only call this if :meth:`is_file_request_receive_file_details` is true. + Check if the union tag is ``paper_folder_change_subscription_details``. - :rtype: FileRequestReceiveFileDetails + :rtype: bool """ - if not self.is_file_request_receive_file_details(): - raise AttributeError("tag 'file_request_receive_file_details' not set") - return self._value + return self._tag == 'paper_folder_change_subscription_details' - def get_group_add_external_id_details(self): + def is_paper_folder_deleted_details(self): """ - Only call this if :meth:`is_group_add_external_id_details` is true. + Check if the union tag is ``paper_folder_deleted_details``. - :rtype: GroupAddExternalIdDetails + :rtype: bool """ - if not self.is_group_add_external_id_details(): - raise AttributeError("tag 'group_add_external_id_details' not set") - return self._value + return self._tag == 'paper_folder_deleted_details' - def get_group_add_member_details(self): + def is_paper_folder_followed_details(self): """ - Only call this if :meth:`is_group_add_member_details` is true. + Check if the union tag is ``paper_folder_followed_details``. - :rtype: GroupAddMemberDetails + :rtype: bool """ - if not self.is_group_add_member_details(): - raise AttributeError("tag 'group_add_member_details' not set") - return self._value + return self._tag == 'paper_folder_followed_details' - def get_group_change_external_id_details(self): + def is_paper_folder_team_invite_details(self): """ - Only call this if :meth:`is_group_change_external_id_details` is true. + Check if the union tag is ``paper_folder_team_invite_details``. - :rtype: GroupChangeExternalIdDetails + :rtype: bool """ - if not self.is_group_change_external_id_details(): - raise AttributeError("tag 'group_change_external_id_details' not set") - return self._value + return self._tag == 'paper_folder_team_invite_details' - def get_group_change_management_type_details(self): + def is_paper_published_link_change_permission_details(self): """ - Only call this if :meth:`is_group_change_management_type_details` is true. + Check if the union tag is ``paper_published_link_change_permission_details``. - :rtype: GroupChangeManagementTypeDetails + :rtype: bool """ - if not self.is_group_change_management_type_details(): - raise AttributeError("tag 'group_change_management_type_details' not set") - return self._value + return self._tag == 'paper_published_link_change_permission_details' - def get_group_change_member_role_details(self): + def is_paper_published_link_create_details(self): """ - Only call this if :meth:`is_group_change_member_role_details` is true. + Check if the union tag is ``paper_published_link_create_details``. - :rtype: GroupChangeMemberRoleDetails + :rtype: bool """ - if not self.is_group_change_member_role_details(): - raise AttributeError("tag 'group_change_member_role_details' not set") - return self._value + return self._tag == 'paper_published_link_create_details' - def get_group_create_details(self): + def is_paper_published_link_disabled_details(self): """ - Only call this if :meth:`is_group_create_details` is true. + Check if the union tag is ``paper_published_link_disabled_details``. - :rtype: GroupCreateDetails + :rtype: bool """ - if not self.is_group_create_details(): - raise AttributeError("tag 'group_create_details' not set") - return self._value + return self._tag == 'paper_published_link_disabled_details' - def get_group_delete_details(self): + def is_paper_published_link_view_details(self): """ - Only call this if :meth:`is_group_delete_details` is true. + Check if the union tag is ``paper_published_link_view_details``. - :rtype: GroupDeleteDetails + :rtype: bool """ - if not self.is_group_delete_details(): - raise AttributeError("tag 'group_delete_details' not set") - return self._value + return self._tag == 'paper_published_link_view_details' - def get_group_description_updated_details(self): + def is_password_change_details(self): """ - Only call this if :meth:`is_group_description_updated_details` is true. + Check if the union tag is ``password_change_details``. - :rtype: GroupDescriptionUpdatedDetails + :rtype: bool """ - if not self.is_group_description_updated_details(): - raise AttributeError("tag 'group_description_updated_details' not set") - return self._value + return self._tag == 'password_change_details' - def get_group_join_policy_updated_details(self): + def is_password_reset_details(self): """ - Only call this if :meth:`is_group_join_policy_updated_details` is true. + Check if the union tag is ``password_reset_details``. - :rtype: GroupJoinPolicyUpdatedDetails + :rtype: bool """ - if not self.is_group_join_policy_updated_details(): - raise AttributeError("tag 'group_join_policy_updated_details' not set") - return self._value + return self._tag == 'password_reset_details' - def get_group_moved_details(self): + def is_password_reset_all_details(self): """ - Only call this if :meth:`is_group_moved_details` is true. + Check if the union tag is ``password_reset_all_details``. - :rtype: GroupMovedDetails + :rtype: bool """ - if not self.is_group_moved_details(): - raise AttributeError("tag 'group_moved_details' not set") - return self._value + return self._tag == 'password_reset_all_details' - def get_group_remove_external_id_details(self): + def is_emm_create_exceptions_report_details(self): """ - Only call this if :meth:`is_group_remove_external_id_details` is true. + Check if the union tag is ``emm_create_exceptions_report_details``. - :rtype: GroupRemoveExternalIdDetails + :rtype: bool """ - if not self.is_group_remove_external_id_details(): - raise AttributeError("tag 'group_remove_external_id_details' not set") - return self._value + return self._tag == 'emm_create_exceptions_report_details' - def get_group_remove_member_details(self): + def is_emm_create_usage_report_details(self): """ - Only call this if :meth:`is_group_remove_member_details` is true. + Check if the union tag is ``emm_create_usage_report_details``. - :rtype: GroupRemoveMemberDetails + :rtype: bool """ - if not self.is_group_remove_member_details(): - raise AttributeError("tag 'group_remove_member_details' not set") - return self._value + return self._tag == 'emm_create_usage_report_details' - def get_group_rename_details(self): + def is_export_members_report_details(self): """ - Only call this if :meth:`is_group_rename_details` is true. + Check if the union tag is ``export_members_report_details``. - :rtype: GroupRenameDetails + :rtype: bool """ - if not self.is_group_rename_details(): - raise AttributeError("tag 'group_rename_details' not set") - return self._value + return self._tag == 'export_members_report_details' - def get_emm_error_details(self): + def is_export_members_report_fail_details(self): """ - Only call this if :meth:`is_emm_error_details` is true. + Check if the union tag is ``export_members_report_fail_details``. - :rtype: EmmErrorDetails + :rtype: bool """ - if not self.is_emm_error_details(): - raise AttributeError("tag 'emm_error_details' not set") - return self._value + return self._tag == 'export_members_report_fail_details' - def get_guest_admin_signed_in_via_trusted_teams_details(self): + def is_no_expiration_link_gen_create_report_details(self): """ - Only call this if :meth:`is_guest_admin_signed_in_via_trusted_teams_details` is true. + Check if the union tag is ``no_expiration_link_gen_create_report_details``. - :rtype: GuestAdminSignedInViaTrustedTeamsDetails + :rtype: bool """ - if not self.is_guest_admin_signed_in_via_trusted_teams_details(): - raise AttributeError("tag 'guest_admin_signed_in_via_trusted_teams_details' not set") - return self._value + return self._tag == 'no_expiration_link_gen_create_report_details' - def get_guest_admin_signed_out_via_trusted_teams_details(self): + def is_no_expiration_link_gen_report_failed_details(self): """ - Only call this if :meth:`is_guest_admin_signed_out_via_trusted_teams_details` is true. + Check if the union tag is ``no_expiration_link_gen_report_failed_details``. - :rtype: GuestAdminSignedOutViaTrustedTeamsDetails + :rtype: bool """ - if not self.is_guest_admin_signed_out_via_trusted_teams_details(): - raise AttributeError("tag 'guest_admin_signed_out_via_trusted_teams_details' not set") - return self._value + return self._tag == 'no_expiration_link_gen_report_failed_details' - def get_login_fail_details(self): + def is_no_password_link_gen_create_report_details(self): """ - Only call this if :meth:`is_login_fail_details` is true. + Check if the union tag is ``no_password_link_gen_create_report_details``. - :rtype: LoginFailDetails + :rtype: bool """ - if not self.is_login_fail_details(): - raise AttributeError("tag 'login_fail_details' not set") - return self._value + return self._tag == 'no_password_link_gen_create_report_details' - def get_login_success_details(self): + def is_no_password_link_gen_report_failed_details(self): """ - Only call this if :meth:`is_login_success_details` is true. + Check if the union tag is ``no_password_link_gen_report_failed_details``. - :rtype: LoginSuccessDetails + :rtype: bool """ - if not self.is_login_success_details(): - raise AttributeError("tag 'login_success_details' not set") - return self._value + return self._tag == 'no_password_link_gen_report_failed_details' - def get_logout_details(self): + def is_no_password_link_view_create_report_details(self): """ - Only call this if :meth:`is_logout_details` is true. + Check if the union tag is ``no_password_link_view_create_report_details``. - :rtype: LogoutDetails + :rtype: bool """ - if not self.is_logout_details(): - raise AttributeError("tag 'logout_details' not set") - return self._value + return self._tag == 'no_password_link_view_create_report_details' - def get_reseller_support_session_end_details(self): + def is_no_password_link_view_report_failed_details(self): """ - Only call this if :meth:`is_reseller_support_session_end_details` is true. + Check if the union tag is ``no_password_link_view_report_failed_details``. - :rtype: ResellerSupportSessionEndDetails + :rtype: bool """ - if not self.is_reseller_support_session_end_details(): - raise AttributeError("tag 'reseller_support_session_end_details' not set") - return self._value + return self._tag == 'no_password_link_view_report_failed_details' - def get_reseller_support_session_start_details(self): + def is_outdated_link_view_create_report_details(self): """ - Only call this if :meth:`is_reseller_support_session_start_details` is true. + Check if the union tag is ``outdated_link_view_create_report_details``. - :rtype: ResellerSupportSessionStartDetails + :rtype: bool """ - if not self.is_reseller_support_session_start_details(): - raise AttributeError("tag 'reseller_support_session_start_details' not set") - return self._value + return self._tag == 'outdated_link_view_create_report_details' - def get_sign_in_as_session_end_details(self): + def is_outdated_link_view_report_failed_details(self): """ - Only call this if :meth:`is_sign_in_as_session_end_details` is true. + Check if the union tag is ``outdated_link_view_report_failed_details``. - :rtype: SignInAsSessionEndDetails + :rtype: bool """ - if not self.is_sign_in_as_session_end_details(): - raise AttributeError("tag 'sign_in_as_session_end_details' not set") - return self._value + return self._tag == 'outdated_link_view_report_failed_details' - def get_sign_in_as_session_start_details(self): + def is_paper_admin_export_start_details(self): """ - Only call this if :meth:`is_sign_in_as_session_start_details` is true. + Check if the union tag is ``paper_admin_export_start_details``. - :rtype: SignInAsSessionStartDetails + :rtype: bool """ - if not self.is_sign_in_as_session_start_details(): - raise AttributeError("tag 'sign_in_as_session_start_details' not set") - return self._value + return self._tag == 'paper_admin_export_start_details' - def get_sso_error_details(self): + def is_smart_sync_create_admin_privilege_report_details(self): """ - Only call this if :meth:`is_sso_error_details` is true. + Check if the union tag is ``smart_sync_create_admin_privilege_report_details``. - :rtype: SsoErrorDetails + :rtype: bool """ - if not self.is_sso_error_details(): - raise AttributeError("tag 'sso_error_details' not set") - return self._value + return self._tag == 'smart_sync_create_admin_privilege_report_details' - def get_member_add_external_id_details(self): + def is_team_activity_create_report_details(self): """ - Only call this if :meth:`is_member_add_external_id_details` is true. + Check if the union tag is ``team_activity_create_report_details``. - :rtype: MemberAddExternalIdDetails + :rtype: bool """ - if not self.is_member_add_external_id_details(): - raise AttributeError("tag 'member_add_external_id_details' not set") - return self._value + return self._tag == 'team_activity_create_report_details' - def get_member_add_name_details(self): + def is_team_activity_create_report_fail_details(self): """ - Only call this if :meth:`is_member_add_name_details` is true. + Check if the union tag is ``team_activity_create_report_fail_details``. - :rtype: MemberAddNameDetails + :rtype: bool """ - if not self.is_member_add_name_details(): - raise AttributeError("tag 'member_add_name_details' not set") - return self._value + return self._tag == 'team_activity_create_report_fail_details' - def get_member_change_admin_role_details(self): + def is_collection_share_details(self): """ - Only call this if :meth:`is_member_change_admin_role_details` is true. + Check if the union tag is ``collection_share_details``. - :rtype: MemberChangeAdminRoleDetails + :rtype: bool """ - if not self.is_member_change_admin_role_details(): - raise AttributeError("tag 'member_change_admin_role_details' not set") - return self._value + return self._tag == 'collection_share_details' - def get_member_change_email_details(self): + def is_file_transfers_file_add_details(self): """ - Only call this if :meth:`is_member_change_email_details` is true. + Check if the union tag is ``file_transfers_file_add_details``. - :rtype: MemberChangeEmailDetails + :rtype: bool """ - if not self.is_member_change_email_details(): - raise AttributeError("tag 'member_change_email_details' not set") - return self._value + return self._tag == 'file_transfers_file_add_details' - def get_member_change_external_id_details(self): + def is_file_transfers_transfer_delete_details(self): """ - Only call this if :meth:`is_member_change_external_id_details` is true. + Check if the union tag is ``file_transfers_transfer_delete_details``. - :rtype: MemberChangeExternalIdDetails + :rtype: bool """ - if not self.is_member_change_external_id_details(): - raise AttributeError("tag 'member_change_external_id_details' not set") - return self._value + return self._tag == 'file_transfers_transfer_delete_details' - def get_member_change_membership_type_details(self): + def is_file_transfers_transfer_download_details(self): """ - Only call this if :meth:`is_member_change_membership_type_details` is true. + Check if the union tag is ``file_transfers_transfer_download_details``. - :rtype: MemberChangeMembershipTypeDetails + :rtype: bool """ - if not self.is_member_change_membership_type_details(): - raise AttributeError("tag 'member_change_membership_type_details' not set") - return self._value + return self._tag == 'file_transfers_transfer_download_details' - def get_member_change_name_details(self): + def is_file_transfers_transfer_send_details(self): """ - Only call this if :meth:`is_member_change_name_details` is true. + Check if the union tag is ``file_transfers_transfer_send_details``. - :rtype: MemberChangeNameDetails + :rtype: bool """ - if not self.is_member_change_name_details(): - raise AttributeError("tag 'member_change_name_details' not set") - return self._value + return self._tag == 'file_transfers_transfer_send_details' - def get_member_change_status_details(self): + def is_file_transfers_transfer_view_details(self): """ - Only call this if :meth:`is_member_change_status_details` is true. + Check if the union tag is ``file_transfers_transfer_view_details``. - :rtype: MemberChangeStatusDetails + :rtype: bool """ - if not self.is_member_change_status_details(): - raise AttributeError("tag 'member_change_status_details' not set") - return self._value + return self._tag == 'file_transfers_transfer_view_details' - def get_member_delete_manual_contacts_details(self): + def is_note_acl_invite_only_details(self): """ - Only call this if :meth:`is_member_delete_manual_contacts_details` is true. + Check if the union tag is ``note_acl_invite_only_details``. - :rtype: MemberDeleteManualContactsDetails + :rtype: bool """ - if not self.is_member_delete_manual_contacts_details(): - raise AttributeError("tag 'member_delete_manual_contacts_details' not set") - return self._value + return self._tag == 'note_acl_invite_only_details' - def get_member_permanently_delete_account_contents_details(self): + def is_note_acl_link_details(self): """ - Only call this if :meth:`is_member_permanently_delete_account_contents_details` is true. + Check if the union tag is ``note_acl_link_details``. - :rtype: MemberPermanentlyDeleteAccountContentsDetails + :rtype: bool """ - if not self.is_member_permanently_delete_account_contents_details(): - raise AttributeError("tag 'member_permanently_delete_account_contents_details' not set") - return self._value + return self._tag == 'note_acl_link_details' - def get_member_remove_external_id_details(self): + def is_note_acl_team_link_details(self): """ - Only call this if :meth:`is_member_remove_external_id_details` is true. + Check if the union tag is ``note_acl_team_link_details``. - :rtype: MemberRemoveExternalIdDetails + :rtype: bool """ - if not self.is_member_remove_external_id_details(): - raise AttributeError("tag 'member_remove_external_id_details' not set") - return self._value + return self._tag == 'note_acl_team_link_details' - def get_member_space_limits_add_custom_quota_details(self): + def is_note_shared_details(self): """ - Only call this if :meth:`is_member_space_limits_add_custom_quota_details` is true. + Check if the union tag is ``note_shared_details``. - :rtype: MemberSpaceLimitsAddCustomQuotaDetails + :rtype: bool """ - if not self.is_member_space_limits_add_custom_quota_details(): - raise AttributeError("tag 'member_space_limits_add_custom_quota_details' not set") - return self._value + return self._tag == 'note_shared_details' - def get_member_space_limits_change_custom_quota_details(self): + def is_note_share_receive_details(self): """ - Only call this if :meth:`is_member_space_limits_change_custom_quota_details` is true. + Check if the union tag is ``note_share_receive_details``. - :rtype: MemberSpaceLimitsChangeCustomQuotaDetails + :rtype: bool """ - if not self.is_member_space_limits_change_custom_quota_details(): - raise AttributeError("tag 'member_space_limits_change_custom_quota_details' not set") - return self._value + return self._tag == 'note_share_receive_details' - def get_member_space_limits_change_status_details(self): + def is_open_note_shared_details(self): """ - Only call this if :meth:`is_member_space_limits_change_status_details` is true. + Check if the union tag is ``open_note_shared_details``. - :rtype: MemberSpaceLimitsChangeStatusDetails + :rtype: bool """ - if not self.is_member_space_limits_change_status_details(): - raise AttributeError("tag 'member_space_limits_change_status_details' not set") - return self._value + return self._tag == 'open_note_shared_details' - def get_member_space_limits_remove_custom_quota_details(self): + def is_sf_add_group_details(self): """ - Only call this if :meth:`is_member_space_limits_remove_custom_quota_details` is true. + Check if the union tag is ``sf_add_group_details``. - :rtype: MemberSpaceLimitsRemoveCustomQuotaDetails + :rtype: bool """ - if not self.is_member_space_limits_remove_custom_quota_details(): - raise AttributeError("tag 'member_space_limits_remove_custom_quota_details' not set") - return self._value + return self._tag == 'sf_add_group_details' - def get_member_suggest_details(self): + def is_sf_allow_non_members_to_view_shared_links_details(self): """ - Only call this if :meth:`is_member_suggest_details` is true. + Check if the union tag is ``sf_allow_non_members_to_view_shared_links_details``. - :rtype: MemberSuggestDetails + :rtype: bool """ - if not self.is_member_suggest_details(): - raise AttributeError("tag 'member_suggest_details' not set") - return self._value + return self._tag == 'sf_allow_non_members_to_view_shared_links_details' - def get_member_transfer_account_contents_details(self): + def is_sf_external_invite_warn_details(self): """ - Only call this if :meth:`is_member_transfer_account_contents_details` is true. + Check if the union tag is ``sf_external_invite_warn_details``. - :rtype: MemberTransferAccountContentsDetails + :rtype: bool """ - if not self.is_member_transfer_account_contents_details(): - raise AttributeError("tag 'member_transfer_account_contents_details' not set") - return self._value + return self._tag == 'sf_external_invite_warn_details' - def get_secondary_mails_policy_changed_details(self): + def is_sf_fb_invite_details(self): """ - Only call this if :meth:`is_secondary_mails_policy_changed_details` is true. + Check if the union tag is ``sf_fb_invite_details``. - :rtype: SecondaryMailsPolicyChangedDetails + :rtype: bool """ - if not self.is_secondary_mails_policy_changed_details(): - raise AttributeError("tag 'secondary_mails_policy_changed_details' not set") - return self._value + return self._tag == 'sf_fb_invite_details' - def get_paper_content_add_member_details(self): + def is_sf_fb_invite_change_role_details(self): """ - Only call this if :meth:`is_paper_content_add_member_details` is true. + Check if the union tag is ``sf_fb_invite_change_role_details``. - :rtype: PaperContentAddMemberDetails + :rtype: bool """ - if not self.is_paper_content_add_member_details(): - raise AttributeError("tag 'paper_content_add_member_details' not set") - return self._value + return self._tag == 'sf_fb_invite_change_role_details' - def get_paper_content_add_to_folder_details(self): + def is_sf_fb_uninvite_details(self): """ - Only call this if :meth:`is_paper_content_add_to_folder_details` is true. + Check if the union tag is ``sf_fb_uninvite_details``. - :rtype: PaperContentAddToFolderDetails + :rtype: bool """ - if not self.is_paper_content_add_to_folder_details(): - raise AttributeError("tag 'paper_content_add_to_folder_details' not set") - return self._value + return self._tag == 'sf_fb_uninvite_details' - def get_paper_content_archive_details(self): + def is_sf_invite_group_details(self): """ - Only call this if :meth:`is_paper_content_archive_details` is true. + Check if the union tag is ``sf_invite_group_details``. - :rtype: PaperContentArchiveDetails + :rtype: bool """ - if not self.is_paper_content_archive_details(): - raise AttributeError("tag 'paper_content_archive_details' not set") - return self._value + return self._tag == 'sf_invite_group_details' - def get_paper_content_create_details(self): + def is_sf_team_grant_access_details(self): """ - Only call this if :meth:`is_paper_content_create_details` is true. + Check if the union tag is ``sf_team_grant_access_details``. - :rtype: PaperContentCreateDetails + :rtype: bool """ - if not self.is_paper_content_create_details(): - raise AttributeError("tag 'paper_content_create_details' not set") - return self._value + return self._tag == 'sf_team_grant_access_details' - def get_paper_content_permanently_delete_details(self): + def is_sf_team_invite_details(self): """ - Only call this if :meth:`is_paper_content_permanently_delete_details` is true. + Check if the union tag is ``sf_team_invite_details``. - :rtype: PaperContentPermanentlyDeleteDetails + :rtype: bool """ - if not self.is_paper_content_permanently_delete_details(): - raise AttributeError("tag 'paper_content_permanently_delete_details' not set") - return self._value + return self._tag == 'sf_team_invite_details' - def get_paper_content_remove_from_folder_details(self): + def is_sf_team_invite_change_role_details(self): """ - Only call this if :meth:`is_paper_content_remove_from_folder_details` is true. + Check if the union tag is ``sf_team_invite_change_role_details``. - :rtype: PaperContentRemoveFromFolderDetails + :rtype: bool """ - if not self.is_paper_content_remove_from_folder_details(): - raise AttributeError("tag 'paper_content_remove_from_folder_details' not set") - return self._value + return self._tag == 'sf_team_invite_change_role_details' - def get_paper_content_remove_member_details(self): + def is_sf_team_join_details(self): """ - Only call this if :meth:`is_paper_content_remove_member_details` is true. + Check if the union tag is ``sf_team_join_details``. - :rtype: PaperContentRemoveMemberDetails + :rtype: bool """ - if not self.is_paper_content_remove_member_details(): - raise AttributeError("tag 'paper_content_remove_member_details' not set") - return self._value + return self._tag == 'sf_team_join_details' - def get_paper_content_rename_details(self): + def is_sf_team_join_from_oob_link_details(self): """ - Only call this if :meth:`is_paper_content_rename_details` is true. + Check if the union tag is ``sf_team_join_from_oob_link_details``. - :rtype: PaperContentRenameDetails + :rtype: bool """ - if not self.is_paper_content_rename_details(): - raise AttributeError("tag 'paper_content_rename_details' not set") - return self._value + return self._tag == 'sf_team_join_from_oob_link_details' - def get_paper_content_restore_details(self): + def is_sf_team_uninvite_details(self): """ - Only call this if :meth:`is_paper_content_restore_details` is true. + Check if the union tag is ``sf_team_uninvite_details``. - :rtype: PaperContentRestoreDetails + :rtype: bool """ - if not self.is_paper_content_restore_details(): - raise AttributeError("tag 'paper_content_restore_details' not set") - return self._value + return self._tag == 'sf_team_uninvite_details' - def get_paper_doc_add_comment_details(self): + def is_shared_content_add_invitees_details(self): """ - Only call this if :meth:`is_paper_doc_add_comment_details` is true. + Check if the union tag is ``shared_content_add_invitees_details``. - :rtype: PaperDocAddCommentDetails + :rtype: bool """ - if not self.is_paper_doc_add_comment_details(): - raise AttributeError("tag 'paper_doc_add_comment_details' not set") - return self._value + return self._tag == 'shared_content_add_invitees_details' - def get_paper_doc_change_member_role_details(self): + def is_shared_content_add_link_expiry_details(self): """ - Only call this if :meth:`is_paper_doc_change_member_role_details` is true. + Check if the union tag is ``shared_content_add_link_expiry_details``. - :rtype: PaperDocChangeMemberRoleDetails + :rtype: bool """ - if not self.is_paper_doc_change_member_role_details(): - raise AttributeError("tag 'paper_doc_change_member_role_details' not set") - return self._value + return self._tag == 'shared_content_add_link_expiry_details' - def get_paper_doc_change_sharing_policy_details(self): + def is_shared_content_add_link_password_details(self): """ - Only call this if :meth:`is_paper_doc_change_sharing_policy_details` is true. + Check if the union tag is ``shared_content_add_link_password_details``. - :rtype: PaperDocChangeSharingPolicyDetails + :rtype: bool """ - if not self.is_paper_doc_change_sharing_policy_details(): - raise AttributeError("tag 'paper_doc_change_sharing_policy_details' not set") - return self._value + return self._tag == 'shared_content_add_link_password_details' - def get_paper_doc_change_subscription_details(self): + def is_shared_content_add_member_details(self): """ - Only call this if :meth:`is_paper_doc_change_subscription_details` is true. + Check if the union tag is ``shared_content_add_member_details``. - :rtype: PaperDocChangeSubscriptionDetails + :rtype: bool """ - if not self.is_paper_doc_change_subscription_details(): - raise AttributeError("tag 'paper_doc_change_subscription_details' not set") - return self._value + return self._tag == 'shared_content_add_member_details' - def get_paper_doc_deleted_details(self): + def is_shared_content_change_downloads_policy_details(self): """ - Only call this if :meth:`is_paper_doc_deleted_details` is true. + Check if the union tag is ``shared_content_change_downloads_policy_details``. - :rtype: PaperDocDeletedDetails + :rtype: bool """ - if not self.is_paper_doc_deleted_details(): - raise AttributeError("tag 'paper_doc_deleted_details' not set") - return self._value + return self._tag == 'shared_content_change_downloads_policy_details' - def get_paper_doc_delete_comment_details(self): + def is_shared_content_change_invitee_role_details(self): """ - Only call this if :meth:`is_paper_doc_delete_comment_details` is true. + Check if the union tag is ``shared_content_change_invitee_role_details``. - :rtype: PaperDocDeleteCommentDetails + :rtype: bool """ - if not self.is_paper_doc_delete_comment_details(): - raise AttributeError("tag 'paper_doc_delete_comment_details' not set") - return self._value + return self._tag == 'shared_content_change_invitee_role_details' - def get_paper_doc_download_details(self): + def is_shared_content_change_link_audience_details(self): """ - Only call this if :meth:`is_paper_doc_download_details` is true. + Check if the union tag is ``shared_content_change_link_audience_details``. - :rtype: PaperDocDownloadDetails + :rtype: bool """ - if not self.is_paper_doc_download_details(): - raise AttributeError("tag 'paper_doc_download_details' not set") - return self._value + return self._tag == 'shared_content_change_link_audience_details' - def get_paper_doc_edit_details(self): + def is_shared_content_change_link_expiry_details(self): """ - Only call this if :meth:`is_paper_doc_edit_details` is true. + Check if the union tag is ``shared_content_change_link_expiry_details``. - :rtype: PaperDocEditDetails + :rtype: bool """ - if not self.is_paper_doc_edit_details(): - raise AttributeError("tag 'paper_doc_edit_details' not set") - return self._value + return self._tag == 'shared_content_change_link_expiry_details' - def get_paper_doc_edit_comment_details(self): + def is_shared_content_change_link_password_details(self): """ - Only call this if :meth:`is_paper_doc_edit_comment_details` is true. + Check if the union tag is ``shared_content_change_link_password_details``. - :rtype: PaperDocEditCommentDetails + :rtype: bool """ - if not self.is_paper_doc_edit_comment_details(): - raise AttributeError("tag 'paper_doc_edit_comment_details' not set") - return self._value + return self._tag == 'shared_content_change_link_password_details' - def get_paper_doc_followed_details(self): + def is_shared_content_change_member_role_details(self): """ - Only call this if :meth:`is_paper_doc_followed_details` is true. + Check if the union tag is ``shared_content_change_member_role_details``. - :rtype: PaperDocFollowedDetails + :rtype: bool """ - if not self.is_paper_doc_followed_details(): - raise AttributeError("tag 'paper_doc_followed_details' not set") - return self._value + return self._tag == 'shared_content_change_member_role_details' - def get_paper_doc_mention_details(self): + def is_shared_content_change_viewer_info_policy_details(self): """ - Only call this if :meth:`is_paper_doc_mention_details` is true. + Check if the union tag is ``shared_content_change_viewer_info_policy_details``. - :rtype: PaperDocMentionDetails + :rtype: bool """ - if not self.is_paper_doc_mention_details(): - raise AttributeError("tag 'paper_doc_mention_details' not set") - return self._value + return self._tag == 'shared_content_change_viewer_info_policy_details' - def get_paper_doc_ownership_changed_details(self): + def is_shared_content_claim_invitation_details(self): """ - Only call this if :meth:`is_paper_doc_ownership_changed_details` is true. + Check if the union tag is ``shared_content_claim_invitation_details``. - :rtype: PaperDocOwnershipChangedDetails + :rtype: bool """ - if not self.is_paper_doc_ownership_changed_details(): - raise AttributeError("tag 'paper_doc_ownership_changed_details' not set") - return self._value + return self._tag == 'shared_content_claim_invitation_details' - def get_paper_doc_request_access_details(self): + def is_shared_content_copy_details(self): """ - Only call this if :meth:`is_paper_doc_request_access_details` is true. + Check if the union tag is ``shared_content_copy_details``. - :rtype: PaperDocRequestAccessDetails + :rtype: bool """ - if not self.is_paper_doc_request_access_details(): - raise AttributeError("tag 'paper_doc_request_access_details' not set") - return self._value + return self._tag == 'shared_content_copy_details' - def get_paper_doc_resolve_comment_details(self): + def is_shared_content_download_details(self): """ - Only call this if :meth:`is_paper_doc_resolve_comment_details` is true. + Check if the union tag is ``shared_content_download_details``. - :rtype: PaperDocResolveCommentDetails + :rtype: bool """ - if not self.is_paper_doc_resolve_comment_details(): - raise AttributeError("tag 'paper_doc_resolve_comment_details' not set") - return self._value + return self._tag == 'shared_content_download_details' - def get_paper_doc_revert_details(self): + def is_shared_content_relinquish_membership_details(self): """ - Only call this if :meth:`is_paper_doc_revert_details` is true. + Check if the union tag is ``shared_content_relinquish_membership_details``. - :rtype: PaperDocRevertDetails + :rtype: bool """ - if not self.is_paper_doc_revert_details(): - raise AttributeError("tag 'paper_doc_revert_details' not set") - return self._value + return self._tag == 'shared_content_relinquish_membership_details' - def get_paper_doc_slack_share_details(self): + def is_shared_content_remove_invitees_details(self): """ - Only call this if :meth:`is_paper_doc_slack_share_details` is true. + Check if the union tag is ``shared_content_remove_invitees_details``. - :rtype: PaperDocSlackShareDetails + :rtype: bool """ - if not self.is_paper_doc_slack_share_details(): - raise AttributeError("tag 'paper_doc_slack_share_details' not set") - return self._value + return self._tag == 'shared_content_remove_invitees_details' - def get_paper_doc_team_invite_details(self): + def is_shared_content_remove_link_expiry_details(self): """ - Only call this if :meth:`is_paper_doc_team_invite_details` is true. + Check if the union tag is ``shared_content_remove_link_expiry_details``. - :rtype: PaperDocTeamInviteDetails + :rtype: bool """ - if not self.is_paper_doc_team_invite_details(): - raise AttributeError("tag 'paper_doc_team_invite_details' not set") - return self._value + return self._tag == 'shared_content_remove_link_expiry_details' - def get_paper_doc_trashed_details(self): + def is_shared_content_remove_link_password_details(self): """ - Only call this if :meth:`is_paper_doc_trashed_details` is true. + Check if the union tag is ``shared_content_remove_link_password_details``. - :rtype: PaperDocTrashedDetails + :rtype: bool """ - if not self.is_paper_doc_trashed_details(): - raise AttributeError("tag 'paper_doc_trashed_details' not set") - return self._value + return self._tag == 'shared_content_remove_link_password_details' - def get_paper_doc_unresolve_comment_details(self): + def is_shared_content_remove_member_details(self): """ - Only call this if :meth:`is_paper_doc_unresolve_comment_details` is true. + Check if the union tag is ``shared_content_remove_member_details``. - :rtype: PaperDocUnresolveCommentDetails + :rtype: bool """ - if not self.is_paper_doc_unresolve_comment_details(): - raise AttributeError("tag 'paper_doc_unresolve_comment_details' not set") - return self._value + return self._tag == 'shared_content_remove_member_details' - def get_paper_doc_untrashed_details(self): + def is_shared_content_request_access_details(self): """ - Only call this if :meth:`is_paper_doc_untrashed_details` is true. + Check if the union tag is ``shared_content_request_access_details``. - :rtype: PaperDocUntrashedDetails + :rtype: bool """ - if not self.is_paper_doc_untrashed_details(): - raise AttributeError("tag 'paper_doc_untrashed_details' not set") - return self._value + return self._tag == 'shared_content_request_access_details' - def get_paper_doc_view_details(self): + def is_shared_content_restore_invitees_details(self): """ - Only call this if :meth:`is_paper_doc_view_details` is true. + Check if the union tag is ``shared_content_restore_invitees_details``. - :rtype: PaperDocViewDetails + :rtype: bool """ - if not self.is_paper_doc_view_details(): - raise AttributeError("tag 'paper_doc_view_details' not set") - return self._value + return self._tag == 'shared_content_restore_invitees_details' - def get_paper_external_view_allow_details(self): + def is_shared_content_restore_member_details(self): """ - Only call this if :meth:`is_paper_external_view_allow_details` is true. + Check if the union tag is ``shared_content_restore_member_details``. - :rtype: PaperExternalViewAllowDetails + :rtype: bool """ - if not self.is_paper_external_view_allow_details(): - raise AttributeError("tag 'paper_external_view_allow_details' not set") - return self._value + return self._tag == 'shared_content_restore_member_details' - def get_paper_external_view_default_team_details(self): + def is_shared_content_unshare_details(self): """ - Only call this if :meth:`is_paper_external_view_default_team_details` is true. + Check if the union tag is ``shared_content_unshare_details``. - :rtype: PaperExternalViewDefaultTeamDetails + :rtype: bool """ - if not self.is_paper_external_view_default_team_details(): - raise AttributeError("tag 'paper_external_view_default_team_details' not set") - return self._value + return self._tag == 'shared_content_unshare_details' - def get_paper_external_view_forbid_details(self): + def is_shared_content_view_details(self): """ - Only call this if :meth:`is_paper_external_view_forbid_details` is true. + Check if the union tag is ``shared_content_view_details``. - :rtype: PaperExternalViewForbidDetails + :rtype: bool """ - if not self.is_paper_external_view_forbid_details(): - raise AttributeError("tag 'paper_external_view_forbid_details' not set") - return self._value + return self._tag == 'shared_content_view_details' - def get_paper_folder_change_subscription_details(self): + def is_shared_folder_change_link_policy_details(self): """ - Only call this if :meth:`is_paper_folder_change_subscription_details` is true. + Check if the union tag is ``shared_folder_change_link_policy_details``. - :rtype: PaperFolderChangeSubscriptionDetails + :rtype: bool """ - if not self.is_paper_folder_change_subscription_details(): - raise AttributeError("tag 'paper_folder_change_subscription_details' not set") - return self._value + return self._tag == 'shared_folder_change_link_policy_details' - def get_paper_folder_deleted_details(self): + def is_shared_folder_change_members_inheritance_policy_details(self): """ - Only call this if :meth:`is_paper_folder_deleted_details` is true. + Check if the union tag is ``shared_folder_change_members_inheritance_policy_details``. - :rtype: PaperFolderDeletedDetails + :rtype: bool """ - if not self.is_paper_folder_deleted_details(): - raise AttributeError("tag 'paper_folder_deleted_details' not set") - return self._value + return self._tag == 'shared_folder_change_members_inheritance_policy_details' - def get_paper_folder_followed_details(self): + def is_shared_folder_change_members_management_policy_details(self): """ - Only call this if :meth:`is_paper_folder_followed_details` is true. + Check if the union tag is ``shared_folder_change_members_management_policy_details``. - :rtype: PaperFolderFollowedDetails + :rtype: bool """ - if not self.is_paper_folder_followed_details(): - raise AttributeError("tag 'paper_folder_followed_details' not set") - return self._value + return self._tag == 'shared_folder_change_members_management_policy_details' - def get_paper_folder_team_invite_details(self): + def is_shared_folder_change_members_policy_details(self): """ - Only call this if :meth:`is_paper_folder_team_invite_details` is true. + Check if the union tag is ``shared_folder_change_members_policy_details``. - :rtype: PaperFolderTeamInviteDetails + :rtype: bool """ - if not self.is_paper_folder_team_invite_details(): - raise AttributeError("tag 'paper_folder_team_invite_details' not set") - return self._value + return self._tag == 'shared_folder_change_members_policy_details' - def get_paper_published_link_create_details(self): + def is_shared_folder_create_details(self): """ - Only call this if :meth:`is_paper_published_link_create_details` is true. + Check if the union tag is ``shared_folder_create_details``. - :rtype: PaperPublishedLinkCreateDetails + :rtype: bool """ - if not self.is_paper_published_link_create_details(): - raise AttributeError("tag 'paper_published_link_create_details' not set") - return self._value + return self._tag == 'shared_folder_create_details' - def get_paper_published_link_disabled_details(self): + def is_shared_folder_decline_invitation_details(self): """ - Only call this if :meth:`is_paper_published_link_disabled_details` is true. + Check if the union tag is ``shared_folder_decline_invitation_details``. - :rtype: PaperPublishedLinkDisabledDetails + :rtype: bool """ - if not self.is_paper_published_link_disabled_details(): - raise AttributeError("tag 'paper_published_link_disabled_details' not set") - return self._value + return self._tag == 'shared_folder_decline_invitation_details' - def get_paper_published_link_view_details(self): + def is_shared_folder_mount_details(self): """ - Only call this if :meth:`is_paper_published_link_view_details` is true. + Check if the union tag is ``shared_folder_mount_details``. - :rtype: PaperPublishedLinkViewDetails + :rtype: bool """ - if not self.is_paper_published_link_view_details(): - raise AttributeError("tag 'paper_published_link_view_details' not set") - return self._value + return self._tag == 'shared_folder_mount_details' - def get_password_change_details(self): + def is_shared_folder_nest_details(self): """ - Only call this if :meth:`is_password_change_details` is true. + Check if the union tag is ``shared_folder_nest_details``. - :rtype: PasswordChangeDetails + :rtype: bool """ - if not self.is_password_change_details(): - raise AttributeError("tag 'password_change_details' not set") - return self._value + return self._tag == 'shared_folder_nest_details' - def get_password_reset_details(self): + def is_shared_folder_transfer_ownership_details(self): """ - Only call this if :meth:`is_password_reset_details` is true. + Check if the union tag is ``shared_folder_transfer_ownership_details``. - :rtype: PasswordResetDetails + :rtype: bool """ - if not self.is_password_reset_details(): - raise AttributeError("tag 'password_reset_details' not set") - return self._value + return self._tag == 'shared_folder_transfer_ownership_details' - def get_password_reset_all_details(self): + def is_shared_folder_unmount_details(self): """ - Only call this if :meth:`is_password_reset_all_details` is true. + Check if the union tag is ``shared_folder_unmount_details``. - :rtype: PasswordResetAllDetails + :rtype: bool """ - if not self.is_password_reset_all_details(): - raise AttributeError("tag 'password_reset_all_details' not set") - return self._value + return self._tag == 'shared_folder_unmount_details' - def get_emm_create_exceptions_report_details(self): + def is_shared_link_add_expiry_details(self): """ - Only call this if :meth:`is_emm_create_exceptions_report_details` is true. + Check if the union tag is ``shared_link_add_expiry_details``. - :rtype: EmmCreateExceptionsReportDetails + :rtype: bool """ - if not self.is_emm_create_exceptions_report_details(): - raise AttributeError("tag 'emm_create_exceptions_report_details' not set") - return self._value + return self._tag == 'shared_link_add_expiry_details' - def get_emm_create_usage_report_details(self): + def is_shared_link_change_expiry_details(self): """ - Only call this if :meth:`is_emm_create_usage_report_details` is true. + Check if the union tag is ``shared_link_change_expiry_details``. - :rtype: EmmCreateUsageReportDetails + :rtype: bool """ - if not self.is_emm_create_usage_report_details(): - raise AttributeError("tag 'emm_create_usage_report_details' not set") - return self._value + return self._tag == 'shared_link_change_expiry_details' - def get_export_members_report_details(self): + def is_shared_link_change_visibility_details(self): """ - Only call this if :meth:`is_export_members_report_details` is true. + Check if the union tag is ``shared_link_change_visibility_details``. - :rtype: ExportMembersReportDetails + :rtype: bool """ - if not self.is_export_members_report_details(): - raise AttributeError("tag 'export_members_report_details' not set") - return self._value + return self._tag == 'shared_link_change_visibility_details' - def get_paper_admin_export_start_details(self): + def is_shared_link_copy_details(self): """ - Only call this if :meth:`is_paper_admin_export_start_details` is true. + Check if the union tag is ``shared_link_copy_details``. - :rtype: PaperAdminExportStartDetails + :rtype: bool """ - if not self.is_paper_admin_export_start_details(): - raise AttributeError("tag 'paper_admin_export_start_details' not set") - return self._value + return self._tag == 'shared_link_copy_details' - def get_smart_sync_create_admin_privilege_report_details(self): + def is_shared_link_create_details(self): """ - Only call this if :meth:`is_smart_sync_create_admin_privilege_report_details` is true. + Check if the union tag is ``shared_link_create_details``. - :rtype: SmartSyncCreateAdminPrivilegeReportDetails + :rtype: bool """ - if not self.is_smart_sync_create_admin_privilege_report_details(): - raise AttributeError("tag 'smart_sync_create_admin_privilege_report_details' not set") - return self._value + return self._tag == 'shared_link_create_details' - def get_team_activity_create_report_details(self): + def is_shared_link_disable_details(self): """ - Only call this if :meth:`is_team_activity_create_report_details` is true. + Check if the union tag is ``shared_link_disable_details``. - :rtype: TeamActivityCreateReportDetails + :rtype: bool """ - if not self.is_team_activity_create_report_details(): - raise AttributeError("tag 'team_activity_create_report_details' not set") - return self._value + return self._tag == 'shared_link_disable_details' - def get_team_activity_create_report_fail_details(self): + def is_shared_link_download_details(self): """ - Only call this if :meth:`is_team_activity_create_report_fail_details` is true. + Check if the union tag is ``shared_link_download_details``. - :rtype: TeamActivityCreateReportFailDetails + :rtype: bool """ - if not self.is_team_activity_create_report_fail_details(): - raise AttributeError("tag 'team_activity_create_report_fail_details' not set") - return self._value + return self._tag == 'shared_link_download_details' - def get_collection_share_details(self): + def is_shared_link_remove_expiry_details(self): """ - Only call this if :meth:`is_collection_share_details` is true. + Check if the union tag is ``shared_link_remove_expiry_details``. - :rtype: CollectionShareDetails + :rtype: bool """ - if not self.is_collection_share_details(): - raise AttributeError("tag 'collection_share_details' not set") - return self._value + return self._tag == 'shared_link_remove_expiry_details' - def get_note_acl_invite_only_details(self): + def is_shared_link_settings_add_expiration_details(self): """ - Only call this if :meth:`is_note_acl_invite_only_details` is true. + Check if the union tag is ``shared_link_settings_add_expiration_details``. - :rtype: NoteAclInviteOnlyDetails + :rtype: bool """ - if not self.is_note_acl_invite_only_details(): - raise AttributeError("tag 'note_acl_invite_only_details' not set") - return self._value + return self._tag == 'shared_link_settings_add_expiration_details' - def get_note_acl_link_details(self): + def is_shared_link_settings_add_password_details(self): """ - Only call this if :meth:`is_note_acl_link_details` is true. + Check if the union tag is ``shared_link_settings_add_password_details``. - :rtype: NoteAclLinkDetails + :rtype: bool """ - if not self.is_note_acl_link_details(): - raise AttributeError("tag 'note_acl_link_details' not set") - return self._value + return self._tag == 'shared_link_settings_add_password_details' - def get_note_acl_team_link_details(self): + def is_shared_link_settings_allow_download_disabled_details(self): """ - Only call this if :meth:`is_note_acl_team_link_details` is true. + Check if the union tag is ``shared_link_settings_allow_download_disabled_details``. - :rtype: NoteAclTeamLinkDetails + :rtype: bool """ - if not self.is_note_acl_team_link_details(): - raise AttributeError("tag 'note_acl_team_link_details' not set") - return self._value + return self._tag == 'shared_link_settings_allow_download_disabled_details' - def get_note_shared_details(self): + def is_shared_link_settings_allow_download_enabled_details(self): """ - Only call this if :meth:`is_note_shared_details` is true. + Check if the union tag is ``shared_link_settings_allow_download_enabled_details``. - :rtype: NoteSharedDetails + :rtype: bool """ - if not self.is_note_shared_details(): - raise AttributeError("tag 'note_shared_details' not set") - return self._value + return self._tag == 'shared_link_settings_allow_download_enabled_details' - def get_note_share_receive_details(self): + def is_shared_link_settings_change_audience_details(self): """ - Only call this if :meth:`is_note_share_receive_details` is true. + Check if the union tag is ``shared_link_settings_change_audience_details``. - :rtype: NoteShareReceiveDetails + :rtype: bool """ - if not self.is_note_share_receive_details(): - raise AttributeError("tag 'note_share_receive_details' not set") - return self._value + return self._tag == 'shared_link_settings_change_audience_details' - def get_open_note_shared_details(self): + def is_shared_link_settings_change_expiration_details(self): """ - Only call this if :meth:`is_open_note_shared_details` is true. + Check if the union tag is ``shared_link_settings_change_expiration_details``. - :rtype: OpenNoteSharedDetails + :rtype: bool """ - if not self.is_open_note_shared_details(): - raise AttributeError("tag 'open_note_shared_details' not set") - return self._value + return self._tag == 'shared_link_settings_change_expiration_details' - def get_sf_add_group_details(self): + def is_shared_link_settings_change_password_details(self): """ - Only call this if :meth:`is_sf_add_group_details` is true. + Check if the union tag is ``shared_link_settings_change_password_details``. - :rtype: SfAddGroupDetails + :rtype: bool """ - if not self.is_sf_add_group_details(): - raise AttributeError("tag 'sf_add_group_details' not set") - return self._value + return self._tag == 'shared_link_settings_change_password_details' - def get_sf_allow_non_members_to_view_shared_links_details(self): + def is_shared_link_settings_remove_expiration_details(self): """ - Only call this if :meth:`is_sf_allow_non_members_to_view_shared_links_details` is true. + Check if the union tag is ``shared_link_settings_remove_expiration_details``. - :rtype: SfAllowNonMembersToViewSharedLinksDetails + :rtype: bool """ - if not self.is_sf_allow_non_members_to_view_shared_links_details(): - raise AttributeError("tag 'sf_allow_non_members_to_view_shared_links_details' not set") - return self._value + return self._tag == 'shared_link_settings_remove_expiration_details' - def get_sf_external_invite_warn_details(self): + def is_shared_link_settings_remove_password_details(self): """ - Only call this if :meth:`is_sf_external_invite_warn_details` is true. + Check if the union tag is ``shared_link_settings_remove_password_details``. - :rtype: SfExternalInviteWarnDetails + :rtype: bool """ - if not self.is_sf_external_invite_warn_details(): - raise AttributeError("tag 'sf_external_invite_warn_details' not set") - return self._value + return self._tag == 'shared_link_settings_remove_password_details' - def get_sf_fb_invite_details(self): + def is_shared_link_share_details(self): """ - Only call this if :meth:`is_sf_fb_invite_details` is true. + Check if the union tag is ``shared_link_share_details``. - :rtype: SfFbInviteDetails + :rtype: bool """ - if not self.is_sf_fb_invite_details(): - raise AttributeError("tag 'sf_fb_invite_details' not set") - return self._value + return self._tag == 'shared_link_share_details' - def get_sf_fb_invite_change_role_details(self): + def is_shared_link_view_details(self): """ - Only call this if :meth:`is_sf_fb_invite_change_role_details` is true. + Check if the union tag is ``shared_link_view_details``. - :rtype: SfFbInviteChangeRoleDetails + :rtype: bool """ - if not self.is_sf_fb_invite_change_role_details(): - raise AttributeError("tag 'sf_fb_invite_change_role_details' not set") - return self._value + return self._tag == 'shared_link_view_details' - def get_sf_fb_uninvite_details(self): + def is_shared_note_opened_details(self): """ - Only call this if :meth:`is_sf_fb_uninvite_details` is true. + Check if the union tag is ``shared_note_opened_details``. - :rtype: SfFbUninviteDetails + :rtype: bool """ - if not self.is_sf_fb_uninvite_details(): - raise AttributeError("tag 'sf_fb_uninvite_details' not set") - return self._value + return self._tag == 'shared_note_opened_details' - def get_sf_invite_group_details(self): + def is_shmodel_group_share_details(self): """ - Only call this if :meth:`is_sf_invite_group_details` is true. + Check if the union tag is ``shmodel_group_share_details``. - :rtype: SfInviteGroupDetails + :rtype: bool """ - if not self.is_sf_invite_group_details(): - raise AttributeError("tag 'sf_invite_group_details' not set") - return self._value + return self._tag == 'shmodel_group_share_details' - def get_sf_team_grant_access_details(self): + def is_showcase_access_granted_details(self): """ - Only call this if :meth:`is_sf_team_grant_access_details` is true. + Check if the union tag is ``showcase_access_granted_details``. - :rtype: SfTeamGrantAccessDetails + :rtype: bool """ - if not self.is_sf_team_grant_access_details(): - raise AttributeError("tag 'sf_team_grant_access_details' not set") - return self._value + return self._tag == 'showcase_access_granted_details' - def get_sf_team_invite_details(self): + def is_showcase_add_member_details(self): """ - Only call this if :meth:`is_sf_team_invite_details` is true. + Check if the union tag is ``showcase_add_member_details``. - :rtype: SfTeamInviteDetails + :rtype: bool """ - if not self.is_sf_team_invite_details(): - raise AttributeError("tag 'sf_team_invite_details' not set") - return self._value + return self._tag == 'showcase_add_member_details' - def get_sf_team_invite_change_role_details(self): + def is_showcase_archived_details(self): """ - Only call this if :meth:`is_sf_team_invite_change_role_details` is true. + Check if the union tag is ``showcase_archived_details``. - :rtype: SfTeamInviteChangeRoleDetails + :rtype: bool """ - if not self.is_sf_team_invite_change_role_details(): - raise AttributeError("tag 'sf_team_invite_change_role_details' not set") - return self._value + return self._tag == 'showcase_archived_details' - def get_sf_team_join_details(self): + def is_showcase_created_details(self): """ - Only call this if :meth:`is_sf_team_join_details` is true. + Check if the union tag is ``showcase_created_details``. - :rtype: SfTeamJoinDetails + :rtype: bool """ - if not self.is_sf_team_join_details(): - raise AttributeError("tag 'sf_team_join_details' not set") - return self._value + return self._tag == 'showcase_created_details' - def get_sf_team_join_from_oob_link_details(self): + def is_showcase_delete_comment_details(self): """ - Only call this if :meth:`is_sf_team_join_from_oob_link_details` is true. + Check if the union tag is ``showcase_delete_comment_details``. - :rtype: SfTeamJoinFromOobLinkDetails + :rtype: bool """ - if not self.is_sf_team_join_from_oob_link_details(): - raise AttributeError("tag 'sf_team_join_from_oob_link_details' not set") - return self._value + return self._tag == 'showcase_delete_comment_details' - def get_sf_team_uninvite_details(self): + def is_showcase_edited_details(self): """ - Only call this if :meth:`is_sf_team_uninvite_details` is true. + Check if the union tag is ``showcase_edited_details``. - :rtype: SfTeamUninviteDetails + :rtype: bool """ - if not self.is_sf_team_uninvite_details(): - raise AttributeError("tag 'sf_team_uninvite_details' not set") - return self._value + return self._tag == 'showcase_edited_details' - def get_shared_content_add_invitees_details(self): + def is_showcase_edit_comment_details(self): """ - Only call this if :meth:`is_shared_content_add_invitees_details` is true. + Check if the union tag is ``showcase_edit_comment_details``. - :rtype: SharedContentAddInviteesDetails + :rtype: bool """ - if not self.is_shared_content_add_invitees_details(): - raise AttributeError("tag 'shared_content_add_invitees_details' not set") - return self._value + return self._tag == 'showcase_edit_comment_details' - def get_shared_content_add_link_expiry_details(self): + def is_showcase_file_added_details(self): """ - Only call this if :meth:`is_shared_content_add_link_expiry_details` is true. + Check if the union tag is ``showcase_file_added_details``. - :rtype: SharedContentAddLinkExpiryDetails + :rtype: bool """ - if not self.is_shared_content_add_link_expiry_details(): - raise AttributeError("tag 'shared_content_add_link_expiry_details' not set") - return self._value + return self._tag == 'showcase_file_added_details' - def get_shared_content_add_link_password_details(self): + def is_showcase_file_download_details(self): """ - Only call this if :meth:`is_shared_content_add_link_password_details` is true. + Check if the union tag is ``showcase_file_download_details``. - :rtype: SharedContentAddLinkPasswordDetails + :rtype: bool """ - if not self.is_shared_content_add_link_password_details(): - raise AttributeError("tag 'shared_content_add_link_password_details' not set") - return self._value + return self._tag == 'showcase_file_download_details' - def get_shared_content_add_member_details(self): + def is_showcase_file_removed_details(self): """ - Only call this if :meth:`is_shared_content_add_member_details` is true. + Check if the union tag is ``showcase_file_removed_details``. - :rtype: SharedContentAddMemberDetails + :rtype: bool """ - if not self.is_shared_content_add_member_details(): - raise AttributeError("tag 'shared_content_add_member_details' not set") - return self._value + return self._tag == 'showcase_file_removed_details' - def get_shared_content_change_downloads_policy_details(self): + def is_showcase_file_view_details(self): """ - Only call this if :meth:`is_shared_content_change_downloads_policy_details` is true. + Check if the union tag is ``showcase_file_view_details``. - :rtype: SharedContentChangeDownloadsPolicyDetails + :rtype: bool """ - if not self.is_shared_content_change_downloads_policy_details(): - raise AttributeError("tag 'shared_content_change_downloads_policy_details' not set") - return self._value + return self._tag == 'showcase_file_view_details' - def get_shared_content_change_invitee_role_details(self): + def is_showcase_permanently_deleted_details(self): """ - Only call this if :meth:`is_shared_content_change_invitee_role_details` is true. + Check if the union tag is ``showcase_permanently_deleted_details``. - :rtype: SharedContentChangeInviteeRoleDetails + :rtype: bool """ - if not self.is_shared_content_change_invitee_role_details(): - raise AttributeError("tag 'shared_content_change_invitee_role_details' not set") - return self._value + return self._tag == 'showcase_permanently_deleted_details' - def get_shared_content_change_link_audience_details(self): + def is_showcase_post_comment_details(self): """ - Only call this if :meth:`is_shared_content_change_link_audience_details` is true. + Check if the union tag is ``showcase_post_comment_details``. - :rtype: SharedContentChangeLinkAudienceDetails + :rtype: bool """ - if not self.is_shared_content_change_link_audience_details(): - raise AttributeError("tag 'shared_content_change_link_audience_details' not set") - return self._value + return self._tag == 'showcase_post_comment_details' - def get_shared_content_change_link_expiry_details(self): + def is_showcase_remove_member_details(self): """ - Only call this if :meth:`is_shared_content_change_link_expiry_details` is true. + Check if the union tag is ``showcase_remove_member_details``. - :rtype: SharedContentChangeLinkExpiryDetails + :rtype: bool """ - if not self.is_shared_content_change_link_expiry_details(): - raise AttributeError("tag 'shared_content_change_link_expiry_details' not set") - return self._value + return self._tag == 'showcase_remove_member_details' - def get_shared_content_change_link_password_details(self): + def is_showcase_renamed_details(self): """ - Only call this if :meth:`is_shared_content_change_link_password_details` is true. + Check if the union tag is ``showcase_renamed_details``. - :rtype: SharedContentChangeLinkPasswordDetails + :rtype: bool """ - if not self.is_shared_content_change_link_password_details(): - raise AttributeError("tag 'shared_content_change_link_password_details' not set") - return self._value + return self._tag == 'showcase_renamed_details' - def get_shared_content_change_member_role_details(self): + def is_showcase_request_access_details(self): """ - Only call this if :meth:`is_shared_content_change_member_role_details` is true. + Check if the union tag is ``showcase_request_access_details``. - :rtype: SharedContentChangeMemberRoleDetails + :rtype: bool """ - if not self.is_shared_content_change_member_role_details(): - raise AttributeError("tag 'shared_content_change_member_role_details' not set") - return self._value + return self._tag == 'showcase_request_access_details' - def get_shared_content_change_viewer_info_policy_details(self): + def is_showcase_resolve_comment_details(self): """ - Only call this if :meth:`is_shared_content_change_viewer_info_policy_details` is true. + Check if the union tag is ``showcase_resolve_comment_details``. - :rtype: SharedContentChangeViewerInfoPolicyDetails + :rtype: bool """ - if not self.is_shared_content_change_viewer_info_policy_details(): - raise AttributeError("tag 'shared_content_change_viewer_info_policy_details' not set") - return self._value + return self._tag == 'showcase_resolve_comment_details' - def get_shared_content_claim_invitation_details(self): + def is_showcase_restored_details(self): """ - Only call this if :meth:`is_shared_content_claim_invitation_details` is true. + Check if the union tag is ``showcase_restored_details``. - :rtype: SharedContentClaimInvitationDetails + :rtype: bool """ - if not self.is_shared_content_claim_invitation_details(): - raise AttributeError("tag 'shared_content_claim_invitation_details' not set") - return self._value + return self._tag == 'showcase_restored_details' - def get_shared_content_copy_details(self): + def is_showcase_trashed_details(self): """ - Only call this if :meth:`is_shared_content_copy_details` is true. + Check if the union tag is ``showcase_trashed_details``. - :rtype: SharedContentCopyDetails + :rtype: bool """ - if not self.is_shared_content_copy_details(): - raise AttributeError("tag 'shared_content_copy_details' not set") - return self._value + return self._tag == 'showcase_trashed_details' - def get_shared_content_download_details(self): + def is_showcase_trashed_deprecated_details(self): """ - Only call this if :meth:`is_shared_content_download_details` is true. + Check if the union tag is ``showcase_trashed_deprecated_details``. - :rtype: SharedContentDownloadDetails + :rtype: bool """ - if not self.is_shared_content_download_details(): - raise AttributeError("tag 'shared_content_download_details' not set") - return self._value + return self._tag == 'showcase_trashed_deprecated_details' - def get_shared_content_relinquish_membership_details(self): + def is_showcase_unresolve_comment_details(self): """ - Only call this if :meth:`is_shared_content_relinquish_membership_details` is true. + Check if the union tag is ``showcase_unresolve_comment_details``. - :rtype: SharedContentRelinquishMembershipDetails + :rtype: bool """ - if not self.is_shared_content_relinquish_membership_details(): - raise AttributeError("tag 'shared_content_relinquish_membership_details' not set") - return self._value + return self._tag == 'showcase_unresolve_comment_details' - def get_shared_content_remove_invitees_details(self): + def is_showcase_untrashed_details(self): """ - Only call this if :meth:`is_shared_content_remove_invitees_details` is true. + Check if the union tag is ``showcase_untrashed_details``. - :rtype: SharedContentRemoveInviteesDetails + :rtype: bool """ - if not self.is_shared_content_remove_invitees_details(): - raise AttributeError("tag 'shared_content_remove_invitees_details' not set") - return self._value + return self._tag == 'showcase_untrashed_details' - def get_shared_content_remove_link_expiry_details(self): + def is_showcase_untrashed_deprecated_details(self): """ - Only call this if :meth:`is_shared_content_remove_link_expiry_details` is true. + Check if the union tag is ``showcase_untrashed_deprecated_details``. - :rtype: SharedContentRemoveLinkExpiryDetails + :rtype: bool """ - if not self.is_shared_content_remove_link_expiry_details(): - raise AttributeError("tag 'shared_content_remove_link_expiry_details' not set") - return self._value + return self._tag == 'showcase_untrashed_deprecated_details' - def get_shared_content_remove_link_password_details(self): + def is_showcase_view_details(self): """ - Only call this if :meth:`is_shared_content_remove_link_password_details` is true. + Check if the union tag is ``showcase_view_details``. - :rtype: SharedContentRemoveLinkPasswordDetails + :rtype: bool """ - if not self.is_shared_content_remove_link_password_details(): - raise AttributeError("tag 'shared_content_remove_link_password_details' not set") - return self._value + return self._tag == 'showcase_view_details' - def get_shared_content_remove_member_details(self): + def is_sso_add_cert_details(self): """ - Only call this if :meth:`is_shared_content_remove_member_details` is true. + Check if the union tag is ``sso_add_cert_details``. - :rtype: SharedContentRemoveMemberDetails + :rtype: bool """ - if not self.is_shared_content_remove_member_details(): - raise AttributeError("tag 'shared_content_remove_member_details' not set") - return self._value + return self._tag == 'sso_add_cert_details' - def get_shared_content_request_access_details(self): + def is_sso_add_login_url_details(self): """ - Only call this if :meth:`is_shared_content_request_access_details` is true. + Check if the union tag is ``sso_add_login_url_details``. - :rtype: SharedContentRequestAccessDetails + :rtype: bool """ - if not self.is_shared_content_request_access_details(): - raise AttributeError("tag 'shared_content_request_access_details' not set") - return self._value + return self._tag == 'sso_add_login_url_details' - def get_shared_content_unshare_details(self): + def is_sso_add_logout_url_details(self): """ - Only call this if :meth:`is_shared_content_unshare_details` is true. + Check if the union tag is ``sso_add_logout_url_details``. - :rtype: SharedContentUnshareDetails + :rtype: bool """ - if not self.is_shared_content_unshare_details(): - raise AttributeError("tag 'shared_content_unshare_details' not set") - return self._value + return self._tag == 'sso_add_logout_url_details' - def get_shared_content_view_details(self): + def is_sso_change_cert_details(self): """ - Only call this if :meth:`is_shared_content_view_details` is true. + Check if the union tag is ``sso_change_cert_details``. - :rtype: SharedContentViewDetails + :rtype: bool """ - if not self.is_shared_content_view_details(): - raise AttributeError("tag 'shared_content_view_details' not set") - return self._value + return self._tag == 'sso_change_cert_details' - def get_shared_folder_change_link_policy_details(self): + def is_sso_change_login_url_details(self): """ - Only call this if :meth:`is_shared_folder_change_link_policy_details` is true. + Check if the union tag is ``sso_change_login_url_details``. - :rtype: SharedFolderChangeLinkPolicyDetails + :rtype: bool """ - if not self.is_shared_folder_change_link_policy_details(): - raise AttributeError("tag 'shared_folder_change_link_policy_details' not set") - return self._value + return self._tag == 'sso_change_login_url_details' - def get_shared_folder_change_members_inheritance_policy_details(self): + def is_sso_change_logout_url_details(self): """ - Only call this if :meth:`is_shared_folder_change_members_inheritance_policy_details` is true. + Check if the union tag is ``sso_change_logout_url_details``. - :rtype: SharedFolderChangeMembersInheritancePolicyDetails + :rtype: bool """ - if not self.is_shared_folder_change_members_inheritance_policy_details(): - raise AttributeError("tag 'shared_folder_change_members_inheritance_policy_details' not set") - return self._value + return self._tag == 'sso_change_logout_url_details' - def get_shared_folder_change_members_management_policy_details(self): + def is_sso_change_saml_identity_mode_details(self): """ - Only call this if :meth:`is_shared_folder_change_members_management_policy_details` is true. + Check if the union tag is ``sso_change_saml_identity_mode_details``. - :rtype: SharedFolderChangeMembersManagementPolicyDetails + :rtype: bool """ - if not self.is_shared_folder_change_members_management_policy_details(): - raise AttributeError("tag 'shared_folder_change_members_management_policy_details' not set") - return self._value + return self._tag == 'sso_change_saml_identity_mode_details' - def get_shared_folder_change_members_policy_details(self): + def is_sso_remove_cert_details(self): """ - Only call this if :meth:`is_shared_folder_change_members_policy_details` is true. + Check if the union tag is ``sso_remove_cert_details``. - :rtype: SharedFolderChangeMembersPolicyDetails + :rtype: bool """ - if not self.is_shared_folder_change_members_policy_details(): - raise AttributeError("tag 'shared_folder_change_members_policy_details' not set") - return self._value + return self._tag == 'sso_remove_cert_details' - def get_shared_folder_create_details(self): + def is_sso_remove_login_url_details(self): """ - Only call this if :meth:`is_shared_folder_create_details` is true. + Check if the union tag is ``sso_remove_login_url_details``. - :rtype: SharedFolderCreateDetails + :rtype: bool """ - if not self.is_shared_folder_create_details(): - raise AttributeError("tag 'shared_folder_create_details' not set") - return self._value + return self._tag == 'sso_remove_login_url_details' - def get_shared_folder_decline_invitation_details(self): + def is_sso_remove_logout_url_details(self): """ - Only call this if :meth:`is_shared_folder_decline_invitation_details` is true. + Check if the union tag is ``sso_remove_logout_url_details``. - :rtype: SharedFolderDeclineInvitationDetails + :rtype: bool """ - if not self.is_shared_folder_decline_invitation_details(): - raise AttributeError("tag 'shared_folder_decline_invitation_details' not set") - return self._value + return self._tag == 'sso_remove_logout_url_details' - def get_shared_folder_mount_details(self): + def is_team_folder_change_status_details(self): """ - Only call this if :meth:`is_shared_folder_mount_details` is true. + Check if the union tag is ``team_folder_change_status_details``. - :rtype: SharedFolderMountDetails + :rtype: bool """ - if not self.is_shared_folder_mount_details(): - raise AttributeError("tag 'shared_folder_mount_details' not set") - return self._value + return self._tag == 'team_folder_change_status_details' - def get_shared_folder_nest_details(self): + def is_team_folder_create_details(self): """ - Only call this if :meth:`is_shared_folder_nest_details` is true. + Check if the union tag is ``team_folder_create_details``. - :rtype: SharedFolderNestDetails + :rtype: bool """ - if not self.is_shared_folder_nest_details(): - raise AttributeError("tag 'shared_folder_nest_details' not set") - return self._value + return self._tag == 'team_folder_create_details' - def get_shared_folder_transfer_ownership_details(self): + def is_team_folder_downgrade_details(self): """ - Only call this if :meth:`is_shared_folder_transfer_ownership_details` is true. + Check if the union tag is ``team_folder_downgrade_details``. - :rtype: SharedFolderTransferOwnershipDetails + :rtype: bool """ - if not self.is_shared_folder_transfer_ownership_details(): - raise AttributeError("tag 'shared_folder_transfer_ownership_details' not set") - return self._value + return self._tag == 'team_folder_downgrade_details' - def get_shared_folder_unmount_details(self): + def is_team_folder_permanently_delete_details(self): """ - Only call this if :meth:`is_shared_folder_unmount_details` is true. + Check if the union tag is ``team_folder_permanently_delete_details``. - :rtype: SharedFolderUnmountDetails + :rtype: bool """ - if not self.is_shared_folder_unmount_details(): - raise AttributeError("tag 'shared_folder_unmount_details' not set") - return self._value + return self._tag == 'team_folder_permanently_delete_details' - def get_shared_link_add_expiry_details(self): + def is_team_folder_rename_details(self): """ - Only call this if :meth:`is_shared_link_add_expiry_details` is true. + Check if the union tag is ``team_folder_rename_details``. - :rtype: SharedLinkAddExpiryDetails + :rtype: bool """ - if not self.is_shared_link_add_expiry_details(): - raise AttributeError("tag 'shared_link_add_expiry_details' not set") - return self._value + return self._tag == 'team_folder_rename_details' - def get_shared_link_change_expiry_details(self): + def is_team_selective_sync_settings_changed_details(self): """ - Only call this if :meth:`is_shared_link_change_expiry_details` is true. + Check if the union tag is ``team_selective_sync_settings_changed_details``. - :rtype: SharedLinkChangeExpiryDetails + :rtype: bool """ - if not self.is_shared_link_change_expiry_details(): - raise AttributeError("tag 'shared_link_change_expiry_details' not set") - return self._value + return self._tag == 'team_selective_sync_settings_changed_details' - def get_shared_link_change_visibility_details(self): + def is_account_capture_change_policy_details(self): """ - Only call this if :meth:`is_shared_link_change_visibility_details` is true. + Check if the union tag is ``account_capture_change_policy_details``. - :rtype: SharedLinkChangeVisibilityDetails + :rtype: bool """ - if not self.is_shared_link_change_visibility_details(): - raise AttributeError("tag 'shared_link_change_visibility_details' not set") - return self._value + return self._tag == 'account_capture_change_policy_details' - def get_shared_link_copy_details(self): + def is_allow_download_disabled_details(self): """ - Only call this if :meth:`is_shared_link_copy_details` is true. + Check if the union tag is ``allow_download_disabled_details``. - :rtype: SharedLinkCopyDetails + :rtype: bool """ - if not self.is_shared_link_copy_details(): - raise AttributeError("tag 'shared_link_copy_details' not set") - return self._value + return self._tag == 'allow_download_disabled_details' - def get_shared_link_create_details(self): + def is_allow_download_enabled_details(self): """ - Only call this if :meth:`is_shared_link_create_details` is true. + Check if the union tag is ``allow_download_enabled_details``. - :rtype: SharedLinkCreateDetails + :rtype: bool """ - if not self.is_shared_link_create_details(): - raise AttributeError("tag 'shared_link_create_details' not set") - return self._value + return self._tag == 'allow_download_enabled_details' - def get_shared_link_disable_details(self): + def is_camera_uploads_policy_changed_details(self): """ - Only call this if :meth:`is_shared_link_disable_details` is true. + Check if the union tag is ``camera_uploads_policy_changed_details``. - :rtype: SharedLinkDisableDetails + :rtype: bool """ - if not self.is_shared_link_disable_details(): - raise AttributeError("tag 'shared_link_disable_details' not set") - return self._value + return self._tag == 'camera_uploads_policy_changed_details' - def get_shared_link_download_details(self): + def is_data_placement_restriction_change_policy_details(self): """ - Only call this if :meth:`is_shared_link_download_details` is true. + Check if the union tag is ``data_placement_restriction_change_policy_details``. - :rtype: SharedLinkDownloadDetails + :rtype: bool """ - if not self.is_shared_link_download_details(): - raise AttributeError("tag 'shared_link_download_details' not set") - return self._value + return self._tag == 'data_placement_restriction_change_policy_details' - def get_shared_link_remove_expiry_details(self): + def is_data_placement_restriction_satisfy_policy_details(self): """ - Only call this if :meth:`is_shared_link_remove_expiry_details` is true. + Check if the union tag is ``data_placement_restriction_satisfy_policy_details``. - :rtype: SharedLinkRemoveExpiryDetails + :rtype: bool """ - if not self.is_shared_link_remove_expiry_details(): - raise AttributeError("tag 'shared_link_remove_expiry_details' not set") - return self._value + return self._tag == 'data_placement_restriction_satisfy_policy_details' - def get_shared_link_share_details(self): + def is_device_approvals_add_exception_details(self): """ - Only call this if :meth:`is_shared_link_share_details` is true. + Check if the union tag is ``device_approvals_add_exception_details``. - :rtype: SharedLinkShareDetails + :rtype: bool """ - if not self.is_shared_link_share_details(): - raise AttributeError("tag 'shared_link_share_details' not set") - return self._value + return self._tag == 'device_approvals_add_exception_details' - def get_shared_link_view_details(self): + def is_device_approvals_change_desktop_policy_details(self): """ - Only call this if :meth:`is_shared_link_view_details` is true. + Check if the union tag is ``device_approvals_change_desktop_policy_details``. - :rtype: SharedLinkViewDetails + :rtype: bool """ - if not self.is_shared_link_view_details(): - raise AttributeError("tag 'shared_link_view_details' not set") - return self._value + return self._tag == 'device_approvals_change_desktop_policy_details' - def get_shared_note_opened_details(self): + def is_device_approvals_change_mobile_policy_details(self): """ - Only call this if :meth:`is_shared_note_opened_details` is true. + Check if the union tag is ``device_approvals_change_mobile_policy_details``. - :rtype: SharedNoteOpenedDetails + :rtype: bool """ - if not self.is_shared_note_opened_details(): - raise AttributeError("tag 'shared_note_opened_details' not set") - return self._value + return self._tag == 'device_approvals_change_mobile_policy_details' - def get_shmodel_group_share_details(self): + def is_device_approvals_change_overage_action_details(self): """ - Only call this if :meth:`is_shmodel_group_share_details` is true. + Check if the union tag is ``device_approvals_change_overage_action_details``. - :rtype: ShmodelGroupShareDetails + :rtype: bool """ - if not self.is_shmodel_group_share_details(): - raise AttributeError("tag 'shmodel_group_share_details' not set") - return self._value + return self._tag == 'device_approvals_change_overage_action_details' - def get_showcase_access_granted_details(self): + def is_device_approvals_change_unlink_action_details(self): """ - Only call this if :meth:`is_showcase_access_granted_details` is true. + Check if the union tag is ``device_approvals_change_unlink_action_details``. - :rtype: ShowcaseAccessGrantedDetails + :rtype: bool """ - if not self.is_showcase_access_granted_details(): - raise AttributeError("tag 'showcase_access_granted_details' not set") - return self._value + return self._tag == 'device_approvals_change_unlink_action_details' - def get_showcase_add_member_details(self): + def is_device_approvals_remove_exception_details(self): """ - Only call this if :meth:`is_showcase_add_member_details` is true. + Check if the union tag is ``device_approvals_remove_exception_details``. - :rtype: ShowcaseAddMemberDetails + :rtype: bool """ - if not self.is_showcase_add_member_details(): - raise AttributeError("tag 'showcase_add_member_details' not set") - return self._value + return self._tag == 'device_approvals_remove_exception_details' - def get_showcase_archived_details(self): + def is_directory_restrictions_add_members_details(self): """ - Only call this if :meth:`is_showcase_archived_details` is true. + Check if the union tag is ``directory_restrictions_add_members_details``. - :rtype: ShowcaseArchivedDetails + :rtype: bool """ - if not self.is_showcase_archived_details(): - raise AttributeError("tag 'showcase_archived_details' not set") - return self._value + return self._tag == 'directory_restrictions_add_members_details' - def get_showcase_created_details(self): + def is_directory_restrictions_remove_members_details(self): """ - Only call this if :meth:`is_showcase_created_details` is true. + Check if the union tag is ``directory_restrictions_remove_members_details``. - :rtype: ShowcaseCreatedDetails + :rtype: bool """ - if not self.is_showcase_created_details(): - raise AttributeError("tag 'showcase_created_details' not set") - return self._value + return self._tag == 'directory_restrictions_remove_members_details' - def get_showcase_delete_comment_details(self): + def is_emm_add_exception_details(self): """ - Only call this if :meth:`is_showcase_delete_comment_details` is true. + Check if the union tag is ``emm_add_exception_details``. - :rtype: ShowcaseDeleteCommentDetails + :rtype: bool """ - if not self.is_showcase_delete_comment_details(): - raise AttributeError("tag 'showcase_delete_comment_details' not set") - return self._value + return self._tag == 'emm_add_exception_details' - def get_showcase_edited_details(self): + def is_emm_change_policy_details(self): """ - Only call this if :meth:`is_showcase_edited_details` is true. + Check if the union tag is ``emm_change_policy_details``. - :rtype: ShowcaseEditedDetails + :rtype: bool """ - if not self.is_showcase_edited_details(): - raise AttributeError("tag 'showcase_edited_details' not set") - return self._value + return self._tag == 'emm_change_policy_details' - def get_showcase_edit_comment_details(self): + def is_emm_remove_exception_details(self): """ - Only call this if :meth:`is_showcase_edit_comment_details` is true. + Check if the union tag is ``emm_remove_exception_details``. - :rtype: ShowcaseEditCommentDetails + :rtype: bool """ - if not self.is_showcase_edit_comment_details(): - raise AttributeError("tag 'showcase_edit_comment_details' not set") - return self._value + return self._tag == 'emm_remove_exception_details' - def get_showcase_file_added_details(self): + def is_extended_version_history_change_policy_details(self): """ - Only call this if :meth:`is_showcase_file_added_details` is true. + Check if the union tag is ``extended_version_history_change_policy_details``. - :rtype: ShowcaseFileAddedDetails + :rtype: bool """ - if not self.is_showcase_file_added_details(): - raise AttributeError("tag 'showcase_file_added_details' not set") - return self._value + return self._tag == 'extended_version_history_change_policy_details' - def get_showcase_file_download_details(self): + def is_file_comments_change_policy_details(self): """ - Only call this if :meth:`is_showcase_file_download_details` is true. + Check if the union tag is ``file_comments_change_policy_details``. - :rtype: ShowcaseFileDownloadDetails + :rtype: bool """ - if not self.is_showcase_file_download_details(): - raise AttributeError("tag 'showcase_file_download_details' not set") - return self._value + return self._tag == 'file_comments_change_policy_details' - def get_showcase_file_removed_details(self): + def is_file_locking_policy_changed_details(self): """ - Only call this if :meth:`is_showcase_file_removed_details` is true. + Check if the union tag is ``file_locking_policy_changed_details``. - :rtype: ShowcaseFileRemovedDetails + :rtype: bool """ - if not self.is_showcase_file_removed_details(): - raise AttributeError("tag 'showcase_file_removed_details' not set") - return self._value + return self._tag == 'file_locking_policy_changed_details' - def get_showcase_file_view_details(self): + def is_file_requests_change_policy_details(self): """ - Only call this if :meth:`is_showcase_file_view_details` is true. + Check if the union tag is ``file_requests_change_policy_details``. - :rtype: ShowcaseFileViewDetails + :rtype: bool """ - if not self.is_showcase_file_view_details(): - raise AttributeError("tag 'showcase_file_view_details' not set") - return self._value + return self._tag == 'file_requests_change_policy_details' - def get_showcase_permanently_deleted_details(self): + def is_file_requests_emails_enabled_details(self): """ - Only call this if :meth:`is_showcase_permanently_deleted_details` is true. + Check if the union tag is ``file_requests_emails_enabled_details``. - :rtype: ShowcasePermanentlyDeletedDetails + :rtype: bool """ - if not self.is_showcase_permanently_deleted_details(): - raise AttributeError("tag 'showcase_permanently_deleted_details' not set") - return self._value + return self._tag == 'file_requests_emails_enabled_details' - def get_showcase_post_comment_details(self): + def is_file_requests_emails_restricted_to_team_only_details(self): """ - Only call this if :meth:`is_showcase_post_comment_details` is true. + Check if the union tag is ``file_requests_emails_restricted_to_team_only_details``. - :rtype: ShowcasePostCommentDetails + :rtype: bool """ - if not self.is_showcase_post_comment_details(): - raise AttributeError("tag 'showcase_post_comment_details' not set") - return self._value + return self._tag == 'file_requests_emails_restricted_to_team_only_details' - def get_showcase_remove_member_details(self): + def is_file_transfers_policy_changed_details(self): """ - Only call this if :meth:`is_showcase_remove_member_details` is true. + Check if the union tag is ``file_transfers_policy_changed_details``. - :rtype: ShowcaseRemoveMemberDetails + :rtype: bool """ - if not self.is_showcase_remove_member_details(): - raise AttributeError("tag 'showcase_remove_member_details' not set") - return self._value + return self._tag == 'file_transfers_policy_changed_details' - def get_showcase_renamed_details(self): + def is_google_sso_change_policy_details(self): """ - Only call this if :meth:`is_showcase_renamed_details` is true. + Check if the union tag is ``google_sso_change_policy_details``. - :rtype: ShowcaseRenamedDetails + :rtype: bool """ - if not self.is_showcase_renamed_details(): - raise AttributeError("tag 'showcase_renamed_details' not set") - return self._value + return self._tag == 'google_sso_change_policy_details' - def get_showcase_request_access_details(self): + def is_group_user_management_change_policy_details(self): """ - Only call this if :meth:`is_showcase_request_access_details` is true. + Check if the union tag is ``group_user_management_change_policy_details``. - :rtype: ShowcaseRequestAccessDetails + :rtype: bool """ - if not self.is_showcase_request_access_details(): - raise AttributeError("tag 'showcase_request_access_details' not set") - return self._value + return self._tag == 'group_user_management_change_policy_details' - def get_showcase_resolve_comment_details(self): + def is_integration_policy_changed_details(self): """ - Only call this if :meth:`is_showcase_resolve_comment_details` is true. + Check if the union tag is ``integration_policy_changed_details``. - :rtype: ShowcaseResolveCommentDetails + :rtype: bool """ - if not self.is_showcase_resolve_comment_details(): - raise AttributeError("tag 'showcase_resolve_comment_details' not set") - return self._value + return self._tag == 'integration_policy_changed_details' - def get_showcase_restored_details(self): + def is_member_requests_change_policy_details(self): """ - Only call this if :meth:`is_showcase_restored_details` is true. + Check if the union tag is ``member_requests_change_policy_details``. - :rtype: ShowcaseRestoredDetails + :rtype: bool """ - if not self.is_showcase_restored_details(): - raise AttributeError("tag 'showcase_restored_details' not set") - return self._value + return self._tag == 'member_requests_change_policy_details' - def get_showcase_trashed_details(self): + def is_member_send_invite_policy_changed_details(self): """ - Only call this if :meth:`is_showcase_trashed_details` is true. + Check if the union tag is ``member_send_invite_policy_changed_details``. - :rtype: ShowcaseTrashedDetails + :rtype: bool """ - if not self.is_showcase_trashed_details(): - raise AttributeError("tag 'showcase_trashed_details' not set") - return self._value + return self._tag == 'member_send_invite_policy_changed_details' - def get_showcase_trashed_deprecated_details(self): + def is_member_space_limits_add_exception_details(self): """ - Only call this if :meth:`is_showcase_trashed_deprecated_details` is true. + Check if the union tag is ``member_space_limits_add_exception_details``. - :rtype: ShowcaseTrashedDeprecatedDetails + :rtype: bool """ - if not self.is_showcase_trashed_deprecated_details(): - raise AttributeError("tag 'showcase_trashed_deprecated_details' not set") - return self._value + return self._tag == 'member_space_limits_add_exception_details' - def get_showcase_unresolve_comment_details(self): + def is_member_space_limits_change_caps_type_policy_details(self): """ - Only call this if :meth:`is_showcase_unresolve_comment_details` is true. + Check if the union tag is ``member_space_limits_change_caps_type_policy_details``. - :rtype: ShowcaseUnresolveCommentDetails + :rtype: bool """ - if not self.is_showcase_unresolve_comment_details(): - raise AttributeError("tag 'showcase_unresolve_comment_details' not set") - return self._value + return self._tag == 'member_space_limits_change_caps_type_policy_details' - def get_showcase_untrashed_details(self): + def is_member_space_limits_change_policy_details(self): """ - Only call this if :meth:`is_showcase_untrashed_details` is true. + Check if the union tag is ``member_space_limits_change_policy_details``. - :rtype: ShowcaseUntrashedDetails + :rtype: bool """ - if not self.is_showcase_untrashed_details(): - raise AttributeError("tag 'showcase_untrashed_details' not set") - return self._value + return self._tag == 'member_space_limits_change_policy_details' - def get_showcase_untrashed_deprecated_details(self): + def is_member_space_limits_remove_exception_details(self): """ - Only call this if :meth:`is_showcase_untrashed_deprecated_details` is true. + Check if the union tag is ``member_space_limits_remove_exception_details``. - :rtype: ShowcaseUntrashedDeprecatedDetails + :rtype: bool """ - if not self.is_showcase_untrashed_deprecated_details(): - raise AttributeError("tag 'showcase_untrashed_deprecated_details' not set") - return self._value + return self._tag == 'member_space_limits_remove_exception_details' - def get_showcase_view_details(self): + def is_member_suggestions_change_policy_details(self): """ - Only call this if :meth:`is_showcase_view_details` is true. + Check if the union tag is ``member_suggestions_change_policy_details``. - :rtype: ShowcaseViewDetails + :rtype: bool """ - if not self.is_showcase_view_details(): - raise AttributeError("tag 'showcase_view_details' not set") - return self._value + return self._tag == 'member_suggestions_change_policy_details' - def get_sso_add_cert_details(self): + def is_microsoft_office_addin_change_policy_details(self): """ - Only call this if :meth:`is_sso_add_cert_details` is true. + Check if the union tag is ``microsoft_office_addin_change_policy_details``. - :rtype: SsoAddCertDetails + :rtype: bool """ - if not self.is_sso_add_cert_details(): - raise AttributeError("tag 'sso_add_cert_details' not set") - return self._value + return self._tag == 'microsoft_office_addin_change_policy_details' - def get_sso_add_login_url_details(self): + def is_network_control_change_policy_details(self): """ - Only call this if :meth:`is_sso_add_login_url_details` is true. + Check if the union tag is ``network_control_change_policy_details``. - :rtype: SsoAddLoginUrlDetails + :rtype: bool """ - if not self.is_sso_add_login_url_details(): - raise AttributeError("tag 'sso_add_login_url_details' not set") - return self._value + return self._tag == 'network_control_change_policy_details' - def get_sso_add_logout_url_details(self): + def is_paper_change_deployment_policy_details(self): """ - Only call this if :meth:`is_sso_add_logout_url_details` is true. + Check if the union tag is ``paper_change_deployment_policy_details``. - :rtype: SsoAddLogoutUrlDetails + :rtype: bool """ - if not self.is_sso_add_logout_url_details(): - raise AttributeError("tag 'sso_add_logout_url_details' not set") - return self._value + return self._tag == 'paper_change_deployment_policy_details' - def get_sso_change_cert_details(self): + def is_paper_change_member_link_policy_details(self): """ - Only call this if :meth:`is_sso_change_cert_details` is true. + Check if the union tag is ``paper_change_member_link_policy_details``. - :rtype: SsoChangeCertDetails + :rtype: bool """ - if not self.is_sso_change_cert_details(): - raise AttributeError("tag 'sso_change_cert_details' not set") - return self._value + return self._tag == 'paper_change_member_link_policy_details' - def get_sso_change_login_url_details(self): + def is_paper_change_member_policy_details(self): """ - Only call this if :meth:`is_sso_change_login_url_details` is true. + Check if the union tag is ``paper_change_member_policy_details``. - :rtype: SsoChangeLoginUrlDetails + :rtype: bool """ - if not self.is_sso_change_login_url_details(): - raise AttributeError("tag 'sso_change_login_url_details' not set") - return self._value + return self._tag == 'paper_change_member_policy_details' - def get_sso_change_logout_url_details(self): + def is_paper_change_policy_details(self): """ - Only call this if :meth:`is_sso_change_logout_url_details` is true. + Check if the union tag is ``paper_change_policy_details``. - :rtype: SsoChangeLogoutUrlDetails + :rtype: bool """ - if not self.is_sso_change_logout_url_details(): - raise AttributeError("tag 'sso_change_logout_url_details' not set") - return self._value + return self._tag == 'paper_change_policy_details' - def get_sso_change_saml_identity_mode_details(self): + def is_paper_default_folder_policy_changed_details(self): """ - Only call this if :meth:`is_sso_change_saml_identity_mode_details` is true. + Check if the union tag is ``paper_default_folder_policy_changed_details``. - :rtype: SsoChangeSamlIdentityModeDetails + :rtype: bool """ - if not self.is_sso_change_saml_identity_mode_details(): - raise AttributeError("tag 'sso_change_saml_identity_mode_details' not set") - return self._value + return self._tag == 'paper_default_folder_policy_changed_details' - def get_sso_remove_cert_details(self): + def is_paper_desktop_policy_changed_details(self): """ - Only call this if :meth:`is_sso_remove_cert_details` is true. + Check if the union tag is ``paper_desktop_policy_changed_details``. - :rtype: SsoRemoveCertDetails + :rtype: bool """ - if not self.is_sso_remove_cert_details(): - raise AttributeError("tag 'sso_remove_cert_details' not set") - return self._value + return self._tag == 'paper_desktop_policy_changed_details' - def get_sso_remove_login_url_details(self): + def is_paper_enabled_users_group_addition_details(self): """ - Only call this if :meth:`is_sso_remove_login_url_details` is true. + Check if the union tag is ``paper_enabled_users_group_addition_details``. - :rtype: SsoRemoveLoginUrlDetails + :rtype: bool """ - if not self.is_sso_remove_login_url_details(): - raise AttributeError("tag 'sso_remove_login_url_details' not set") - return self._value + return self._tag == 'paper_enabled_users_group_addition_details' - def get_sso_remove_logout_url_details(self): + def is_paper_enabled_users_group_removal_details(self): """ - Only call this if :meth:`is_sso_remove_logout_url_details` is true. + Check if the union tag is ``paper_enabled_users_group_removal_details``. - :rtype: SsoRemoveLogoutUrlDetails + :rtype: bool """ - if not self.is_sso_remove_logout_url_details(): - raise AttributeError("tag 'sso_remove_logout_url_details' not set") - return self._value + return self._tag == 'paper_enabled_users_group_removal_details' - def get_team_folder_change_status_details(self): + def is_password_strength_requirements_change_policy_details(self): """ - Only call this if :meth:`is_team_folder_change_status_details` is true. + Check if the union tag is ``password_strength_requirements_change_policy_details``. - :rtype: TeamFolderChangeStatusDetails + :rtype: bool """ - if not self.is_team_folder_change_status_details(): - raise AttributeError("tag 'team_folder_change_status_details' not set") - return self._value + return self._tag == 'password_strength_requirements_change_policy_details' - def get_team_folder_create_details(self): + def is_permanent_delete_change_policy_details(self): """ - Only call this if :meth:`is_team_folder_create_details` is true. + Check if the union tag is ``permanent_delete_change_policy_details``. - :rtype: TeamFolderCreateDetails + :rtype: bool """ - if not self.is_team_folder_create_details(): - raise AttributeError("tag 'team_folder_create_details' not set") - return self._value + return self._tag == 'permanent_delete_change_policy_details' - def get_team_folder_downgrade_details(self): + def is_reseller_support_change_policy_details(self): """ - Only call this if :meth:`is_team_folder_downgrade_details` is true. + Check if the union tag is ``reseller_support_change_policy_details``. - :rtype: TeamFolderDowngradeDetails + :rtype: bool """ - if not self.is_team_folder_downgrade_details(): - raise AttributeError("tag 'team_folder_downgrade_details' not set") - return self._value + return self._tag == 'reseller_support_change_policy_details' - def get_team_folder_permanently_delete_details(self): + def is_rewind_policy_changed_details(self): """ - Only call this if :meth:`is_team_folder_permanently_delete_details` is true. + Check if the union tag is ``rewind_policy_changed_details``. - :rtype: TeamFolderPermanentlyDeleteDetails + :rtype: bool """ - if not self.is_team_folder_permanently_delete_details(): - raise AttributeError("tag 'team_folder_permanently_delete_details' not set") - return self._value + return self._tag == 'rewind_policy_changed_details' - def get_team_folder_rename_details(self): + def is_sharing_change_folder_join_policy_details(self): """ - Only call this if :meth:`is_team_folder_rename_details` is true. + Check if the union tag is ``sharing_change_folder_join_policy_details``. - :rtype: TeamFolderRenameDetails + :rtype: bool """ - if not self.is_team_folder_rename_details(): - raise AttributeError("tag 'team_folder_rename_details' not set") - return self._value + return self._tag == 'sharing_change_folder_join_policy_details' - def get_team_selective_sync_settings_changed_details(self): + def is_sharing_change_link_policy_details(self): """ - Only call this if :meth:`is_team_selective_sync_settings_changed_details` is true. + Check if the union tag is ``sharing_change_link_policy_details``. - :rtype: TeamSelectiveSyncSettingsChangedDetails + :rtype: bool """ - if not self.is_team_selective_sync_settings_changed_details(): - raise AttributeError("tag 'team_selective_sync_settings_changed_details' not set") - return self._value + return self._tag == 'sharing_change_link_policy_details' - def get_account_capture_change_policy_details(self): + def is_sharing_change_member_policy_details(self): """ - Only call this if :meth:`is_account_capture_change_policy_details` is true. + Check if the union tag is ``sharing_change_member_policy_details``. - :rtype: AccountCaptureChangePolicyDetails + :rtype: bool """ - if not self.is_account_capture_change_policy_details(): - raise AttributeError("tag 'account_capture_change_policy_details' not set") - return self._value + return self._tag == 'sharing_change_member_policy_details' - def get_allow_download_disabled_details(self): + def is_showcase_change_download_policy_details(self): """ - Only call this if :meth:`is_allow_download_disabled_details` is true. + Check if the union tag is ``showcase_change_download_policy_details``. - :rtype: AllowDownloadDisabledDetails + :rtype: bool """ - if not self.is_allow_download_disabled_details(): - raise AttributeError("tag 'allow_download_disabled_details' not set") - return self._value + return self._tag == 'showcase_change_download_policy_details' - def get_allow_download_enabled_details(self): + def is_showcase_change_enabled_policy_details(self): """ - Only call this if :meth:`is_allow_download_enabled_details` is true. + Check if the union tag is ``showcase_change_enabled_policy_details``. - :rtype: AllowDownloadEnabledDetails + :rtype: bool """ - if not self.is_allow_download_enabled_details(): - raise AttributeError("tag 'allow_download_enabled_details' not set") - return self._value + return self._tag == 'showcase_change_enabled_policy_details' - def get_camera_uploads_policy_changed_details(self): + def is_showcase_change_external_sharing_policy_details(self): """ - Only call this if :meth:`is_camera_uploads_policy_changed_details` is true. + Check if the union tag is ``showcase_change_external_sharing_policy_details``. - :rtype: CameraUploadsPolicyChangedDetails + :rtype: bool """ - if not self.is_camera_uploads_policy_changed_details(): - raise AttributeError("tag 'camera_uploads_policy_changed_details' not set") - return self._value + return self._tag == 'showcase_change_external_sharing_policy_details' - def get_data_placement_restriction_change_policy_details(self): + def is_smarter_smart_sync_policy_changed_details(self): """ - Only call this if :meth:`is_data_placement_restriction_change_policy_details` is true. + Check if the union tag is ``smarter_smart_sync_policy_changed_details``. - :rtype: DataPlacementRestrictionChangePolicyDetails + :rtype: bool """ - if not self.is_data_placement_restriction_change_policy_details(): - raise AttributeError("tag 'data_placement_restriction_change_policy_details' not set") - return self._value + return self._tag == 'smarter_smart_sync_policy_changed_details' - def get_data_placement_restriction_satisfy_policy_details(self): + def is_smart_sync_change_policy_details(self): """ - Only call this if :meth:`is_data_placement_restriction_satisfy_policy_details` is true. + Check if the union tag is ``smart_sync_change_policy_details``. - :rtype: DataPlacementRestrictionSatisfyPolicyDetails + :rtype: bool """ - if not self.is_data_placement_restriction_satisfy_policy_details(): - raise AttributeError("tag 'data_placement_restriction_satisfy_policy_details' not set") - return self._value + return self._tag == 'smart_sync_change_policy_details' - def get_device_approvals_change_desktop_policy_details(self): + def is_smart_sync_not_opt_out_details(self): """ - Only call this if :meth:`is_device_approvals_change_desktop_policy_details` is true. + Check if the union tag is ``smart_sync_not_opt_out_details``. - :rtype: DeviceApprovalsChangeDesktopPolicyDetails + :rtype: bool """ - if not self.is_device_approvals_change_desktop_policy_details(): - raise AttributeError("tag 'device_approvals_change_desktop_policy_details' not set") - return self._value + return self._tag == 'smart_sync_not_opt_out_details' - def get_device_approvals_change_mobile_policy_details(self): + def is_smart_sync_opt_out_details(self): """ - Only call this if :meth:`is_device_approvals_change_mobile_policy_details` is true. + Check if the union tag is ``smart_sync_opt_out_details``. - :rtype: DeviceApprovalsChangeMobilePolicyDetails + :rtype: bool """ - if not self.is_device_approvals_change_mobile_policy_details(): - raise AttributeError("tag 'device_approvals_change_mobile_policy_details' not set") - return self._value + return self._tag == 'smart_sync_opt_out_details' - def get_device_approvals_change_overage_action_details(self): + def is_sso_change_policy_details(self): """ - Only call this if :meth:`is_device_approvals_change_overage_action_details` is true. + Check if the union tag is ``sso_change_policy_details``. - :rtype: DeviceApprovalsChangeOverageActionDetails + :rtype: bool """ - if not self.is_device_approvals_change_overage_action_details(): - raise AttributeError("tag 'device_approvals_change_overage_action_details' not set") - return self._value + return self._tag == 'sso_change_policy_details' - def get_device_approvals_change_unlink_action_details(self): + def is_team_extensions_policy_changed_details(self): """ - Only call this if :meth:`is_device_approvals_change_unlink_action_details` is true. + Check if the union tag is ``team_extensions_policy_changed_details``. - :rtype: DeviceApprovalsChangeUnlinkActionDetails + :rtype: bool """ - if not self.is_device_approvals_change_unlink_action_details(): - raise AttributeError("tag 'device_approvals_change_unlink_action_details' not set") - return self._value + return self._tag == 'team_extensions_policy_changed_details' - def get_directory_restrictions_add_members_details(self): + def is_team_selective_sync_policy_changed_details(self): """ - Only call this if :meth:`is_directory_restrictions_add_members_details` is true. + Check if the union tag is ``team_selective_sync_policy_changed_details``. - :rtype: DirectoryRestrictionsAddMembersDetails + :rtype: bool """ - if not self.is_directory_restrictions_add_members_details(): - raise AttributeError("tag 'directory_restrictions_add_members_details' not set") - return self._value + return self._tag == 'team_selective_sync_policy_changed_details' - def get_directory_restrictions_remove_members_details(self): + def is_team_sharing_whitelist_subjects_changed_details(self): """ - Only call this if :meth:`is_directory_restrictions_remove_members_details` is true. + Check if the union tag is ``team_sharing_whitelist_subjects_changed_details``. - :rtype: DirectoryRestrictionsRemoveMembersDetails + :rtype: bool """ - if not self.is_directory_restrictions_remove_members_details(): - raise AttributeError("tag 'directory_restrictions_remove_members_details' not set") - return self._value + return self._tag == 'team_sharing_whitelist_subjects_changed_details' - def get_emm_add_exception_details(self): + def is_tfa_add_exception_details(self): """ - Only call this if :meth:`is_emm_add_exception_details` is true. + Check if the union tag is ``tfa_add_exception_details``. - :rtype: EmmAddExceptionDetails + :rtype: bool """ - if not self.is_emm_add_exception_details(): - raise AttributeError("tag 'emm_add_exception_details' not set") - return self._value + return self._tag == 'tfa_add_exception_details' - def get_emm_change_policy_details(self): + def is_tfa_change_policy_details(self): """ - Only call this if :meth:`is_emm_change_policy_details` is true. + Check if the union tag is ``tfa_change_policy_details``. - :rtype: EmmChangePolicyDetails + :rtype: bool """ - if not self.is_emm_change_policy_details(): - raise AttributeError("tag 'emm_change_policy_details' not set") - return self._value + return self._tag == 'tfa_change_policy_details' - def get_emm_remove_exception_details(self): + def is_tfa_remove_exception_details(self): """ - Only call this if :meth:`is_emm_remove_exception_details` is true. + Check if the union tag is ``tfa_remove_exception_details``. - :rtype: EmmRemoveExceptionDetails + :rtype: bool """ - if not self.is_emm_remove_exception_details(): - raise AttributeError("tag 'emm_remove_exception_details' not set") - return self._value + return self._tag == 'tfa_remove_exception_details' - def get_extended_version_history_change_policy_details(self): + def is_two_account_change_policy_details(self): """ - Only call this if :meth:`is_extended_version_history_change_policy_details` is true. + Check if the union tag is ``two_account_change_policy_details``. - :rtype: ExtendedVersionHistoryChangePolicyDetails + :rtype: bool """ - if not self.is_extended_version_history_change_policy_details(): - raise AttributeError("tag 'extended_version_history_change_policy_details' not set") - return self._value + return self._tag == 'two_account_change_policy_details' - def get_file_comments_change_policy_details(self): + def is_viewer_info_policy_changed_details(self): """ - Only call this if :meth:`is_file_comments_change_policy_details` is true. + Check if the union tag is ``viewer_info_policy_changed_details``. - :rtype: FileCommentsChangePolicyDetails + :rtype: bool """ - if not self.is_file_comments_change_policy_details(): - raise AttributeError("tag 'file_comments_change_policy_details' not set") - return self._value + return self._tag == 'viewer_info_policy_changed_details' - def get_file_requests_change_policy_details(self): + def is_watermarking_policy_changed_details(self): """ - Only call this if :meth:`is_file_requests_change_policy_details` is true. + Check if the union tag is ``watermarking_policy_changed_details``. - :rtype: FileRequestsChangePolicyDetails + :rtype: bool """ - if not self.is_file_requests_change_policy_details(): - raise AttributeError("tag 'file_requests_change_policy_details' not set") - return self._value + return self._tag == 'watermarking_policy_changed_details' - def get_file_requests_emails_enabled_details(self): + def is_web_sessions_change_active_session_limit_details(self): """ - Only call this if :meth:`is_file_requests_emails_enabled_details` is true. + Check if the union tag is ``web_sessions_change_active_session_limit_details``. - :rtype: FileRequestsEmailsEnabledDetails + :rtype: bool """ - if not self.is_file_requests_emails_enabled_details(): - raise AttributeError("tag 'file_requests_emails_enabled_details' not set") - return self._value + return self._tag == 'web_sessions_change_active_session_limit_details' - def get_file_requests_emails_restricted_to_team_only_details(self): + def is_web_sessions_change_fixed_length_policy_details(self): """ - Only call this if :meth:`is_file_requests_emails_restricted_to_team_only_details` is true. + Check if the union tag is ``web_sessions_change_fixed_length_policy_details``. - :rtype: FileRequestsEmailsRestrictedToTeamOnlyDetails + :rtype: bool """ - if not self.is_file_requests_emails_restricted_to_team_only_details(): - raise AttributeError("tag 'file_requests_emails_restricted_to_team_only_details' not set") - return self._value + return self._tag == 'web_sessions_change_fixed_length_policy_details' - def get_google_sso_change_policy_details(self): + def is_web_sessions_change_idle_length_policy_details(self): """ - Only call this if :meth:`is_google_sso_change_policy_details` is true. + Check if the union tag is ``web_sessions_change_idle_length_policy_details``. - :rtype: GoogleSsoChangePolicyDetails + :rtype: bool """ - if not self.is_google_sso_change_policy_details(): - raise AttributeError("tag 'google_sso_change_policy_details' not set") - return self._value + return self._tag == 'web_sessions_change_idle_length_policy_details' - def get_group_user_management_change_policy_details(self): + def is_team_merge_from_details(self): """ - Only call this if :meth:`is_group_user_management_change_policy_details` is true. + Check if the union tag is ``team_merge_from_details``. - :rtype: GroupUserManagementChangePolicyDetails + :rtype: bool """ - if not self.is_group_user_management_change_policy_details(): - raise AttributeError("tag 'group_user_management_change_policy_details' not set") - return self._value + return self._tag == 'team_merge_from_details' - def get_integration_policy_changed_details(self): + def is_team_merge_to_details(self): """ - Only call this if :meth:`is_integration_policy_changed_details` is true. + Check if the union tag is ``team_merge_to_details``. - :rtype: IntegrationPolicyChangedDetails + :rtype: bool """ - if not self.is_integration_policy_changed_details(): - raise AttributeError("tag 'integration_policy_changed_details' not set") - return self._value + return self._tag == 'team_merge_to_details' - def get_member_requests_change_policy_details(self): + def is_team_profile_add_logo_details(self): """ - Only call this if :meth:`is_member_requests_change_policy_details` is true. + Check if the union tag is ``team_profile_add_logo_details``. - :rtype: MemberRequestsChangePolicyDetails + :rtype: bool """ - if not self.is_member_requests_change_policy_details(): - raise AttributeError("tag 'member_requests_change_policy_details' not set") - return self._value + return self._tag == 'team_profile_add_logo_details' - def get_member_space_limits_add_exception_details(self): + def is_team_profile_change_default_language_details(self): """ - Only call this if :meth:`is_member_space_limits_add_exception_details` is true. + Check if the union tag is ``team_profile_change_default_language_details``. - :rtype: MemberSpaceLimitsAddExceptionDetails + :rtype: bool """ - if not self.is_member_space_limits_add_exception_details(): - raise AttributeError("tag 'member_space_limits_add_exception_details' not set") - return self._value + return self._tag == 'team_profile_change_default_language_details' - def get_member_space_limits_change_caps_type_policy_details(self): + def is_team_profile_change_logo_details(self): """ - Only call this if :meth:`is_member_space_limits_change_caps_type_policy_details` is true. + Check if the union tag is ``team_profile_change_logo_details``. - :rtype: MemberSpaceLimitsChangeCapsTypePolicyDetails + :rtype: bool """ - if not self.is_member_space_limits_change_caps_type_policy_details(): - raise AttributeError("tag 'member_space_limits_change_caps_type_policy_details' not set") - return self._value + return self._tag == 'team_profile_change_logo_details' - def get_member_space_limits_change_policy_details(self): + def is_team_profile_change_name_details(self): """ - Only call this if :meth:`is_member_space_limits_change_policy_details` is true. + Check if the union tag is ``team_profile_change_name_details``. - :rtype: MemberSpaceLimitsChangePolicyDetails + :rtype: bool """ - if not self.is_member_space_limits_change_policy_details(): - raise AttributeError("tag 'member_space_limits_change_policy_details' not set") - return self._value + return self._tag == 'team_profile_change_name_details' - def get_member_space_limits_remove_exception_details(self): + def is_team_profile_remove_logo_details(self): """ - Only call this if :meth:`is_member_space_limits_remove_exception_details` is true. + Check if the union tag is ``team_profile_remove_logo_details``. - :rtype: MemberSpaceLimitsRemoveExceptionDetails + :rtype: bool """ - if not self.is_member_space_limits_remove_exception_details(): - raise AttributeError("tag 'member_space_limits_remove_exception_details' not set") - return self._value + return self._tag == 'team_profile_remove_logo_details' - def get_member_suggestions_change_policy_details(self): + def is_tfa_add_backup_phone_details(self): """ - Only call this if :meth:`is_member_suggestions_change_policy_details` is true. + Check if the union tag is ``tfa_add_backup_phone_details``. - :rtype: MemberSuggestionsChangePolicyDetails + :rtype: bool """ - if not self.is_member_suggestions_change_policy_details(): - raise AttributeError("tag 'member_suggestions_change_policy_details' not set") - return self._value + return self._tag == 'tfa_add_backup_phone_details' - def get_microsoft_office_addin_change_policy_details(self): + def is_tfa_add_security_key_details(self): """ - Only call this if :meth:`is_microsoft_office_addin_change_policy_details` is true. + Check if the union tag is ``tfa_add_security_key_details``. - :rtype: MicrosoftOfficeAddinChangePolicyDetails + :rtype: bool """ - if not self.is_microsoft_office_addin_change_policy_details(): - raise AttributeError("tag 'microsoft_office_addin_change_policy_details' not set") - return self._value + return self._tag == 'tfa_add_security_key_details' - def get_network_control_change_policy_details(self): + def is_tfa_change_backup_phone_details(self): """ - Only call this if :meth:`is_network_control_change_policy_details` is true. + Check if the union tag is ``tfa_change_backup_phone_details``. - :rtype: NetworkControlChangePolicyDetails + :rtype: bool """ - if not self.is_network_control_change_policy_details(): - raise AttributeError("tag 'network_control_change_policy_details' not set") - return self._value + return self._tag == 'tfa_change_backup_phone_details' - def get_paper_change_deployment_policy_details(self): + def is_tfa_change_status_details(self): """ - Only call this if :meth:`is_paper_change_deployment_policy_details` is true. + Check if the union tag is ``tfa_change_status_details``. - :rtype: PaperChangeDeploymentPolicyDetails + :rtype: bool """ - if not self.is_paper_change_deployment_policy_details(): - raise AttributeError("tag 'paper_change_deployment_policy_details' not set") - return self._value + return self._tag == 'tfa_change_status_details' - def get_paper_change_member_link_policy_details(self): + def is_tfa_remove_backup_phone_details(self): """ - Only call this if :meth:`is_paper_change_member_link_policy_details` is true. + Check if the union tag is ``tfa_remove_backup_phone_details``. - :rtype: PaperChangeMemberLinkPolicyDetails + :rtype: bool """ - if not self.is_paper_change_member_link_policy_details(): - raise AttributeError("tag 'paper_change_member_link_policy_details' not set") - return self._value + return self._tag == 'tfa_remove_backup_phone_details' - def get_paper_change_member_policy_details(self): + def is_tfa_remove_security_key_details(self): """ - Only call this if :meth:`is_paper_change_member_policy_details` is true. + Check if the union tag is ``tfa_remove_security_key_details``. - :rtype: PaperChangeMemberPolicyDetails + :rtype: bool """ - if not self.is_paper_change_member_policy_details(): - raise AttributeError("tag 'paper_change_member_policy_details' not set") - return self._value + return self._tag == 'tfa_remove_security_key_details' - def get_paper_change_policy_details(self): + def is_tfa_reset_details(self): """ - Only call this if :meth:`is_paper_change_policy_details` is true. + Check if the union tag is ``tfa_reset_details``. - :rtype: PaperChangePolicyDetails + :rtype: bool """ - if not self.is_paper_change_policy_details(): - raise AttributeError("tag 'paper_change_policy_details' not set") - return self._value + return self._tag == 'tfa_reset_details' - def get_paper_default_folder_policy_changed_details(self): + def is_changed_enterprise_admin_role_details(self): """ - Only call this if :meth:`is_paper_default_folder_policy_changed_details` is true. + Check if the union tag is ``changed_enterprise_admin_role_details``. - :rtype: PaperDefaultFolderPolicyChangedDetails + :rtype: bool """ - if not self.is_paper_default_folder_policy_changed_details(): - raise AttributeError("tag 'paper_default_folder_policy_changed_details' not set") - return self._value + return self._tag == 'changed_enterprise_admin_role_details' - def get_paper_desktop_policy_changed_details(self): + def is_changed_enterprise_connected_team_status_details(self): """ - Only call this if :meth:`is_paper_desktop_policy_changed_details` is true. + Check if the union tag is ``changed_enterprise_connected_team_status_details``. - :rtype: PaperDesktopPolicyChangedDetails + :rtype: bool """ - if not self.is_paper_desktop_policy_changed_details(): - raise AttributeError("tag 'paper_desktop_policy_changed_details' not set") - return self._value + return self._tag == 'changed_enterprise_connected_team_status_details' - def get_paper_enabled_users_group_addition_details(self): + def is_ended_enterprise_admin_session_details(self): """ - Only call this if :meth:`is_paper_enabled_users_group_addition_details` is true. + Check if the union tag is ``ended_enterprise_admin_session_details``. - :rtype: PaperEnabledUsersGroupAdditionDetails + :rtype: bool """ - if not self.is_paper_enabled_users_group_addition_details(): - raise AttributeError("tag 'paper_enabled_users_group_addition_details' not set") - return self._value + return self._tag == 'ended_enterprise_admin_session_details' - def get_paper_enabled_users_group_removal_details(self): + def is_ended_enterprise_admin_session_deprecated_details(self): """ - Only call this if :meth:`is_paper_enabled_users_group_removal_details` is true. + Check if the union tag is ``ended_enterprise_admin_session_deprecated_details``. - :rtype: PaperEnabledUsersGroupRemovalDetails + :rtype: bool """ - if not self.is_paper_enabled_users_group_removal_details(): - raise AttributeError("tag 'paper_enabled_users_group_removal_details' not set") - return self._value + return self._tag == 'ended_enterprise_admin_session_deprecated_details' - def get_permanent_delete_change_policy_details(self): + def is_enterprise_settings_locking_details(self): """ - Only call this if :meth:`is_permanent_delete_change_policy_details` is true. + Check if the union tag is ``enterprise_settings_locking_details``. - :rtype: PermanentDeleteChangePolicyDetails + :rtype: bool """ - if not self.is_permanent_delete_change_policy_details(): - raise AttributeError("tag 'permanent_delete_change_policy_details' not set") - return self._value + return self._tag == 'enterprise_settings_locking_details' - def get_reseller_support_change_policy_details(self): + def is_guest_admin_change_status_details(self): """ - Only call this if :meth:`is_reseller_support_change_policy_details` is true. + Check if the union tag is ``guest_admin_change_status_details``. - :rtype: ResellerSupportChangePolicyDetails + :rtype: bool """ - if not self.is_reseller_support_change_policy_details(): - raise AttributeError("tag 'reseller_support_change_policy_details' not set") - return self._value + return self._tag == 'guest_admin_change_status_details' - def get_sharing_change_folder_join_policy_details(self): + def is_started_enterprise_admin_session_details(self): """ - Only call this if :meth:`is_sharing_change_folder_join_policy_details` is true. + Check if the union tag is ``started_enterprise_admin_session_details``. - :rtype: SharingChangeFolderJoinPolicyDetails + :rtype: bool """ - if not self.is_sharing_change_folder_join_policy_details(): - raise AttributeError("tag 'sharing_change_folder_join_policy_details' not set") - return self._value + return self._tag == 'started_enterprise_admin_session_details' - def get_sharing_change_link_policy_details(self): + def is_team_merge_request_accepted_details(self): """ - Only call this if :meth:`is_sharing_change_link_policy_details` is true. + Check if the union tag is ``team_merge_request_accepted_details``. - :rtype: SharingChangeLinkPolicyDetails + :rtype: bool """ - if not self.is_sharing_change_link_policy_details(): - raise AttributeError("tag 'sharing_change_link_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_accepted_details' - def get_sharing_change_member_policy_details(self): + def is_team_merge_request_accepted_shown_to_primary_team_details(self): """ - Only call this if :meth:`is_sharing_change_member_policy_details` is true. + Check if the union tag is ``team_merge_request_accepted_shown_to_primary_team_details``. - :rtype: SharingChangeMemberPolicyDetails + :rtype: bool """ - if not self.is_sharing_change_member_policy_details(): - raise AttributeError("tag 'sharing_change_member_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_accepted_shown_to_primary_team_details' - def get_showcase_change_download_policy_details(self): + def is_team_merge_request_accepted_shown_to_secondary_team_details(self): """ - Only call this if :meth:`is_showcase_change_download_policy_details` is true. + Check if the union tag is ``team_merge_request_accepted_shown_to_secondary_team_details``. - :rtype: ShowcaseChangeDownloadPolicyDetails + :rtype: bool """ - if not self.is_showcase_change_download_policy_details(): - raise AttributeError("tag 'showcase_change_download_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_accepted_shown_to_secondary_team_details' - def get_showcase_change_enabled_policy_details(self): + def is_team_merge_request_auto_canceled_details(self): """ - Only call this if :meth:`is_showcase_change_enabled_policy_details` is true. + Check if the union tag is ``team_merge_request_auto_canceled_details``. - :rtype: ShowcaseChangeEnabledPolicyDetails + :rtype: bool """ - if not self.is_showcase_change_enabled_policy_details(): - raise AttributeError("tag 'showcase_change_enabled_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_auto_canceled_details' - def get_showcase_change_external_sharing_policy_details(self): + def is_team_merge_request_canceled_details(self): """ - Only call this if :meth:`is_showcase_change_external_sharing_policy_details` is true. + Check if the union tag is ``team_merge_request_canceled_details``. - :rtype: ShowcaseChangeExternalSharingPolicyDetails + :rtype: bool """ - if not self.is_showcase_change_external_sharing_policy_details(): - raise AttributeError("tag 'showcase_change_external_sharing_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_canceled_details' - def get_smart_sync_change_policy_details(self): + def is_team_merge_request_canceled_shown_to_primary_team_details(self): """ - Only call this if :meth:`is_smart_sync_change_policy_details` is true. + Check if the union tag is ``team_merge_request_canceled_shown_to_primary_team_details``. - :rtype: SmartSyncChangePolicyDetails + :rtype: bool """ - if not self.is_smart_sync_change_policy_details(): - raise AttributeError("tag 'smart_sync_change_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_canceled_shown_to_primary_team_details' - def get_smart_sync_not_opt_out_details(self): + def is_team_merge_request_canceled_shown_to_secondary_team_details(self): """ - Only call this if :meth:`is_smart_sync_not_opt_out_details` is true. + Check if the union tag is ``team_merge_request_canceled_shown_to_secondary_team_details``. - :rtype: SmartSyncNotOptOutDetails + :rtype: bool """ - if not self.is_smart_sync_not_opt_out_details(): - raise AttributeError("tag 'smart_sync_not_opt_out_details' not set") - return self._value + return self._tag == 'team_merge_request_canceled_shown_to_secondary_team_details' - def get_smart_sync_opt_out_details(self): + def is_team_merge_request_expired_details(self): """ - Only call this if :meth:`is_smart_sync_opt_out_details` is true. + Check if the union tag is ``team_merge_request_expired_details``. - :rtype: SmartSyncOptOutDetails + :rtype: bool """ - if not self.is_smart_sync_opt_out_details(): - raise AttributeError("tag 'smart_sync_opt_out_details' not set") - return self._value + return self._tag == 'team_merge_request_expired_details' - def get_sso_change_policy_details(self): + def is_team_merge_request_expired_shown_to_primary_team_details(self): """ - Only call this if :meth:`is_sso_change_policy_details` is true. + Check if the union tag is ``team_merge_request_expired_shown_to_primary_team_details``. - :rtype: SsoChangePolicyDetails + :rtype: bool """ - if not self.is_sso_change_policy_details(): - raise AttributeError("tag 'sso_change_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_expired_shown_to_primary_team_details' - def get_team_extensions_policy_changed_details(self): + def is_team_merge_request_expired_shown_to_secondary_team_details(self): """ - Only call this if :meth:`is_team_extensions_policy_changed_details` is true. + Check if the union tag is ``team_merge_request_expired_shown_to_secondary_team_details``. - :rtype: TeamExtensionsPolicyChangedDetails + :rtype: bool """ - if not self.is_team_extensions_policy_changed_details(): - raise AttributeError("tag 'team_extensions_policy_changed_details' not set") - return self._value + return self._tag == 'team_merge_request_expired_shown_to_secondary_team_details' - def get_team_selective_sync_policy_changed_details(self): + def is_team_merge_request_rejected_shown_to_primary_team_details(self): """ - Only call this if :meth:`is_team_selective_sync_policy_changed_details` is true. + Check if the union tag is ``team_merge_request_rejected_shown_to_primary_team_details``. - :rtype: TeamSelectiveSyncPolicyChangedDetails + :rtype: bool """ - if not self.is_team_selective_sync_policy_changed_details(): - raise AttributeError("tag 'team_selective_sync_policy_changed_details' not set") - return self._value + return self._tag == 'team_merge_request_rejected_shown_to_primary_team_details' - def get_tfa_change_policy_details(self): + def is_team_merge_request_rejected_shown_to_secondary_team_details(self): """ - Only call this if :meth:`is_tfa_change_policy_details` is true. + Check if the union tag is ``team_merge_request_rejected_shown_to_secondary_team_details``. - :rtype: TfaChangePolicyDetails + :rtype: bool """ - if not self.is_tfa_change_policy_details(): - raise AttributeError("tag 'tfa_change_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_rejected_shown_to_secondary_team_details' - def get_two_account_change_policy_details(self): + def is_team_merge_request_reminder_details(self): """ - Only call this if :meth:`is_two_account_change_policy_details` is true. + Check if the union tag is ``team_merge_request_reminder_details``. - :rtype: TwoAccountChangePolicyDetails + :rtype: bool """ - if not self.is_two_account_change_policy_details(): - raise AttributeError("tag 'two_account_change_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_reminder_details' - def get_viewer_info_policy_changed_details(self): + def is_team_merge_request_reminder_shown_to_primary_team_details(self): """ - Only call this if :meth:`is_viewer_info_policy_changed_details` is true. + Check if the union tag is ``team_merge_request_reminder_shown_to_primary_team_details``. - :rtype: ViewerInfoPolicyChangedDetails + :rtype: bool """ - if not self.is_viewer_info_policy_changed_details(): - raise AttributeError("tag 'viewer_info_policy_changed_details' not set") - return self._value + return self._tag == 'team_merge_request_reminder_shown_to_primary_team_details' - def get_web_sessions_change_fixed_length_policy_details(self): + def is_team_merge_request_reminder_shown_to_secondary_team_details(self): """ - Only call this if :meth:`is_web_sessions_change_fixed_length_policy_details` is true. + Check if the union tag is ``team_merge_request_reminder_shown_to_secondary_team_details``. - :rtype: WebSessionsChangeFixedLengthPolicyDetails + :rtype: bool """ - if not self.is_web_sessions_change_fixed_length_policy_details(): - raise AttributeError("tag 'web_sessions_change_fixed_length_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_reminder_shown_to_secondary_team_details' - def get_web_sessions_change_idle_length_policy_details(self): + def is_team_merge_request_revoked_details(self): """ - Only call this if :meth:`is_web_sessions_change_idle_length_policy_details` is true. + Check if the union tag is ``team_merge_request_revoked_details``. - :rtype: WebSessionsChangeIdleLengthPolicyDetails + :rtype: bool """ - if not self.is_web_sessions_change_idle_length_policy_details(): - raise AttributeError("tag 'web_sessions_change_idle_length_policy_details' not set") - return self._value + return self._tag == 'team_merge_request_revoked_details' - def get_team_merge_from_details(self): + def is_team_merge_request_sent_shown_to_primary_team_details(self): """ - Only call this if :meth:`is_team_merge_from_details` is true. + Check if the union tag is ``team_merge_request_sent_shown_to_primary_team_details``. - :rtype: TeamMergeFromDetails + :rtype: bool """ - if not self.is_team_merge_from_details(): - raise AttributeError("tag 'team_merge_from_details' not set") - return self._value + return self._tag == 'team_merge_request_sent_shown_to_primary_team_details' - def get_team_merge_to_details(self): + def is_team_merge_request_sent_shown_to_secondary_team_details(self): """ - Only call this if :meth:`is_team_merge_to_details` is true. + Check if the union tag is ``team_merge_request_sent_shown_to_secondary_team_details``. - :rtype: TeamMergeToDetails + :rtype: bool """ - if not self.is_team_merge_to_details(): - raise AttributeError("tag 'team_merge_to_details' not set") - return self._value + return self._tag == 'team_merge_request_sent_shown_to_secondary_team_details' - def get_team_profile_add_logo_details(self): + def is_missing_details(self): """ - Only call this if :meth:`is_team_profile_add_logo_details` is true. + Check if the union tag is ``missing_details``. - :rtype: TeamProfileAddLogoDetails + :rtype: bool """ - if not self.is_team_profile_add_logo_details(): - raise AttributeError("tag 'team_profile_add_logo_details' not set") - return self._value + return self._tag == 'missing_details' - def get_team_profile_change_default_language_details(self): + def is_other(self): """ - Only call this if :meth:`is_team_profile_change_default_language_details` is true. + Check if the union tag is ``other``. - :rtype: TeamProfileChangeDefaultLanguageDetails + :rtype: bool """ - if not self.is_team_profile_change_default_language_details(): - raise AttributeError("tag 'team_profile_change_default_language_details' not set") - return self._value + return self._tag == 'other' - def get_team_profile_change_logo_details(self): + def get_app_link_team_details(self): """ - Only call this if :meth:`is_team_profile_change_logo_details` is true. + Only call this if :meth:`is_app_link_team_details` is true. - :rtype: TeamProfileChangeLogoDetails + :rtype: AppLinkTeamDetails """ - if not self.is_team_profile_change_logo_details(): - raise AttributeError("tag 'team_profile_change_logo_details' not set") + if not self.is_app_link_team_details(): + raise AttributeError("tag 'app_link_team_details' not set") return self._value - def get_team_profile_change_name_details(self): + def get_app_link_user_details(self): """ - Only call this if :meth:`is_team_profile_change_name_details` is true. + Only call this if :meth:`is_app_link_user_details` is true. - :rtype: TeamProfileChangeNameDetails + :rtype: AppLinkUserDetails """ - if not self.is_team_profile_change_name_details(): - raise AttributeError("tag 'team_profile_change_name_details' not set") + if not self.is_app_link_user_details(): + raise AttributeError("tag 'app_link_user_details' not set") return self._value - def get_team_profile_remove_logo_details(self): + def get_app_unlink_team_details(self): """ - Only call this if :meth:`is_team_profile_remove_logo_details` is true. + Only call this if :meth:`is_app_unlink_team_details` is true. - :rtype: TeamProfileRemoveLogoDetails + :rtype: AppUnlinkTeamDetails """ - if not self.is_team_profile_remove_logo_details(): - raise AttributeError("tag 'team_profile_remove_logo_details' not set") + if not self.is_app_unlink_team_details(): + raise AttributeError("tag 'app_unlink_team_details' not set") return self._value - def get_tfa_add_backup_phone_details(self): + def get_app_unlink_user_details(self): """ - Only call this if :meth:`is_tfa_add_backup_phone_details` is true. + Only call this if :meth:`is_app_unlink_user_details` is true. - :rtype: TfaAddBackupPhoneDetails + :rtype: AppUnlinkUserDetails """ - if not self.is_tfa_add_backup_phone_details(): - raise AttributeError("tag 'tfa_add_backup_phone_details' not set") + if not self.is_app_unlink_user_details(): + raise AttributeError("tag 'app_unlink_user_details' not set") return self._value - def get_tfa_add_security_key_details(self): + def get_integration_connected_details(self): """ - Only call this if :meth:`is_tfa_add_security_key_details` is true. + Only call this if :meth:`is_integration_connected_details` is true. - :rtype: TfaAddSecurityKeyDetails + :rtype: IntegrationConnectedDetails """ - if not self.is_tfa_add_security_key_details(): - raise AttributeError("tag 'tfa_add_security_key_details' not set") + if not self.is_integration_connected_details(): + raise AttributeError("tag 'integration_connected_details' not set") return self._value - def get_tfa_change_backup_phone_details(self): + def get_integration_disconnected_details(self): """ - Only call this if :meth:`is_tfa_change_backup_phone_details` is true. + Only call this if :meth:`is_integration_disconnected_details` is true. - :rtype: TfaChangeBackupPhoneDetails + :rtype: IntegrationDisconnectedDetails """ - if not self.is_tfa_change_backup_phone_details(): - raise AttributeError("tag 'tfa_change_backup_phone_details' not set") + if not self.is_integration_disconnected_details(): + raise AttributeError("tag 'integration_disconnected_details' not set") return self._value - def get_tfa_change_status_details(self): + def get_file_add_comment_details(self): """ - Only call this if :meth:`is_tfa_change_status_details` is true. + Only call this if :meth:`is_file_add_comment_details` is true. - :rtype: TfaChangeStatusDetails + :rtype: FileAddCommentDetails """ - if not self.is_tfa_change_status_details(): - raise AttributeError("tag 'tfa_change_status_details' not set") + if not self.is_file_add_comment_details(): + raise AttributeError("tag 'file_add_comment_details' not set") return self._value - def get_tfa_remove_backup_phone_details(self): + def get_file_change_comment_subscription_details(self): """ - Only call this if :meth:`is_tfa_remove_backup_phone_details` is true. + Only call this if :meth:`is_file_change_comment_subscription_details` is true. - :rtype: TfaRemoveBackupPhoneDetails + :rtype: FileChangeCommentSubscriptionDetails """ - if not self.is_tfa_remove_backup_phone_details(): - raise AttributeError("tag 'tfa_remove_backup_phone_details' not set") + if not self.is_file_change_comment_subscription_details(): + raise AttributeError("tag 'file_change_comment_subscription_details' not set") return self._value - def get_tfa_remove_security_key_details(self): + def get_file_delete_comment_details(self): """ - Only call this if :meth:`is_tfa_remove_security_key_details` is true. + Only call this if :meth:`is_file_delete_comment_details` is true. - :rtype: TfaRemoveSecurityKeyDetails + :rtype: FileDeleteCommentDetails """ - if not self.is_tfa_remove_security_key_details(): - raise AttributeError("tag 'tfa_remove_security_key_details' not set") + if not self.is_file_delete_comment_details(): + raise AttributeError("tag 'file_delete_comment_details' not set") return self._value - def get_tfa_reset_details(self): + def get_file_edit_comment_details(self): """ - Only call this if :meth:`is_tfa_reset_details` is true. + Only call this if :meth:`is_file_edit_comment_details` is true. - :rtype: TfaResetDetails + :rtype: FileEditCommentDetails """ - if not self.is_tfa_reset_details(): - raise AttributeError("tag 'tfa_reset_details' not set") + if not self.is_file_edit_comment_details(): + raise AttributeError("tag 'file_edit_comment_details' not set") return self._value - def get_guest_admin_change_status_details(self): + def get_file_like_comment_details(self): """ - Only call this if :meth:`is_guest_admin_change_status_details` is true. + Only call this if :meth:`is_file_like_comment_details` is true. - :rtype: GuestAdminChangeStatusDetails + :rtype: FileLikeCommentDetails """ - if not self.is_guest_admin_change_status_details(): - raise AttributeError("tag 'guest_admin_change_status_details' not set") + if not self.is_file_like_comment_details(): + raise AttributeError("tag 'file_like_comment_details' not set") return self._value - def get_team_merge_request_accepted_details(self): + def get_file_resolve_comment_details(self): """ - Only call this if :meth:`is_team_merge_request_accepted_details` is true. + Only call this if :meth:`is_file_resolve_comment_details` is true. - :rtype: TeamMergeRequestAcceptedDetails + :rtype: FileResolveCommentDetails """ - if not self.is_team_merge_request_accepted_details(): - raise AttributeError("tag 'team_merge_request_accepted_details' not set") + if not self.is_file_resolve_comment_details(): + raise AttributeError("tag 'file_resolve_comment_details' not set") return self._value - def get_team_merge_request_accepted_shown_to_primary_team_details(self): + def get_file_unlike_comment_details(self): """ - Only call this if :meth:`is_team_merge_request_accepted_shown_to_primary_team_details` is true. + Only call this if :meth:`is_file_unlike_comment_details` is true. - :rtype: TeamMergeRequestAcceptedShownToPrimaryTeamDetails + :rtype: FileUnlikeCommentDetails """ - if not self.is_team_merge_request_accepted_shown_to_primary_team_details(): - raise AttributeError("tag 'team_merge_request_accepted_shown_to_primary_team_details' not set") + if not self.is_file_unlike_comment_details(): + raise AttributeError("tag 'file_unlike_comment_details' not set") return self._value - def get_team_merge_request_accepted_shown_to_secondary_team_details(self): + def get_file_unresolve_comment_details(self): """ - Only call this if :meth:`is_team_merge_request_accepted_shown_to_secondary_team_details` is true. + Only call this if :meth:`is_file_unresolve_comment_details` is true. - :rtype: TeamMergeRequestAcceptedShownToSecondaryTeamDetails + :rtype: FileUnresolveCommentDetails """ - if not self.is_team_merge_request_accepted_shown_to_secondary_team_details(): - raise AttributeError("tag 'team_merge_request_accepted_shown_to_secondary_team_details' not set") + if not self.is_file_unresolve_comment_details(): + raise AttributeError("tag 'file_unresolve_comment_details' not set") return self._value - def get_team_merge_request_auto_canceled_details(self): + def get_device_change_ip_desktop_details(self): """ - Only call this if :meth:`is_team_merge_request_auto_canceled_details` is true. + Only call this if :meth:`is_device_change_ip_desktop_details` is true. - :rtype: TeamMergeRequestAutoCanceledDetails + :rtype: DeviceChangeIpDesktopDetails """ - if not self.is_team_merge_request_auto_canceled_details(): - raise AttributeError("tag 'team_merge_request_auto_canceled_details' not set") + if not self.is_device_change_ip_desktop_details(): + raise AttributeError("tag 'device_change_ip_desktop_details' not set") return self._value - def get_team_merge_request_canceled_details(self): + def get_device_change_ip_mobile_details(self): """ - Only call this if :meth:`is_team_merge_request_canceled_details` is true. + Only call this if :meth:`is_device_change_ip_mobile_details` is true. - :rtype: TeamMergeRequestCanceledDetails + :rtype: DeviceChangeIpMobileDetails """ - if not self.is_team_merge_request_canceled_details(): - raise AttributeError("tag 'team_merge_request_canceled_details' not set") + if not self.is_device_change_ip_mobile_details(): + raise AttributeError("tag 'device_change_ip_mobile_details' not set") return self._value - def get_team_merge_request_canceled_shown_to_primary_team_details(self): + def get_device_change_ip_web_details(self): """ - Only call this if :meth:`is_team_merge_request_canceled_shown_to_primary_team_details` is true. + Only call this if :meth:`is_device_change_ip_web_details` is true. - :rtype: TeamMergeRequestCanceledShownToPrimaryTeamDetails + :rtype: DeviceChangeIpWebDetails """ - if not self.is_team_merge_request_canceled_shown_to_primary_team_details(): - raise AttributeError("tag 'team_merge_request_canceled_shown_to_primary_team_details' not set") + if not self.is_device_change_ip_web_details(): + raise AttributeError("tag 'device_change_ip_web_details' not set") return self._value - def get_team_merge_request_canceled_shown_to_secondary_team_details(self): + def get_device_delete_on_unlink_fail_details(self): """ - Only call this if :meth:`is_team_merge_request_canceled_shown_to_secondary_team_details` is true. + Only call this if :meth:`is_device_delete_on_unlink_fail_details` is true. - :rtype: TeamMergeRequestCanceledShownToSecondaryTeamDetails + :rtype: DeviceDeleteOnUnlinkFailDetails """ - if not self.is_team_merge_request_canceled_shown_to_secondary_team_details(): - raise AttributeError("tag 'team_merge_request_canceled_shown_to_secondary_team_details' not set") + if not self.is_device_delete_on_unlink_fail_details(): + raise AttributeError("tag 'device_delete_on_unlink_fail_details' not set") return self._value - def get_team_merge_request_expired_details(self): + def get_device_delete_on_unlink_success_details(self): """ - Only call this if :meth:`is_team_merge_request_expired_details` is true. + Only call this if :meth:`is_device_delete_on_unlink_success_details` is true. - :rtype: TeamMergeRequestExpiredDetails + :rtype: DeviceDeleteOnUnlinkSuccessDetails """ - if not self.is_team_merge_request_expired_details(): - raise AttributeError("tag 'team_merge_request_expired_details' not set") + if not self.is_device_delete_on_unlink_success_details(): + raise AttributeError("tag 'device_delete_on_unlink_success_details' not set") return self._value - def get_team_merge_request_expired_shown_to_primary_team_details(self): + def get_device_link_fail_details(self): """ - Only call this if :meth:`is_team_merge_request_expired_shown_to_primary_team_details` is true. + Only call this if :meth:`is_device_link_fail_details` is true. - :rtype: TeamMergeRequestExpiredShownToPrimaryTeamDetails + :rtype: DeviceLinkFailDetails """ - if not self.is_team_merge_request_expired_shown_to_primary_team_details(): - raise AttributeError("tag 'team_merge_request_expired_shown_to_primary_team_details' not set") + if not self.is_device_link_fail_details(): + raise AttributeError("tag 'device_link_fail_details' not set") return self._value - def get_team_merge_request_expired_shown_to_secondary_team_details(self): + def get_device_link_success_details(self): """ - Only call this if :meth:`is_team_merge_request_expired_shown_to_secondary_team_details` is true. + Only call this if :meth:`is_device_link_success_details` is true. - :rtype: TeamMergeRequestExpiredShownToSecondaryTeamDetails + :rtype: DeviceLinkSuccessDetails """ - if not self.is_team_merge_request_expired_shown_to_secondary_team_details(): - raise AttributeError("tag 'team_merge_request_expired_shown_to_secondary_team_details' not set") + if not self.is_device_link_success_details(): + raise AttributeError("tag 'device_link_success_details' not set") return self._value - def get_team_merge_request_rejected_shown_to_primary_team_details(self): + def get_device_management_disabled_details(self): """ - Only call this if :meth:`is_team_merge_request_rejected_shown_to_primary_team_details` is true. + Only call this if :meth:`is_device_management_disabled_details` is true. - :rtype: TeamMergeRequestRejectedShownToPrimaryTeamDetails + :rtype: DeviceManagementDisabledDetails """ - if not self.is_team_merge_request_rejected_shown_to_primary_team_details(): - raise AttributeError("tag 'team_merge_request_rejected_shown_to_primary_team_details' not set") + if not self.is_device_management_disabled_details(): + raise AttributeError("tag 'device_management_disabled_details' not set") return self._value - def get_team_merge_request_rejected_shown_to_secondary_team_details(self): + def get_device_management_enabled_details(self): """ - Only call this if :meth:`is_team_merge_request_rejected_shown_to_secondary_team_details` is true. + Only call this if :meth:`is_device_management_enabled_details` is true. - :rtype: TeamMergeRequestRejectedShownToSecondaryTeamDetails + :rtype: DeviceManagementEnabledDetails """ - if not self.is_team_merge_request_rejected_shown_to_secondary_team_details(): - raise AttributeError("tag 'team_merge_request_rejected_shown_to_secondary_team_details' not set") + if not self.is_device_management_enabled_details(): + raise AttributeError("tag 'device_management_enabled_details' not set") return self._value - def get_team_merge_request_reminder_details(self): + def get_device_unlink_details(self): """ - Only call this if :meth:`is_team_merge_request_reminder_details` is true. + Only call this if :meth:`is_device_unlink_details` is true. - :rtype: TeamMergeRequestReminderDetails + :rtype: DeviceUnlinkDetails """ - if not self.is_team_merge_request_reminder_details(): - raise AttributeError("tag 'team_merge_request_reminder_details' not set") + if not self.is_device_unlink_details(): + raise AttributeError("tag 'device_unlink_details' not set") return self._value - def get_team_merge_request_reminder_shown_to_primary_team_details(self): + def get_emm_refresh_auth_token_details(self): """ - Only call this if :meth:`is_team_merge_request_reminder_shown_to_primary_team_details` is true. + Only call this if :meth:`is_emm_refresh_auth_token_details` is true. - :rtype: TeamMergeRequestReminderShownToPrimaryTeamDetails + :rtype: EmmRefreshAuthTokenDetails """ - if not self.is_team_merge_request_reminder_shown_to_primary_team_details(): - raise AttributeError("tag 'team_merge_request_reminder_shown_to_primary_team_details' not set") + if not self.is_emm_refresh_auth_token_details(): + raise AttributeError("tag 'emm_refresh_auth_token_details' not set") return self._value - def get_team_merge_request_reminder_shown_to_secondary_team_details(self): + def get_account_capture_change_availability_details(self): """ - Only call this if :meth:`is_team_merge_request_reminder_shown_to_secondary_team_details` is true. + Only call this if :meth:`is_account_capture_change_availability_details` is true. - :rtype: TeamMergeRequestReminderShownToSecondaryTeamDetails + :rtype: AccountCaptureChangeAvailabilityDetails """ - if not self.is_team_merge_request_reminder_shown_to_secondary_team_details(): - raise AttributeError("tag 'team_merge_request_reminder_shown_to_secondary_team_details' not set") + if not self.is_account_capture_change_availability_details(): + raise AttributeError("tag 'account_capture_change_availability_details' not set") return self._value - def get_team_merge_request_revoked_details(self): + def get_account_capture_migrate_account_details(self): """ - Only call this if :meth:`is_team_merge_request_revoked_details` is true. + Only call this if :meth:`is_account_capture_migrate_account_details` is true. - :rtype: TeamMergeRequestRevokedDetails + :rtype: AccountCaptureMigrateAccountDetails """ - if not self.is_team_merge_request_revoked_details(): - raise AttributeError("tag 'team_merge_request_revoked_details' not set") + if not self.is_account_capture_migrate_account_details(): + raise AttributeError("tag 'account_capture_migrate_account_details' not set") return self._value - def get_team_merge_request_sent_shown_to_primary_team_details(self): + def get_account_capture_notification_emails_sent_details(self): """ - Only call this if :meth:`is_team_merge_request_sent_shown_to_primary_team_details` is true. + Only call this if :meth:`is_account_capture_notification_emails_sent_details` is true. - :rtype: TeamMergeRequestSentShownToPrimaryTeamDetails + :rtype: AccountCaptureNotificationEmailsSentDetails """ - if not self.is_team_merge_request_sent_shown_to_primary_team_details(): - raise AttributeError("tag 'team_merge_request_sent_shown_to_primary_team_details' not set") + if not self.is_account_capture_notification_emails_sent_details(): + raise AttributeError("tag 'account_capture_notification_emails_sent_details' not set") return self._value - def get_team_merge_request_sent_shown_to_secondary_team_details(self): + def get_account_capture_relinquish_account_details(self): """ - Only call this if :meth:`is_team_merge_request_sent_shown_to_secondary_team_details` is true. + Only call this if :meth:`is_account_capture_relinquish_account_details` is true. - :rtype: TeamMergeRequestSentShownToSecondaryTeamDetails + :rtype: AccountCaptureRelinquishAccountDetails """ - if not self.is_team_merge_request_sent_shown_to_secondary_team_details(): - raise AttributeError("tag 'team_merge_request_sent_shown_to_secondary_team_details' not set") + if not self.is_account_capture_relinquish_account_details(): + raise AttributeError("tag 'account_capture_relinquish_account_details' not set") return self._value - def get_missing_details(self): + def get_disabled_domain_invites_details(self): """ - Hints that this event was returned with missing details due to an - internal error. + Only call this if :meth:`is_disabled_domain_invites_details` is true. - Only call this if :meth:`is_missing_details` is true. + :rtype: DisabledDomainInvitesDetails + """ + if not self.is_disabled_domain_invites_details(): + raise AttributeError("tag 'disabled_domain_invites_details' not set") + return self._value - :rtype: MissingDetails + def get_domain_invites_approve_request_to_join_team_details(self): """ - if not self.is_missing_details(): - raise AttributeError("tag 'missing_details' not set") + Only call this if :meth:`is_domain_invites_approve_request_to_join_team_details` is true. + + :rtype: DomainInvitesApproveRequestToJoinTeamDetails + """ + if not self.is_domain_invites_approve_request_to_join_team_details(): + raise AttributeError("tag 'domain_invites_approve_request_to_join_team_details' not set") return self._value - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EventDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + def get_domain_invites_decline_request_to_join_team_details(self): + """ + Only call this if :meth:`is_domain_invites_decline_request_to_join_team_details` is true. - def __repr__(self): - return 'EventDetails(%r, %r)' % (self._tag, self._value) + :rtype: DomainInvitesDeclineRequestToJoinTeamDetails + """ + if not self.is_domain_invites_decline_request_to_join_team_details(): + raise AttributeError("tag 'domain_invites_decline_request_to_join_team_details' not set") + return self._value -EventDetails_validator = bv.Union(EventDetails) + def get_domain_invites_email_existing_users_details(self): + """ + Only call this if :meth:`is_domain_invites_email_existing_users_details` is true. -class EventType(bb.Union): - """ - The type of the event. + :rtype: DomainInvitesEmailExistingUsersDetails + """ + if not self.is_domain_invites_email_existing_users_details(): + raise AttributeError("tag 'domain_invites_email_existing_users_details' not set") + return self._value - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + def get_domain_invites_request_to_join_team_details(self): + """ + Only call this if :meth:`is_domain_invites_request_to_join_team_details` is true. - :ivar AppLinkTeamType EventType.app_link_team: (apps) Linked app for team - :ivar AppLinkUserType EventType.app_link_user: (apps) Linked app for member - :ivar AppUnlinkTeamType EventType.app_unlink_team: (apps) Unlinked app for - team - :ivar AppUnlinkUserType EventType.app_unlink_user: (apps) Unlinked app for - member - :ivar IntegrationConnectedType EventType.integration_connected: (apps) - Connected integration for member - :ivar IntegrationDisconnectedType EventType.integration_disconnected: (apps) - Disconnected integration for member - :ivar FileAddCommentType EventType.file_add_comment: (comments) Added file - comment - :ivar FileChangeCommentSubscriptionType - EventType.file_change_comment_subscription: (comments) Subscribed to or - unsubscribed from comment notifications for file - :ivar FileDeleteCommentType EventType.file_delete_comment: (comments) - Deleted file comment - :ivar FileEditCommentType EventType.file_edit_comment: (comments) Edited - file comment - :ivar FileLikeCommentType EventType.file_like_comment: (comments) Liked file - comment (deprecated, no longer logged) - :ivar FileResolveCommentType EventType.file_resolve_comment: (comments) - Resolved file comment - :ivar FileUnlikeCommentType EventType.file_unlike_comment: (comments) - Unliked file comment (deprecated, no longer logged) - :ivar FileUnresolveCommentType EventType.file_unresolve_comment: (comments) - Unresolved file comment - :ivar DeviceChangeIpDesktopType EventType.device_change_ip_desktop: - (devices) Changed IP address associated with active desktop session - :ivar DeviceChangeIpMobileType EventType.device_change_ip_mobile: (devices) - Changed IP address associated with active mobile session - :ivar DeviceChangeIpWebType EventType.device_change_ip_web: (devices) - Changed IP address associated with active web session - :ivar DeviceDeleteOnUnlinkFailType EventType.device_delete_on_unlink_fail: - (devices) Failed to delete all files from unlinked device - :ivar DeviceDeleteOnUnlinkSuccessType - EventType.device_delete_on_unlink_success: (devices) Deleted all files - from unlinked device - :ivar DeviceLinkFailType EventType.device_link_fail: (devices) Failed to - link device - :ivar DeviceLinkSuccessType EventType.device_link_success: (devices) Linked - device - :ivar DeviceManagementDisabledType EventType.device_management_disabled: - (devices) Disabled device management (deprecated, no longer logged) - :ivar DeviceManagementEnabledType EventType.device_management_enabled: - (devices) Enabled device management (deprecated, no longer logged) - :ivar DeviceUnlinkType EventType.device_unlink: (devices) Disconnected - device - :ivar EmmRefreshAuthTokenType EventType.emm_refresh_auth_token: (devices) - Refreshed auth token used for setting up EMM - :ivar AccountCaptureChangeAvailabilityType - EventType.account_capture_change_availability: (domains) Granted/revoked - option to enable account capture on team domains - :ivar AccountCaptureMigrateAccountType - EventType.account_capture_migrate_account: (domains) Account-captured - user migrated account to team - :ivar AccountCaptureNotificationEmailsSentType - EventType.account_capture_notification_emails_sent: (domains) Sent - proactive account capture email to all unmanaged members - :ivar AccountCaptureRelinquishAccountType - EventType.account_capture_relinquish_account: (domains) Account-captured - user changed account email to personal email - :ivar DisabledDomainInvitesType EventType.disabled_domain_invites: (domains) - Disabled domain invites (deprecated, no longer logged) - :ivar DomainInvitesApproveRequestToJoinTeamType - EventType.domain_invites_approve_request_to_join_team: (domains) - Approved user's request to join team - :ivar DomainInvitesDeclineRequestToJoinTeamType - EventType.domain_invites_decline_request_to_join_team: (domains) - Declined user's request to join team - :ivar DomainInvitesEmailExistingUsersType - EventType.domain_invites_email_existing_users: (domains) Sent domain - invites to existing domain accounts (deprecated, no longer logged) - :ivar DomainInvitesRequestToJoinTeamType - EventType.domain_invites_request_to_join_team: (domains) Requested to - join team - :ivar DomainInvitesSetInviteNewUserPrefToNoType - EventType.domain_invites_set_invite_new_user_pref_to_no: (domains) - Disabled "Automatically invite new users" (deprecated, no longer logged) - :ivar DomainInvitesSetInviteNewUserPrefToYesType - EventType.domain_invites_set_invite_new_user_pref_to_yes: (domains) - Enabled "Automatically invite new users" (deprecated, no longer logged) - :ivar DomainVerificationAddDomainFailType - EventType.domain_verification_add_domain_fail: (domains) Failed to - verify team domain - :ivar DomainVerificationAddDomainSuccessType - EventType.domain_verification_add_domain_success: (domains) Verified - team domain - :ivar DomainVerificationRemoveDomainType - EventType.domain_verification_remove_domain: (domains) Removed domain - from list of verified team domains - :ivar EnabledDomainInvitesType EventType.enabled_domain_invites: (domains) - Enabled domain invites (deprecated, no longer logged) - :ivar CreateFolderType EventType.create_folder: (file_operations) Created - folders (deprecated, no longer logged) - :ivar FileAddType EventType.file_add: (file_operations) Added files and/or - folders - :ivar FileCopyType EventType.file_copy: (file_operations) Copied files - and/or folders - :ivar FileDeleteType EventType.file_delete: (file_operations) Deleted files - and/or folders - :ivar FileDownloadType EventType.file_download: (file_operations) Downloaded - files and/or folders - :ivar FileEditType EventType.file_edit: (file_operations) Edited files - :ivar FileGetCopyReferenceType EventType.file_get_copy_reference: - (file_operations) Created copy reference to file/folder - :ivar FileMoveType EventType.file_move: (file_operations) Moved files and/or - folders - :ivar FilePermanentlyDeleteType EventType.file_permanently_delete: - (file_operations) Permanently deleted files and/or folders - :ivar FilePreviewType EventType.file_preview: (file_operations) Previewed - files and/or folders - :ivar FileRenameType EventType.file_rename: (file_operations) Renamed files - and/or folders - :ivar FileRestoreType EventType.file_restore: (file_operations) Restored - deleted files and/or folders - :ivar FileRevertType EventType.file_revert: (file_operations) Reverted files - to previous version - :ivar FileRollbackChangesType EventType.file_rollback_changes: - (file_operations) Rolled back file actions - :ivar FileSaveCopyReferenceType EventType.file_save_copy_reference: - (file_operations) Saved file/folder using copy reference - :ivar FileRequestChangeType EventType.file_request_change: (file_requests) - Changed file request - :ivar FileRequestCloseType EventType.file_request_close: (file_requests) - Closed file request - :ivar FileRequestCreateType EventType.file_request_create: (file_requests) - Created file request - :ivar FileRequestDeleteType EventType.file_request_delete: (file_requests) - Delete file request - :ivar FileRequestReceiveFileType EventType.file_request_receive_file: - (file_requests) Received files for file request - :ivar GroupAddExternalIdType EventType.group_add_external_id: (groups) Added - external ID for group - :ivar GroupAddMemberType EventType.group_add_member: (groups) Added team - members to group - :ivar GroupChangeExternalIdType EventType.group_change_external_id: (groups) - Changed external ID for group - :ivar GroupChangeManagementTypeType EventType.group_change_management_type: - (groups) Changed group management type - :ivar GroupChangeMemberRoleType EventType.group_change_member_role: (groups) - Changed manager permissions of group member - :ivar GroupCreateType EventType.group_create: (groups) Created group - :ivar GroupDeleteType EventType.group_delete: (groups) Deleted group - :ivar GroupDescriptionUpdatedType EventType.group_description_updated: - (groups) Updated group (deprecated, no longer logged) - :ivar GroupJoinPolicyUpdatedType EventType.group_join_policy_updated: - (groups) Updated group join policy (deprecated, no longer logged) - :ivar GroupMovedType EventType.group_moved: (groups) Moved group - (deprecated, no longer logged) - :ivar GroupRemoveExternalIdType EventType.group_remove_external_id: (groups) - Removed external ID for group - :ivar GroupRemoveMemberType EventType.group_remove_member: (groups) Removed - team members from group - :ivar GroupRenameType EventType.group_rename: (groups) Renamed group - :ivar EmmErrorType EventType.emm_error: (logins) Failed to sign in via EMM - (deprecated, replaced by 'Failed to sign in') - :ivar GuestAdminSignedInViaTrustedTeamsType - EventType.guest_admin_signed_in_via_trusted_teams: (logins) Started - trusted team admin session - :ivar GuestAdminSignedOutViaTrustedTeamsType - EventType.guest_admin_signed_out_via_trusted_teams: (logins) Ended - trusted team admin session - :ivar LoginFailType EventType.login_fail: (logins) Failed to sign in - :ivar LoginSuccessType EventType.login_success: (logins) Signed in - :ivar LogoutType EventType.logout: (logins) Signed out - :ivar ResellerSupportSessionEndType EventType.reseller_support_session_end: - (logins) Ended reseller support session - :ivar ResellerSupportSessionStartType - EventType.reseller_support_session_start: (logins) Started reseller - support session - :ivar SignInAsSessionEndType EventType.sign_in_as_session_end: (logins) - Ended admin sign-in-as session - :ivar SignInAsSessionStartType EventType.sign_in_as_session_start: (logins) - Started admin sign-in-as session - :ivar SsoErrorType EventType.sso_error: (logins) Failed to sign in via SSO - (deprecated, replaced by 'Failed to sign in') - :ivar MemberAddExternalIdType EventType.member_add_external_id: (members) - Added an external ID for team member + :rtype: DomainInvitesRequestToJoinTeamDetails + """ + if not self.is_domain_invites_request_to_join_team_details(): + raise AttributeError("tag 'domain_invites_request_to_join_team_details' not set") + return self._value + + def get_domain_invites_set_invite_new_user_pref_to_no_details(self): + """ + Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_no_details` is true. + + :rtype: DomainInvitesSetInviteNewUserPrefToNoDetails + """ + if not self.is_domain_invites_set_invite_new_user_pref_to_no_details(): + raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_no_details' not set") + return self._value + + def get_domain_invites_set_invite_new_user_pref_to_yes_details(self): + """ + Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_yes_details` is true. + + :rtype: DomainInvitesSetInviteNewUserPrefToYesDetails + """ + if not self.is_domain_invites_set_invite_new_user_pref_to_yes_details(): + raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_yes_details' not set") + return self._value + + def get_domain_verification_add_domain_fail_details(self): + """ + Only call this if :meth:`is_domain_verification_add_domain_fail_details` is true. + + :rtype: DomainVerificationAddDomainFailDetails + """ + if not self.is_domain_verification_add_domain_fail_details(): + raise AttributeError("tag 'domain_verification_add_domain_fail_details' not set") + return self._value + + def get_domain_verification_add_domain_success_details(self): + """ + Only call this if :meth:`is_domain_verification_add_domain_success_details` is true. + + :rtype: DomainVerificationAddDomainSuccessDetails + """ + if not self.is_domain_verification_add_domain_success_details(): + raise AttributeError("tag 'domain_verification_add_domain_success_details' not set") + return self._value + + def get_domain_verification_remove_domain_details(self): + """ + Only call this if :meth:`is_domain_verification_remove_domain_details` is true. + + :rtype: DomainVerificationRemoveDomainDetails + """ + if not self.is_domain_verification_remove_domain_details(): + raise AttributeError("tag 'domain_verification_remove_domain_details' not set") + return self._value + + def get_enabled_domain_invites_details(self): + """ + Only call this if :meth:`is_enabled_domain_invites_details` is true. + + :rtype: EnabledDomainInvitesDetails + """ + if not self.is_enabled_domain_invites_details(): + raise AttributeError("tag 'enabled_domain_invites_details' not set") + return self._value + + def get_create_folder_details(self): + """ + Only call this if :meth:`is_create_folder_details` is true. + + :rtype: CreateFolderDetails + """ + if not self.is_create_folder_details(): + raise AttributeError("tag 'create_folder_details' not set") + return self._value + + def get_file_add_details(self): + """ + Only call this if :meth:`is_file_add_details` is true. + + :rtype: FileAddDetails + """ + if not self.is_file_add_details(): + raise AttributeError("tag 'file_add_details' not set") + return self._value + + def get_file_copy_details(self): + """ + Only call this if :meth:`is_file_copy_details` is true. + + :rtype: FileCopyDetails + """ + if not self.is_file_copy_details(): + raise AttributeError("tag 'file_copy_details' not set") + return self._value + + def get_file_delete_details(self): + """ + Only call this if :meth:`is_file_delete_details` is true. + + :rtype: FileDeleteDetails + """ + if not self.is_file_delete_details(): + raise AttributeError("tag 'file_delete_details' not set") + return self._value + + def get_file_download_details(self): + """ + Only call this if :meth:`is_file_download_details` is true. + + :rtype: FileDownloadDetails + """ + if not self.is_file_download_details(): + raise AttributeError("tag 'file_download_details' not set") + return self._value + + def get_file_edit_details(self): + """ + Only call this if :meth:`is_file_edit_details` is true. + + :rtype: FileEditDetails + """ + if not self.is_file_edit_details(): + raise AttributeError("tag 'file_edit_details' not set") + return self._value + + def get_file_get_copy_reference_details(self): + """ + Only call this if :meth:`is_file_get_copy_reference_details` is true. + + :rtype: FileGetCopyReferenceDetails + """ + if not self.is_file_get_copy_reference_details(): + raise AttributeError("tag 'file_get_copy_reference_details' not set") + return self._value + + def get_file_locking_lock_status_changed_details(self): + """ + Only call this if :meth:`is_file_locking_lock_status_changed_details` is true. + + :rtype: FileLockingLockStatusChangedDetails + """ + if not self.is_file_locking_lock_status_changed_details(): + raise AttributeError("tag 'file_locking_lock_status_changed_details' not set") + return self._value + + def get_file_move_details(self): + """ + Only call this if :meth:`is_file_move_details` is true. + + :rtype: FileMoveDetails + """ + if not self.is_file_move_details(): + raise AttributeError("tag 'file_move_details' not set") + return self._value + + def get_file_permanently_delete_details(self): + """ + Only call this if :meth:`is_file_permanently_delete_details` is true. + + :rtype: FilePermanentlyDeleteDetails + """ + if not self.is_file_permanently_delete_details(): + raise AttributeError("tag 'file_permanently_delete_details' not set") + return self._value + + def get_file_preview_details(self): + """ + Only call this if :meth:`is_file_preview_details` is true. + + :rtype: FilePreviewDetails + """ + if not self.is_file_preview_details(): + raise AttributeError("tag 'file_preview_details' not set") + return self._value + + def get_file_rename_details(self): + """ + Only call this if :meth:`is_file_rename_details` is true. + + :rtype: FileRenameDetails + """ + if not self.is_file_rename_details(): + raise AttributeError("tag 'file_rename_details' not set") + return self._value + + def get_file_restore_details(self): + """ + Only call this if :meth:`is_file_restore_details` is true. + + :rtype: FileRestoreDetails + """ + if not self.is_file_restore_details(): + raise AttributeError("tag 'file_restore_details' not set") + return self._value + + def get_file_revert_details(self): + """ + Only call this if :meth:`is_file_revert_details` is true. + + :rtype: FileRevertDetails + """ + if not self.is_file_revert_details(): + raise AttributeError("tag 'file_revert_details' not set") + return self._value + + def get_file_rollback_changes_details(self): + """ + Only call this if :meth:`is_file_rollback_changes_details` is true. + + :rtype: FileRollbackChangesDetails + """ + if not self.is_file_rollback_changes_details(): + raise AttributeError("tag 'file_rollback_changes_details' not set") + return self._value + + def get_file_save_copy_reference_details(self): + """ + Only call this if :meth:`is_file_save_copy_reference_details` is true. + + :rtype: FileSaveCopyReferenceDetails + """ + if not self.is_file_save_copy_reference_details(): + raise AttributeError("tag 'file_save_copy_reference_details' not set") + return self._value + + def get_folder_overview_description_changed_details(self): + """ + Only call this if :meth:`is_folder_overview_description_changed_details` is true. + + :rtype: FolderOverviewDescriptionChangedDetails + """ + if not self.is_folder_overview_description_changed_details(): + raise AttributeError("tag 'folder_overview_description_changed_details' not set") + return self._value + + def get_folder_overview_item_pinned_details(self): + """ + Only call this if :meth:`is_folder_overview_item_pinned_details` is true. + + :rtype: FolderOverviewItemPinnedDetails + """ + if not self.is_folder_overview_item_pinned_details(): + raise AttributeError("tag 'folder_overview_item_pinned_details' not set") + return self._value + + def get_folder_overview_item_unpinned_details(self): + """ + Only call this if :meth:`is_folder_overview_item_unpinned_details` is true. + + :rtype: FolderOverviewItemUnpinnedDetails + """ + if not self.is_folder_overview_item_unpinned_details(): + raise AttributeError("tag 'folder_overview_item_unpinned_details' not set") + return self._value + + def get_rewind_folder_details(self): + """ + Only call this if :meth:`is_rewind_folder_details` is true. + + :rtype: RewindFolderDetails + """ + if not self.is_rewind_folder_details(): + raise AttributeError("tag 'rewind_folder_details' not set") + return self._value + + def get_file_request_change_details(self): + """ + Only call this if :meth:`is_file_request_change_details` is true. + + :rtype: FileRequestChangeDetails + """ + if not self.is_file_request_change_details(): + raise AttributeError("tag 'file_request_change_details' not set") + return self._value + + def get_file_request_close_details(self): + """ + Only call this if :meth:`is_file_request_close_details` is true. + + :rtype: FileRequestCloseDetails + """ + if not self.is_file_request_close_details(): + raise AttributeError("tag 'file_request_close_details' not set") + return self._value + + def get_file_request_create_details(self): + """ + Only call this if :meth:`is_file_request_create_details` is true. + + :rtype: FileRequestCreateDetails + """ + if not self.is_file_request_create_details(): + raise AttributeError("tag 'file_request_create_details' not set") + return self._value + + def get_file_request_delete_details(self): + """ + Only call this if :meth:`is_file_request_delete_details` is true. + + :rtype: FileRequestDeleteDetails + """ + if not self.is_file_request_delete_details(): + raise AttributeError("tag 'file_request_delete_details' not set") + return self._value + + def get_file_request_receive_file_details(self): + """ + Only call this if :meth:`is_file_request_receive_file_details` is true. + + :rtype: FileRequestReceiveFileDetails + """ + if not self.is_file_request_receive_file_details(): + raise AttributeError("tag 'file_request_receive_file_details' not set") + return self._value + + def get_group_add_external_id_details(self): + """ + Only call this if :meth:`is_group_add_external_id_details` is true. + + :rtype: GroupAddExternalIdDetails + """ + if not self.is_group_add_external_id_details(): + raise AttributeError("tag 'group_add_external_id_details' not set") + return self._value + + def get_group_add_member_details(self): + """ + Only call this if :meth:`is_group_add_member_details` is true. + + :rtype: GroupAddMemberDetails + """ + if not self.is_group_add_member_details(): + raise AttributeError("tag 'group_add_member_details' not set") + return self._value + + def get_group_change_external_id_details(self): + """ + Only call this if :meth:`is_group_change_external_id_details` is true. + + :rtype: GroupChangeExternalIdDetails + """ + if not self.is_group_change_external_id_details(): + raise AttributeError("tag 'group_change_external_id_details' not set") + return self._value + + def get_group_change_management_type_details(self): + """ + Only call this if :meth:`is_group_change_management_type_details` is true. + + :rtype: GroupChangeManagementTypeDetails + """ + if not self.is_group_change_management_type_details(): + raise AttributeError("tag 'group_change_management_type_details' not set") + return self._value + + def get_group_change_member_role_details(self): + """ + Only call this if :meth:`is_group_change_member_role_details` is true. + + :rtype: GroupChangeMemberRoleDetails + """ + if not self.is_group_change_member_role_details(): + raise AttributeError("tag 'group_change_member_role_details' not set") + return self._value + + def get_group_create_details(self): + """ + Only call this if :meth:`is_group_create_details` is true. + + :rtype: GroupCreateDetails + """ + if not self.is_group_create_details(): + raise AttributeError("tag 'group_create_details' not set") + return self._value + + def get_group_delete_details(self): + """ + Only call this if :meth:`is_group_delete_details` is true. + + :rtype: GroupDeleteDetails + """ + if not self.is_group_delete_details(): + raise AttributeError("tag 'group_delete_details' not set") + return self._value + + def get_group_description_updated_details(self): + """ + Only call this if :meth:`is_group_description_updated_details` is true. + + :rtype: GroupDescriptionUpdatedDetails + """ + if not self.is_group_description_updated_details(): + raise AttributeError("tag 'group_description_updated_details' not set") + return self._value + + def get_group_join_policy_updated_details(self): + """ + Only call this if :meth:`is_group_join_policy_updated_details` is true. + + :rtype: GroupJoinPolicyUpdatedDetails + """ + if not self.is_group_join_policy_updated_details(): + raise AttributeError("tag 'group_join_policy_updated_details' not set") + return self._value + + def get_group_moved_details(self): + """ + Only call this if :meth:`is_group_moved_details` is true. + + :rtype: GroupMovedDetails + """ + if not self.is_group_moved_details(): + raise AttributeError("tag 'group_moved_details' not set") + return self._value + + def get_group_remove_external_id_details(self): + """ + Only call this if :meth:`is_group_remove_external_id_details` is true. + + :rtype: GroupRemoveExternalIdDetails + """ + if not self.is_group_remove_external_id_details(): + raise AttributeError("tag 'group_remove_external_id_details' not set") + return self._value + + def get_group_remove_member_details(self): + """ + Only call this if :meth:`is_group_remove_member_details` is true. + + :rtype: GroupRemoveMemberDetails + """ + if not self.is_group_remove_member_details(): + raise AttributeError("tag 'group_remove_member_details' not set") + return self._value + + def get_group_rename_details(self): + """ + Only call this if :meth:`is_group_rename_details` is true. + + :rtype: GroupRenameDetails + """ + if not self.is_group_rename_details(): + raise AttributeError("tag 'group_rename_details' not set") + return self._value + + def get_legal_holds_activate_a_hold_details(self): + """ + Only call this if :meth:`is_legal_holds_activate_a_hold_details` is true. + + :rtype: LegalHoldsActivateAHoldDetails + """ + if not self.is_legal_holds_activate_a_hold_details(): + raise AttributeError("tag 'legal_holds_activate_a_hold_details' not set") + return self._value + + def get_legal_holds_add_members_details(self): + """ + Only call this if :meth:`is_legal_holds_add_members_details` is true. + + :rtype: LegalHoldsAddMembersDetails + """ + if not self.is_legal_holds_add_members_details(): + raise AttributeError("tag 'legal_holds_add_members_details' not set") + return self._value + + def get_legal_holds_change_hold_details_details(self): + """ + Only call this if :meth:`is_legal_holds_change_hold_details_details` is true. + + :rtype: LegalHoldsChangeHoldDetailsDetails + """ + if not self.is_legal_holds_change_hold_details_details(): + raise AttributeError("tag 'legal_holds_change_hold_details_details' not set") + return self._value + + def get_legal_holds_change_hold_name_details(self): + """ + Only call this if :meth:`is_legal_holds_change_hold_name_details` is true. + + :rtype: LegalHoldsChangeHoldNameDetails + """ + if not self.is_legal_holds_change_hold_name_details(): + raise AttributeError("tag 'legal_holds_change_hold_name_details' not set") + return self._value + + def get_legal_holds_export_a_hold_details(self): + """ + Only call this if :meth:`is_legal_holds_export_a_hold_details` is true. + + :rtype: LegalHoldsExportAHoldDetails + """ + if not self.is_legal_holds_export_a_hold_details(): + raise AttributeError("tag 'legal_holds_export_a_hold_details' not set") + return self._value + + def get_legal_holds_export_cancelled_details(self): + """ + Only call this if :meth:`is_legal_holds_export_cancelled_details` is true. + + :rtype: LegalHoldsExportCancelledDetails + """ + if not self.is_legal_holds_export_cancelled_details(): + raise AttributeError("tag 'legal_holds_export_cancelled_details' not set") + return self._value + + def get_legal_holds_export_downloaded_details(self): + """ + Only call this if :meth:`is_legal_holds_export_downloaded_details` is true. + + :rtype: LegalHoldsExportDownloadedDetails + """ + if not self.is_legal_holds_export_downloaded_details(): + raise AttributeError("tag 'legal_holds_export_downloaded_details' not set") + return self._value + + def get_legal_holds_export_removed_details(self): + """ + Only call this if :meth:`is_legal_holds_export_removed_details` is true. + + :rtype: LegalHoldsExportRemovedDetails + """ + if not self.is_legal_holds_export_removed_details(): + raise AttributeError("tag 'legal_holds_export_removed_details' not set") + return self._value + + def get_legal_holds_release_a_hold_details(self): + """ + Only call this if :meth:`is_legal_holds_release_a_hold_details` is true. + + :rtype: LegalHoldsReleaseAHoldDetails + """ + if not self.is_legal_holds_release_a_hold_details(): + raise AttributeError("tag 'legal_holds_release_a_hold_details' not set") + return self._value + + def get_legal_holds_remove_members_details(self): + """ + Only call this if :meth:`is_legal_holds_remove_members_details` is true. + + :rtype: LegalHoldsRemoveMembersDetails + """ + if not self.is_legal_holds_remove_members_details(): + raise AttributeError("tag 'legal_holds_remove_members_details' not set") + return self._value + + def get_legal_holds_report_a_hold_details(self): + """ + Only call this if :meth:`is_legal_holds_report_a_hold_details` is true. + + :rtype: LegalHoldsReportAHoldDetails + """ + if not self.is_legal_holds_report_a_hold_details(): + raise AttributeError("tag 'legal_holds_report_a_hold_details' not set") + return self._value + + def get_account_lock_or_unlocked_details(self): + """ + Only call this if :meth:`is_account_lock_or_unlocked_details` is true. + + :rtype: AccountLockOrUnlockedDetails + """ + if not self.is_account_lock_or_unlocked_details(): + raise AttributeError("tag 'account_lock_or_unlocked_details' not set") + return self._value + + def get_emm_error_details(self): + """ + Only call this if :meth:`is_emm_error_details` is true. + + :rtype: EmmErrorDetails + """ + if not self.is_emm_error_details(): + raise AttributeError("tag 'emm_error_details' not set") + return self._value + + def get_guest_admin_signed_in_via_trusted_teams_details(self): + """ + Only call this if :meth:`is_guest_admin_signed_in_via_trusted_teams_details` is true. + + :rtype: GuestAdminSignedInViaTrustedTeamsDetails + """ + if not self.is_guest_admin_signed_in_via_trusted_teams_details(): + raise AttributeError("tag 'guest_admin_signed_in_via_trusted_teams_details' not set") + return self._value + + def get_guest_admin_signed_out_via_trusted_teams_details(self): + """ + Only call this if :meth:`is_guest_admin_signed_out_via_trusted_teams_details` is true. + + :rtype: GuestAdminSignedOutViaTrustedTeamsDetails + """ + if not self.is_guest_admin_signed_out_via_trusted_teams_details(): + raise AttributeError("tag 'guest_admin_signed_out_via_trusted_teams_details' not set") + return self._value + + def get_login_fail_details(self): + """ + Only call this if :meth:`is_login_fail_details` is true. + + :rtype: LoginFailDetails + """ + if not self.is_login_fail_details(): + raise AttributeError("tag 'login_fail_details' not set") + return self._value + + def get_login_success_details(self): + """ + Only call this if :meth:`is_login_success_details` is true. + + :rtype: LoginSuccessDetails + """ + if not self.is_login_success_details(): + raise AttributeError("tag 'login_success_details' not set") + return self._value + + def get_logout_details(self): + """ + Only call this if :meth:`is_logout_details` is true. + + :rtype: LogoutDetails + """ + if not self.is_logout_details(): + raise AttributeError("tag 'logout_details' not set") + return self._value + + def get_reseller_support_session_end_details(self): + """ + Only call this if :meth:`is_reseller_support_session_end_details` is true. + + :rtype: ResellerSupportSessionEndDetails + """ + if not self.is_reseller_support_session_end_details(): + raise AttributeError("tag 'reseller_support_session_end_details' not set") + return self._value + + def get_reseller_support_session_start_details(self): + """ + Only call this if :meth:`is_reseller_support_session_start_details` is true. + + :rtype: ResellerSupportSessionStartDetails + """ + if not self.is_reseller_support_session_start_details(): + raise AttributeError("tag 'reseller_support_session_start_details' not set") + return self._value + + def get_sign_in_as_session_end_details(self): + """ + Only call this if :meth:`is_sign_in_as_session_end_details` is true. + + :rtype: SignInAsSessionEndDetails + """ + if not self.is_sign_in_as_session_end_details(): + raise AttributeError("tag 'sign_in_as_session_end_details' not set") + return self._value + + def get_sign_in_as_session_start_details(self): + """ + Only call this if :meth:`is_sign_in_as_session_start_details` is true. + + :rtype: SignInAsSessionStartDetails + """ + if not self.is_sign_in_as_session_start_details(): + raise AttributeError("tag 'sign_in_as_session_start_details' not set") + return self._value + + def get_sso_error_details(self): + """ + Only call this if :meth:`is_sso_error_details` is true. + + :rtype: SsoErrorDetails + """ + if not self.is_sso_error_details(): + raise AttributeError("tag 'sso_error_details' not set") + return self._value + + def get_create_team_invite_link_details(self): + """ + Only call this if :meth:`is_create_team_invite_link_details` is true. + + :rtype: CreateTeamInviteLinkDetails + """ + if not self.is_create_team_invite_link_details(): + raise AttributeError("tag 'create_team_invite_link_details' not set") + return self._value + + def get_delete_team_invite_link_details(self): + """ + Only call this if :meth:`is_delete_team_invite_link_details` is true. + + :rtype: DeleteTeamInviteLinkDetails + """ + if not self.is_delete_team_invite_link_details(): + raise AttributeError("tag 'delete_team_invite_link_details' not set") + return self._value + + def get_member_add_external_id_details(self): + """ + Only call this if :meth:`is_member_add_external_id_details` is true. + + :rtype: MemberAddExternalIdDetails + """ + if not self.is_member_add_external_id_details(): + raise AttributeError("tag 'member_add_external_id_details' not set") + return self._value + + def get_member_add_name_details(self): + """ + Only call this if :meth:`is_member_add_name_details` is true. + + :rtype: MemberAddNameDetails + """ + if not self.is_member_add_name_details(): + raise AttributeError("tag 'member_add_name_details' not set") + return self._value + + def get_member_change_admin_role_details(self): + """ + Only call this if :meth:`is_member_change_admin_role_details` is true. + + :rtype: MemberChangeAdminRoleDetails + """ + if not self.is_member_change_admin_role_details(): + raise AttributeError("tag 'member_change_admin_role_details' not set") + return self._value + + def get_member_change_email_details(self): + """ + Only call this if :meth:`is_member_change_email_details` is true. + + :rtype: MemberChangeEmailDetails + """ + if not self.is_member_change_email_details(): + raise AttributeError("tag 'member_change_email_details' not set") + return self._value + + def get_member_change_external_id_details(self): + """ + Only call this if :meth:`is_member_change_external_id_details` is true. + + :rtype: MemberChangeExternalIdDetails + """ + if not self.is_member_change_external_id_details(): + raise AttributeError("tag 'member_change_external_id_details' not set") + return self._value + + def get_member_change_membership_type_details(self): + """ + Only call this if :meth:`is_member_change_membership_type_details` is true. + + :rtype: MemberChangeMembershipTypeDetails + """ + if not self.is_member_change_membership_type_details(): + raise AttributeError("tag 'member_change_membership_type_details' not set") + return self._value + + def get_member_change_name_details(self): + """ + Only call this if :meth:`is_member_change_name_details` is true. + + :rtype: MemberChangeNameDetails + """ + if not self.is_member_change_name_details(): + raise AttributeError("tag 'member_change_name_details' not set") + return self._value + + def get_member_change_status_details(self): + """ + Only call this if :meth:`is_member_change_status_details` is true. + + :rtype: MemberChangeStatusDetails + """ + if not self.is_member_change_status_details(): + raise AttributeError("tag 'member_change_status_details' not set") + return self._value + + def get_member_delete_manual_contacts_details(self): + """ + Only call this if :meth:`is_member_delete_manual_contacts_details` is true. + + :rtype: MemberDeleteManualContactsDetails + """ + if not self.is_member_delete_manual_contacts_details(): + raise AttributeError("tag 'member_delete_manual_contacts_details' not set") + return self._value + + def get_member_delete_profile_photo_details(self): + """ + Only call this if :meth:`is_member_delete_profile_photo_details` is true. + + :rtype: MemberDeleteProfilePhotoDetails + """ + if not self.is_member_delete_profile_photo_details(): + raise AttributeError("tag 'member_delete_profile_photo_details' not set") + return self._value + + def get_member_permanently_delete_account_contents_details(self): + """ + Only call this if :meth:`is_member_permanently_delete_account_contents_details` is true. + + :rtype: MemberPermanentlyDeleteAccountContentsDetails + """ + if not self.is_member_permanently_delete_account_contents_details(): + raise AttributeError("tag 'member_permanently_delete_account_contents_details' not set") + return self._value + + def get_member_remove_external_id_details(self): + """ + Only call this if :meth:`is_member_remove_external_id_details` is true. + + :rtype: MemberRemoveExternalIdDetails + """ + if not self.is_member_remove_external_id_details(): + raise AttributeError("tag 'member_remove_external_id_details' not set") + return self._value + + def get_member_set_profile_photo_details(self): + """ + Only call this if :meth:`is_member_set_profile_photo_details` is true. + + :rtype: MemberSetProfilePhotoDetails + """ + if not self.is_member_set_profile_photo_details(): + raise AttributeError("tag 'member_set_profile_photo_details' not set") + return self._value + + def get_member_space_limits_add_custom_quota_details(self): + """ + Only call this if :meth:`is_member_space_limits_add_custom_quota_details` is true. + + :rtype: MemberSpaceLimitsAddCustomQuotaDetails + """ + if not self.is_member_space_limits_add_custom_quota_details(): + raise AttributeError("tag 'member_space_limits_add_custom_quota_details' not set") + return self._value + + def get_member_space_limits_change_custom_quota_details(self): + """ + Only call this if :meth:`is_member_space_limits_change_custom_quota_details` is true. + + :rtype: MemberSpaceLimitsChangeCustomQuotaDetails + """ + if not self.is_member_space_limits_change_custom_quota_details(): + raise AttributeError("tag 'member_space_limits_change_custom_quota_details' not set") + return self._value + + def get_member_space_limits_change_status_details(self): + """ + Only call this if :meth:`is_member_space_limits_change_status_details` is true. + + :rtype: MemberSpaceLimitsChangeStatusDetails + """ + if not self.is_member_space_limits_change_status_details(): + raise AttributeError("tag 'member_space_limits_change_status_details' not set") + return self._value + + def get_member_space_limits_remove_custom_quota_details(self): + """ + Only call this if :meth:`is_member_space_limits_remove_custom_quota_details` is true. + + :rtype: MemberSpaceLimitsRemoveCustomQuotaDetails + """ + if not self.is_member_space_limits_remove_custom_quota_details(): + raise AttributeError("tag 'member_space_limits_remove_custom_quota_details' not set") + return self._value + + def get_member_suggest_details(self): + """ + Only call this if :meth:`is_member_suggest_details` is true. + + :rtype: MemberSuggestDetails + """ + if not self.is_member_suggest_details(): + raise AttributeError("tag 'member_suggest_details' not set") + return self._value + + def get_member_transfer_account_contents_details(self): + """ + Only call this if :meth:`is_member_transfer_account_contents_details` is true. + + :rtype: MemberTransferAccountContentsDetails + """ + if not self.is_member_transfer_account_contents_details(): + raise AttributeError("tag 'member_transfer_account_contents_details' not set") + return self._value + + def get_pending_secondary_email_added_details(self): + """ + Only call this if :meth:`is_pending_secondary_email_added_details` is true. + + :rtype: PendingSecondaryEmailAddedDetails + """ + if not self.is_pending_secondary_email_added_details(): + raise AttributeError("tag 'pending_secondary_email_added_details' not set") + return self._value + + def get_secondary_email_deleted_details(self): + """ + Only call this if :meth:`is_secondary_email_deleted_details` is true. + + :rtype: SecondaryEmailDeletedDetails + """ + if not self.is_secondary_email_deleted_details(): + raise AttributeError("tag 'secondary_email_deleted_details' not set") + return self._value + + def get_secondary_email_verified_details(self): + """ + Only call this if :meth:`is_secondary_email_verified_details` is true. + + :rtype: SecondaryEmailVerifiedDetails + """ + if not self.is_secondary_email_verified_details(): + raise AttributeError("tag 'secondary_email_verified_details' not set") + return self._value + + def get_secondary_mails_policy_changed_details(self): + """ + Only call this if :meth:`is_secondary_mails_policy_changed_details` is true. + + :rtype: SecondaryMailsPolicyChangedDetails + """ + if not self.is_secondary_mails_policy_changed_details(): + raise AttributeError("tag 'secondary_mails_policy_changed_details' not set") + return self._value + + def get_binder_add_page_details(self): + """ + Only call this if :meth:`is_binder_add_page_details` is true. + + :rtype: BinderAddPageDetails + """ + if not self.is_binder_add_page_details(): + raise AttributeError("tag 'binder_add_page_details' not set") + return self._value + + def get_binder_add_section_details(self): + """ + Only call this if :meth:`is_binder_add_section_details` is true. + + :rtype: BinderAddSectionDetails + """ + if not self.is_binder_add_section_details(): + raise AttributeError("tag 'binder_add_section_details' not set") + return self._value + + def get_binder_remove_page_details(self): + """ + Only call this if :meth:`is_binder_remove_page_details` is true. + + :rtype: BinderRemovePageDetails + """ + if not self.is_binder_remove_page_details(): + raise AttributeError("tag 'binder_remove_page_details' not set") + return self._value + + def get_binder_remove_section_details(self): + """ + Only call this if :meth:`is_binder_remove_section_details` is true. + + :rtype: BinderRemoveSectionDetails + """ + if not self.is_binder_remove_section_details(): + raise AttributeError("tag 'binder_remove_section_details' not set") + return self._value + + def get_binder_rename_page_details(self): + """ + Only call this if :meth:`is_binder_rename_page_details` is true. + + :rtype: BinderRenamePageDetails + """ + if not self.is_binder_rename_page_details(): + raise AttributeError("tag 'binder_rename_page_details' not set") + return self._value + + def get_binder_rename_section_details(self): + """ + Only call this if :meth:`is_binder_rename_section_details` is true. + + :rtype: BinderRenameSectionDetails + """ + if not self.is_binder_rename_section_details(): + raise AttributeError("tag 'binder_rename_section_details' not set") + return self._value + + def get_binder_reorder_page_details(self): + """ + Only call this if :meth:`is_binder_reorder_page_details` is true. + + :rtype: BinderReorderPageDetails + """ + if not self.is_binder_reorder_page_details(): + raise AttributeError("tag 'binder_reorder_page_details' not set") + return self._value + + def get_binder_reorder_section_details(self): + """ + Only call this if :meth:`is_binder_reorder_section_details` is true. + + :rtype: BinderReorderSectionDetails + """ + if not self.is_binder_reorder_section_details(): + raise AttributeError("tag 'binder_reorder_section_details' not set") + return self._value + + def get_paper_content_add_member_details(self): + """ + Only call this if :meth:`is_paper_content_add_member_details` is true. + + :rtype: PaperContentAddMemberDetails + """ + if not self.is_paper_content_add_member_details(): + raise AttributeError("tag 'paper_content_add_member_details' not set") + return self._value + + def get_paper_content_add_to_folder_details(self): + """ + Only call this if :meth:`is_paper_content_add_to_folder_details` is true. + + :rtype: PaperContentAddToFolderDetails + """ + if not self.is_paper_content_add_to_folder_details(): + raise AttributeError("tag 'paper_content_add_to_folder_details' not set") + return self._value + + def get_paper_content_archive_details(self): + """ + Only call this if :meth:`is_paper_content_archive_details` is true. + + :rtype: PaperContentArchiveDetails + """ + if not self.is_paper_content_archive_details(): + raise AttributeError("tag 'paper_content_archive_details' not set") + return self._value + + def get_paper_content_create_details(self): + """ + Only call this if :meth:`is_paper_content_create_details` is true. + + :rtype: PaperContentCreateDetails + """ + if not self.is_paper_content_create_details(): + raise AttributeError("tag 'paper_content_create_details' not set") + return self._value + + def get_paper_content_permanently_delete_details(self): + """ + Only call this if :meth:`is_paper_content_permanently_delete_details` is true. + + :rtype: PaperContentPermanentlyDeleteDetails + """ + if not self.is_paper_content_permanently_delete_details(): + raise AttributeError("tag 'paper_content_permanently_delete_details' not set") + return self._value + + def get_paper_content_remove_from_folder_details(self): + """ + Only call this if :meth:`is_paper_content_remove_from_folder_details` is true. + + :rtype: PaperContentRemoveFromFolderDetails + """ + if not self.is_paper_content_remove_from_folder_details(): + raise AttributeError("tag 'paper_content_remove_from_folder_details' not set") + return self._value + + def get_paper_content_remove_member_details(self): + """ + Only call this if :meth:`is_paper_content_remove_member_details` is true. + + :rtype: PaperContentRemoveMemberDetails + """ + if not self.is_paper_content_remove_member_details(): + raise AttributeError("tag 'paper_content_remove_member_details' not set") + return self._value + + def get_paper_content_rename_details(self): + """ + Only call this if :meth:`is_paper_content_rename_details` is true. + + :rtype: PaperContentRenameDetails + """ + if not self.is_paper_content_rename_details(): + raise AttributeError("tag 'paper_content_rename_details' not set") + return self._value + + def get_paper_content_restore_details(self): + """ + Only call this if :meth:`is_paper_content_restore_details` is true. + + :rtype: PaperContentRestoreDetails + """ + if not self.is_paper_content_restore_details(): + raise AttributeError("tag 'paper_content_restore_details' not set") + return self._value + + def get_paper_doc_add_comment_details(self): + """ + Only call this if :meth:`is_paper_doc_add_comment_details` is true. + + :rtype: PaperDocAddCommentDetails + """ + if not self.is_paper_doc_add_comment_details(): + raise AttributeError("tag 'paper_doc_add_comment_details' not set") + return self._value + + def get_paper_doc_change_member_role_details(self): + """ + Only call this if :meth:`is_paper_doc_change_member_role_details` is true. + + :rtype: PaperDocChangeMemberRoleDetails + """ + if not self.is_paper_doc_change_member_role_details(): + raise AttributeError("tag 'paper_doc_change_member_role_details' not set") + return self._value + + def get_paper_doc_change_sharing_policy_details(self): + """ + Only call this if :meth:`is_paper_doc_change_sharing_policy_details` is true. + + :rtype: PaperDocChangeSharingPolicyDetails + """ + if not self.is_paper_doc_change_sharing_policy_details(): + raise AttributeError("tag 'paper_doc_change_sharing_policy_details' not set") + return self._value + + def get_paper_doc_change_subscription_details(self): + """ + Only call this if :meth:`is_paper_doc_change_subscription_details` is true. + + :rtype: PaperDocChangeSubscriptionDetails + """ + if not self.is_paper_doc_change_subscription_details(): + raise AttributeError("tag 'paper_doc_change_subscription_details' not set") + return self._value + + def get_paper_doc_deleted_details(self): + """ + Only call this if :meth:`is_paper_doc_deleted_details` is true. + + :rtype: PaperDocDeletedDetails + """ + if not self.is_paper_doc_deleted_details(): + raise AttributeError("tag 'paper_doc_deleted_details' not set") + return self._value + + def get_paper_doc_delete_comment_details(self): + """ + Only call this if :meth:`is_paper_doc_delete_comment_details` is true. + + :rtype: PaperDocDeleteCommentDetails + """ + if not self.is_paper_doc_delete_comment_details(): + raise AttributeError("tag 'paper_doc_delete_comment_details' not set") + return self._value + + def get_paper_doc_download_details(self): + """ + Only call this if :meth:`is_paper_doc_download_details` is true. + + :rtype: PaperDocDownloadDetails + """ + if not self.is_paper_doc_download_details(): + raise AttributeError("tag 'paper_doc_download_details' not set") + return self._value + + def get_paper_doc_edit_details(self): + """ + Only call this if :meth:`is_paper_doc_edit_details` is true. + + :rtype: PaperDocEditDetails + """ + if not self.is_paper_doc_edit_details(): + raise AttributeError("tag 'paper_doc_edit_details' not set") + return self._value + + def get_paper_doc_edit_comment_details(self): + """ + Only call this if :meth:`is_paper_doc_edit_comment_details` is true. + + :rtype: PaperDocEditCommentDetails + """ + if not self.is_paper_doc_edit_comment_details(): + raise AttributeError("tag 'paper_doc_edit_comment_details' not set") + return self._value + + def get_paper_doc_followed_details(self): + """ + Only call this if :meth:`is_paper_doc_followed_details` is true. + + :rtype: PaperDocFollowedDetails + """ + if not self.is_paper_doc_followed_details(): + raise AttributeError("tag 'paper_doc_followed_details' not set") + return self._value + + def get_paper_doc_mention_details(self): + """ + Only call this if :meth:`is_paper_doc_mention_details` is true. + + :rtype: PaperDocMentionDetails + """ + if not self.is_paper_doc_mention_details(): + raise AttributeError("tag 'paper_doc_mention_details' not set") + return self._value + + def get_paper_doc_ownership_changed_details(self): + """ + Only call this if :meth:`is_paper_doc_ownership_changed_details` is true. + + :rtype: PaperDocOwnershipChangedDetails + """ + if not self.is_paper_doc_ownership_changed_details(): + raise AttributeError("tag 'paper_doc_ownership_changed_details' not set") + return self._value + + def get_paper_doc_request_access_details(self): + """ + Only call this if :meth:`is_paper_doc_request_access_details` is true. + + :rtype: PaperDocRequestAccessDetails + """ + if not self.is_paper_doc_request_access_details(): + raise AttributeError("tag 'paper_doc_request_access_details' not set") + return self._value + + def get_paper_doc_resolve_comment_details(self): + """ + Only call this if :meth:`is_paper_doc_resolve_comment_details` is true. + + :rtype: PaperDocResolveCommentDetails + """ + if not self.is_paper_doc_resolve_comment_details(): + raise AttributeError("tag 'paper_doc_resolve_comment_details' not set") + return self._value + + def get_paper_doc_revert_details(self): + """ + Only call this if :meth:`is_paper_doc_revert_details` is true. + + :rtype: PaperDocRevertDetails + """ + if not self.is_paper_doc_revert_details(): + raise AttributeError("tag 'paper_doc_revert_details' not set") + return self._value + + def get_paper_doc_slack_share_details(self): + """ + Only call this if :meth:`is_paper_doc_slack_share_details` is true. + + :rtype: PaperDocSlackShareDetails + """ + if not self.is_paper_doc_slack_share_details(): + raise AttributeError("tag 'paper_doc_slack_share_details' not set") + return self._value + + def get_paper_doc_team_invite_details(self): + """ + Only call this if :meth:`is_paper_doc_team_invite_details` is true. + + :rtype: PaperDocTeamInviteDetails + """ + if not self.is_paper_doc_team_invite_details(): + raise AttributeError("tag 'paper_doc_team_invite_details' not set") + return self._value + + def get_paper_doc_trashed_details(self): + """ + Only call this if :meth:`is_paper_doc_trashed_details` is true. + + :rtype: PaperDocTrashedDetails + """ + if not self.is_paper_doc_trashed_details(): + raise AttributeError("tag 'paper_doc_trashed_details' not set") + return self._value + + def get_paper_doc_unresolve_comment_details(self): + """ + Only call this if :meth:`is_paper_doc_unresolve_comment_details` is true. + + :rtype: PaperDocUnresolveCommentDetails + """ + if not self.is_paper_doc_unresolve_comment_details(): + raise AttributeError("tag 'paper_doc_unresolve_comment_details' not set") + return self._value + + def get_paper_doc_untrashed_details(self): + """ + Only call this if :meth:`is_paper_doc_untrashed_details` is true. + + :rtype: PaperDocUntrashedDetails + """ + if not self.is_paper_doc_untrashed_details(): + raise AttributeError("tag 'paper_doc_untrashed_details' not set") + return self._value + + def get_paper_doc_view_details(self): + """ + Only call this if :meth:`is_paper_doc_view_details` is true. + + :rtype: PaperDocViewDetails + """ + if not self.is_paper_doc_view_details(): + raise AttributeError("tag 'paper_doc_view_details' not set") + return self._value + + def get_paper_external_view_allow_details(self): + """ + Only call this if :meth:`is_paper_external_view_allow_details` is true. + + :rtype: PaperExternalViewAllowDetails + """ + if not self.is_paper_external_view_allow_details(): + raise AttributeError("tag 'paper_external_view_allow_details' not set") + return self._value + + def get_paper_external_view_default_team_details(self): + """ + Only call this if :meth:`is_paper_external_view_default_team_details` is true. + + :rtype: PaperExternalViewDefaultTeamDetails + """ + if not self.is_paper_external_view_default_team_details(): + raise AttributeError("tag 'paper_external_view_default_team_details' not set") + return self._value + + def get_paper_external_view_forbid_details(self): + """ + Only call this if :meth:`is_paper_external_view_forbid_details` is true. + + :rtype: PaperExternalViewForbidDetails + """ + if not self.is_paper_external_view_forbid_details(): + raise AttributeError("tag 'paper_external_view_forbid_details' not set") + return self._value + + def get_paper_folder_change_subscription_details(self): + """ + Only call this if :meth:`is_paper_folder_change_subscription_details` is true. + + :rtype: PaperFolderChangeSubscriptionDetails + """ + if not self.is_paper_folder_change_subscription_details(): + raise AttributeError("tag 'paper_folder_change_subscription_details' not set") + return self._value + + def get_paper_folder_deleted_details(self): + """ + Only call this if :meth:`is_paper_folder_deleted_details` is true. + + :rtype: PaperFolderDeletedDetails + """ + if not self.is_paper_folder_deleted_details(): + raise AttributeError("tag 'paper_folder_deleted_details' not set") + return self._value + + def get_paper_folder_followed_details(self): + """ + Only call this if :meth:`is_paper_folder_followed_details` is true. + + :rtype: PaperFolderFollowedDetails + """ + if not self.is_paper_folder_followed_details(): + raise AttributeError("tag 'paper_folder_followed_details' not set") + return self._value + + def get_paper_folder_team_invite_details(self): + """ + Only call this if :meth:`is_paper_folder_team_invite_details` is true. + + :rtype: PaperFolderTeamInviteDetails + """ + if not self.is_paper_folder_team_invite_details(): + raise AttributeError("tag 'paper_folder_team_invite_details' not set") + return self._value + + def get_paper_published_link_change_permission_details(self): + """ + Only call this if :meth:`is_paper_published_link_change_permission_details` is true. + + :rtype: PaperPublishedLinkChangePermissionDetails + """ + if not self.is_paper_published_link_change_permission_details(): + raise AttributeError("tag 'paper_published_link_change_permission_details' not set") + return self._value + + def get_paper_published_link_create_details(self): + """ + Only call this if :meth:`is_paper_published_link_create_details` is true. + + :rtype: PaperPublishedLinkCreateDetails + """ + if not self.is_paper_published_link_create_details(): + raise AttributeError("tag 'paper_published_link_create_details' not set") + return self._value + + def get_paper_published_link_disabled_details(self): + """ + Only call this if :meth:`is_paper_published_link_disabled_details` is true. + + :rtype: PaperPublishedLinkDisabledDetails + """ + if not self.is_paper_published_link_disabled_details(): + raise AttributeError("tag 'paper_published_link_disabled_details' not set") + return self._value + + def get_paper_published_link_view_details(self): + """ + Only call this if :meth:`is_paper_published_link_view_details` is true. + + :rtype: PaperPublishedLinkViewDetails + """ + if not self.is_paper_published_link_view_details(): + raise AttributeError("tag 'paper_published_link_view_details' not set") + return self._value + + def get_password_change_details(self): + """ + Only call this if :meth:`is_password_change_details` is true. + + :rtype: PasswordChangeDetails + """ + if not self.is_password_change_details(): + raise AttributeError("tag 'password_change_details' not set") + return self._value + + def get_password_reset_details(self): + """ + Only call this if :meth:`is_password_reset_details` is true. + + :rtype: PasswordResetDetails + """ + if not self.is_password_reset_details(): + raise AttributeError("tag 'password_reset_details' not set") + return self._value + + def get_password_reset_all_details(self): + """ + Only call this if :meth:`is_password_reset_all_details` is true. + + :rtype: PasswordResetAllDetails + """ + if not self.is_password_reset_all_details(): + raise AttributeError("tag 'password_reset_all_details' not set") + return self._value + + def get_emm_create_exceptions_report_details(self): + """ + Only call this if :meth:`is_emm_create_exceptions_report_details` is true. + + :rtype: EmmCreateExceptionsReportDetails + """ + if not self.is_emm_create_exceptions_report_details(): + raise AttributeError("tag 'emm_create_exceptions_report_details' not set") + return self._value + + def get_emm_create_usage_report_details(self): + """ + Only call this if :meth:`is_emm_create_usage_report_details` is true. + + :rtype: EmmCreateUsageReportDetails + """ + if not self.is_emm_create_usage_report_details(): + raise AttributeError("tag 'emm_create_usage_report_details' not set") + return self._value + + def get_export_members_report_details(self): + """ + Only call this if :meth:`is_export_members_report_details` is true. + + :rtype: ExportMembersReportDetails + """ + if not self.is_export_members_report_details(): + raise AttributeError("tag 'export_members_report_details' not set") + return self._value + + def get_export_members_report_fail_details(self): + """ + Only call this if :meth:`is_export_members_report_fail_details` is true. + + :rtype: ExportMembersReportFailDetails + """ + if not self.is_export_members_report_fail_details(): + raise AttributeError("tag 'export_members_report_fail_details' not set") + return self._value + + def get_no_expiration_link_gen_create_report_details(self): + """ + Only call this if :meth:`is_no_expiration_link_gen_create_report_details` is true. + + :rtype: NoExpirationLinkGenCreateReportDetails + """ + if not self.is_no_expiration_link_gen_create_report_details(): + raise AttributeError("tag 'no_expiration_link_gen_create_report_details' not set") + return self._value + + def get_no_expiration_link_gen_report_failed_details(self): + """ + Only call this if :meth:`is_no_expiration_link_gen_report_failed_details` is true. + + :rtype: NoExpirationLinkGenReportFailedDetails + """ + if not self.is_no_expiration_link_gen_report_failed_details(): + raise AttributeError("tag 'no_expiration_link_gen_report_failed_details' not set") + return self._value + + def get_no_password_link_gen_create_report_details(self): + """ + Only call this if :meth:`is_no_password_link_gen_create_report_details` is true. + + :rtype: NoPasswordLinkGenCreateReportDetails + """ + if not self.is_no_password_link_gen_create_report_details(): + raise AttributeError("tag 'no_password_link_gen_create_report_details' not set") + return self._value + + def get_no_password_link_gen_report_failed_details(self): + """ + Only call this if :meth:`is_no_password_link_gen_report_failed_details` is true. + + :rtype: NoPasswordLinkGenReportFailedDetails + """ + if not self.is_no_password_link_gen_report_failed_details(): + raise AttributeError("tag 'no_password_link_gen_report_failed_details' not set") + return self._value + + def get_no_password_link_view_create_report_details(self): + """ + Only call this if :meth:`is_no_password_link_view_create_report_details` is true. + + :rtype: NoPasswordLinkViewCreateReportDetails + """ + if not self.is_no_password_link_view_create_report_details(): + raise AttributeError("tag 'no_password_link_view_create_report_details' not set") + return self._value + + def get_no_password_link_view_report_failed_details(self): + """ + Only call this if :meth:`is_no_password_link_view_report_failed_details` is true. + + :rtype: NoPasswordLinkViewReportFailedDetails + """ + if not self.is_no_password_link_view_report_failed_details(): + raise AttributeError("tag 'no_password_link_view_report_failed_details' not set") + return self._value + + def get_outdated_link_view_create_report_details(self): + """ + Only call this if :meth:`is_outdated_link_view_create_report_details` is true. + + :rtype: OutdatedLinkViewCreateReportDetails + """ + if not self.is_outdated_link_view_create_report_details(): + raise AttributeError("tag 'outdated_link_view_create_report_details' not set") + return self._value + + def get_outdated_link_view_report_failed_details(self): + """ + Only call this if :meth:`is_outdated_link_view_report_failed_details` is true. + + :rtype: OutdatedLinkViewReportFailedDetails + """ + if not self.is_outdated_link_view_report_failed_details(): + raise AttributeError("tag 'outdated_link_view_report_failed_details' not set") + return self._value + + def get_paper_admin_export_start_details(self): + """ + Only call this if :meth:`is_paper_admin_export_start_details` is true. + + :rtype: PaperAdminExportStartDetails + """ + if not self.is_paper_admin_export_start_details(): + raise AttributeError("tag 'paper_admin_export_start_details' not set") + return self._value + + def get_smart_sync_create_admin_privilege_report_details(self): + """ + Only call this if :meth:`is_smart_sync_create_admin_privilege_report_details` is true. + + :rtype: SmartSyncCreateAdminPrivilegeReportDetails + """ + if not self.is_smart_sync_create_admin_privilege_report_details(): + raise AttributeError("tag 'smart_sync_create_admin_privilege_report_details' not set") + return self._value + + def get_team_activity_create_report_details(self): + """ + Only call this if :meth:`is_team_activity_create_report_details` is true. + + :rtype: TeamActivityCreateReportDetails + """ + if not self.is_team_activity_create_report_details(): + raise AttributeError("tag 'team_activity_create_report_details' not set") + return self._value + + def get_team_activity_create_report_fail_details(self): + """ + Only call this if :meth:`is_team_activity_create_report_fail_details` is true. + + :rtype: TeamActivityCreateReportFailDetails + """ + if not self.is_team_activity_create_report_fail_details(): + raise AttributeError("tag 'team_activity_create_report_fail_details' not set") + return self._value + + def get_collection_share_details(self): + """ + Only call this if :meth:`is_collection_share_details` is true. + + :rtype: CollectionShareDetails + """ + if not self.is_collection_share_details(): + raise AttributeError("tag 'collection_share_details' not set") + return self._value + + def get_file_transfers_file_add_details(self): + """ + Only call this if :meth:`is_file_transfers_file_add_details` is true. + + :rtype: FileTransfersFileAddDetails + """ + if not self.is_file_transfers_file_add_details(): + raise AttributeError("tag 'file_transfers_file_add_details' not set") + return self._value + + def get_file_transfers_transfer_delete_details(self): + """ + Only call this if :meth:`is_file_transfers_transfer_delete_details` is true. + + :rtype: FileTransfersTransferDeleteDetails + """ + if not self.is_file_transfers_transfer_delete_details(): + raise AttributeError("tag 'file_transfers_transfer_delete_details' not set") + return self._value + + def get_file_transfers_transfer_download_details(self): + """ + Only call this if :meth:`is_file_transfers_transfer_download_details` is true. + + :rtype: FileTransfersTransferDownloadDetails + """ + if not self.is_file_transfers_transfer_download_details(): + raise AttributeError("tag 'file_transfers_transfer_download_details' not set") + return self._value + + def get_file_transfers_transfer_send_details(self): + """ + Only call this if :meth:`is_file_transfers_transfer_send_details` is true. + + :rtype: FileTransfersTransferSendDetails + """ + if not self.is_file_transfers_transfer_send_details(): + raise AttributeError("tag 'file_transfers_transfer_send_details' not set") + return self._value + + def get_file_transfers_transfer_view_details(self): + """ + Only call this if :meth:`is_file_transfers_transfer_view_details` is true. + + :rtype: FileTransfersTransferViewDetails + """ + if not self.is_file_transfers_transfer_view_details(): + raise AttributeError("tag 'file_transfers_transfer_view_details' not set") + return self._value + + def get_note_acl_invite_only_details(self): + """ + Only call this if :meth:`is_note_acl_invite_only_details` is true. + + :rtype: NoteAclInviteOnlyDetails + """ + if not self.is_note_acl_invite_only_details(): + raise AttributeError("tag 'note_acl_invite_only_details' not set") + return self._value + + def get_note_acl_link_details(self): + """ + Only call this if :meth:`is_note_acl_link_details` is true. + + :rtype: NoteAclLinkDetails + """ + if not self.is_note_acl_link_details(): + raise AttributeError("tag 'note_acl_link_details' not set") + return self._value + + def get_note_acl_team_link_details(self): + """ + Only call this if :meth:`is_note_acl_team_link_details` is true. + + :rtype: NoteAclTeamLinkDetails + """ + if not self.is_note_acl_team_link_details(): + raise AttributeError("tag 'note_acl_team_link_details' not set") + return self._value + + def get_note_shared_details(self): + """ + Only call this if :meth:`is_note_shared_details` is true. + + :rtype: NoteSharedDetails + """ + if not self.is_note_shared_details(): + raise AttributeError("tag 'note_shared_details' not set") + return self._value + + def get_note_share_receive_details(self): + """ + Only call this if :meth:`is_note_share_receive_details` is true. + + :rtype: NoteShareReceiveDetails + """ + if not self.is_note_share_receive_details(): + raise AttributeError("tag 'note_share_receive_details' not set") + return self._value + + def get_open_note_shared_details(self): + """ + Only call this if :meth:`is_open_note_shared_details` is true. + + :rtype: OpenNoteSharedDetails + """ + if not self.is_open_note_shared_details(): + raise AttributeError("tag 'open_note_shared_details' not set") + return self._value + + def get_sf_add_group_details(self): + """ + Only call this if :meth:`is_sf_add_group_details` is true. + + :rtype: SfAddGroupDetails + """ + if not self.is_sf_add_group_details(): + raise AttributeError("tag 'sf_add_group_details' not set") + return self._value + + def get_sf_allow_non_members_to_view_shared_links_details(self): + """ + Only call this if :meth:`is_sf_allow_non_members_to_view_shared_links_details` is true. + + :rtype: SfAllowNonMembersToViewSharedLinksDetails + """ + if not self.is_sf_allow_non_members_to_view_shared_links_details(): + raise AttributeError("tag 'sf_allow_non_members_to_view_shared_links_details' not set") + return self._value + + def get_sf_external_invite_warn_details(self): + """ + Only call this if :meth:`is_sf_external_invite_warn_details` is true. + + :rtype: SfExternalInviteWarnDetails + """ + if not self.is_sf_external_invite_warn_details(): + raise AttributeError("tag 'sf_external_invite_warn_details' not set") + return self._value + + def get_sf_fb_invite_details(self): + """ + Only call this if :meth:`is_sf_fb_invite_details` is true. + + :rtype: SfFbInviteDetails + """ + if not self.is_sf_fb_invite_details(): + raise AttributeError("tag 'sf_fb_invite_details' not set") + return self._value + + def get_sf_fb_invite_change_role_details(self): + """ + Only call this if :meth:`is_sf_fb_invite_change_role_details` is true. + + :rtype: SfFbInviteChangeRoleDetails + """ + if not self.is_sf_fb_invite_change_role_details(): + raise AttributeError("tag 'sf_fb_invite_change_role_details' not set") + return self._value + + def get_sf_fb_uninvite_details(self): + """ + Only call this if :meth:`is_sf_fb_uninvite_details` is true. + + :rtype: SfFbUninviteDetails + """ + if not self.is_sf_fb_uninvite_details(): + raise AttributeError("tag 'sf_fb_uninvite_details' not set") + return self._value + + def get_sf_invite_group_details(self): + """ + Only call this if :meth:`is_sf_invite_group_details` is true. + + :rtype: SfInviteGroupDetails + """ + if not self.is_sf_invite_group_details(): + raise AttributeError("tag 'sf_invite_group_details' not set") + return self._value + + def get_sf_team_grant_access_details(self): + """ + Only call this if :meth:`is_sf_team_grant_access_details` is true. + + :rtype: SfTeamGrantAccessDetails + """ + if not self.is_sf_team_grant_access_details(): + raise AttributeError("tag 'sf_team_grant_access_details' not set") + return self._value + + def get_sf_team_invite_details(self): + """ + Only call this if :meth:`is_sf_team_invite_details` is true. + + :rtype: SfTeamInviteDetails + """ + if not self.is_sf_team_invite_details(): + raise AttributeError("tag 'sf_team_invite_details' not set") + return self._value + + def get_sf_team_invite_change_role_details(self): + """ + Only call this if :meth:`is_sf_team_invite_change_role_details` is true. + + :rtype: SfTeamInviteChangeRoleDetails + """ + if not self.is_sf_team_invite_change_role_details(): + raise AttributeError("tag 'sf_team_invite_change_role_details' not set") + return self._value + + def get_sf_team_join_details(self): + """ + Only call this if :meth:`is_sf_team_join_details` is true. + + :rtype: SfTeamJoinDetails + """ + if not self.is_sf_team_join_details(): + raise AttributeError("tag 'sf_team_join_details' not set") + return self._value + + def get_sf_team_join_from_oob_link_details(self): + """ + Only call this if :meth:`is_sf_team_join_from_oob_link_details` is true. + + :rtype: SfTeamJoinFromOobLinkDetails + """ + if not self.is_sf_team_join_from_oob_link_details(): + raise AttributeError("tag 'sf_team_join_from_oob_link_details' not set") + return self._value + + def get_sf_team_uninvite_details(self): + """ + Only call this if :meth:`is_sf_team_uninvite_details` is true. + + :rtype: SfTeamUninviteDetails + """ + if not self.is_sf_team_uninvite_details(): + raise AttributeError("tag 'sf_team_uninvite_details' not set") + return self._value + + def get_shared_content_add_invitees_details(self): + """ + Only call this if :meth:`is_shared_content_add_invitees_details` is true. + + :rtype: SharedContentAddInviteesDetails + """ + if not self.is_shared_content_add_invitees_details(): + raise AttributeError("tag 'shared_content_add_invitees_details' not set") + return self._value + + def get_shared_content_add_link_expiry_details(self): + """ + Only call this if :meth:`is_shared_content_add_link_expiry_details` is true. + + :rtype: SharedContentAddLinkExpiryDetails + """ + if not self.is_shared_content_add_link_expiry_details(): + raise AttributeError("tag 'shared_content_add_link_expiry_details' not set") + return self._value + + def get_shared_content_add_link_password_details(self): + """ + Only call this if :meth:`is_shared_content_add_link_password_details` is true. + + :rtype: SharedContentAddLinkPasswordDetails + """ + if not self.is_shared_content_add_link_password_details(): + raise AttributeError("tag 'shared_content_add_link_password_details' not set") + return self._value + + def get_shared_content_add_member_details(self): + """ + Only call this if :meth:`is_shared_content_add_member_details` is true. + + :rtype: SharedContentAddMemberDetails + """ + if not self.is_shared_content_add_member_details(): + raise AttributeError("tag 'shared_content_add_member_details' not set") + return self._value + + def get_shared_content_change_downloads_policy_details(self): + """ + Only call this if :meth:`is_shared_content_change_downloads_policy_details` is true. + + :rtype: SharedContentChangeDownloadsPolicyDetails + """ + if not self.is_shared_content_change_downloads_policy_details(): + raise AttributeError("tag 'shared_content_change_downloads_policy_details' not set") + return self._value + + def get_shared_content_change_invitee_role_details(self): + """ + Only call this if :meth:`is_shared_content_change_invitee_role_details` is true. + + :rtype: SharedContentChangeInviteeRoleDetails + """ + if not self.is_shared_content_change_invitee_role_details(): + raise AttributeError("tag 'shared_content_change_invitee_role_details' not set") + return self._value + + def get_shared_content_change_link_audience_details(self): + """ + Only call this if :meth:`is_shared_content_change_link_audience_details` is true. + + :rtype: SharedContentChangeLinkAudienceDetails + """ + if not self.is_shared_content_change_link_audience_details(): + raise AttributeError("tag 'shared_content_change_link_audience_details' not set") + return self._value + + def get_shared_content_change_link_expiry_details(self): + """ + Only call this if :meth:`is_shared_content_change_link_expiry_details` is true. + + :rtype: SharedContentChangeLinkExpiryDetails + """ + if not self.is_shared_content_change_link_expiry_details(): + raise AttributeError("tag 'shared_content_change_link_expiry_details' not set") + return self._value + + def get_shared_content_change_link_password_details(self): + """ + Only call this if :meth:`is_shared_content_change_link_password_details` is true. + + :rtype: SharedContentChangeLinkPasswordDetails + """ + if not self.is_shared_content_change_link_password_details(): + raise AttributeError("tag 'shared_content_change_link_password_details' not set") + return self._value + + def get_shared_content_change_member_role_details(self): + """ + Only call this if :meth:`is_shared_content_change_member_role_details` is true. + + :rtype: SharedContentChangeMemberRoleDetails + """ + if not self.is_shared_content_change_member_role_details(): + raise AttributeError("tag 'shared_content_change_member_role_details' not set") + return self._value + + def get_shared_content_change_viewer_info_policy_details(self): + """ + Only call this if :meth:`is_shared_content_change_viewer_info_policy_details` is true. + + :rtype: SharedContentChangeViewerInfoPolicyDetails + """ + if not self.is_shared_content_change_viewer_info_policy_details(): + raise AttributeError("tag 'shared_content_change_viewer_info_policy_details' not set") + return self._value + + def get_shared_content_claim_invitation_details(self): + """ + Only call this if :meth:`is_shared_content_claim_invitation_details` is true. + + :rtype: SharedContentClaimInvitationDetails + """ + if not self.is_shared_content_claim_invitation_details(): + raise AttributeError("tag 'shared_content_claim_invitation_details' not set") + return self._value + + def get_shared_content_copy_details(self): + """ + Only call this if :meth:`is_shared_content_copy_details` is true. + + :rtype: SharedContentCopyDetails + """ + if not self.is_shared_content_copy_details(): + raise AttributeError("tag 'shared_content_copy_details' not set") + return self._value + + def get_shared_content_download_details(self): + """ + Only call this if :meth:`is_shared_content_download_details` is true. + + :rtype: SharedContentDownloadDetails + """ + if not self.is_shared_content_download_details(): + raise AttributeError("tag 'shared_content_download_details' not set") + return self._value + + def get_shared_content_relinquish_membership_details(self): + """ + Only call this if :meth:`is_shared_content_relinquish_membership_details` is true. + + :rtype: SharedContentRelinquishMembershipDetails + """ + if not self.is_shared_content_relinquish_membership_details(): + raise AttributeError("tag 'shared_content_relinquish_membership_details' not set") + return self._value + + def get_shared_content_remove_invitees_details(self): + """ + Only call this if :meth:`is_shared_content_remove_invitees_details` is true. + + :rtype: SharedContentRemoveInviteesDetails + """ + if not self.is_shared_content_remove_invitees_details(): + raise AttributeError("tag 'shared_content_remove_invitees_details' not set") + return self._value + + def get_shared_content_remove_link_expiry_details(self): + """ + Only call this if :meth:`is_shared_content_remove_link_expiry_details` is true. + + :rtype: SharedContentRemoveLinkExpiryDetails + """ + if not self.is_shared_content_remove_link_expiry_details(): + raise AttributeError("tag 'shared_content_remove_link_expiry_details' not set") + return self._value + + def get_shared_content_remove_link_password_details(self): + """ + Only call this if :meth:`is_shared_content_remove_link_password_details` is true. + + :rtype: SharedContentRemoveLinkPasswordDetails + """ + if not self.is_shared_content_remove_link_password_details(): + raise AttributeError("tag 'shared_content_remove_link_password_details' not set") + return self._value + + def get_shared_content_remove_member_details(self): + """ + Only call this if :meth:`is_shared_content_remove_member_details` is true. + + :rtype: SharedContentRemoveMemberDetails + """ + if not self.is_shared_content_remove_member_details(): + raise AttributeError("tag 'shared_content_remove_member_details' not set") + return self._value + + def get_shared_content_request_access_details(self): + """ + Only call this if :meth:`is_shared_content_request_access_details` is true. + + :rtype: SharedContentRequestAccessDetails + """ + if not self.is_shared_content_request_access_details(): + raise AttributeError("tag 'shared_content_request_access_details' not set") + return self._value + + def get_shared_content_restore_invitees_details(self): + """ + Only call this if :meth:`is_shared_content_restore_invitees_details` is true. + + :rtype: SharedContentRestoreInviteesDetails + """ + if not self.is_shared_content_restore_invitees_details(): + raise AttributeError("tag 'shared_content_restore_invitees_details' not set") + return self._value + + def get_shared_content_restore_member_details(self): + """ + Only call this if :meth:`is_shared_content_restore_member_details` is true. + + :rtype: SharedContentRestoreMemberDetails + """ + if not self.is_shared_content_restore_member_details(): + raise AttributeError("tag 'shared_content_restore_member_details' not set") + return self._value + + def get_shared_content_unshare_details(self): + """ + Only call this if :meth:`is_shared_content_unshare_details` is true. + + :rtype: SharedContentUnshareDetails + """ + if not self.is_shared_content_unshare_details(): + raise AttributeError("tag 'shared_content_unshare_details' not set") + return self._value + + def get_shared_content_view_details(self): + """ + Only call this if :meth:`is_shared_content_view_details` is true. + + :rtype: SharedContentViewDetails + """ + if not self.is_shared_content_view_details(): + raise AttributeError("tag 'shared_content_view_details' not set") + return self._value + + def get_shared_folder_change_link_policy_details(self): + """ + Only call this if :meth:`is_shared_folder_change_link_policy_details` is true. + + :rtype: SharedFolderChangeLinkPolicyDetails + """ + if not self.is_shared_folder_change_link_policy_details(): + raise AttributeError("tag 'shared_folder_change_link_policy_details' not set") + return self._value + + def get_shared_folder_change_members_inheritance_policy_details(self): + """ + Only call this if :meth:`is_shared_folder_change_members_inheritance_policy_details` is true. + + :rtype: SharedFolderChangeMembersInheritancePolicyDetails + """ + if not self.is_shared_folder_change_members_inheritance_policy_details(): + raise AttributeError("tag 'shared_folder_change_members_inheritance_policy_details' not set") + return self._value + + def get_shared_folder_change_members_management_policy_details(self): + """ + Only call this if :meth:`is_shared_folder_change_members_management_policy_details` is true. + + :rtype: SharedFolderChangeMembersManagementPolicyDetails + """ + if not self.is_shared_folder_change_members_management_policy_details(): + raise AttributeError("tag 'shared_folder_change_members_management_policy_details' not set") + return self._value + + def get_shared_folder_change_members_policy_details(self): + """ + Only call this if :meth:`is_shared_folder_change_members_policy_details` is true. + + :rtype: SharedFolderChangeMembersPolicyDetails + """ + if not self.is_shared_folder_change_members_policy_details(): + raise AttributeError("tag 'shared_folder_change_members_policy_details' not set") + return self._value + + def get_shared_folder_create_details(self): + """ + Only call this if :meth:`is_shared_folder_create_details` is true. + + :rtype: SharedFolderCreateDetails + """ + if not self.is_shared_folder_create_details(): + raise AttributeError("tag 'shared_folder_create_details' not set") + return self._value + + def get_shared_folder_decline_invitation_details(self): + """ + Only call this if :meth:`is_shared_folder_decline_invitation_details` is true. + + :rtype: SharedFolderDeclineInvitationDetails + """ + if not self.is_shared_folder_decline_invitation_details(): + raise AttributeError("tag 'shared_folder_decline_invitation_details' not set") + return self._value + + def get_shared_folder_mount_details(self): + """ + Only call this if :meth:`is_shared_folder_mount_details` is true. + + :rtype: SharedFolderMountDetails + """ + if not self.is_shared_folder_mount_details(): + raise AttributeError("tag 'shared_folder_mount_details' not set") + return self._value + + def get_shared_folder_nest_details(self): + """ + Only call this if :meth:`is_shared_folder_nest_details` is true. + + :rtype: SharedFolderNestDetails + """ + if not self.is_shared_folder_nest_details(): + raise AttributeError("tag 'shared_folder_nest_details' not set") + return self._value + + def get_shared_folder_transfer_ownership_details(self): + """ + Only call this if :meth:`is_shared_folder_transfer_ownership_details` is true. + + :rtype: SharedFolderTransferOwnershipDetails + """ + if not self.is_shared_folder_transfer_ownership_details(): + raise AttributeError("tag 'shared_folder_transfer_ownership_details' not set") + return self._value + + def get_shared_folder_unmount_details(self): + """ + Only call this if :meth:`is_shared_folder_unmount_details` is true. + + :rtype: SharedFolderUnmountDetails + """ + if not self.is_shared_folder_unmount_details(): + raise AttributeError("tag 'shared_folder_unmount_details' not set") + return self._value + + def get_shared_link_add_expiry_details(self): + """ + Only call this if :meth:`is_shared_link_add_expiry_details` is true. + + :rtype: SharedLinkAddExpiryDetails + """ + if not self.is_shared_link_add_expiry_details(): + raise AttributeError("tag 'shared_link_add_expiry_details' not set") + return self._value + + def get_shared_link_change_expiry_details(self): + """ + Only call this if :meth:`is_shared_link_change_expiry_details` is true. + + :rtype: SharedLinkChangeExpiryDetails + """ + if not self.is_shared_link_change_expiry_details(): + raise AttributeError("tag 'shared_link_change_expiry_details' not set") + return self._value + + def get_shared_link_change_visibility_details(self): + """ + Only call this if :meth:`is_shared_link_change_visibility_details` is true. + + :rtype: SharedLinkChangeVisibilityDetails + """ + if not self.is_shared_link_change_visibility_details(): + raise AttributeError("tag 'shared_link_change_visibility_details' not set") + return self._value + + def get_shared_link_copy_details(self): + """ + Only call this if :meth:`is_shared_link_copy_details` is true. + + :rtype: SharedLinkCopyDetails + """ + if not self.is_shared_link_copy_details(): + raise AttributeError("tag 'shared_link_copy_details' not set") + return self._value + + def get_shared_link_create_details(self): + """ + Only call this if :meth:`is_shared_link_create_details` is true. + + :rtype: SharedLinkCreateDetails + """ + if not self.is_shared_link_create_details(): + raise AttributeError("tag 'shared_link_create_details' not set") + return self._value + + def get_shared_link_disable_details(self): + """ + Only call this if :meth:`is_shared_link_disable_details` is true. + + :rtype: SharedLinkDisableDetails + """ + if not self.is_shared_link_disable_details(): + raise AttributeError("tag 'shared_link_disable_details' not set") + return self._value + + def get_shared_link_download_details(self): + """ + Only call this if :meth:`is_shared_link_download_details` is true. + + :rtype: SharedLinkDownloadDetails + """ + if not self.is_shared_link_download_details(): + raise AttributeError("tag 'shared_link_download_details' not set") + return self._value + + def get_shared_link_remove_expiry_details(self): + """ + Only call this if :meth:`is_shared_link_remove_expiry_details` is true. + + :rtype: SharedLinkRemoveExpiryDetails + """ + if not self.is_shared_link_remove_expiry_details(): + raise AttributeError("tag 'shared_link_remove_expiry_details' not set") + return self._value + + def get_shared_link_settings_add_expiration_details(self): + """ + Only call this if :meth:`is_shared_link_settings_add_expiration_details` is true. + + :rtype: SharedLinkSettingsAddExpirationDetails + """ + if not self.is_shared_link_settings_add_expiration_details(): + raise AttributeError("tag 'shared_link_settings_add_expiration_details' not set") + return self._value + + def get_shared_link_settings_add_password_details(self): + """ + Only call this if :meth:`is_shared_link_settings_add_password_details` is true. + + :rtype: SharedLinkSettingsAddPasswordDetails + """ + if not self.is_shared_link_settings_add_password_details(): + raise AttributeError("tag 'shared_link_settings_add_password_details' not set") + return self._value + + def get_shared_link_settings_allow_download_disabled_details(self): + """ + Only call this if :meth:`is_shared_link_settings_allow_download_disabled_details` is true. + + :rtype: SharedLinkSettingsAllowDownloadDisabledDetails + """ + if not self.is_shared_link_settings_allow_download_disabled_details(): + raise AttributeError("tag 'shared_link_settings_allow_download_disabled_details' not set") + return self._value + + def get_shared_link_settings_allow_download_enabled_details(self): + """ + Only call this if :meth:`is_shared_link_settings_allow_download_enabled_details` is true. + + :rtype: SharedLinkSettingsAllowDownloadEnabledDetails + """ + if not self.is_shared_link_settings_allow_download_enabled_details(): + raise AttributeError("tag 'shared_link_settings_allow_download_enabled_details' not set") + return self._value + + def get_shared_link_settings_change_audience_details(self): + """ + Only call this if :meth:`is_shared_link_settings_change_audience_details` is true. + + :rtype: SharedLinkSettingsChangeAudienceDetails + """ + if not self.is_shared_link_settings_change_audience_details(): + raise AttributeError("tag 'shared_link_settings_change_audience_details' not set") + return self._value + + def get_shared_link_settings_change_expiration_details(self): + """ + Only call this if :meth:`is_shared_link_settings_change_expiration_details` is true. + + :rtype: SharedLinkSettingsChangeExpirationDetails + """ + if not self.is_shared_link_settings_change_expiration_details(): + raise AttributeError("tag 'shared_link_settings_change_expiration_details' not set") + return self._value + + def get_shared_link_settings_change_password_details(self): + """ + Only call this if :meth:`is_shared_link_settings_change_password_details` is true. + + :rtype: SharedLinkSettingsChangePasswordDetails + """ + if not self.is_shared_link_settings_change_password_details(): + raise AttributeError("tag 'shared_link_settings_change_password_details' not set") + return self._value + + def get_shared_link_settings_remove_expiration_details(self): + """ + Only call this if :meth:`is_shared_link_settings_remove_expiration_details` is true. + + :rtype: SharedLinkSettingsRemoveExpirationDetails + """ + if not self.is_shared_link_settings_remove_expiration_details(): + raise AttributeError("tag 'shared_link_settings_remove_expiration_details' not set") + return self._value + + def get_shared_link_settings_remove_password_details(self): + """ + Only call this if :meth:`is_shared_link_settings_remove_password_details` is true. + + :rtype: SharedLinkSettingsRemovePasswordDetails + """ + if not self.is_shared_link_settings_remove_password_details(): + raise AttributeError("tag 'shared_link_settings_remove_password_details' not set") + return self._value + + def get_shared_link_share_details(self): + """ + Only call this if :meth:`is_shared_link_share_details` is true. + + :rtype: SharedLinkShareDetails + """ + if not self.is_shared_link_share_details(): + raise AttributeError("tag 'shared_link_share_details' not set") + return self._value + + def get_shared_link_view_details(self): + """ + Only call this if :meth:`is_shared_link_view_details` is true. + + :rtype: SharedLinkViewDetails + """ + if not self.is_shared_link_view_details(): + raise AttributeError("tag 'shared_link_view_details' not set") + return self._value + + def get_shared_note_opened_details(self): + """ + Only call this if :meth:`is_shared_note_opened_details` is true. + + :rtype: SharedNoteOpenedDetails + """ + if not self.is_shared_note_opened_details(): + raise AttributeError("tag 'shared_note_opened_details' not set") + return self._value + + def get_shmodel_group_share_details(self): + """ + Only call this if :meth:`is_shmodel_group_share_details` is true. + + :rtype: ShmodelGroupShareDetails + """ + if not self.is_shmodel_group_share_details(): + raise AttributeError("tag 'shmodel_group_share_details' not set") + return self._value + + def get_showcase_access_granted_details(self): + """ + Only call this if :meth:`is_showcase_access_granted_details` is true. + + :rtype: ShowcaseAccessGrantedDetails + """ + if not self.is_showcase_access_granted_details(): + raise AttributeError("tag 'showcase_access_granted_details' not set") + return self._value + + def get_showcase_add_member_details(self): + """ + Only call this if :meth:`is_showcase_add_member_details` is true. + + :rtype: ShowcaseAddMemberDetails + """ + if not self.is_showcase_add_member_details(): + raise AttributeError("tag 'showcase_add_member_details' not set") + return self._value + + def get_showcase_archived_details(self): + """ + Only call this if :meth:`is_showcase_archived_details` is true. + + :rtype: ShowcaseArchivedDetails + """ + if not self.is_showcase_archived_details(): + raise AttributeError("tag 'showcase_archived_details' not set") + return self._value + + def get_showcase_created_details(self): + """ + Only call this if :meth:`is_showcase_created_details` is true. + + :rtype: ShowcaseCreatedDetails + """ + if not self.is_showcase_created_details(): + raise AttributeError("tag 'showcase_created_details' not set") + return self._value + + def get_showcase_delete_comment_details(self): + """ + Only call this if :meth:`is_showcase_delete_comment_details` is true. + + :rtype: ShowcaseDeleteCommentDetails + """ + if not self.is_showcase_delete_comment_details(): + raise AttributeError("tag 'showcase_delete_comment_details' not set") + return self._value + + def get_showcase_edited_details(self): + """ + Only call this if :meth:`is_showcase_edited_details` is true. + + :rtype: ShowcaseEditedDetails + """ + if not self.is_showcase_edited_details(): + raise AttributeError("tag 'showcase_edited_details' not set") + return self._value + + def get_showcase_edit_comment_details(self): + """ + Only call this if :meth:`is_showcase_edit_comment_details` is true. + + :rtype: ShowcaseEditCommentDetails + """ + if not self.is_showcase_edit_comment_details(): + raise AttributeError("tag 'showcase_edit_comment_details' not set") + return self._value + + def get_showcase_file_added_details(self): + """ + Only call this if :meth:`is_showcase_file_added_details` is true. + + :rtype: ShowcaseFileAddedDetails + """ + if not self.is_showcase_file_added_details(): + raise AttributeError("tag 'showcase_file_added_details' not set") + return self._value + + def get_showcase_file_download_details(self): + """ + Only call this if :meth:`is_showcase_file_download_details` is true. + + :rtype: ShowcaseFileDownloadDetails + """ + if not self.is_showcase_file_download_details(): + raise AttributeError("tag 'showcase_file_download_details' not set") + return self._value + + def get_showcase_file_removed_details(self): + """ + Only call this if :meth:`is_showcase_file_removed_details` is true. + + :rtype: ShowcaseFileRemovedDetails + """ + if not self.is_showcase_file_removed_details(): + raise AttributeError("tag 'showcase_file_removed_details' not set") + return self._value + + def get_showcase_file_view_details(self): + """ + Only call this if :meth:`is_showcase_file_view_details` is true. + + :rtype: ShowcaseFileViewDetails + """ + if not self.is_showcase_file_view_details(): + raise AttributeError("tag 'showcase_file_view_details' not set") + return self._value + + def get_showcase_permanently_deleted_details(self): + """ + Only call this if :meth:`is_showcase_permanently_deleted_details` is true. + + :rtype: ShowcasePermanentlyDeletedDetails + """ + if not self.is_showcase_permanently_deleted_details(): + raise AttributeError("tag 'showcase_permanently_deleted_details' not set") + return self._value + + def get_showcase_post_comment_details(self): + """ + Only call this if :meth:`is_showcase_post_comment_details` is true. + + :rtype: ShowcasePostCommentDetails + """ + if not self.is_showcase_post_comment_details(): + raise AttributeError("tag 'showcase_post_comment_details' not set") + return self._value + + def get_showcase_remove_member_details(self): + """ + Only call this if :meth:`is_showcase_remove_member_details` is true. + + :rtype: ShowcaseRemoveMemberDetails + """ + if not self.is_showcase_remove_member_details(): + raise AttributeError("tag 'showcase_remove_member_details' not set") + return self._value + + def get_showcase_renamed_details(self): + """ + Only call this if :meth:`is_showcase_renamed_details` is true. + + :rtype: ShowcaseRenamedDetails + """ + if not self.is_showcase_renamed_details(): + raise AttributeError("tag 'showcase_renamed_details' not set") + return self._value + + def get_showcase_request_access_details(self): + """ + Only call this if :meth:`is_showcase_request_access_details` is true. + + :rtype: ShowcaseRequestAccessDetails + """ + if not self.is_showcase_request_access_details(): + raise AttributeError("tag 'showcase_request_access_details' not set") + return self._value + + def get_showcase_resolve_comment_details(self): + """ + Only call this if :meth:`is_showcase_resolve_comment_details` is true. + + :rtype: ShowcaseResolveCommentDetails + """ + if not self.is_showcase_resolve_comment_details(): + raise AttributeError("tag 'showcase_resolve_comment_details' not set") + return self._value + + def get_showcase_restored_details(self): + """ + Only call this if :meth:`is_showcase_restored_details` is true. + + :rtype: ShowcaseRestoredDetails + """ + if not self.is_showcase_restored_details(): + raise AttributeError("tag 'showcase_restored_details' not set") + return self._value + + def get_showcase_trashed_details(self): + """ + Only call this if :meth:`is_showcase_trashed_details` is true. + + :rtype: ShowcaseTrashedDetails + """ + if not self.is_showcase_trashed_details(): + raise AttributeError("tag 'showcase_trashed_details' not set") + return self._value + + def get_showcase_trashed_deprecated_details(self): + """ + Only call this if :meth:`is_showcase_trashed_deprecated_details` is true. + + :rtype: ShowcaseTrashedDeprecatedDetails + """ + if not self.is_showcase_trashed_deprecated_details(): + raise AttributeError("tag 'showcase_trashed_deprecated_details' not set") + return self._value + + def get_showcase_unresolve_comment_details(self): + """ + Only call this if :meth:`is_showcase_unresolve_comment_details` is true. + + :rtype: ShowcaseUnresolveCommentDetails + """ + if not self.is_showcase_unresolve_comment_details(): + raise AttributeError("tag 'showcase_unresolve_comment_details' not set") + return self._value + + def get_showcase_untrashed_details(self): + """ + Only call this if :meth:`is_showcase_untrashed_details` is true. + + :rtype: ShowcaseUntrashedDetails + """ + if not self.is_showcase_untrashed_details(): + raise AttributeError("tag 'showcase_untrashed_details' not set") + return self._value + + def get_showcase_untrashed_deprecated_details(self): + """ + Only call this if :meth:`is_showcase_untrashed_deprecated_details` is true. + + :rtype: ShowcaseUntrashedDeprecatedDetails + """ + if not self.is_showcase_untrashed_deprecated_details(): + raise AttributeError("tag 'showcase_untrashed_deprecated_details' not set") + return self._value + + def get_showcase_view_details(self): + """ + Only call this if :meth:`is_showcase_view_details` is true. + + :rtype: ShowcaseViewDetails + """ + if not self.is_showcase_view_details(): + raise AttributeError("tag 'showcase_view_details' not set") + return self._value + + def get_sso_add_cert_details(self): + """ + Only call this if :meth:`is_sso_add_cert_details` is true. + + :rtype: SsoAddCertDetails + """ + if not self.is_sso_add_cert_details(): + raise AttributeError("tag 'sso_add_cert_details' not set") + return self._value + + def get_sso_add_login_url_details(self): + """ + Only call this if :meth:`is_sso_add_login_url_details` is true. + + :rtype: SsoAddLoginUrlDetails + """ + if not self.is_sso_add_login_url_details(): + raise AttributeError("tag 'sso_add_login_url_details' not set") + return self._value + + def get_sso_add_logout_url_details(self): + """ + Only call this if :meth:`is_sso_add_logout_url_details` is true. + + :rtype: SsoAddLogoutUrlDetails + """ + if not self.is_sso_add_logout_url_details(): + raise AttributeError("tag 'sso_add_logout_url_details' not set") + return self._value + + def get_sso_change_cert_details(self): + """ + Only call this if :meth:`is_sso_change_cert_details` is true. + + :rtype: SsoChangeCertDetails + """ + if not self.is_sso_change_cert_details(): + raise AttributeError("tag 'sso_change_cert_details' not set") + return self._value + + def get_sso_change_login_url_details(self): + """ + Only call this if :meth:`is_sso_change_login_url_details` is true. + + :rtype: SsoChangeLoginUrlDetails + """ + if not self.is_sso_change_login_url_details(): + raise AttributeError("tag 'sso_change_login_url_details' not set") + return self._value + + def get_sso_change_logout_url_details(self): + """ + Only call this if :meth:`is_sso_change_logout_url_details` is true. + + :rtype: SsoChangeLogoutUrlDetails + """ + if not self.is_sso_change_logout_url_details(): + raise AttributeError("tag 'sso_change_logout_url_details' not set") + return self._value + + def get_sso_change_saml_identity_mode_details(self): + """ + Only call this if :meth:`is_sso_change_saml_identity_mode_details` is true. + + :rtype: SsoChangeSamlIdentityModeDetails + """ + if not self.is_sso_change_saml_identity_mode_details(): + raise AttributeError("tag 'sso_change_saml_identity_mode_details' not set") + return self._value + + def get_sso_remove_cert_details(self): + """ + Only call this if :meth:`is_sso_remove_cert_details` is true. + + :rtype: SsoRemoveCertDetails + """ + if not self.is_sso_remove_cert_details(): + raise AttributeError("tag 'sso_remove_cert_details' not set") + return self._value + + def get_sso_remove_login_url_details(self): + """ + Only call this if :meth:`is_sso_remove_login_url_details` is true. + + :rtype: SsoRemoveLoginUrlDetails + """ + if not self.is_sso_remove_login_url_details(): + raise AttributeError("tag 'sso_remove_login_url_details' not set") + return self._value + + def get_sso_remove_logout_url_details(self): + """ + Only call this if :meth:`is_sso_remove_logout_url_details` is true. + + :rtype: SsoRemoveLogoutUrlDetails + """ + if not self.is_sso_remove_logout_url_details(): + raise AttributeError("tag 'sso_remove_logout_url_details' not set") + return self._value + + def get_team_folder_change_status_details(self): + """ + Only call this if :meth:`is_team_folder_change_status_details` is true. + + :rtype: TeamFolderChangeStatusDetails + """ + if not self.is_team_folder_change_status_details(): + raise AttributeError("tag 'team_folder_change_status_details' not set") + return self._value + + def get_team_folder_create_details(self): + """ + Only call this if :meth:`is_team_folder_create_details` is true. + + :rtype: TeamFolderCreateDetails + """ + if not self.is_team_folder_create_details(): + raise AttributeError("tag 'team_folder_create_details' not set") + return self._value + + def get_team_folder_downgrade_details(self): + """ + Only call this if :meth:`is_team_folder_downgrade_details` is true. + + :rtype: TeamFolderDowngradeDetails + """ + if not self.is_team_folder_downgrade_details(): + raise AttributeError("tag 'team_folder_downgrade_details' not set") + return self._value + + def get_team_folder_permanently_delete_details(self): + """ + Only call this if :meth:`is_team_folder_permanently_delete_details` is true. + + :rtype: TeamFolderPermanentlyDeleteDetails + """ + if not self.is_team_folder_permanently_delete_details(): + raise AttributeError("tag 'team_folder_permanently_delete_details' not set") + return self._value + + def get_team_folder_rename_details(self): + """ + Only call this if :meth:`is_team_folder_rename_details` is true. + + :rtype: TeamFolderRenameDetails + """ + if not self.is_team_folder_rename_details(): + raise AttributeError("tag 'team_folder_rename_details' not set") + return self._value + + def get_team_selective_sync_settings_changed_details(self): + """ + Only call this if :meth:`is_team_selective_sync_settings_changed_details` is true. + + :rtype: TeamSelectiveSyncSettingsChangedDetails + """ + if not self.is_team_selective_sync_settings_changed_details(): + raise AttributeError("tag 'team_selective_sync_settings_changed_details' not set") + return self._value + + def get_account_capture_change_policy_details(self): + """ + Only call this if :meth:`is_account_capture_change_policy_details` is true. + + :rtype: AccountCaptureChangePolicyDetails + """ + if not self.is_account_capture_change_policy_details(): + raise AttributeError("tag 'account_capture_change_policy_details' not set") + return self._value + + def get_allow_download_disabled_details(self): + """ + Only call this if :meth:`is_allow_download_disabled_details` is true. + + :rtype: AllowDownloadDisabledDetails + """ + if not self.is_allow_download_disabled_details(): + raise AttributeError("tag 'allow_download_disabled_details' not set") + return self._value + + def get_allow_download_enabled_details(self): + """ + Only call this if :meth:`is_allow_download_enabled_details` is true. + + :rtype: AllowDownloadEnabledDetails + """ + if not self.is_allow_download_enabled_details(): + raise AttributeError("tag 'allow_download_enabled_details' not set") + return self._value + + def get_camera_uploads_policy_changed_details(self): + """ + Only call this if :meth:`is_camera_uploads_policy_changed_details` is true. + + :rtype: CameraUploadsPolicyChangedDetails + """ + if not self.is_camera_uploads_policy_changed_details(): + raise AttributeError("tag 'camera_uploads_policy_changed_details' not set") + return self._value + + def get_data_placement_restriction_change_policy_details(self): + """ + Only call this if :meth:`is_data_placement_restriction_change_policy_details` is true. + + :rtype: DataPlacementRestrictionChangePolicyDetails + """ + if not self.is_data_placement_restriction_change_policy_details(): + raise AttributeError("tag 'data_placement_restriction_change_policy_details' not set") + return self._value + + def get_data_placement_restriction_satisfy_policy_details(self): + """ + Only call this if :meth:`is_data_placement_restriction_satisfy_policy_details` is true. + + :rtype: DataPlacementRestrictionSatisfyPolicyDetails + """ + if not self.is_data_placement_restriction_satisfy_policy_details(): + raise AttributeError("tag 'data_placement_restriction_satisfy_policy_details' not set") + return self._value + + def get_device_approvals_add_exception_details(self): + """ + Only call this if :meth:`is_device_approvals_add_exception_details` is true. + + :rtype: DeviceApprovalsAddExceptionDetails + """ + if not self.is_device_approvals_add_exception_details(): + raise AttributeError("tag 'device_approvals_add_exception_details' not set") + return self._value + + def get_device_approvals_change_desktop_policy_details(self): + """ + Only call this if :meth:`is_device_approvals_change_desktop_policy_details` is true. + + :rtype: DeviceApprovalsChangeDesktopPolicyDetails + """ + if not self.is_device_approvals_change_desktop_policy_details(): + raise AttributeError("tag 'device_approvals_change_desktop_policy_details' not set") + return self._value + + def get_device_approvals_change_mobile_policy_details(self): + """ + Only call this if :meth:`is_device_approvals_change_mobile_policy_details` is true. + + :rtype: DeviceApprovalsChangeMobilePolicyDetails + """ + if not self.is_device_approvals_change_mobile_policy_details(): + raise AttributeError("tag 'device_approvals_change_mobile_policy_details' not set") + return self._value + + def get_device_approvals_change_overage_action_details(self): + """ + Only call this if :meth:`is_device_approvals_change_overage_action_details` is true. + + :rtype: DeviceApprovalsChangeOverageActionDetails + """ + if not self.is_device_approvals_change_overage_action_details(): + raise AttributeError("tag 'device_approvals_change_overage_action_details' not set") + return self._value + + def get_device_approvals_change_unlink_action_details(self): + """ + Only call this if :meth:`is_device_approvals_change_unlink_action_details` is true. + + :rtype: DeviceApprovalsChangeUnlinkActionDetails + """ + if not self.is_device_approvals_change_unlink_action_details(): + raise AttributeError("tag 'device_approvals_change_unlink_action_details' not set") + return self._value + + def get_device_approvals_remove_exception_details(self): + """ + Only call this if :meth:`is_device_approvals_remove_exception_details` is true. + + :rtype: DeviceApprovalsRemoveExceptionDetails + """ + if not self.is_device_approvals_remove_exception_details(): + raise AttributeError("tag 'device_approvals_remove_exception_details' not set") + return self._value + + def get_directory_restrictions_add_members_details(self): + """ + Only call this if :meth:`is_directory_restrictions_add_members_details` is true. + + :rtype: DirectoryRestrictionsAddMembersDetails + """ + if not self.is_directory_restrictions_add_members_details(): + raise AttributeError("tag 'directory_restrictions_add_members_details' not set") + return self._value + + def get_directory_restrictions_remove_members_details(self): + """ + Only call this if :meth:`is_directory_restrictions_remove_members_details` is true. + + :rtype: DirectoryRestrictionsRemoveMembersDetails + """ + if not self.is_directory_restrictions_remove_members_details(): + raise AttributeError("tag 'directory_restrictions_remove_members_details' not set") + return self._value + + def get_emm_add_exception_details(self): + """ + Only call this if :meth:`is_emm_add_exception_details` is true. + + :rtype: EmmAddExceptionDetails + """ + if not self.is_emm_add_exception_details(): + raise AttributeError("tag 'emm_add_exception_details' not set") + return self._value + + def get_emm_change_policy_details(self): + """ + Only call this if :meth:`is_emm_change_policy_details` is true. + + :rtype: EmmChangePolicyDetails + """ + if not self.is_emm_change_policy_details(): + raise AttributeError("tag 'emm_change_policy_details' not set") + return self._value + + def get_emm_remove_exception_details(self): + """ + Only call this if :meth:`is_emm_remove_exception_details` is true. + + :rtype: EmmRemoveExceptionDetails + """ + if not self.is_emm_remove_exception_details(): + raise AttributeError("tag 'emm_remove_exception_details' not set") + return self._value + + def get_extended_version_history_change_policy_details(self): + """ + Only call this if :meth:`is_extended_version_history_change_policy_details` is true. + + :rtype: ExtendedVersionHistoryChangePolicyDetails + """ + if not self.is_extended_version_history_change_policy_details(): + raise AttributeError("tag 'extended_version_history_change_policy_details' not set") + return self._value + + def get_file_comments_change_policy_details(self): + """ + Only call this if :meth:`is_file_comments_change_policy_details` is true. + + :rtype: FileCommentsChangePolicyDetails + """ + if not self.is_file_comments_change_policy_details(): + raise AttributeError("tag 'file_comments_change_policy_details' not set") + return self._value + + def get_file_locking_policy_changed_details(self): + """ + Only call this if :meth:`is_file_locking_policy_changed_details` is true. + + :rtype: FileLockingPolicyChangedDetails + """ + if not self.is_file_locking_policy_changed_details(): + raise AttributeError("tag 'file_locking_policy_changed_details' not set") + return self._value + + def get_file_requests_change_policy_details(self): + """ + Only call this if :meth:`is_file_requests_change_policy_details` is true. + + :rtype: FileRequestsChangePolicyDetails + """ + if not self.is_file_requests_change_policy_details(): + raise AttributeError("tag 'file_requests_change_policy_details' not set") + return self._value + + def get_file_requests_emails_enabled_details(self): + """ + Only call this if :meth:`is_file_requests_emails_enabled_details` is true. + + :rtype: FileRequestsEmailsEnabledDetails + """ + if not self.is_file_requests_emails_enabled_details(): + raise AttributeError("tag 'file_requests_emails_enabled_details' not set") + return self._value + + def get_file_requests_emails_restricted_to_team_only_details(self): + """ + Only call this if :meth:`is_file_requests_emails_restricted_to_team_only_details` is true. + + :rtype: FileRequestsEmailsRestrictedToTeamOnlyDetails + """ + if not self.is_file_requests_emails_restricted_to_team_only_details(): + raise AttributeError("tag 'file_requests_emails_restricted_to_team_only_details' not set") + return self._value + + def get_file_transfers_policy_changed_details(self): + """ + Only call this if :meth:`is_file_transfers_policy_changed_details` is true. + + :rtype: FileTransfersPolicyChangedDetails + """ + if not self.is_file_transfers_policy_changed_details(): + raise AttributeError("tag 'file_transfers_policy_changed_details' not set") + return self._value + + def get_google_sso_change_policy_details(self): + """ + Only call this if :meth:`is_google_sso_change_policy_details` is true. + + :rtype: GoogleSsoChangePolicyDetails + """ + if not self.is_google_sso_change_policy_details(): + raise AttributeError("tag 'google_sso_change_policy_details' not set") + return self._value + + def get_group_user_management_change_policy_details(self): + """ + Only call this if :meth:`is_group_user_management_change_policy_details` is true. + + :rtype: GroupUserManagementChangePolicyDetails + """ + if not self.is_group_user_management_change_policy_details(): + raise AttributeError("tag 'group_user_management_change_policy_details' not set") + return self._value + + def get_integration_policy_changed_details(self): + """ + Only call this if :meth:`is_integration_policy_changed_details` is true. + + :rtype: IntegrationPolicyChangedDetails + """ + if not self.is_integration_policy_changed_details(): + raise AttributeError("tag 'integration_policy_changed_details' not set") + return self._value + + def get_member_requests_change_policy_details(self): + """ + Only call this if :meth:`is_member_requests_change_policy_details` is true. + + :rtype: MemberRequestsChangePolicyDetails + """ + if not self.is_member_requests_change_policy_details(): + raise AttributeError("tag 'member_requests_change_policy_details' not set") + return self._value + + def get_member_send_invite_policy_changed_details(self): + """ + Only call this if :meth:`is_member_send_invite_policy_changed_details` is true. + + :rtype: MemberSendInvitePolicyChangedDetails + """ + if not self.is_member_send_invite_policy_changed_details(): + raise AttributeError("tag 'member_send_invite_policy_changed_details' not set") + return self._value + + def get_member_space_limits_add_exception_details(self): + """ + Only call this if :meth:`is_member_space_limits_add_exception_details` is true. + + :rtype: MemberSpaceLimitsAddExceptionDetails + """ + if not self.is_member_space_limits_add_exception_details(): + raise AttributeError("tag 'member_space_limits_add_exception_details' not set") + return self._value + + def get_member_space_limits_change_caps_type_policy_details(self): + """ + Only call this if :meth:`is_member_space_limits_change_caps_type_policy_details` is true. + + :rtype: MemberSpaceLimitsChangeCapsTypePolicyDetails + """ + if not self.is_member_space_limits_change_caps_type_policy_details(): + raise AttributeError("tag 'member_space_limits_change_caps_type_policy_details' not set") + return self._value + + def get_member_space_limits_change_policy_details(self): + """ + Only call this if :meth:`is_member_space_limits_change_policy_details` is true. + + :rtype: MemberSpaceLimitsChangePolicyDetails + """ + if not self.is_member_space_limits_change_policy_details(): + raise AttributeError("tag 'member_space_limits_change_policy_details' not set") + return self._value + + def get_member_space_limits_remove_exception_details(self): + """ + Only call this if :meth:`is_member_space_limits_remove_exception_details` is true. + + :rtype: MemberSpaceLimitsRemoveExceptionDetails + """ + if not self.is_member_space_limits_remove_exception_details(): + raise AttributeError("tag 'member_space_limits_remove_exception_details' not set") + return self._value + + def get_member_suggestions_change_policy_details(self): + """ + Only call this if :meth:`is_member_suggestions_change_policy_details` is true. + + :rtype: MemberSuggestionsChangePolicyDetails + """ + if not self.is_member_suggestions_change_policy_details(): + raise AttributeError("tag 'member_suggestions_change_policy_details' not set") + return self._value + + def get_microsoft_office_addin_change_policy_details(self): + """ + Only call this if :meth:`is_microsoft_office_addin_change_policy_details` is true. + + :rtype: MicrosoftOfficeAddinChangePolicyDetails + """ + if not self.is_microsoft_office_addin_change_policy_details(): + raise AttributeError("tag 'microsoft_office_addin_change_policy_details' not set") + return self._value + + def get_network_control_change_policy_details(self): + """ + Only call this if :meth:`is_network_control_change_policy_details` is true. + + :rtype: NetworkControlChangePolicyDetails + """ + if not self.is_network_control_change_policy_details(): + raise AttributeError("tag 'network_control_change_policy_details' not set") + return self._value + + def get_paper_change_deployment_policy_details(self): + """ + Only call this if :meth:`is_paper_change_deployment_policy_details` is true. + + :rtype: PaperChangeDeploymentPolicyDetails + """ + if not self.is_paper_change_deployment_policy_details(): + raise AttributeError("tag 'paper_change_deployment_policy_details' not set") + return self._value + + def get_paper_change_member_link_policy_details(self): + """ + Only call this if :meth:`is_paper_change_member_link_policy_details` is true. + + :rtype: PaperChangeMemberLinkPolicyDetails + """ + if not self.is_paper_change_member_link_policy_details(): + raise AttributeError("tag 'paper_change_member_link_policy_details' not set") + return self._value + + def get_paper_change_member_policy_details(self): + """ + Only call this if :meth:`is_paper_change_member_policy_details` is true. + + :rtype: PaperChangeMemberPolicyDetails + """ + if not self.is_paper_change_member_policy_details(): + raise AttributeError("tag 'paper_change_member_policy_details' not set") + return self._value + + def get_paper_change_policy_details(self): + """ + Only call this if :meth:`is_paper_change_policy_details` is true. + + :rtype: PaperChangePolicyDetails + """ + if not self.is_paper_change_policy_details(): + raise AttributeError("tag 'paper_change_policy_details' not set") + return self._value + + def get_paper_default_folder_policy_changed_details(self): + """ + Only call this if :meth:`is_paper_default_folder_policy_changed_details` is true. + + :rtype: PaperDefaultFolderPolicyChangedDetails + """ + if not self.is_paper_default_folder_policy_changed_details(): + raise AttributeError("tag 'paper_default_folder_policy_changed_details' not set") + return self._value + + def get_paper_desktop_policy_changed_details(self): + """ + Only call this if :meth:`is_paper_desktop_policy_changed_details` is true. + + :rtype: PaperDesktopPolicyChangedDetails + """ + if not self.is_paper_desktop_policy_changed_details(): + raise AttributeError("tag 'paper_desktop_policy_changed_details' not set") + return self._value + + def get_paper_enabled_users_group_addition_details(self): + """ + Only call this if :meth:`is_paper_enabled_users_group_addition_details` is true. + + :rtype: PaperEnabledUsersGroupAdditionDetails + """ + if not self.is_paper_enabled_users_group_addition_details(): + raise AttributeError("tag 'paper_enabled_users_group_addition_details' not set") + return self._value + + def get_paper_enabled_users_group_removal_details(self): + """ + Only call this if :meth:`is_paper_enabled_users_group_removal_details` is true. + + :rtype: PaperEnabledUsersGroupRemovalDetails + """ + if not self.is_paper_enabled_users_group_removal_details(): + raise AttributeError("tag 'paper_enabled_users_group_removal_details' not set") + return self._value + + def get_password_strength_requirements_change_policy_details(self): + """ + Only call this if :meth:`is_password_strength_requirements_change_policy_details` is true. + + :rtype: PasswordStrengthRequirementsChangePolicyDetails + """ + if not self.is_password_strength_requirements_change_policy_details(): + raise AttributeError("tag 'password_strength_requirements_change_policy_details' not set") + return self._value + + def get_permanent_delete_change_policy_details(self): + """ + Only call this if :meth:`is_permanent_delete_change_policy_details` is true. + + :rtype: PermanentDeleteChangePolicyDetails + """ + if not self.is_permanent_delete_change_policy_details(): + raise AttributeError("tag 'permanent_delete_change_policy_details' not set") + return self._value + + def get_reseller_support_change_policy_details(self): + """ + Only call this if :meth:`is_reseller_support_change_policy_details` is true. + + :rtype: ResellerSupportChangePolicyDetails + """ + if not self.is_reseller_support_change_policy_details(): + raise AttributeError("tag 'reseller_support_change_policy_details' not set") + return self._value + + def get_rewind_policy_changed_details(self): + """ + Only call this if :meth:`is_rewind_policy_changed_details` is true. + + :rtype: RewindPolicyChangedDetails + """ + if not self.is_rewind_policy_changed_details(): + raise AttributeError("tag 'rewind_policy_changed_details' not set") + return self._value + + def get_sharing_change_folder_join_policy_details(self): + """ + Only call this if :meth:`is_sharing_change_folder_join_policy_details` is true. + + :rtype: SharingChangeFolderJoinPolicyDetails + """ + if not self.is_sharing_change_folder_join_policy_details(): + raise AttributeError("tag 'sharing_change_folder_join_policy_details' not set") + return self._value + + def get_sharing_change_link_policy_details(self): + """ + Only call this if :meth:`is_sharing_change_link_policy_details` is true. + + :rtype: SharingChangeLinkPolicyDetails + """ + if not self.is_sharing_change_link_policy_details(): + raise AttributeError("tag 'sharing_change_link_policy_details' not set") + return self._value + + def get_sharing_change_member_policy_details(self): + """ + Only call this if :meth:`is_sharing_change_member_policy_details` is true. + + :rtype: SharingChangeMemberPolicyDetails + """ + if not self.is_sharing_change_member_policy_details(): + raise AttributeError("tag 'sharing_change_member_policy_details' not set") + return self._value + + def get_showcase_change_download_policy_details(self): + """ + Only call this if :meth:`is_showcase_change_download_policy_details` is true. + + :rtype: ShowcaseChangeDownloadPolicyDetails + """ + if not self.is_showcase_change_download_policy_details(): + raise AttributeError("tag 'showcase_change_download_policy_details' not set") + return self._value + + def get_showcase_change_enabled_policy_details(self): + """ + Only call this if :meth:`is_showcase_change_enabled_policy_details` is true. + + :rtype: ShowcaseChangeEnabledPolicyDetails + """ + if not self.is_showcase_change_enabled_policy_details(): + raise AttributeError("tag 'showcase_change_enabled_policy_details' not set") + return self._value + + def get_showcase_change_external_sharing_policy_details(self): + """ + Only call this if :meth:`is_showcase_change_external_sharing_policy_details` is true. + + :rtype: ShowcaseChangeExternalSharingPolicyDetails + """ + if not self.is_showcase_change_external_sharing_policy_details(): + raise AttributeError("tag 'showcase_change_external_sharing_policy_details' not set") + return self._value + + def get_smarter_smart_sync_policy_changed_details(self): + """ + Only call this if :meth:`is_smarter_smart_sync_policy_changed_details` is true. + + :rtype: SmarterSmartSyncPolicyChangedDetails + """ + if not self.is_smarter_smart_sync_policy_changed_details(): + raise AttributeError("tag 'smarter_smart_sync_policy_changed_details' not set") + return self._value + + def get_smart_sync_change_policy_details(self): + """ + Only call this if :meth:`is_smart_sync_change_policy_details` is true. + + :rtype: SmartSyncChangePolicyDetails + """ + if not self.is_smart_sync_change_policy_details(): + raise AttributeError("tag 'smart_sync_change_policy_details' not set") + return self._value + + def get_smart_sync_not_opt_out_details(self): + """ + Only call this if :meth:`is_smart_sync_not_opt_out_details` is true. + + :rtype: SmartSyncNotOptOutDetails + """ + if not self.is_smart_sync_not_opt_out_details(): + raise AttributeError("tag 'smart_sync_not_opt_out_details' not set") + return self._value + + def get_smart_sync_opt_out_details(self): + """ + Only call this if :meth:`is_smart_sync_opt_out_details` is true. + + :rtype: SmartSyncOptOutDetails + """ + if not self.is_smart_sync_opt_out_details(): + raise AttributeError("tag 'smart_sync_opt_out_details' not set") + return self._value + + def get_sso_change_policy_details(self): + """ + Only call this if :meth:`is_sso_change_policy_details` is true. + + :rtype: SsoChangePolicyDetails + """ + if not self.is_sso_change_policy_details(): + raise AttributeError("tag 'sso_change_policy_details' not set") + return self._value + + def get_team_extensions_policy_changed_details(self): + """ + Only call this if :meth:`is_team_extensions_policy_changed_details` is true. + + :rtype: TeamExtensionsPolicyChangedDetails + """ + if not self.is_team_extensions_policy_changed_details(): + raise AttributeError("tag 'team_extensions_policy_changed_details' not set") + return self._value + + def get_team_selective_sync_policy_changed_details(self): + """ + Only call this if :meth:`is_team_selective_sync_policy_changed_details` is true. + + :rtype: TeamSelectiveSyncPolicyChangedDetails + """ + if not self.is_team_selective_sync_policy_changed_details(): + raise AttributeError("tag 'team_selective_sync_policy_changed_details' not set") + return self._value + + def get_team_sharing_whitelist_subjects_changed_details(self): + """ + Only call this if :meth:`is_team_sharing_whitelist_subjects_changed_details` is true. + + :rtype: TeamSharingWhitelistSubjectsChangedDetails + """ + if not self.is_team_sharing_whitelist_subjects_changed_details(): + raise AttributeError("tag 'team_sharing_whitelist_subjects_changed_details' not set") + return self._value + + def get_tfa_add_exception_details(self): + """ + Only call this if :meth:`is_tfa_add_exception_details` is true. + + :rtype: TfaAddExceptionDetails + """ + if not self.is_tfa_add_exception_details(): + raise AttributeError("tag 'tfa_add_exception_details' not set") + return self._value + + def get_tfa_change_policy_details(self): + """ + Only call this if :meth:`is_tfa_change_policy_details` is true. + + :rtype: TfaChangePolicyDetails + """ + if not self.is_tfa_change_policy_details(): + raise AttributeError("tag 'tfa_change_policy_details' not set") + return self._value + + def get_tfa_remove_exception_details(self): + """ + Only call this if :meth:`is_tfa_remove_exception_details` is true. + + :rtype: TfaRemoveExceptionDetails + """ + if not self.is_tfa_remove_exception_details(): + raise AttributeError("tag 'tfa_remove_exception_details' not set") + return self._value + + def get_two_account_change_policy_details(self): + """ + Only call this if :meth:`is_two_account_change_policy_details` is true. + + :rtype: TwoAccountChangePolicyDetails + """ + if not self.is_two_account_change_policy_details(): + raise AttributeError("tag 'two_account_change_policy_details' not set") + return self._value + + def get_viewer_info_policy_changed_details(self): + """ + Only call this if :meth:`is_viewer_info_policy_changed_details` is true. + + :rtype: ViewerInfoPolicyChangedDetails + """ + if not self.is_viewer_info_policy_changed_details(): + raise AttributeError("tag 'viewer_info_policy_changed_details' not set") + return self._value + + def get_watermarking_policy_changed_details(self): + """ + Only call this if :meth:`is_watermarking_policy_changed_details` is true. + + :rtype: WatermarkingPolicyChangedDetails + """ + if not self.is_watermarking_policy_changed_details(): + raise AttributeError("tag 'watermarking_policy_changed_details' not set") + return self._value + + def get_web_sessions_change_active_session_limit_details(self): + """ + Only call this if :meth:`is_web_sessions_change_active_session_limit_details` is true. + + :rtype: WebSessionsChangeActiveSessionLimitDetails + """ + if not self.is_web_sessions_change_active_session_limit_details(): + raise AttributeError("tag 'web_sessions_change_active_session_limit_details' not set") + return self._value + + def get_web_sessions_change_fixed_length_policy_details(self): + """ + Only call this if :meth:`is_web_sessions_change_fixed_length_policy_details` is true. + + :rtype: WebSessionsChangeFixedLengthPolicyDetails + """ + if not self.is_web_sessions_change_fixed_length_policy_details(): + raise AttributeError("tag 'web_sessions_change_fixed_length_policy_details' not set") + return self._value + + def get_web_sessions_change_idle_length_policy_details(self): + """ + Only call this if :meth:`is_web_sessions_change_idle_length_policy_details` is true. + + :rtype: WebSessionsChangeIdleLengthPolicyDetails + """ + if not self.is_web_sessions_change_idle_length_policy_details(): + raise AttributeError("tag 'web_sessions_change_idle_length_policy_details' not set") + return self._value + + def get_team_merge_from_details(self): + """ + Only call this if :meth:`is_team_merge_from_details` is true. + + :rtype: TeamMergeFromDetails + """ + if not self.is_team_merge_from_details(): + raise AttributeError("tag 'team_merge_from_details' not set") + return self._value + + def get_team_merge_to_details(self): + """ + Only call this if :meth:`is_team_merge_to_details` is true. + + :rtype: TeamMergeToDetails + """ + if not self.is_team_merge_to_details(): + raise AttributeError("tag 'team_merge_to_details' not set") + return self._value + + def get_team_profile_add_logo_details(self): + """ + Only call this if :meth:`is_team_profile_add_logo_details` is true. + + :rtype: TeamProfileAddLogoDetails + """ + if not self.is_team_profile_add_logo_details(): + raise AttributeError("tag 'team_profile_add_logo_details' not set") + return self._value + + def get_team_profile_change_default_language_details(self): + """ + Only call this if :meth:`is_team_profile_change_default_language_details` is true. + + :rtype: TeamProfileChangeDefaultLanguageDetails + """ + if not self.is_team_profile_change_default_language_details(): + raise AttributeError("tag 'team_profile_change_default_language_details' not set") + return self._value + + def get_team_profile_change_logo_details(self): + """ + Only call this if :meth:`is_team_profile_change_logo_details` is true. + + :rtype: TeamProfileChangeLogoDetails + """ + if not self.is_team_profile_change_logo_details(): + raise AttributeError("tag 'team_profile_change_logo_details' not set") + return self._value + + def get_team_profile_change_name_details(self): + """ + Only call this if :meth:`is_team_profile_change_name_details` is true. + + :rtype: TeamProfileChangeNameDetails + """ + if not self.is_team_profile_change_name_details(): + raise AttributeError("tag 'team_profile_change_name_details' not set") + return self._value + + def get_team_profile_remove_logo_details(self): + """ + Only call this if :meth:`is_team_profile_remove_logo_details` is true. + + :rtype: TeamProfileRemoveLogoDetails + """ + if not self.is_team_profile_remove_logo_details(): + raise AttributeError("tag 'team_profile_remove_logo_details' not set") + return self._value + + def get_tfa_add_backup_phone_details(self): + """ + Only call this if :meth:`is_tfa_add_backup_phone_details` is true. + + :rtype: TfaAddBackupPhoneDetails + """ + if not self.is_tfa_add_backup_phone_details(): + raise AttributeError("tag 'tfa_add_backup_phone_details' not set") + return self._value + + def get_tfa_add_security_key_details(self): + """ + Only call this if :meth:`is_tfa_add_security_key_details` is true. + + :rtype: TfaAddSecurityKeyDetails + """ + if not self.is_tfa_add_security_key_details(): + raise AttributeError("tag 'tfa_add_security_key_details' not set") + return self._value + + def get_tfa_change_backup_phone_details(self): + """ + Only call this if :meth:`is_tfa_change_backup_phone_details` is true. + + :rtype: TfaChangeBackupPhoneDetails + """ + if not self.is_tfa_change_backup_phone_details(): + raise AttributeError("tag 'tfa_change_backup_phone_details' not set") + return self._value + + def get_tfa_change_status_details(self): + """ + Only call this if :meth:`is_tfa_change_status_details` is true. + + :rtype: TfaChangeStatusDetails + """ + if not self.is_tfa_change_status_details(): + raise AttributeError("tag 'tfa_change_status_details' not set") + return self._value + + def get_tfa_remove_backup_phone_details(self): + """ + Only call this if :meth:`is_tfa_remove_backup_phone_details` is true. + + :rtype: TfaRemoveBackupPhoneDetails + """ + if not self.is_tfa_remove_backup_phone_details(): + raise AttributeError("tag 'tfa_remove_backup_phone_details' not set") + return self._value + + def get_tfa_remove_security_key_details(self): + """ + Only call this if :meth:`is_tfa_remove_security_key_details` is true. + + :rtype: TfaRemoveSecurityKeyDetails + """ + if not self.is_tfa_remove_security_key_details(): + raise AttributeError("tag 'tfa_remove_security_key_details' not set") + return self._value + + def get_tfa_reset_details(self): + """ + Only call this if :meth:`is_tfa_reset_details` is true. + + :rtype: TfaResetDetails + """ + if not self.is_tfa_reset_details(): + raise AttributeError("tag 'tfa_reset_details' not set") + return self._value + + def get_changed_enterprise_admin_role_details(self): + """ + Only call this if :meth:`is_changed_enterprise_admin_role_details` is true. + + :rtype: ChangedEnterpriseAdminRoleDetails + """ + if not self.is_changed_enterprise_admin_role_details(): + raise AttributeError("tag 'changed_enterprise_admin_role_details' not set") + return self._value + + def get_changed_enterprise_connected_team_status_details(self): + """ + Only call this if :meth:`is_changed_enterprise_connected_team_status_details` is true. + + :rtype: ChangedEnterpriseConnectedTeamStatusDetails + """ + if not self.is_changed_enterprise_connected_team_status_details(): + raise AttributeError("tag 'changed_enterprise_connected_team_status_details' not set") + return self._value + + def get_ended_enterprise_admin_session_details(self): + """ + Only call this if :meth:`is_ended_enterprise_admin_session_details` is true. + + :rtype: EndedEnterpriseAdminSessionDetails + """ + if not self.is_ended_enterprise_admin_session_details(): + raise AttributeError("tag 'ended_enterprise_admin_session_details' not set") + return self._value + + def get_ended_enterprise_admin_session_deprecated_details(self): + """ + Only call this if :meth:`is_ended_enterprise_admin_session_deprecated_details` is true. + + :rtype: EndedEnterpriseAdminSessionDeprecatedDetails + """ + if not self.is_ended_enterprise_admin_session_deprecated_details(): + raise AttributeError("tag 'ended_enterprise_admin_session_deprecated_details' not set") + return self._value + + def get_enterprise_settings_locking_details(self): + """ + Only call this if :meth:`is_enterprise_settings_locking_details` is true. + + :rtype: EnterpriseSettingsLockingDetails + """ + if not self.is_enterprise_settings_locking_details(): + raise AttributeError("tag 'enterprise_settings_locking_details' not set") + return self._value + + def get_guest_admin_change_status_details(self): + """ + Only call this if :meth:`is_guest_admin_change_status_details` is true. + + :rtype: GuestAdminChangeStatusDetails + """ + if not self.is_guest_admin_change_status_details(): + raise AttributeError("tag 'guest_admin_change_status_details' not set") + return self._value + + def get_started_enterprise_admin_session_details(self): + """ + Only call this if :meth:`is_started_enterprise_admin_session_details` is true. + + :rtype: StartedEnterpriseAdminSessionDetails + """ + if not self.is_started_enterprise_admin_session_details(): + raise AttributeError("tag 'started_enterprise_admin_session_details' not set") + return self._value + + def get_team_merge_request_accepted_details(self): + """ + Only call this if :meth:`is_team_merge_request_accepted_details` is true. + + :rtype: TeamMergeRequestAcceptedDetails + """ + if not self.is_team_merge_request_accepted_details(): + raise AttributeError("tag 'team_merge_request_accepted_details' not set") + return self._value + + def get_team_merge_request_accepted_shown_to_primary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_accepted_shown_to_primary_team_details` is true. + + :rtype: TeamMergeRequestAcceptedShownToPrimaryTeamDetails + """ + if not self.is_team_merge_request_accepted_shown_to_primary_team_details(): + raise AttributeError("tag 'team_merge_request_accepted_shown_to_primary_team_details' not set") + return self._value + + def get_team_merge_request_accepted_shown_to_secondary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_accepted_shown_to_secondary_team_details` is true. + + :rtype: TeamMergeRequestAcceptedShownToSecondaryTeamDetails + """ + if not self.is_team_merge_request_accepted_shown_to_secondary_team_details(): + raise AttributeError("tag 'team_merge_request_accepted_shown_to_secondary_team_details' not set") + return self._value + + def get_team_merge_request_auto_canceled_details(self): + """ + Only call this if :meth:`is_team_merge_request_auto_canceled_details` is true. + + :rtype: TeamMergeRequestAutoCanceledDetails + """ + if not self.is_team_merge_request_auto_canceled_details(): + raise AttributeError("tag 'team_merge_request_auto_canceled_details' not set") + return self._value + + def get_team_merge_request_canceled_details(self): + """ + Only call this if :meth:`is_team_merge_request_canceled_details` is true. + + :rtype: TeamMergeRequestCanceledDetails + """ + if not self.is_team_merge_request_canceled_details(): + raise AttributeError("tag 'team_merge_request_canceled_details' not set") + return self._value + + def get_team_merge_request_canceled_shown_to_primary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_canceled_shown_to_primary_team_details` is true. + + :rtype: TeamMergeRequestCanceledShownToPrimaryTeamDetails + """ + if not self.is_team_merge_request_canceled_shown_to_primary_team_details(): + raise AttributeError("tag 'team_merge_request_canceled_shown_to_primary_team_details' not set") + return self._value + + def get_team_merge_request_canceled_shown_to_secondary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_canceled_shown_to_secondary_team_details` is true. + + :rtype: TeamMergeRequestCanceledShownToSecondaryTeamDetails + """ + if not self.is_team_merge_request_canceled_shown_to_secondary_team_details(): + raise AttributeError("tag 'team_merge_request_canceled_shown_to_secondary_team_details' not set") + return self._value + + def get_team_merge_request_expired_details(self): + """ + Only call this if :meth:`is_team_merge_request_expired_details` is true. + + :rtype: TeamMergeRequestExpiredDetails + """ + if not self.is_team_merge_request_expired_details(): + raise AttributeError("tag 'team_merge_request_expired_details' not set") + return self._value + + def get_team_merge_request_expired_shown_to_primary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_expired_shown_to_primary_team_details` is true. + + :rtype: TeamMergeRequestExpiredShownToPrimaryTeamDetails + """ + if not self.is_team_merge_request_expired_shown_to_primary_team_details(): + raise AttributeError("tag 'team_merge_request_expired_shown_to_primary_team_details' not set") + return self._value + + def get_team_merge_request_expired_shown_to_secondary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_expired_shown_to_secondary_team_details` is true. + + :rtype: TeamMergeRequestExpiredShownToSecondaryTeamDetails + """ + if not self.is_team_merge_request_expired_shown_to_secondary_team_details(): + raise AttributeError("tag 'team_merge_request_expired_shown_to_secondary_team_details' not set") + return self._value + + def get_team_merge_request_rejected_shown_to_primary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_rejected_shown_to_primary_team_details` is true. + + :rtype: TeamMergeRequestRejectedShownToPrimaryTeamDetails + """ + if not self.is_team_merge_request_rejected_shown_to_primary_team_details(): + raise AttributeError("tag 'team_merge_request_rejected_shown_to_primary_team_details' not set") + return self._value + + def get_team_merge_request_rejected_shown_to_secondary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_rejected_shown_to_secondary_team_details` is true. + + :rtype: TeamMergeRequestRejectedShownToSecondaryTeamDetails + """ + if not self.is_team_merge_request_rejected_shown_to_secondary_team_details(): + raise AttributeError("tag 'team_merge_request_rejected_shown_to_secondary_team_details' not set") + return self._value + + def get_team_merge_request_reminder_details(self): + """ + Only call this if :meth:`is_team_merge_request_reminder_details` is true. + + :rtype: TeamMergeRequestReminderDetails + """ + if not self.is_team_merge_request_reminder_details(): + raise AttributeError("tag 'team_merge_request_reminder_details' not set") + return self._value + + def get_team_merge_request_reminder_shown_to_primary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_reminder_shown_to_primary_team_details` is true. + + :rtype: TeamMergeRequestReminderShownToPrimaryTeamDetails + """ + if not self.is_team_merge_request_reminder_shown_to_primary_team_details(): + raise AttributeError("tag 'team_merge_request_reminder_shown_to_primary_team_details' not set") + return self._value + + def get_team_merge_request_reminder_shown_to_secondary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_reminder_shown_to_secondary_team_details` is true. + + :rtype: TeamMergeRequestReminderShownToSecondaryTeamDetails + """ + if not self.is_team_merge_request_reminder_shown_to_secondary_team_details(): + raise AttributeError("tag 'team_merge_request_reminder_shown_to_secondary_team_details' not set") + return self._value + + def get_team_merge_request_revoked_details(self): + """ + Only call this if :meth:`is_team_merge_request_revoked_details` is true. + + :rtype: TeamMergeRequestRevokedDetails + """ + if not self.is_team_merge_request_revoked_details(): + raise AttributeError("tag 'team_merge_request_revoked_details' not set") + return self._value + + def get_team_merge_request_sent_shown_to_primary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_sent_shown_to_primary_team_details` is true. + + :rtype: TeamMergeRequestSentShownToPrimaryTeamDetails + """ + if not self.is_team_merge_request_sent_shown_to_primary_team_details(): + raise AttributeError("tag 'team_merge_request_sent_shown_to_primary_team_details' not set") + return self._value + + def get_team_merge_request_sent_shown_to_secondary_team_details(self): + """ + Only call this if :meth:`is_team_merge_request_sent_shown_to_secondary_team_details` is true. + + :rtype: TeamMergeRequestSentShownToSecondaryTeamDetails + """ + if not self.is_team_merge_request_sent_shown_to_secondary_team_details(): + raise AttributeError("tag 'team_merge_request_sent_shown_to_secondary_team_details' not set") + return self._value + + def get_missing_details(self): + """ + Hints that this event was returned with missing details due to an + internal error. + + Only call this if :meth:`is_missing_details` is true. + + :rtype: MissingDetails + """ + if not self.is_missing_details(): + raise AttributeError("tag 'missing_details' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EventDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EventDetails(%r, %r)' % (self._tag, self._value) + +EventDetails_validator = bv.Union(EventDetails) + +class EventType(bb.Union): + """ + The type of the event with description. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar AppLinkTeamType EventType.app_link_team: (apps) Linked app for team + :ivar AppLinkUserType EventType.app_link_user: (apps) Linked app for member + :ivar AppUnlinkTeamType EventType.app_unlink_team: (apps) Unlinked app for + team + :ivar AppUnlinkUserType EventType.app_unlink_user: (apps) Unlinked app for + member + :ivar IntegrationConnectedType EventType.integration_connected: (apps) + Connected integration for member + :ivar IntegrationDisconnectedType EventType.integration_disconnected: (apps) + Disconnected integration for member + :ivar FileAddCommentType EventType.file_add_comment: (comments) Added file + comment + :ivar FileChangeCommentSubscriptionType + EventType.file_change_comment_subscription: (comments) Subscribed to or + unsubscribed from comment notifications for file + :ivar FileDeleteCommentType EventType.file_delete_comment: (comments) + Deleted file comment + :ivar FileEditCommentType EventType.file_edit_comment: (comments) Edited + file comment + :ivar FileLikeCommentType EventType.file_like_comment: (comments) Liked file + comment (deprecated, no longer logged) + :ivar FileResolveCommentType EventType.file_resolve_comment: (comments) + Resolved file comment + :ivar FileUnlikeCommentType EventType.file_unlike_comment: (comments) + Unliked file comment (deprecated, no longer logged) + :ivar FileUnresolveCommentType EventType.file_unresolve_comment: (comments) + Unresolved file comment + :ivar DeviceChangeIpDesktopType EventType.device_change_ip_desktop: + (devices) Changed IP address associated with active desktop session + :ivar DeviceChangeIpMobileType EventType.device_change_ip_mobile: (devices) + Changed IP address associated with active mobile session + :ivar DeviceChangeIpWebType EventType.device_change_ip_web: (devices) + Changed IP address associated with active web session + :ivar DeviceDeleteOnUnlinkFailType EventType.device_delete_on_unlink_fail: + (devices) Failed to delete all files from unlinked device + :ivar DeviceDeleteOnUnlinkSuccessType + EventType.device_delete_on_unlink_success: (devices) Deleted all files + from unlinked device + :ivar DeviceLinkFailType EventType.device_link_fail: (devices) Failed to + link device + :ivar DeviceLinkSuccessType EventType.device_link_success: (devices) Linked + device + :ivar DeviceManagementDisabledType EventType.device_management_disabled: + (devices) Disabled device management (deprecated, no longer logged) + :ivar DeviceManagementEnabledType EventType.device_management_enabled: + (devices) Enabled device management (deprecated, no longer logged) + :ivar DeviceUnlinkType EventType.device_unlink: (devices) Disconnected + device + :ivar EmmRefreshAuthTokenType EventType.emm_refresh_auth_token: (devices) + Refreshed auth token used for setting up EMM + :ivar AccountCaptureChangeAvailabilityType + EventType.account_capture_change_availability: (domains) Granted/revoked + option to enable account capture on team domains + :ivar AccountCaptureMigrateAccountType + EventType.account_capture_migrate_account: (domains) Account-captured + user migrated account to team + :ivar AccountCaptureNotificationEmailsSentType + EventType.account_capture_notification_emails_sent: (domains) Sent + account capture email to all unmanaged members + :ivar AccountCaptureRelinquishAccountType + EventType.account_capture_relinquish_account: (domains) Account-captured + user changed account email to personal email + :ivar DisabledDomainInvitesType EventType.disabled_domain_invites: (domains) + Disabled domain invites (deprecated, no longer logged) + :ivar DomainInvitesApproveRequestToJoinTeamType + EventType.domain_invites_approve_request_to_join_team: (domains) + Approved user's request to join team + :ivar DomainInvitesDeclineRequestToJoinTeamType + EventType.domain_invites_decline_request_to_join_team: (domains) + Declined user's request to join team + :ivar DomainInvitesEmailExistingUsersType + EventType.domain_invites_email_existing_users: (domains) Sent domain + invites to existing domain accounts (deprecated, no longer logged) + :ivar DomainInvitesRequestToJoinTeamType + EventType.domain_invites_request_to_join_team: (domains) Requested to + join team + :ivar DomainInvitesSetInviteNewUserPrefToNoType + EventType.domain_invites_set_invite_new_user_pref_to_no: (domains) + Disabled "Automatically invite new users" (deprecated, no longer logged) + :ivar DomainInvitesSetInviteNewUserPrefToYesType + EventType.domain_invites_set_invite_new_user_pref_to_yes: (domains) + Enabled "Automatically invite new users" (deprecated, no longer logged) + :ivar DomainVerificationAddDomainFailType + EventType.domain_verification_add_domain_fail: (domains) Failed to + verify team domain + :ivar DomainVerificationAddDomainSuccessType + EventType.domain_verification_add_domain_success: (domains) Verified + team domain + :ivar DomainVerificationRemoveDomainType + EventType.domain_verification_remove_domain: (domains) Removed domain + from list of verified team domains + :ivar EnabledDomainInvitesType EventType.enabled_domain_invites: (domains) + Enabled domain invites (deprecated, no longer logged) + :ivar CreateFolderType EventType.create_folder: (file_operations) Created + folders (deprecated, no longer logged) + :ivar FileAddType EventType.file_add: (file_operations) Added files and/or + folders + :ivar FileCopyType EventType.file_copy: (file_operations) Copied files + and/or folders + :ivar FileDeleteType EventType.file_delete: (file_operations) Deleted files + and/or folders + :ivar FileDownloadType EventType.file_download: (file_operations) Downloaded + files and/or folders + :ivar FileEditType EventType.file_edit: (file_operations) Edited files + :ivar FileGetCopyReferenceType EventType.file_get_copy_reference: + (file_operations) Created copy reference to file/folder + :ivar FileLockingLockStatusChangedType + EventType.file_locking_lock_status_changed: (file_operations) + Locked/unlocked editing for a file + :ivar FileMoveType EventType.file_move: (file_operations) Moved files and/or + folders + :ivar FilePermanentlyDeleteType EventType.file_permanently_delete: + (file_operations) Permanently deleted files and/or folders + :ivar FilePreviewType EventType.file_preview: (file_operations) Previewed + files and/or folders + :ivar FileRenameType EventType.file_rename: (file_operations) Renamed files + and/or folders + :ivar FileRestoreType EventType.file_restore: (file_operations) Restored + deleted files and/or folders + :ivar FileRevertType EventType.file_revert: (file_operations) Reverted files + to previous version + :ivar FileRollbackChangesType EventType.file_rollback_changes: + (file_operations) Rolled back file actions + :ivar FileSaveCopyReferenceType EventType.file_save_copy_reference: + (file_operations) Saved file/folder using copy reference + :ivar FolderOverviewDescriptionChangedType + EventType.folder_overview_description_changed: (file_operations) Updated + folder overview + :ivar FolderOverviewItemPinnedType EventType.folder_overview_item_pinned: + (file_operations) Pinned item to folder overview + :ivar FolderOverviewItemUnpinnedType + EventType.folder_overview_item_unpinned: (file_operations) Unpinned item + from folder overview + :ivar RewindFolderType EventType.rewind_folder: (file_operations) Rewound a + folder + :ivar FileRequestChangeType EventType.file_request_change: (file_requests) + Changed file request + :ivar FileRequestCloseType EventType.file_request_close: (file_requests) + Closed file request + :ivar FileRequestCreateType EventType.file_request_create: (file_requests) + Created file request + :ivar FileRequestDeleteType EventType.file_request_delete: (file_requests) + Delete file request + :ivar FileRequestReceiveFileType EventType.file_request_receive_file: + (file_requests) Received files for file request + :ivar GroupAddExternalIdType EventType.group_add_external_id: (groups) Added + external ID for group + :ivar GroupAddMemberType EventType.group_add_member: (groups) Added team + members to group + :ivar GroupChangeExternalIdType EventType.group_change_external_id: (groups) + Changed external ID for group + :ivar GroupChangeManagementTypeType EventType.group_change_management_type: + (groups) Changed group management type + :ivar GroupChangeMemberRoleType EventType.group_change_member_role: (groups) + Changed manager permissions of group member + :ivar GroupCreateType EventType.group_create: (groups) Created group + :ivar GroupDeleteType EventType.group_delete: (groups) Deleted group + :ivar GroupDescriptionUpdatedType EventType.group_description_updated: + (groups) Updated group (deprecated, no longer logged) + :ivar GroupJoinPolicyUpdatedType EventType.group_join_policy_updated: + (groups) Updated group join policy (deprecated, no longer logged) + :ivar GroupMovedType EventType.group_moved: (groups) Moved group + (deprecated, no longer logged) + :ivar GroupRemoveExternalIdType EventType.group_remove_external_id: (groups) + Removed external ID for group + :ivar GroupRemoveMemberType EventType.group_remove_member: (groups) Removed + team members from group + :ivar GroupRenameType EventType.group_rename: (groups) Renamed group + :ivar LegalHoldsActivateAHoldType EventType.legal_holds_activate_a_hold: + (legal_holds) Activated a hold + :ivar LegalHoldsAddMembersType EventType.legal_holds_add_members: + (legal_holds) Added members to a hold + :ivar LegalHoldsChangeHoldDetailsType + EventType.legal_holds_change_hold_details: (legal_holds) Edited details + for a hold + :ivar LegalHoldsChangeHoldNameType EventType.legal_holds_change_hold_name: + (legal_holds) Renamed a hold + :ivar LegalHoldsExportAHoldType EventType.legal_holds_export_a_hold: + (legal_holds) Exported hold + :ivar LegalHoldsExportCancelledType EventType.legal_holds_export_cancelled: + (legal_holds) Canceled export for a hold + :ivar LegalHoldsExportDownloadedType + EventType.legal_holds_export_downloaded: (legal_holds) Downloaded export + for a hold + :ivar LegalHoldsExportRemovedType EventType.legal_holds_export_removed: + (legal_holds) Removed export for a hold + :ivar LegalHoldsReleaseAHoldType EventType.legal_holds_release_a_hold: + (legal_holds) Released a hold + :ivar LegalHoldsRemoveMembersType EventType.legal_holds_remove_members: + (legal_holds) Removed members from a hold + :ivar LegalHoldsReportAHoldType EventType.legal_holds_report_a_hold: + (legal_holds) Created a summary report for a hold + :ivar AccountLockOrUnlockedType EventType.account_lock_or_unlocked: (logins) + Unlocked/locked account after failed sign in attempts + :ivar EmmErrorType EventType.emm_error: (logins) Failed to sign in via EMM + (deprecated, replaced by 'Failed to sign in') + :ivar GuestAdminSignedInViaTrustedTeamsType + EventType.guest_admin_signed_in_via_trusted_teams: (logins) Started + trusted team admin session + :ivar GuestAdminSignedOutViaTrustedTeamsType + EventType.guest_admin_signed_out_via_trusted_teams: (logins) Ended + trusted team admin session + :ivar LoginFailType EventType.login_fail: (logins) Failed to sign in + :ivar LoginSuccessType EventType.login_success: (logins) Signed in + :ivar LogoutType EventType.logout: (logins) Signed out + :ivar ResellerSupportSessionEndType EventType.reseller_support_session_end: + (logins) Ended reseller support session + :ivar ResellerSupportSessionStartType + EventType.reseller_support_session_start: (logins) Started reseller + support session + :ivar SignInAsSessionEndType EventType.sign_in_as_session_end: (logins) + Ended admin sign-in-as session + :ivar SignInAsSessionStartType EventType.sign_in_as_session_start: (logins) + Started admin sign-in-as session + :ivar SsoErrorType EventType.sso_error: (logins) Failed to sign in via SSO + (deprecated, replaced by 'Failed to sign in') + :ivar CreateTeamInviteLinkType EventType.create_team_invite_link: (members) + Created team invite link + :ivar DeleteTeamInviteLinkType EventType.delete_team_invite_link: (members) + Deleted team invite link + :ivar MemberAddExternalIdType EventType.member_add_external_id: (members) + Added an external ID for team member :ivar MemberAddNameType EventType.member_add_name: (members) Added team member name :ivar MemberChangeAdminRoleType EventType.member_change_admin_role: (members) Changed team member admin role - :ivar MemberChangeEmailType EventType.member_change_email: (members) Changed - team member email - :ivar MemberChangeExternalIdType EventType.member_change_external_id: + :ivar MemberChangeEmailType EventType.member_change_email: (members) Changed + team member email + :ivar MemberChangeExternalIdType EventType.member_change_external_id: + (members) Changed the external ID for team member + :ivar MemberChangeMembershipTypeType + EventType.member_change_membership_type: (members) Changed membership + type (limited/full) of member (deprecated, no longer logged) + :ivar MemberChangeNameType EventType.member_change_name: (members) Changed + team member name + :ivar MemberChangeStatusType EventType.member_change_status: (members) + Changed member status (invited, joined, suspended, etc.) + :ivar MemberDeleteManualContactsType + EventType.member_delete_manual_contacts: (members) Cleared manually + added contacts + :ivar MemberDeleteProfilePhotoType EventType.member_delete_profile_photo: + (members) Deleted team member profile photo + :ivar MemberPermanentlyDeleteAccountContentsType + EventType.member_permanently_delete_account_contents: (members) + Permanently deleted contents of deleted team member account + :ivar MemberRemoveExternalIdType EventType.member_remove_external_id: + (members) Removed the external ID for team member + :ivar MemberSetProfilePhotoType EventType.member_set_profile_photo: + (members) Set team member profile photo + :ivar MemberSpaceLimitsAddCustomQuotaType + EventType.member_space_limits_add_custom_quota: (members) Set custom + member space limit + :ivar MemberSpaceLimitsChangeCustomQuotaType + EventType.member_space_limits_change_custom_quota: (members) Changed + custom member space limit + :ivar MemberSpaceLimitsChangeStatusType + EventType.member_space_limits_change_status: (members) Changed space + limit status + :ivar MemberSpaceLimitsRemoveCustomQuotaType + EventType.member_space_limits_remove_custom_quota: (members) Removed + custom member space limit + :ivar MemberSuggestType EventType.member_suggest: (members) Suggested person + to add to team + :ivar MemberTransferAccountContentsType + EventType.member_transfer_account_contents: (members) Transferred + contents of deleted member account to another member + :ivar PendingSecondaryEmailAddedType + EventType.pending_secondary_email_added: (members) Added pending + secondary email + :ivar SecondaryEmailDeletedType EventType.secondary_email_deleted: (members) + Deleted secondary email + :ivar SecondaryEmailVerifiedType EventType.secondary_email_verified: + (members) Verified secondary email + :ivar SecondaryMailsPolicyChangedType + EventType.secondary_mails_policy_changed: (members) Secondary mails + policy changed + :ivar BinderAddPageType EventType.binder_add_page: (paper) Added Binder page + (deprecated, replaced by 'Edited files') + :ivar BinderAddSectionType EventType.binder_add_section: (paper) Added + Binder section (deprecated, replaced by 'Edited files') + :ivar BinderRemovePageType EventType.binder_remove_page: (paper) Removed + Binder page (deprecated, replaced by 'Edited files') + :ivar BinderRemoveSectionType EventType.binder_remove_section: (paper) + Removed Binder section (deprecated, replaced by 'Edited files') + :ivar BinderRenamePageType EventType.binder_rename_page: (paper) Renamed + Binder page (deprecated, replaced by 'Edited files') + :ivar BinderRenameSectionType EventType.binder_rename_section: (paper) + Renamed Binder section (deprecated, replaced by 'Edited files') + :ivar BinderReorderPageType EventType.binder_reorder_page: (paper) Reordered + Binder page (deprecated, replaced by 'Edited files') + :ivar BinderReorderSectionType EventType.binder_reorder_section: (paper) + Reordered Binder section (deprecated, replaced by 'Edited files') + :ivar PaperContentAddMemberType EventType.paper_content_add_member: (paper) + Added users and/or groups to Paper doc/folder + :ivar PaperContentAddToFolderType EventType.paper_content_add_to_folder: + (paper) Added Paper doc/folder to folder + :ivar PaperContentArchiveType EventType.paper_content_archive: (paper) + Archived Paper doc/folder + :ivar PaperContentCreateType EventType.paper_content_create: (paper) Created + Paper doc/folder + :ivar PaperContentPermanentlyDeleteType + EventType.paper_content_permanently_delete: (paper) Permanently deleted + Paper doc/folder + :ivar PaperContentRemoveFromFolderType + EventType.paper_content_remove_from_folder: (paper) Removed Paper + doc/folder from folder + :ivar PaperContentRemoveMemberType EventType.paper_content_remove_member: + (paper) Removed users and/or groups from Paper doc/folder + :ivar PaperContentRenameType EventType.paper_content_rename: (paper) Renamed + Paper doc/folder + :ivar PaperContentRestoreType EventType.paper_content_restore: (paper) + Restored archived Paper doc/folder + :ivar PaperDocAddCommentType EventType.paper_doc_add_comment: (paper) Added + Paper doc comment + :ivar PaperDocChangeMemberRoleType EventType.paper_doc_change_member_role: + (paper) Changed member permissions for Paper doc + :ivar PaperDocChangeSharingPolicyType + EventType.paper_doc_change_sharing_policy: (paper) Changed sharing + setting for Paper doc + :ivar PaperDocChangeSubscriptionType + EventType.paper_doc_change_subscription: (paper) Followed/unfollowed + Paper doc + :ivar PaperDocDeletedType EventType.paper_doc_deleted: (paper) Archived + Paper doc (deprecated, no longer logged) + :ivar PaperDocDeleteCommentType EventType.paper_doc_delete_comment: (paper) + Deleted Paper doc comment + :ivar PaperDocDownloadType EventType.paper_doc_download: (paper) Downloaded + Paper doc in specific format + :ivar PaperDocEditType EventType.paper_doc_edit: (paper) Edited Paper doc + :ivar PaperDocEditCommentType EventType.paper_doc_edit_comment: (paper) + Edited Paper doc comment + :ivar PaperDocFollowedType EventType.paper_doc_followed: (paper) Followed + Paper doc (deprecated, replaced by 'Followed/unfollowed Paper doc') + :ivar PaperDocMentionType EventType.paper_doc_mention: (paper) Mentioned + user in Paper doc + :ivar PaperDocOwnershipChangedType EventType.paper_doc_ownership_changed: + (paper) Transferred ownership of Paper doc + :ivar PaperDocRequestAccessType EventType.paper_doc_request_access: (paper) + Requested access to Paper doc + :ivar PaperDocResolveCommentType EventType.paper_doc_resolve_comment: + (paper) Resolved Paper doc comment + :ivar PaperDocRevertType EventType.paper_doc_revert: (paper) Restored Paper + doc to previous version + :ivar PaperDocSlackShareType EventType.paper_doc_slack_share: (paper) Shared + Paper doc via Slack + :ivar PaperDocTeamInviteType EventType.paper_doc_team_invite: (paper) Shared + Paper doc with users and/or groups (deprecated, no longer logged) + :ivar PaperDocTrashedType EventType.paper_doc_trashed: (paper) Deleted Paper + doc + :ivar PaperDocUnresolveCommentType EventType.paper_doc_unresolve_comment: + (paper) Unresolved Paper doc comment + :ivar PaperDocUntrashedType EventType.paper_doc_untrashed: (paper) Restored + Paper doc + :ivar PaperDocViewType EventType.paper_doc_view: (paper) Viewed Paper doc + :ivar PaperExternalViewAllowType EventType.paper_external_view_allow: + (paper) Changed Paper external sharing setting to anyone (deprecated, no + longer logged) + :ivar PaperExternalViewDefaultTeamType + EventType.paper_external_view_default_team: (paper) Changed Paper + external sharing setting to default team (deprecated, no longer logged) + :ivar PaperExternalViewForbidType EventType.paper_external_view_forbid: + (paper) Changed Paper external sharing setting to team-only (deprecated, + no longer logged) + :ivar PaperFolderChangeSubscriptionType + EventType.paper_folder_change_subscription: (paper) Followed/unfollowed + Paper folder + :ivar PaperFolderDeletedType EventType.paper_folder_deleted: (paper) + Archived Paper folder (deprecated, no longer logged) + :ivar PaperFolderFollowedType EventType.paper_folder_followed: (paper) + Followed Paper folder (deprecated, replaced by 'Followed/unfollowed + Paper folder') + :ivar PaperFolderTeamInviteType EventType.paper_folder_team_invite: (paper) + Shared Paper folder with users and/or groups (deprecated, no longer + logged) + :ivar PaperPublishedLinkChangePermissionType + EventType.paper_published_link_change_permission: (paper) Changed + permissions for published doc + :ivar PaperPublishedLinkCreateType EventType.paper_published_link_create: + (paper) Published doc + :ivar PaperPublishedLinkDisabledType + EventType.paper_published_link_disabled: (paper) Unpublished doc + :ivar PaperPublishedLinkViewType EventType.paper_published_link_view: + (paper) Viewed published doc + :ivar PasswordChangeType EventType.password_change: (passwords) Changed + password + :ivar PasswordResetType EventType.password_reset: (passwords) Reset password + :ivar PasswordResetAllType EventType.password_reset_all: (passwords) Reset + all team member passwords + :ivar EmmCreateExceptionsReportType EventType.emm_create_exceptions_report: + (reports) Created EMM-excluded users report + :ivar EmmCreateUsageReportType EventType.emm_create_usage_report: (reports) + Created EMM mobile app usage report + :ivar ExportMembersReportType EventType.export_members_report: (reports) + Created member data report + :ivar ExportMembersReportFailType EventType.export_members_report_fail: + (reports) Failed to create members data report + :ivar NoExpirationLinkGenCreateReportType + EventType.no_expiration_link_gen_create_report: (reports) Report + created: Links created with no expiration + :ivar NoExpirationLinkGenReportFailedType + EventType.no_expiration_link_gen_report_failed: (reports) Couldn't + create report: Links created with no expiration + :ivar NoPasswordLinkGenCreateReportType + EventType.no_password_link_gen_create_report: (reports) Report created: + Links created without passwords + :ivar NoPasswordLinkGenReportFailedType + EventType.no_password_link_gen_report_failed: (reports) Couldn't create + report: Links created without passwords + :ivar NoPasswordLinkViewCreateReportType + EventType.no_password_link_view_create_report: (reports) Report created: + Views of links without passwords + :ivar NoPasswordLinkViewReportFailedType + EventType.no_password_link_view_report_failed: (reports) Couldn't create + report: Views of links without passwords + :ivar OutdatedLinkViewCreateReportType + EventType.outdated_link_view_create_report: (reports) Report created: + Views of old links + :ivar OutdatedLinkViewReportFailedType + EventType.outdated_link_view_report_failed: (reports) Couldn't create + report: Views of old links + :ivar PaperAdminExportStartType EventType.paper_admin_export_start: + (reports) Exported all team Paper docs + :ivar SmartSyncCreateAdminPrivilegeReportType + EventType.smart_sync_create_admin_privilege_report: (reports) Created + Smart Sync non-admin devices report + :ivar TeamActivityCreateReportType EventType.team_activity_create_report: + (reports) Created team activity report + :ivar TeamActivityCreateReportFailType + EventType.team_activity_create_report_fail: (reports) Couldn't generate + team activity report + :ivar CollectionShareType EventType.collection_share: (sharing) Shared album + :ivar FileTransfersFileAddType EventType.file_transfers_file_add: (sharing) + Transfer files added + :ivar FileTransfersTransferDeleteType + EventType.file_transfers_transfer_delete: (sharing) Deleted transfer + :ivar FileTransfersTransferDownloadType + EventType.file_transfers_transfer_download: (sharing) Transfer + downloaded + :ivar FileTransfersTransferSendType EventType.file_transfers_transfer_send: + (sharing) Sent transfer + :ivar FileTransfersTransferViewType EventType.file_transfers_transfer_view: + (sharing) Viewed transfer + :ivar NoteAclInviteOnlyType EventType.note_acl_invite_only: (sharing) + Changed Paper doc to invite-only (deprecated, no longer logged) + :ivar NoteAclLinkType EventType.note_acl_link: (sharing) Changed Paper doc + to link-accessible (deprecated, no longer logged) + :ivar NoteAclTeamLinkType EventType.note_acl_team_link: (sharing) Changed + Paper doc to link-accessible for team (deprecated, no longer logged) + :ivar NoteSharedType EventType.note_shared: (sharing) Shared Paper doc + (deprecated, no longer logged) + :ivar NoteShareReceiveType EventType.note_share_receive: (sharing) Shared + received Paper doc (deprecated, no longer logged) + :ivar OpenNoteSharedType EventType.open_note_shared: (sharing) Opened shared + Paper doc (deprecated, no longer logged) + :ivar SfAddGroupType EventType.sf_add_group: (sharing) Added team to shared + folder (deprecated, no longer logged) + :ivar SfAllowNonMembersToViewSharedLinksType + EventType.sf_allow_non_members_to_view_shared_links: (sharing) Allowed + non-collaborators to view links to files in shared folder (deprecated, + no longer logged) + :ivar SfExternalInviteWarnType EventType.sf_external_invite_warn: (sharing) + Set team members to see warning before sharing folders outside team + (deprecated, no longer logged) + :ivar SfFbInviteType EventType.sf_fb_invite: (sharing) Invited Facebook + users to shared folder (deprecated, no longer logged) + :ivar SfFbInviteChangeRoleType EventType.sf_fb_invite_change_role: (sharing) + Changed Facebook user's role in shared folder (deprecated, no longer + logged) + :ivar SfFbUninviteType EventType.sf_fb_uninvite: (sharing) Uninvited + Facebook user from shared folder (deprecated, no longer logged) + :ivar SfInviteGroupType EventType.sf_invite_group: (sharing) Invited group + to shared folder (deprecated, no longer logged) + :ivar SfTeamGrantAccessType EventType.sf_team_grant_access: (sharing) + Granted access to shared folder (deprecated, no longer logged) + :ivar SfTeamInviteType EventType.sf_team_invite: (sharing) Invited team + members to shared folder (deprecated, replaced by 'Invited user to + Dropbox and added them to shared file/folder') + :ivar SfTeamInviteChangeRoleType EventType.sf_team_invite_change_role: + (sharing) Changed team member's role in shared folder (deprecated, no + longer logged) + :ivar SfTeamJoinType EventType.sf_team_join: (sharing) Joined team member's + shared folder (deprecated, no longer logged) + :ivar SfTeamJoinFromOobLinkType EventType.sf_team_join_from_oob_link: + (sharing) Joined team member's shared folder from link (deprecated, no + longer logged) + :ivar SfTeamUninviteType EventType.sf_team_uninvite: (sharing) Unshared + folder with team member (deprecated, replaced by 'Removed invitee from + shared file/folder before invite was accepted') + :ivar SharedContentAddInviteesType EventType.shared_content_add_invitees: + (sharing) Invited user to Dropbox and added them to shared file/folder + :ivar SharedContentAddLinkExpiryType + EventType.shared_content_add_link_expiry: (sharing) Added expiration + date to link for shared file/folder (deprecated, no longer logged) + :ivar SharedContentAddLinkPasswordType + EventType.shared_content_add_link_password: (sharing) Added password to + link for shared file/folder (deprecated, no longer logged) + :ivar SharedContentAddMemberType EventType.shared_content_add_member: + (sharing) Added users and/or groups to shared file/folder + :ivar SharedContentChangeDownloadsPolicyType + EventType.shared_content_change_downloads_policy: (sharing) Changed + whether members can download shared file/folder (deprecated, no longer + logged) + :ivar SharedContentChangeInviteeRoleType + EventType.shared_content_change_invitee_role: (sharing) Changed access + type of invitee to shared file/folder before invite was accepted + :ivar SharedContentChangeLinkAudienceType + EventType.shared_content_change_link_audience: (sharing) Changed link + audience of shared file/folder (deprecated, no longer logged) + :ivar SharedContentChangeLinkExpiryType + EventType.shared_content_change_link_expiry: (sharing) Changed link + expiration of shared file/folder (deprecated, no longer logged) + :ivar SharedContentChangeLinkPasswordType + EventType.shared_content_change_link_password: (sharing) Changed link + password of shared file/folder (deprecated, no longer logged) + :ivar SharedContentChangeMemberRoleType + EventType.shared_content_change_member_role: (sharing) Changed access + type of shared file/folder member + :ivar SharedContentChangeViewerInfoPolicyType + EventType.shared_content_change_viewer_info_policy: (sharing) Changed + whether members can see who viewed shared file/folder + :ivar SharedContentClaimInvitationType + EventType.shared_content_claim_invitation: (sharing) Acquired membership + of shared file/folder by accepting invite + :ivar SharedContentCopyType EventType.shared_content_copy: (sharing) Copied + shared file/folder to own Dropbox + :ivar SharedContentDownloadType EventType.shared_content_download: (sharing) + Downloaded shared file/folder + :ivar SharedContentRelinquishMembershipType + EventType.shared_content_relinquish_membership: (sharing) Left shared + file/folder + :ivar SharedContentRemoveInviteesType + EventType.shared_content_remove_invitees: (sharing) Removed invitee from + shared file/folder before invite was accepted + :ivar SharedContentRemoveLinkExpiryType + EventType.shared_content_remove_link_expiry: (sharing) Removed link + expiration date of shared file/folder (deprecated, no longer logged) + :ivar SharedContentRemoveLinkPasswordType + EventType.shared_content_remove_link_password: (sharing) Removed link + password of shared file/folder (deprecated, no longer logged) + :ivar SharedContentRemoveMemberType EventType.shared_content_remove_member: + (sharing) Removed user/group from shared file/folder + :ivar SharedContentRequestAccessType + EventType.shared_content_request_access: (sharing) Requested access to + shared file/folder + :ivar SharedContentRestoreInviteesType + EventType.shared_content_restore_invitees: (sharing) Restored shared + file/folder invitees + :ivar SharedContentRestoreMemberType + EventType.shared_content_restore_member: (sharing) Restored users and/or + groups to membership of shared file/folder + :ivar SharedContentUnshareType EventType.shared_content_unshare: (sharing) + Unshared file/folder by clearing membership + :ivar SharedContentViewType EventType.shared_content_view: (sharing) + Previewed shared file/folder + :ivar SharedFolderChangeLinkPolicyType + EventType.shared_folder_change_link_policy: (sharing) Changed who can + access shared folder via link + :ivar SharedFolderChangeMembersInheritancePolicyType + EventType.shared_folder_change_members_inheritance_policy: (sharing) + Changed whether shared folder inherits members from parent folder + :ivar SharedFolderChangeMembersManagementPolicyType + EventType.shared_folder_change_members_management_policy: (sharing) + Changed who can add/remove members of shared folder + :ivar SharedFolderChangeMembersPolicyType + EventType.shared_folder_change_members_policy: (sharing) Changed who can + become member of shared folder + :ivar SharedFolderCreateType EventType.shared_folder_create: (sharing) + Created shared folder + :ivar SharedFolderDeclineInvitationType + EventType.shared_folder_decline_invitation: (sharing) Declined team + member's invite to shared folder + :ivar SharedFolderMountType EventType.shared_folder_mount: (sharing) Added + shared folder to own Dropbox + :ivar SharedFolderNestType EventType.shared_folder_nest: (sharing) Changed + parent of shared folder + :ivar SharedFolderTransferOwnershipType + EventType.shared_folder_transfer_ownership: (sharing) Transferred + ownership of shared folder to another member + :ivar SharedFolderUnmountType EventType.shared_folder_unmount: (sharing) + Deleted shared folder from Dropbox + :ivar SharedLinkAddExpiryType EventType.shared_link_add_expiry: (sharing) + Added shared link expiration date + :ivar SharedLinkChangeExpiryType EventType.shared_link_change_expiry: + (sharing) Changed shared link expiration date + :ivar SharedLinkChangeVisibilityType + EventType.shared_link_change_visibility: (sharing) Changed visibility of + shared link + :ivar SharedLinkCopyType EventType.shared_link_copy: (sharing) Added + file/folder to Dropbox from shared link + :ivar SharedLinkCreateType EventType.shared_link_create: (sharing) Created + shared link + :ivar SharedLinkDisableType EventType.shared_link_disable: (sharing) Removed + shared link + :ivar SharedLinkDownloadType EventType.shared_link_download: (sharing) + Downloaded file/folder from shared link + :ivar SharedLinkRemoveExpiryType EventType.shared_link_remove_expiry: + (sharing) Removed shared link expiration date + :ivar SharedLinkSettingsAddExpirationType + EventType.shared_link_settings_add_expiration: (sharing) Added an + expiration date to the shared link + :ivar SharedLinkSettingsAddPasswordType + EventType.shared_link_settings_add_password: (sharing) Added a password + to the shared link + :ivar SharedLinkSettingsAllowDownloadDisabledType + EventType.shared_link_settings_allow_download_disabled: (sharing) + Disabled downloads + :ivar SharedLinkSettingsAllowDownloadEnabledType + EventType.shared_link_settings_allow_download_enabled: (sharing) Enabled + downloads + :ivar SharedLinkSettingsChangeAudienceType + EventType.shared_link_settings_change_audience: (sharing) Changed the + audience of the shared link + :ivar SharedLinkSettingsChangeExpirationType + EventType.shared_link_settings_change_expiration: (sharing) Changed the + expiration date of the shared link + :ivar SharedLinkSettingsChangePasswordType + EventType.shared_link_settings_change_password: (sharing) Changed the + password of the shared link + :ivar SharedLinkSettingsRemoveExpirationType + EventType.shared_link_settings_remove_expiration: (sharing) Removed the + expiration date from the shared link + :ivar SharedLinkSettingsRemovePasswordType + EventType.shared_link_settings_remove_password: (sharing) Removed the + password from the shared link + :ivar SharedLinkShareType EventType.shared_link_share: (sharing) Added + members as audience of shared link + :ivar SharedLinkViewType EventType.shared_link_view: (sharing) Opened shared + link + :ivar SharedNoteOpenedType EventType.shared_note_opened: (sharing) Opened + shared Paper doc (deprecated, no longer logged) + :ivar ShmodelGroupShareType EventType.shmodel_group_share: (sharing) Shared + link with group (deprecated, no longer logged) + :ivar ShowcaseAccessGrantedType EventType.showcase_access_granted: + (showcase) Granted access to showcase + :ivar ShowcaseAddMemberType EventType.showcase_add_member: (showcase) Added + member to showcase + :ivar ShowcaseArchivedType EventType.showcase_archived: (showcase) Archived + showcase + :ivar ShowcaseCreatedType EventType.showcase_created: (showcase) Created + showcase + :ivar ShowcaseDeleteCommentType EventType.showcase_delete_comment: + (showcase) Deleted showcase comment + :ivar ShowcaseEditedType EventType.showcase_edited: (showcase) Edited + showcase + :ivar ShowcaseEditCommentType EventType.showcase_edit_comment: (showcase) + Edited showcase comment + :ivar ShowcaseFileAddedType EventType.showcase_file_added: (showcase) Added + file to showcase + :ivar ShowcaseFileDownloadType EventType.showcase_file_download: (showcase) + Downloaded file from showcase + :ivar ShowcaseFileRemovedType EventType.showcase_file_removed: (showcase) + Removed file from showcase + :ivar ShowcaseFileViewType EventType.showcase_file_view: (showcase) Viewed + file in showcase + :ivar ShowcasePermanentlyDeletedType EventType.showcase_permanently_deleted: + (showcase) Permanently deleted showcase + :ivar ShowcasePostCommentType EventType.showcase_post_comment: (showcase) + Added showcase comment + :ivar ShowcaseRemoveMemberType EventType.showcase_remove_member: (showcase) + Removed member from showcase + :ivar ShowcaseRenamedType EventType.showcase_renamed: (showcase) Renamed + showcase + :ivar ShowcaseRequestAccessType EventType.showcase_request_access: + (showcase) Requested access to showcase + :ivar ShowcaseResolveCommentType EventType.showcase_resolve_comment: + (showcase) Resolved showcase comment + :ivar ShowcaseRestoredType EventType.showcase_restored: (showcase) + Unarchived showcase + :ivar ShowcaseTrashedType EventType.showcase_trashed: (showcase) Deleted + showcase + :ivar ShowcaseTrashedDeprecatedType EventType.showcase_trashed_deprecated: + (showcase) Deleted showcase (old version) (deprecated, replaced by + 'Deleted showcase') + :ivar ShowcaseUnresolveCommentType EventType.showcase_unresolve_comment: + (showcase) Unresolved showcase comment + :ivar ShowcaseUntrashedType EventType.showcase_untrashed: (showcase) + Restored showcase + :ivar ShowcaseUntrashedDeprecatedType + EventType.showcase_untrashed_deprecated: (showcase) Restored showcase + (old version) (deprecated, replaced by 'Restored showcase') + :ivar ShowcaseViewType EventType.showcase_view: (showcase) Viewed showcase + :ivar SsoAddCertType EventType.sso_add_cert: (sso) Added X.509 certificate + for SSO + :ivar SsoAddLoginUrlType EventType.sso_add_login_url: (sso) Added sign-in + URL for SSO + :ivar SsoAddLogoutUrlType EventType.sso_add_logout_url: (sso) Added sign-out + URL for SSO + :ivar SsoChangeCertType EventType.sso_change_cert: (sso) Changed X.509 + certificate for SSO + :ivar SsoChangeLoginUrlType EventType.sso_change_login_url: (sso) Changed + sign-in URL for SSO + :ivar SsoChangeLogoutUrlType EventType.sso_change_logout_url: (sso) Changed + sign-out URL for SSO + :ivar SsoChangeSamlIdentityModeType EventType.sso_change_saml_identity_mode: + (sso) Changed SAML identity mode for SSO + :ivar SsoRemoveCertType EventType.sso_remove_cert: (sso) Removed X.509 + certificate for SSO + :ivar SsoRemoveLoginUrlType EventType.sso_remove_login_url: (sso) Removed + sign-in URL for SSO + :ivar SsoRemoveLogoutUrlType EventType.sso_remove_logout_url: (sso) Removed + sign-out URL for SSO + :ivar TeamFolderChangeStatusType EventType.team_folder_change_status: + (team_folders) Changed archival status of team folder + :ivar TeamFolderCreateType EventType.team_folder_create: (team_folders) + Created team folder in active status + :ivar TeamFolderDowngradeType EventType.team_folder_downgrade: + (team_folders) Downgraded team folder to regular shared folder + :ivar TeamFolderPermanentlyDeleteType + EventType.team_folder_permanently_delete: (team_folders) Permanently + deleted archived team folder + :ivar TeamFolderRenameType EventType.team_folder_rename: (team_folders) + Renamed active/archived team folder + :ivar TeamSelectiveSyncSettingsChangedType + EventType.team_selective_sync_settings_changed: (team_folders) Changed + sync default + :ivar AccountCaptureChangePolicyType + EventType.account_capture_change_policy: (team_policies) Changed account + capture setting on team domain + :ivar AllowDownloadDisabledType EventType.allow_download_disabled: + (team_policies) Disabled downloads (deprecated, no longer logged) + :ivar AllowDownloadEnabledType EventType.allow_download_enabled: + (team_policies) Enabled downloads (deprecated, no longer logged) + :ivar CameraUploadsPolicyChangedType + EventType.camera_uploads_policy_changed: (team_policies) Changed camera + uploads setting for team + :ivar DataPlacementRestrictionChangePolicyType + EventType.data_placement_restriction_change_policy: (team_policies) Set + restrictions on data center locations where team data resides + :ivar DataPlacementRestrictionSatisfyPolicyType + EventType.data_placement_restriction_satisfy_policy: (team_policies) + Completed restrictions on data center locations where team data resides + :ivar DeviceApprovalsAddExceptionType + EventType.device_approvals_add_exception: (team_policies) Added members + to device approvals exception list + :ivar DeviceApprovalsChangeDesktopPolicyType + EventType.device_approvals_change_desktop_policy: (team_policies) + Set/removed limit on number of computers member can link to team Dropbox + account + :ivar DeviceApprovalsChangeMobilePolicyType + EventType.device_approvals_change_mobile_policy: (team_policies) + Set/removed limit on number of mobile devices member can link to team + Dropbox account + :ivar DeviceApprovalsChangeOverageActionType + EventType.device_approvals_change_overage_action: (team_policies) + Changed device approvals setting when member is over limit + :ivar DeviceApprovalsChangeUnlinkActionType + EventType.device_approvals_change_unlink_action: (team_policies) Changed + device approvals setting when member unlinks approved device + :ivar DeviceApprovalsRemoveExceptionType + EventType.device_approvals_remove_exception: (team_policies) Removed + members from device approvals exception list + :ivar DirectoryRestrictionsAddMembersType + EventType.directory_restrictions_add_members: (team_policies) Added + members to directory restrictions list + :ivar DirectoryRestrictionsRemoveMembersType + EventType.directory_restrictions_remove_members: (team_policies) Removed + members from directory restrictions list + :ivar EmmAddExceptionType EventType.emm_add_exception: (team_policies) Added + members to EMM exception list + :ivar EmmChangePolicyType EventType.emm_change_policy: (team_policies) + Enabled/disabled enterprise mobility management for members + :ivar EmmRemoveExceptionType EventType.emm_remove_exception: (team_policies) + Removed members from EMM exception list + :ivar ExtendedVersionHistoryChangePolicyType + EventType.extended_version_history_change_policy: (team_policies) + Accepted/opted out of extended version history + :ivar FileCommentsChangePolicyType EventType.file_comments_change_policy: + (team_policies) Enabled/disabled commenting on team files + :ivar FileLockingPolicyChangedType EventType.file_locking_policy_changed: + (team_policies) Changed file locking policy for team + :ivar FileRequestsChangePolicyType EventType.file_requests_change_policy: + (team_policies) Enabled/disabled file requests + :ivar FileRequestsEmailsEnabledType EventType.file_requests_emails_enabled: + (team_policies) Enabled file request emails for everyone (deprecated, no + longer logged) + :ivar FileRequestsEmailsRestrictedToTeamOnlyType + EventType.file_requests_emails_restricted_to_team_only: (team_policies) + Enabled file request emails for team (deprecated, no longer logged) + :ivar FileTransfersPolicyChangedType + EventType.file_transfers_policy_changed: (team_policies) Changed file + transfers policy for team + :ivar GoogleSsoChangePolicyType EventType.google_sso_change_policy: + (team_policies) Enabled/disabled Google single sign-on for team + :ivar GroupUserManagementChangePolicyType + EventType.group_user_management_change_policy: (team_policies) Changed + who can create groups + :ivar IntegrationPolicyChangedType EventType.integration_policy_changed: + (team_policies) Changed integration policy for team + :ivar MemberRequestsChangePolicyType + EventType.member_requests_change_policy: (team_policies) Changed whether + users can find team when not invited + :ivar MemberSendInvitePolicyChangedType + EventType.member_send_invite_policy_changed: (team_policies) Changed + member send invite policy for team + :ivar MemberSpaceLimitsAddExceptionType + EventType.member_space_limits_add_exception: (team_policies) Added + members to member space limit exception list + :ivar MemberSpaceLimitsChangeCapsTypePolicyType + EventType.member_space_limits_change_caps_type_policy: (team_policies) + Changed member space limit type for team + :ivar MemberSpaceLimitsChangePolicyType + EventType.member_space_limits_change_policy: (team_policies) Changed + team default member space limit + :ivar MemberSpaceLimitsRemoveExceptionType + EventType.member_space_limits_remove_exception: (team_policies) Removed + members from member space limit exception list + :ivar MemberSuggestionsChangePolicyType + EventType.member_suggestions_change_policy: (team_policies) + Enabled/disabled option for team members to suggest people to add to + team + :ivar MicrosoftOfficeAddinChangePolicyType + EventType.microsoft_office_addin_change_policy: (team_policies) + Enabled/disabled Microsoft Office add-in + :ivar NetworkControlChangePolicyType + EventType.network_control_change_policy: (team_policies) + Enabled/disabled network control + :ivar PaperChangeDeploymentPolicyType + EventType.paper_change_deployment_policy: (team_policies) Changed + whether Dropbox Paper, when enabled, is deployed to all members or to + specific members + :ivar PaperChangeMemberLinkPolicyType + EventType.paper_change_member_link_policy: (team_policies) Changed + whether non-members can view Paper docs with link (deprecated, no longer + logged) + :ivar PaperChangeMemberPolicyType EventType.paper_change_member_policy: + (team_policies) Changed whether members can share Paper docs outside + team, and if docs are accessible only by team members or anyone by + default + :ivar PaperChangePolicyType EventType.paper_change_policy: (team_policies) + Enabled/disabled Dropbox Paper for team + :ivar PaperDefaultFolderPolicyChangedType + EventType.paper_default_folder_policy_changed: (team_policies) Changed + Paper Default Folder Policy setting for team + :ivar PaperDesktopPolicyChangedType EventType.paper_desktop_policy_changed: + (team_policies) Enabled/disabled Paper Desktop for team + :ivar PaperEnabledUsersGroupAdditionType + EventType.paper_enabled_users_group_addition: (team_policies) Added + users to Paper-enabled users list + :ivar PaperEnabledUsersGroupRemovalType + EventType.paper_enabled_users_group_removal: (team_policies) Removed + users from Paper-enabled users list + :ivar PasswordStrengthRequirementsChangePolicyType + EventType.password_strength_requirements_change_policy: (team_policies) + Changed team password strength requirements + :ivar PermanentDeleteChangePolicyType + EventType.permanent_delete_change_policy: (team_policies) + Enabled/disabled ability of team members to permanently delete content + :ivar ResellerSupportChangePolicyType + EventType.reseller_support_change_policy: (team_policies) + Enabled/disabled reseller support + :ivar RewindPolicyChangedType EventType.rewind_policy_changed: + (team_policies) Changed Rewind policy for team + :ivar SharingChangeFolderJoinPolicyType + EventType.sharing_change_folder_join_policy: (team_policies) Changed + whether team members can join shared folders owned outside team + :ivar SharingChangeLinkPolicyType EventType.sharing_change_link_policy: + (team_policies) Changed whether members can share links outside team, + and if links are accessible only by team members or anyone by default + :ivar SharingChangeMemberPolicyType EventType.sharing_change_member_policy: + (team_policies) Changed whether members can share files/folders outside + team + :ivar ShowcaseChangeDownloadPolicyType + EventType.showcase_change_download_policy: (team_policies) + Enabled/disabled downloading files from Dropbox Showcase for team + :ivar ShowcaseChangeEnabledPolicyType + EventType.showcase_change_enabled_policy: (team_policies) + Enabled/disabled Dropbox Showcase for team + :ivar ShowcaseChangeExternalSharingPolicyType + EventType.showcase_change_external_sharing_policy: (team_policies) + Enabled/disabled sharing Dropbox Showcase externally for team + :ivar SmarterSmartSyncPolicyChangedType + EventType.smarter_smart_sync_policy_changed: (team_policies) Changed + automatic Smart Sync setting for team + :ivar SmartSyncChangePolicyType EventType.smart_sync_change_policy: + (team_policies) Changed default Smart Sync setting for team members + :ivar SmartSyncNotOptOutType EventType.smart_sync_not_opt_out: + (team_policies) Opted team into Smart Sync + :ivar SmartSyncOptOutType EventType.smart_sync_opt_out: (team_policies) + Opted team out of Smart Sync + :ivar SsoChangePolicyType EventType.sso_change_policy: (team_policies) + Changed single sign-on setting for team + :ivar TeamExtensionsPolicyChangedType + EventType.team_extensions_policy_changed: (team_policies) Changed App + Integrations setting for team + :ivar TeamSelectiveSyncPolicyChangedType + EventType.team_selective_sync_policy_changed: (team_policies) + Enabled/disabled Team Selective Sync for team + :ivar TeamSharingWhitelistSubjectsChangedType + EventType.team_sharing_whitelist_subjects_changed: (team_policies) + Edited the approved list for sharing externally + :ivar TfaAddExceptionType EventType.tfa_add_exception: (team_policies) Added + members to two factor authentication exception list + :ivar TfaChangePolicyType EventType.tfa_change_policy: (team_policies) + Changed two-step verification setting for team + :ivar TfaRemoveExceptionType EventType.tfa_remove_exception: (team_policies) + Removed members from two factor authentication exception list + :ivar TwoAccountChangePolicyType EventType.two_account_change_policy: + (team_policies) Enabled/disabled option for members to link personal + Dropbox account and team account to same computer + :ivar ViewerInfoPolicyChangedType EventType.viewer_info_policy_changed: + (team_policies) Changed team policy for viewer info + :ivar WatermarkingPolicyChangedType EventType.watermarking_policy_changed: + (team_policies) Changed watermarking policy for team + :ivar WebSessionsChangeActiveSessionLimitType + EventType.web_sessions_change_active_session_limit: (team_policies) + Changed limit on active sessions per member + :ivar WebSessionsChangeFixedLengthPolicyType + EventType.web_sessions_change_fixed_length_policy: (team_policies) + Changed how long members can stay signed in to Dropbox.com + :ivar WebSessionsChangeIdleLengthPolicyType + EventType.web_sessions_change_idle_length_policy: (team_policies) + Changed how long team members can be idle while signed in to Dropbox.com + :ivar TeamMergeFromType EventType.team_merge_from: (team_profile) Merged + another team into this team + :ivar TeamMergeToType EventType.team_merge_to: (team_profile) Merged this + team into another team + :ivar TeamProfileAddLogoType EventType.team_profile_add_logo: (team_profile) + Added team logo to display on shared link headers + :ivar TeamProfileChangeDefaultLanguageType + EventType.team_profile_change_default_language: (team_profile) Changed + default language for team + :ivar TeamProfileChangeLogoType EventType.team_profile_change_logo: + (team_profile) Changed team logo displayed on shared link headers + :ivar TeamProfileChangeNameType EventType.team_profile_change_name: + (team_profile) Changed team name + :ivar TeamProfileRemoveLogoType EventType.team_profile_remove_logo: + (team_profile) Removed team logo displayed on shared link headers + :ivar TfaAddBackupPhoneType EventType.tfa_add_backup_phone: (tfa) Added + backup phone for two-step verification + :ivar TfaAddSecurityKeyType EventType.tfa_add_security_key: (tfa) Added + security key for two-step verification + :ivar TfaChangeBackupPhoneType EventType.tfa_change_backup_phone: (tfa) + Changed backup phone for two-step verification + :ivar TfaChangeStatusType EventType.tfa_change_status: (tfa) + Enabled/disabled/changed two-step verification setting + :ivar TfaRemoveBackupPhoneType EventType.tfa_remove_backup_phone: (tfa) + Removed backup phone for two-step verification + :ivar TfaRemoveSecurityKeyType EventType.tfa_remove_security_key: (tfa) + Removed security key for two-step verification + :ivar TfaResetType EventType.tfa_reset: (tfa) Reset two-step verification + for team member + :ivar ChangedEnterpriseAdminRoleType + EventType.changed_enterprise_admin_role: (trusted_teams) Changed + enterprise admin role + :ivar ChangedEnterpriseConnectedTeamStatusType + EventType.changed_enterprise_connected_team_status: (trusted_teams) + Changed enterprise-connected team status + :ivar EndedEnterpriseAdminSessionType + EventType.ended_enterprise_admin_session: (trusted_teams) Ended + enterprise admin session + :ivar EndedEnterpriseAdminSessionDeprecatedType + EventType.ended_enterprise_admin_session_deprecated: (trusted_teams) + Ended enterprise admin session (deprecated, replaced by 'Ended + enterprise admin session') + :ivar EnterpriseSettingsLockingType EventType.enterprise_settings_locking: + (trusted_teams) Changed who can update a setting + :ivar GuestAdminChangeStatusType EventType.guest_admin_change_status: + (trusted_teams) Changed guest team admin status + :ivar StartedEnterpriseAdminSessionType + EventType.started_enterprise_admin_session: (trusted_teams) Started + enterprise admin session + :ivar TeamMergeRequestAcceptedType EventType.team_merge_request_accepted: + (trusted_teams) Accepted a team merge request + :ivar TeamMergeRequestAcceptedShownToPrimaryTeamType + EventType.team_merge_request_accepted_shown_to_primary_team: + (trusted_teams) Accepted a team merge request (deprecated, replaced by + 'Accepted a team merge request') + :ivar TeamMergeRequestAcceptedShownToSecondaryTeamType + EventType.team_merge_request_accepted_shown_to_secondary_team: + (trusted_teams) Accepted a team merge request (deprecated, replaced by + 'Accepted a team merge request') + :ivar TeamMergeRequestAutoCanceledType + EventType.team_merge_request_auto_canceled: (trusted_teams) + Automatically canceled team merge request + :ivar TeamMergeRequestCanceledType EventType.team_merge_request_canceled: + (trusted_teams) Canceled a team merge request + :ivar TeamMergeRequestCanceledShownToPrimaryTeamType + EventType.team_merge_request_canceled_shown_to_primary_team: + (trusted_teams) Canceled a team merge request (deprecated, replaced by + 'Canceled a team merge request') + :ivar TeamMergeRequestCanceledShownToSecondaryTeamType + EventType.team_merge_request_canceled_shown_to_secondary_team: + (trusted_teams) Canceled a team merge request (deprecated, replaced by + 'Canceled a team merge request') + :ivar TeamMergeRequestExpiredType EventType.team_merge_request_expired: + (trusted_teams) Team merge request expired + :ivar TeamMergeRequestExpiredShownToPrimaryTeamType + EventType.team_merge_request_expired_shown_to_primary_team: + (trusted_teams) Team merge request expired (deprecated, replaced by + 'Team merge request expired') + :ivar TeamMergeRequestExpiredShownToSecondaryTeamType + EventType.team_merge_request_expired_shown_to_secondary_team: + (trusted_teams) Team merge request expired (deprecated, replaced by + 'Team merge request expired') + :ivar TeamMergeRequestRejectedShownToPrimaryTeamType + EventType.team_merge_request_rejected_shown_to_primary_team: + (trusted_teams) Rejected a team merge request (deprecated, no longer + logged) + :ivar TeamMergeRequestRejectedShownToSecondaryTeamType + EventType.team_merge_request_rejected_shown_to_secondary_team: + (trusted_teams) Rejected a team merge request (deprecated, no longer + logged) + :ivar TeamMergeRequestReminderType EventType.team_merge_request_reminder: + (trusted_teams) Sent a team merge request reminder + :ivar TeamMergeRequestReminderShownToPrimaryTeamType + EventType.team_merge_request_reminder_shown_to_primary_team: + (trusted_teams) Sent a team merge request reminder (deprecated, replaced + by 'Sent a team merge request reminder') + :ivar TeamMergeRequestReminderShownToSecondaryTeamType + EventType.team_merge_request_reminder_shown_to_secondary_team: + (trusted_teams) Sent a team merge request reminder (deprecated, replaced + by 'Sent a team merge request reminder') + :ivar TeamMergeRequestRevokedType EventType.team_merge_request_revoked: + (trusted_teams) Canceled the team merge + :ivar TeamMergeRequestSentShownToPrimaryTeamType + EventType.team_merge_request_sent_shown_to_primary_team: (trusted_teams) + Requested to merge their Dropbox team into yours + :ivar TeamMergeRequestSentShownToSecondaryTeamType + EventType.team_merge_request_sent_shown_to_secondary_team: + (trusted_teams) Requested to merge your team into another Dropbox team + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def app_link_team(cls, val): + """ + Create an instance of this class set to the ``app_link_team`` tag with + value ``val``. + + :param AppLinkTeamType val: + :rtype: EventType + """ + return cls('app_link_team', val) + + @classmethod + def app_link_user(cls, val): + """ + Create an instance of this class set to the ``app_link_user`` tag with + value ``val``. + + :param AppLinkUserType val: + :rtype: EventType + """ + return cls('app_link_user', val) + + @classmethod + def app_unlink_team(cls, val): + """ + Create an instance of this class set to the ``app_unlink_team`` tag with + value ``val``. + + :param AppUnlinkTeamType val: + :rtype: EventType + """ + return cls('app_unlink_team', val) + + @classmethod + def app_unlink_user(cls, val): + """ + Create an instance of this class set to the ``app_unlink_user`` tag with + value ``val``. + + :param AppUnlinkUserType val: + :rtype: EventType + """ + return cls('app_unlink_user', val) + + @classmethod + def integration_connected(cls, val): + """ + Create an instance of this class set to the ``integration_connected`` + tag with value ``val``. + + :param IntegrationConnectedType val: + :rtype: EventType + """ + return cls('integration_connected', val) + + @classmethod + def integration_disconnected(cls, val): + """ + Create an instance of this class set to the ``integration_disconnected`` + tag with value ``val``. + + :param IntegrationDisconnectedType val: + :rtype: EventType + """ + return cls('integration_disconnected', val) + + @classmethod + def file_add_comment(cls, val): + """ + Create an instance of this class set to the ``file_add_comment`` tag + with value ``val``. + + :param FileAddCommentType val: + :rtype: EventType + """ + return cls('file_add_comment', val) + + @classmethod + def file_change_comment_subscription(cls, val): + """ + Create an instance of this class set to the + ``file_change_comment_subscription`` tag with value ``val``. + + :param FileChangeCommentSubscriptionType val: + :rtype: EventType + """ + return cls('file_change_comment_subscription', val) + + @classmethod + def file_delete_comment(cls, val): + """ + Create an instance of this class set to the ``file_delete_comment`` tag + with value ``val``. + + :param FileDeleteCommentType val: + :rtype: EventType + """ + return cls('file_delete_comment', val) + + @classmethod + def file_edit_comment(cls, val): + """ + Create an instance of this class set to the ``file_edit_comment`` tag + with value ``val``. + + :param FileEditCommentType val: + :rtype: EventType + """ + return cls('file_edit_comment', val) + + @classmethod + def file_like_comment(cls, val): + """ + Create an instance of this class set to the ``file_like_comment`` tag + with value ``val``. + + :param FileLikeCommentType val: + :rtype: EventType + """ + return cls('file_like_comment', val) + + @classmethod + def file_resolve_comment(cls, val): + """ + Create an instance of this class set to the ``file_resolve_comment`` tag + with value ``val``. + + :param FileResolveCommentType val: + :rtype: EventType + """ + return cls('file_resolve_comment', val) + + @classmethod + def file_unlike_comment(cls, val): + """ + Create an instance of this class set to the ``file_unlike_comment`` tag + with value ``val``. + + :param FileUnlikeCommentType val: + :rtype: EventType + """ + return cls('file_unlike_comment', val) + + @classmethod + def file_unresolve_comment(cls, val): + """ + Create an instance of this class set to the ``file_unresolve_comment`` + tag with value ``val``. + + :param FileUnresolveCommentType val: + :rtype: EventType + """ + return cls('file_unresolve_comment', val) + + @classmethod + def device_change_ip_desktop(cls, val): + """ + Create an instance of this class set to the ``device_change_ip_desktop`` + tag with value ``val``. + + :param DeviceChangeIpDesktopType val: + :rtype: EventType + """ + return cls('device_change_ip_desktop', val) + + @classmethod + def device_change_ip_mobile(cls, val): + """ + Create an instance of this class set to the ``device_change_ip_mobile`` + tag with value ``val``. + + :param DeviceChangeIpMobileType val: + :rtype: EventType + """ + return cls('device_change_ip_mobile', val) + + @classmethod + def device_change_ip_web(cls, val): + """ + Create an instance of this class set to the ``device_change_ip_web`` tag + with value ``val``. + + :param DeviceChangeIpWebType val: + :rtype: EventType + """ + return cls('device_change_ip_web', val) + + @classmethod + def device_delete_on_unlink_fail(cls, val): + """ + Create an instance of this class set to the + ``device_delete_on_unlink_fail`` tag with value ``val``. + + :param DeviceDeleteOnUnlinkFailType val: + :rtype: EventType + """ + return cls('device_delete_on_unlink_fail', val) + + @classmethod + def device_delete_on_unlink_success(cls, val): + """ + Create an instance of this class set to the + ``device_delete_on_unlink_success`` tag with value ``val``. + + :param DeviceDeleteOnUnlinkSuccessType val: + :rtype: EventType + """ + return cls('device_delete_on_unlink_success', val) + + @classmethod + def device_link_fail(cls, val): + """ + Create an instance of this class set to the ``device_link_fail`` tag + with value ``val``. + + :param DeviceLinkFailType val: + :rtype: EventType + """ + return cls('device_link_fail', val) + + @classmethod + def device_link_success(cls, val): + """ + Create an instance of this class set to the ``device_link_success`` tag + with value ``val``. + + :param DeviceLinkSuccessType val: + :rtype: EventType + """ + return cls('device_link_success', val) + + @classmethod + def device_management_disabled(cls, val): + """ + Create an instance of this class set to the + ``device_management_disabled`` tag with value ``val``. + + :param DeviceManagementDisabledType val: + :rtype: EventType + """ + return cls('device_management_disabled', val) + + @classmethod + def device_management_enabled(cls, val): + """ + Create an instance of this class set to the + ``device_management_enabled`` tag with value ``val``. + + :param DeviceManagementEnabledType val: + :rtype: EventType + """ + return cls('device_management_enabled', val) + + @classmethod + def device_unlink(cls, val): + """ + Create an instance of this class set to the ``device_unlink`` tag with + value ``val``. + + :param DeviceUnlinkType val: + :rtype: EventType + """ + return cls('device_unlink', val) + + @classmethod + def emm_refresh_auth_token(cls, val): + """ + Create an instance of this class set to the ``emm_refresh_auth_token`` + tag with value ``val``. + + :param EmmRefreshAuthTokenType val: + :rtype: EventType + """ + return cls('emm_refresh_auth_token', val) + + @classmethod + def account_capture_change_availability(cls, val): + """ + Create an instance of this class set to the + ``account_capture_change_availability`` tag with value ``val``. + + :param AccountCaptureChangeAvailabilityType val: + :rtype: EventType + """ + return cls('account_capture_change_availability', val) + + @classmethod + def account_capture_migrate_account(cls, val): + """ + Create an instance of this class set to the + ``account_capture_migrate_account`` tag with value ``val``. + + :param AccountCaptureMigrateAccountType val: + :rtype: EventType + """ + return cls('account_capture_migrate_account', val) + + @classmethod + def account_capture_notification_emails_sent(cls, val): + """ + Create an instance of this class set to the + ``account_capture_notification_emails_sent`` tag with value ``val``. + + :param AccountCaptureNotificationEmailsSentType val: + :rtype: EventType + """ + return cls('account_capture_notification_emails_sent', val) + + @classmethod + def account_capture_relinquish_account(cls, val): + """ + Create an instance of this class set to the + ``account_capture_relinquish_account`` tag with value ``val``. + + :param AccountCaptureRelinquishAccountType val: + :rtype: EventType + """ + return cls('account_capture_relinquish_account', val) + + @classmethod + def disabled_domain_invites(cls, val): + """ + Create an instance of this class set to the ``disabled_domain_invites`` + tag with value ``val``. + + :param DisabledDomainInvitesType val: + :rtype: EventType + """ + return cls('disabled_domain_invites', val) + + @classmethod + def domain_invites_approve_request_to_join_team(cls, val): + """ + Create an instance of this class set to the + ``domain_invites_approve_request_to_join_team`` tag with value ``val``. + + :param DomainInvitesApproveRequestToJoinTeamType val: + :rtype: EventType + """ + return cls('domain_invites_approve_request_to_join_team', val) + + @classmethod + def domain_invites_decline_request_to_join_team(cls, val): + """ + Create an instance of this class set to the + ``domain_invites_decline_request_to_join_team`` tag with value ``val``. + + :param DomainInvitesDeclineRequestToJoinTeamType val: + :rtype: EventType + """ + return cls('domain_invites_decline_request_to_join_team', val) + + @classmethod + def domain_invites_email_existing_users(cls, val): + """ + Create an instance of this class set to the + ``domain_invites_email_existing_users`` tag with value ``val``. + + :param DomainInvitesEmailExistingUsersType val: + :rtype: EventType + """ + return cls('domain_invites_email_existing_users', val) + + @classmethod + def domain_invites_request_to_join_team(cls, val): + """ + Create an instance of this class set to the + ``domain_invites_request_to_join_team`` tag with value ``val``. + + :param DomainInvitesRequestToJoinTeamType val: + :rtype: EventType + """ + return cls('domain_invites_request_to_join_team', val) + + @classmethod + def domain_invites_set_invite_new_user_pref_to_no(cls, val): + """ + Create an instance of this class set to the + ``domain_invites_set_invite_new_user_pref_to_no`` tag with value + ``val``. + + :param DomainInvitesSetInviteNewUserPrefToNoType val: + :rtype: EventType + """ + return cls('domain_invites_set_invite_new_user_pref_to_no', val) + + @classmethod + def domain_invites_set_invite_new_user_pref_to_yes(cls, val): + """ + Create an instance of this class set to the + ``domain_invites_set_invite_new_user_pref_to_yes`` tag with value + ``val``. + + :param DomainInvitesSetInviteNewUserPrefToYesType val: + :rtype: EventType + """ + return cls('domain_invites_set_invite_new_user_pref_to_yes', val) + + @classmethod + def domain_verification_add_domain_fail(cls, val): + """ + Create an instance of this class set to the + ``domain_verification_add_domain_fail`` tag with value ``val``. + + :param DomainVerificationAddDomainFailType val: + :rtype: EventType + """ + return cls('domain_verification_add_domain_fail', val) + + @classmethod + def domain_verification_add_domain_success(cls, val): + """ + Create an instance of this class set to the + ``domain_verification_add_domain_success`` tag with value ``val``. + + :param DomainVerificationAddDomainSuccessType val: + :rtype: EventType + """ + return cls('domain_verification_add_domain_success', val) + + @classmethod + def domain_verification_remove_domain(cls, val): + """ + Create an instance of this class set to the + ``domain_verification_remove_domain`` tag with value ``val``. + + :param DomainVerificationRemoveDomainType val: + :rtype: EventType + """ + return cls('domain_verification_remove_domain', val) + + @classmethod + def enabled_domain_invites(cls, val): + """ + Create an instance of this class set to the ``enabled_domain_invites`` + tag with value ``val``. + + :param EnabledDomainInvitesType val: + :rtype: EventType + """ + return cls('enabled_domain_invites', val) + + @classmethod + def create_folder(cls, val): + """ + Create an instance of this class set to the ``create_folder`` tag with + value ``val``. + + :param CreateFolderType val: + :rtype: EventType + """ + return cls('create_folder', val) + + @classmethod + def file_add(cls, val): + """ + Create an instance of this class set to the ``file_add`` tag with value + ``val``. + + :param FileAddType val: + :rtype: EventType + """ + return cls('file_add', val) + + @classmethod + def file_copy(cls, val): + """ + Create an instance of this class set to the ``file_copy`` tag with value + ``val``. + + :param FileCopyType val: + :rtype: EventType + """ + return cls('file_copy', val) + + @classmethod + def file_delete(cls, val): + """ + Create an instance of this class set to the ``file_delete`` tag with + value ``val``. + + :param FileDeleteType val: + :rtype: EventType + """ + return cls('file_delete', val) + + @classmethod + def file_download(cls, val): + """ + Create an instance of this class set to the ``file_download`` tag with + value ``val``. + + :param FileDownloadType val: + :rtype: EventType + """ + return cls('file_download', val) + + @classmethod + def file_edit(cls, val): + """ + Create an instance of this class set to the ``file_edit`` tag with value + ``val``. + + :param FileEditType val: + :rtype: EventType + """ + return cls('file_edit', val) + + @classmethod + def file_get_copy_reference(cls, val): + """ + Create an instance of this class set to the ``file_get_copy_reference`` + tag with value ``val``. + + :param FileGetCopyReferenceType val: + :rtype: EventType + """ + return cls('file_get_copy_reference', val) + + @classmethod + def file_locking_lock_status_changed(cls, val): + """ + Create an instance of this class set to the + ``file_locking_lock_status_changed`` tag with value ``val``. + + :param FileLockingLockStatusChangedType val: + :rtype: EventType + """ + return cls('file_locking_lock_status_changed', val) + + @classmethod + def file_move(cls, val): + """ + Create an instance of this class set to the ``file_move`` tag with value + ``val``. + + :param FileMoveType val: + :rtype: EventType + """ + return cls('file_move', val) + + @classmethod + def file_permanently_delete(cls, val): + """ + Create an instance of this class set to the ``file_permanently_delete`` + tag with value ``val``. + + :param FilePermanentlyDeleteType val: + :rtype: EventType + """ + return cls('file_permanently_delete', val) + + @classmethod + def file_preview(cls, val): + """ + Create an instance of this class set to the ``file_preview`` tag with + value ``val``. + + :param FilePreviewType val: + :rtype: EventType + """ + return cls('file_preview', val) + + @classmethod + def file_rename(cls, val): + """ + Create an instance of this class set to the ``file_rename`` tag with + value ``val``. + + :param FileRenameType val: + :rtype: EventType + """ + return cls('file_rename', val) + + @classmethod + def file_restore(cls, val): + """ + Create an instance of this class set to the ``file_restore`` tag with + value ``val``. + + :param FileRestoreType val: + :rtype: EventType + """ + return cls('file_restore', val) + + @classmethod + def file_revert(cls, val): + """ + Create an instance of this class set to the ``file_revert`` tag with + value ``val``. + + :param FileRevertType val: + :rtype: EventType + """ + return cls('file_revert', val) + + @classmethod + def file_rollback_changes(cls, val): + """ + Create an instance of this class set to the ``file_rollback_changes`` + tag with value ``val``. + + :param FileRollbackChangesType val: + :rtype: EventType + """ + return cls('file_rollback_changes', val) + + @classmethod + def file_save_copy_reference(cls, val): + """ + Create an instance of this class set to the ``file_save_copy_reference`` + tag with value ``val``. + + :param FileSaveCopyReferenceType val: + :rtype: EventType + """ + return cls('file_save_copy_reference', val) + + @classmethod + def folder_overview_description_changed(cls, val): + """ + Create an instance of this class set to the + ``folder_overview_description_changed`` tag with value ``val``. + + :param FolderOverviewDescriptionChangedType val: + :rtype: EventType + """ + return cls('folder_overview_description_changed', val) + + @classmethod + def folder_overview_item_pinned(cls, val): + """ + Create an instance of this class set to the + ``folder_overview_item_pinned`` tag with value ``val``. + + :param FolderOverviewItemPinnedType val: + :rtype: EventType + """ + return cls('folder_overview_item_pinned', val) + + @classmethod + def folder_overview_item_unpinned(cls, val): + """ + Create an instance of this class set to the + ``folder_overview_item_unpinned`` tag with value ``val``. + + :param FolderOverviewItemUnpinnedType val: + :rtype: EventType + """ + return cls('folder_overview_item_unpinned', val) + + @classmethod + def rewind_folder(cls, val): + """ + Create an instance of this class set to the ``rewind_folder`` tag with + value ``val``. + + :param RewindFolderType val: + :rtype: EventType + """ + return cls('rewind_folder', val) + + @classmethod + def file_request_change(cls, val): + """ + Create an instance of this class set to the ``file_request_change`` tag + with value ``val``. + + :param FileRequestChangeType val: + :rtype: EventType + """ + return cls('file_request_change', val) + + @classmethod + def file_request_close(cls, val): + """ + Create an instance of this class set to the ``file_request_close`` tag + with value ``val``. + + :param FileRequestCloseType val: + :rtype: EventType + """ + return cls('file_request_close', val) + + @classmethod + def file_request_create(cls, val): + """ + Create an instance of this class set to the ``file_request_create`` tag + with value ``val``. + + :param FileRequestCreateType val: + :rtype: EventType + """ + return cls('file_request_create', val) + + @classmethod + def file_request_delete(cls, val): + """ + Create an instance of this class set to the ``file_request_delete`` tag + with value ``val``. + + :param FileRequestDeleteType val: + :rtype: EventType + """ + return cls('file_request_delete', val) + + @classmethod + def file_request_receive_file(cls, val): + """ + Create an instance of this class set to the + ``file_request_receive_file`` tag with value ``val``. + + :param FileRequestReceiveFileType val: + :rtype: EventType + """ + return cls('file_request_receive_file', val) + + @classmethod + def group_add_external_id(cls, val): + """ + Create an instance of this class set to the ``group_add_external_id`` + tag with value ``val``. + + :param GroupAddExternalIdType val: + :rtype: EventType + """ + return cls('group_add_external_id', val) + + @classmethod + def group_add_member(cls, val): + """ + Create an instance of this class set to the ``group_add_member`` tag + with value ``val``. + + :param GroupAddMemberType val: + :rtype: EventType + """ + return cls('group_add_member', val) + + @classmethod + def group_change_external_id(cls, val): + """ + Create an instance of this class set to the ``group_change_external_id`` + tag with value ``val``. + + :param GroupChangeExternalIdType val: + :rtype: EventType + """ + return cls('group_change_external_id', val) + + @classmethod + def group_change_management_type(cls, val): + """ + Create an instance of this class set to the + ``group_change_management_type`` tag with value ``val``. + + :param GroupChangeManagementTypeType val: + :rtype: EventType + """ + return cls('group_change_management_type', val) + + @classmethod + def group_change_member_role(cls, val): + """ + Create an instance of this class set to the ``group_change_member_role`` + tag with value ``val``. + + :param GroupChangeMemberRoleType val: + :rtype: EventType + """ + return cls('group_change_member_role', val) + + @classmethod + def group_create(cls, val): + """ + Create an instance of this class set to the ``group_create`` tag with + value ``val``. + + :param GroupCreateType val: + :rtype: EventType + """ + return cls('group_create', val) + + @classmethod + def group_delete(cls, val): + """ + Create an instance of this class set to the ``group_delete`` tag with + value ``val``. + + :param GroupDeleteType val: + :rtype: EventType + """ + return cls('group_delete', val) + + @classmethod + def group_description_updated(cls, val): + """ + Create an instance of this class set to the + ``group_description_updated`` tag with value ``val``. + + :param GroupDescriptionUpdatedType val: + :rtype: EventType + """ + return cls('group_description_updated', val) + + @classmethod + def group_join_policy_updated(cls, val): + """ + Create an instance of this class set to the + ``group_join_policy_updated`` tag with value ``val``. + + :param GroupJoinPolicyUpdatedType val: + :rtype: EventType + """ + return cls('group_join_policy_updated', val) + + @classmethod + def group_moved(cls, val): + """ + Create an instance of this class set to the ``group_moved`` tag with + value ``val``. + + :param GroupMovedType val: + :rtype: EventType + """ + return cls('group_moved', val) + + @classmethod + def group_remove_external_id(cls, val): + """ + Create an instance of this class set to the ``group_remove_external_id`` + tag with value ``val``. + + :param GroupRemoveExternalIdType val: + :rtype: EventType + """ + return cls('group_remove_external_id', val) + + @classmethod + def group_remove_member(cls, val): + """ + Create an instance of this class set to the ``group_remove_member`` tag + with value ``val``. + + :param GroupRemoveMemberType val: + :rtype: EventType + """ + return cls('group_remove_member', val) + + @classmethod + def group_rename(cls, val): + """ + Create an instance of this class set to the ``group_rename`` tag with + value ``val``. + + :param GroupRenameType val: + :rtype: EventType + """ + return cls('group_rename', val) + + @classmethod + def legal_holds_activate_a_hold(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_activate_a_hold`` tag with value ``val``. + + :param LegalHoldsActivateAHoldType val: + :rtype: EventType + """ + return cls('legal_holds_activate_a_hold', val) + + @classmethod + def legal_holds_add_members(cls, val): + """ + Create an instance of this class set to the ``legal_holds_add_members`` + tag with value ``val``. + + :param LegalHoldsAddMembersType val: + :rtype: EventType + """ + return cls('legal_holds_add_members', val) + + @classmethod + def legal_holds_change_hold_details(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_change_hold_details`` tag with value ``val``. + + :param LegalHoldsChangeHoldDetailsType val: + :rtype: EventType + """ + return cls('legal_holds_change_hold_details', val) + + @classmethod + def legal_holds_change_hold_name(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_change_hold_name`` tag with value ``val``. + + :param LegalHoldsChangeHoldNameType val: + :rtype: EventType + """ + return cls('legal_holds_change_hold_name', val) + + @classmethod + def legal_holds_export_a_hold(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_export_a_hold`` tag with value ``val``. + + :param LegalHoldsExportAHoldType val: + :rtype: EventType + """ + return cls('legal_holds_export_a_hold', val) + + @classmethod + def legal_holds_export_cancelled(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_export_cancelled`` tag with value ``val``. + + :param LegalHoldsExportCancelledType val: + :rtype: EventType + """ + return cls('legal_holds_export_cancelled', val) + + @classmethod + def legal_holds_export_downloaded(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_export_downloaded`` tag with value ``val``. + + :param LegalHoldsExportDownloadedType val: + :rtype: EventType + """ + return cls('legal_holds_export_downloaded', val) + + @classmethod + def legal_holds_export_removed(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_export_removed`` tag with value ``val``. + + :param LegalHoldsExportRemovedType val: + :rtype: EventType + """ + return cls('legal_holds_export_removed', val) + + @classmethod + def legal_holds_release_a_hold(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_release_a_hold`` tag with value ``val``. + + :param LegalHoldsReleaseAHoldType val: + :rtype: EventType + """ + return cls('legal_holds_release_a_hold', val) + + @classmethod + def legal_holds_remove_members(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_remove_members`` tag with value ``val``. + + :param LegalHoldsRemoveMembersType val: + :rtype: EventType + """ + return cls('legal_holds_remove_members', val) + + @classmethod + def legal_holds_report_a_hold(cls, val): + """ + Create an instance of this class set to the + ``legal_holds_report_a_hold`` tag with value ``val``. + + :param LegalHoldsReportAHoldType val: + :rtype: EventType + """ + return cls('legal_holds_report_a_hold', val) + + @classmethod + def account_lock_or_unlocked(cls, val): + """ + Create an instance of this class set to the ``account_lock_or_unlocked`` + tag with value ``val``. + + :param AccountLockOrUnlockedType val: + :rtype: EventType + """ + return cls('account_lock_or_unlocked', val) + + @classmethod + def emm_error(cls, val): + """ + Create an instance of this class set to the ``emm_error`` tag with value + ``val``. + + :param EmmErrorType val: + :rtype: EventType + """ + return cls('emm_error', val) + + @classmethod + def guest_admin_signed_in_via_trusted_teams(cls, val): + """ + Create an instance of this class set to the + ``guest_admin_signed_in_via_trusted_teams`` tag with value ``val``. + + :param GuestAdminSignedInViaTrustedTeamsType val: + :rtype: EventType + """ + return cls('guest_admin_signed_in_via_trusted_teams', val) + + @classmethod + def guest_admin_signed_out_via_trusted_teams(cls, val): + """ + Create an instance of this class set to the + ``guest_admin_signed_out_via_trusted_teams`` tag with value ``val``. + + :param GuestAdminSignedOutViaTrustedTeamsType val: + :rtype: EventType + """ + return cls('guest_admin_signed_out_via_trusted_teams', val) + + @classmethod + def login_fail(cls, val): + """ + Create an instance of this class set to the ``login_fail`` tag with + value ``val``. + + :param LoginFailType val: + :rtype: EventType + """ + return cls('login_fail', val) + + @classmethod + def login_success(cls, val): + """ + Create an instance of this class set to the ``login_success`` tag with + value ``val``. + + :param LoginSuccessType val: + :rtype: EventType + """ + return cls('login_success', val) + + @classmethod + def logout(cls, val): + """ + Create an instance of this class set to the ``logout`` tag with value + ``val``. + + :param LogoutType val: + :rtype: EventType + """ + return cls('logout', val) + + @classmethod + def reseller_support_session_end(cls, val): + """ + Create an instance of this class set to the + ``reseller_support_session_end`` tag with value ``val``. + + :param ResellerSupportSessionEndType val: + :rtype: EventType + """ + return cls('reseller_support_session_end', val) + + @classmethod + def reseller_support_session_start(cls, val): + """ + Create an instance of this class set to the + ``reseller_support_session_start`` tag with value ``val``. + + :param ResellerSupportSessionStartType val: + :rtype: EventType + """ + return cls('reseller_support_session_start', val) + + @classmethod + def sign_in_as_session_end(cls, val): + """ + Create an instance of this class set to the ``sign_in_as_session_end`` + tag with value ``val``. + + :param SignInAsSessionEndType val: + :rtype: EventType + """ + return cls('sign_in_as_session_end', val) + + @classmethod + def sign_in_as_session_start(cls, val): + """ + Create an instance of this class set to the ``sign_in_as_session_start`` + tag with value ``val``. + + :param SignInAsSessionStartType val: + :rtype: EventType + """ + return cls('sign_in_as_session_start', val) + + @classmethod + def sso_error(cls, val): + """ + Create an instance of this class set to the ``sso_error`` tag with value + ``val``. + + :param SsoErrorType val: + :rtype: EventType + """ + return cls('sso_error', val) + + @classmethod + def create_team_invite_link(cls, val): + """ + Create an instance of this class set to the ``create_team_invite_link`` + tag with value ``val``. + + :param CreateTeamInviteLinkType val: + :rtype: EventType + """ + return cls('create_team_invite_link', val) + + @classmethod + def delete_team_invite_link(cls, val): + """ + Create an instance of this class set to the ``delete_team_invite_link`` + tag with value ``val``. + + :param DeleteTeamInviteLinkType val: + :rtype: EventType + """ + return cls('delete_team_invite_link', val) + + @classmethod + def member_add_external_id(cls, val): + """ + Create an instance of this class set to the ``member_add_external_id`` + tag with value ``val``. + + :param MemberAddExternalIdType val: + :rtype: EventType + """ + return cls('member_add_external_id', val) + + @classmethod + def member_add_name(cls, val): + """ + Create an instance of this class set to the ``member_add_name`` tag with + value ``val``. + + :param MemberAddNameType val: + :rtype: EventType + """ + return cls('member_add_name', val) + + @classmethod + def member_change_admin_role(cls, val): + """ + Create an instance of this class set to the ``member_change_admin_role`` + tag with value ``val``. + + :param MemberChangeAdminRoleType val: + :rtype: EventType + """ + return cls('member_change_admin_role', val) + + @classmethod + def member_change_email(cls, val): + """ + Create an instance of this class set to the ``member_change_email`` tag + with value ``val``. + + :param MemberChangeEmailType val: + :rtype: EventType + """ + return cls('member_change_email', val) + + @classmethod + def member_change_external_id(cls, val): + """ + Create an instance of this class set to the + ``member_change_external_id`` tag with value ``val``. + + :param MemberChangeExternalIdType val: + :rtype: EventType + """ + return cls('member_change_external_id', val) + + @classmethod + def member_change_membership_type(cls, val): + """ + Create an instance of this class set to the + ``member_change_membership_type`` tag with value ``val``. + + :param MemberChangeMembershipTypeType val: + :rtype: EventType + """ + return cls('member_change_membership_type', val) + + @classmethod + def member_change_name(cls, val): + """ + Create an instance of this class set to the ``member_change_name`` tag + with value ``val``. + + :param MemberChangeNameType val: + :rtype: EventType + """ + return cls('member_change_name', val) + + @classmethod + def member_change_status(cls, val): + """ + Create an instance of this class set to the ``member_change_status`` tag + with value ``val``. + + :param MemberChangeStatusType val: + :rtype: EventType + """ + return cls('member_change_status', val) + + @classmethod + def member_delete_manual_contacts(cls, val): + """ + Create an instance of this class set to the + ``member_delete_manual_contacts`` tag with value ``val``. + + :param MemberDeleteManualContactsType val: + :rtype: EventType + """ + return cls('member_delete_manual_contacts', val) + + @classmethod + def member_delete_profile_photo(cls, val): + """ + Create an instance of this class set to the + ``member_delete_profile_photo`` tag with value ``val``. + + :param MemberDeleteProfilePhotoType val: + :rtype: EventType + """ + return cls('member_delete_profile_photo', val) + + @classmethod + def member_permanently_delete_account_contents(cls, val): + """ + Create an instance of this class set to the + ``member_permanently_delete_account_contents`` tag with value ``val``. + + :param MemberPermanentlyDeleteAccountContentsType val: + :rtype: EventType + """ + return cls('member_permanently_delete_account_contents', val) + + @classmethod + def member_remove_external_id(cls, val): + """ + Create an instance of this class set to the + ``member_remove_external_id`` tag with value ``val``. + + :param MemberRemoveExternalIdType val: + :rtype: EventType + """ + return cls('member_remove_external_id', val) + + @classmethod + def member_set_profile_photo(cls, val): + """ + Create an instance of this class set to the ``member_set_profile_photo`` + tag with value ``val``. + + :param MemberSetProfilePhotoType val: + :rtype: EventType + """ + return cls('member_set_profile_photo', val) + + @classmethod + def member_space_limits_add_custom_quota(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_add_custom_quota`` tag with value ``val``. + + :param MemberSpaceLimitsAddCustomQuotaType val: + :rtype: EventType + """ + return cls('member_space_limits_add_custom_quota', val) + + @classmethod + def member_space_limits_change_custom_quota(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_change_custom_quota`` tag with value ``val``. + + :param MemberSpaceLimitsChangeCustomQuotaType val: + :rtype: EventType + """ + return cls('member_space_limits_change_custom_quota', val) + + @classmethod + def member_space_limits_change_status(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_change_status`` tag with value ``val``. + + :param MemberSpaceLimitsChangeStatusType val: + :rtype: EventType + """ + return cls('member_space_limits_change_status', val) + + @classmethod + def member_space_limits_remove_custom_quota(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_remove_custom_quota`` tag with value ``val``. + + :param MemberSpaceLimitsRemoveCustomQuotaType val: + :rtype: EventType + """ + return cls('member_space_limits_remove_custom_quota', val) + + @classmethod + def member_suggest(cls, val): + """ + Create an instance of this class set to the ``member_suggest`` tag with + value ``val``. + + :param MemberSuggestType val: + :rtype: EventType + """ + return cls('member_suggest', val) + + @classmethod + def member_transfer_account_contents(cls, val): + """ + Create an instance of this class set to the + ``member_transfer_account_contents`` tag with value ``val``. + + :param MemberTransferAccountContentsType val: + :rtype: EventType + """ + return cls('member_transfer_account_contents', val) + + @classmethod + def pending_secondary_email_added(cls, val): + """ + Create an instance of this class set to the + ``pending_secondary_email_added`` tag with value ``val``. + + :param PendingSecondaryEmailAddedType val: + :rtype: EventType + """ + return cls('pending_secondary_email_added', val) + + @classmethod + def secondary_email_deleted(cls, val): + """ + Create an instance of this class set to the ``secondary_email_deleted`` + tag with value ``val``. + + :param SecondaryEmailDeletedType val: + :rtype: EventType + """ + return cls('secondary_email_deleted', val) + + @classmethod + def secondary_email_verified(cls, val): + """ + Create an instance of this class set to the ``secondary_email_verified`` + tag with value ``val``. + + :param SecondaryEmailVerifiedType val: + :rtype: EventType + """ + return cls('secondary_email_verified', val) + + @classmethod + def secondary_mails_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``secondary_mails_policy_changed`` tag with value ``val``. + + :param SecondaryMailsPolicyChangedType val: + :rtype: EventType + """ + return cls('secondary_mails_policy_changed', val) + + @classmethod + def binder_add_page(cls, val): + """ + Create an instance of this class set to the ``binder_add_page`` tag with + value ``val``. + + :param BinderAddPageType val: + :rtype: EventType + """ + return cls('binder_add_page', val) + + @classmethod + def binder_add_section(cls, val): + """ + Create an instance of this class set to the ``binder_add_section`` tag + with value ``val``. + + :param BinderAddSectionType val: + :rtype: EventType + """ + return cls('binder_add_section', val) + + @classmethod + def binder_remove_page(cls, val): + """ + Create an instance of this class set to the ``binder_remove_page`` tag + with value ``val``. + + :param BinderRemovePageType val: + :rtype: EventType + """ + return cls('binder_remove_page', val) + + @classmethod + def binder_remove_section(cls, val): + """ + Create an instance of this class set to the ``binder_remove_section`` + tag with value ``val``. + + :param BinderRemoveSectionType val: + :rtype: EventType + """ + return cls('binder_remove_section', val) + + @classmethod + def binder_rename_page(cls, val): + """ + Create an instance of this class set to the ``binder_rename_page`` tag + with value ``val``. + + :param BinderRenamePageType val: + :rtype: EventType + """ + return cls('binder_rename_page', val) + + @classmethod + def binder_rename_section(cls, val): + """ + Create an instance of this class set to the ``binder_rename_section`` + tag with value ``val``. + + :param BinderRenameSectionType val: + :rtype: EventType + """ + return cls('binder_rename_section', val) + + @classmethod + def binder_reorder_page(cls, val): + """ + Create an instance of this class set to the ``binder_reorder_page`` tag + with value ``val``. + + :param BinderReorderPageType val: + :rtype: EventType + """ + return cls('binder_reorder_page', val) + + @classmethod + def binder_reorder_section(cls, val): + """ + Create an instance of this class set to the ``binder_reorder_section`` + tag with value ``val``. + + :param BinderReorderSectionType val: + :rtype: EventType + """ + return cls('binder_reorder_section', val) + + @classmethod + def paper_content_add_member(cls, val): + """ + Create an instance of this class set to the ``paper_content_add_member`` + tag with value ``val``. + + :param PaperContentAddMemberType val: + :rtype: EventType + """ + return cls('paper_content_add_member', val) + + @classmethod + def paper_content_add_to_folder(cls, val): + """ + Create an instance of this class set to the + ``paper_content_add_to_folder`` tag with value ``val``. + + :param PaperContentAddToFolderType val: + :rtype: EventType + """ + return cls('paper_content_add_to_folder', val) + + @classmethod + def paper_content_archive(cls, val): + """ + Create an instance of this class set to the ``paper_content_archive`` + tag with value ``val``. + + :param PaperContentArchiveType val: + :rtype: EventType + """ + return cls('paper_content_archive', val) + + @classmethod + def paper_content_create(cls, val): + """ + Create an instance of this class set to the ``paper_content_create`` tag + with value ``val``. + + :param PaperContentCreateType val: + :rtype: EventType + """ + return cls('paper_content_create', val) + + @classmethod + def paper_content_permanently_delete(cls, val): + """ + Create an instance of this class set to the + ``paper_content_permanently_delete`` tag with value ``val``. + + :param PaperContentPermanentlyDeleteType val: + :rtype: EventType + """ + return cls('paper_content_permanently_delete', val) + + @classmethod + def paper_content_remove_from_folder(cls, val): + """ + Create an instance of this class set to the + ``paper_content_remove_from_folder`` tag with value ``val``. + + :param PaperContentRemoveFromFolderType val: + :rtype: EventType + """ + return cls('paper_content_remove_from_folder', val) + + @classmethod + def paper_content_remove_member(cls, val): + """ + Create an instance of this class set to the + ``paper_content_remove_member`` tag with value ``val``. + + :param PaperContentRemoveMemberType val: + :rtype: EventType + """ + return cls('paper_content_remove_member', val) + + @classmethod + def paper_content_rename(cls, val): + """ + Create an instance of this class set to the ``paper_content_rename`` tag + with value ``val``. + + :param PaperContentRenameType val: + :rtype: EventType + """ + return cls('paper_content_rename', val) + + @classmethod + def paper_content_restore(cls, val): + """ + Create an instance of this class set to the ``paper_content_restore`` + tag with value ``val``. + + :param PaperContentRestoreType val: + :rtype: EventType + """ + return cls('paper_content_restore', val) + + @classmethod + def paper_doc_add_comment(cls, val): + """ + Create an instance of this class set to the ``paper_doc_add_comment`` + tag with value ``val``. + + :param PaperDocAddCommentType val: + :rtype: EventType + """ + return cls('paper_doc_add_comment', val) + + @classmethod + def paper_doc_change_member_role(cls, val): + """ + Create an instance of this class set to the + ``paper_doc_change_member_role`` tag with value ``val``. + + :param PaperDocChangeMemberRoleType val: + :rtype: EventType + """ + return cls('paper_doc_change_member_role', val) + + @classmethod + def paper_doc_change_sharing_policy(cls, val): + """ + Create an instance of this class set to the + ``paper_doc_change_sharing_policy`` tag with value ``val``. + + :param PaperDocChangeSharingPolicyType val: + :rtype: EventType + """ + return cls('paper_doc_change_sharing_policy', val) + + @classmethod + def paper_doc_change_subscription(cls, val): + """ + Create an instance of this class set to the + ``paper_doc_change_subscription`` tag with value ``val``. + + :param PaperDocChangeSubscriptionType val: + :rtype: EventType + """ + return cls('paper_doc_change_subscription', val) + + @classmethod + def paper_doc_deleted(cls, val): + """ + Create an instance of this class set to the ``paper_doc_deleted`` tag + with value ``val``. + + :param PaperDocDeletedType val: + :rtype: EventType + """ + return cls('paper_doc_deleted', val) + + @classmethod + def paper_doc_delete_comment(cls, val): + """ + Create an instance of this class set to the ``paper_doc_delete_comment`` + tag with value ``val``. + + :param PaperDocDeleteCommentType val: + :rtype: EventType + """ + return cls('paper_doc_delete_comment', val) + + @classmethod + def paper_doc_download(cls, val): + """ + Create an instance of this class set to the ``paper_doc_download`` tag + with value ``val``. + + :param PaperDocDownloadType val: + :rtype: EventType + """ + return cls('paper_doc_download', val) + + @classmethod + def paper_doc_edit(cls, val): + """ + Create an instance of this class set to the ``paper_doc_edit`` tag with + value ``val``. + + :param PaperDocEditType val: + :rtype: EventType + """ + return cls('paper_doc_edit', val) + + @classmethod + def paper_doc_edit_comment(cls, val): + """ + Create an instance of this class set to the ``paper_doc_edit_comment`` + tag with value ``val``. + + :param PaperDocEditCommentType val: + :rtype: EventType + """ + return cls('paper_doc_edit_comment', val) + + @classmethod + def paper_doc_followed(cls, val): + """ + Create an instance of this class set to the ``paper_doc_followed`` tag + with value ``val``. + + :param PaperDocFollowedType val: + :rtype: EventType + """ + return cls('paper_doc_followed', val) + + @classmethod + def paper_doc_mention(cls, val): + """ + Create an instance of this class set to the ``paper_doc_mention`` tag + with value ``val``. + + :param PaperDocMentionType val: + :rtype: EventType + """ + return cls('paper_doc_mention', val) + + @classmethod + def paper_doc_ownership_changed(cls, val): + """ + Create an instance of this class set to the + ``paper_doc_ownership_changed`` tag with value ``val``. + + :param PaperDocOwnershipChangedType val: + :rtype: EventType + """ + return cls('paper_doc_ownership_changed', val) + + @classmethod + def paper_doc_request_access(cls, val): + """ + Create an instance of this class set to the ``paper_doc_request_access`` + tag with value ``val``. + + :param PaperDocRequestAccessType val: + :rtype: EventType + """ + return cls('paper_doc_request_access', val) + + @classmethod + def paper_doc_resolve_comment(cls, val): + """ + Create an instance of this class set to the + ``paper_doc_resolve_comment`` tag with value ``val``. + + :param PaperDocResolveCommentType val: + :rtype: EventType + """ + return cls('paper_doc_resolve_comment', val) + + @classmethod + def paper_doc_revert(cls, val): + """ + Create an instance of this class set to the ``paper_doc_revert`` tag + with value ``val``. + + :param PaperDocRevertType val: + :rtype: EventType + """ + return cls('paper_doc_revert', val) + + @classmethod + def paper_doc_slack_share(cls, val): + """ + Create an instance of this class set to the ``paper_doc_slack_share`` + tag with value ``val``. + + :param PaperDocSlackShareType val: + :rtype: EventType + """ + return cls('paper_doc_slack_share', val) + + @classmethod + def paper_doc_team_invite(cls, val): + """ + Create an instance of this class set to the ``paper_doc_team_invite`` + tag with value ``val``. + + :param PaperDocTeamInviteType val: + :rtype: EventType + """ + return cls('paper_doc_team_invite', val) + + @classmethod + def paper_doc_trashed(cls, val): + """ + Create an instance of this class set to the ``paper_doc_trashed`` tag + with value ``val``. + + :param PaperDocTrashedType val: + :rtype: EventType + """ + return cls('paper_doc_trashed', val) + + @classmethod + def paper_doc_unresolve_comment(cls, val): + """ + Create an instance of this class set to the + ``paper_doc_unresolve_comment`` tag with value ``val``. + + :param PaperDocUnresolveCommentType val: + :rtype: EventType + """ + return cls('paper_doc_unresolve_comment', val) + + @classmethod + def paper_doc_untrashed(cls, val): + """ + Create an instance of this class set to the ``paper_doc_untrashed`` tag + with value ``val``. + + :param PaperDocUntrashedType val: + :rtype: EventType + """ + return cls('paper_doc_untrashed', val) + + @classmethod + def paper_doc_view(cls, val): + """ + Create an instance of this class set to the ``paper_doc_view`` tag with + value ``val``. + + :param PaperDocViewType val: + :rtype: EventType + """ + return cls('paper_doc_view', val) + + @classmethod + def paper_external_view_allow(cls, val): + """ + Create an instance of this class set to the + ``paper_external_view_allow`` tag with value ``val``. + + :param PaperExternalViewAllowType val: + :rtype: EventType + """ + return cls('paper_external_view_allow', val) + + @classmethod + def paper_external_view_default_team(cls, val): + """ + Create an instance of this class set to the + ``paper_external_view_default_team`` tag with value ``val``. + + :param PaperExternalViewDefaultTeamType val: + :rtype: EventType + """ + return cls('paper_external_view_default_team', val) + + @classmethod + def paper_external_view_forbid(cls, val): + """ + Create an instance of this class set to the + ``paper_external_view_forbid`` tag with value ``val``. + + :param PaperExternalViewForbidType val: + :rtype: EventType + """ + return cls('paper_external_view_forbid', val) + + @classmethod + def paper_folder_change_subscription(cls, val): + """ + Create an instance of this class set to the + ``paper_folder_change_subscription`` tag with value ``val``. + + :param PaperFolderChangeSubscriptionType val: + :rtype: EventType + """ + return cls('paper_folder_change_subscription', val) + + @classmethod + def paper_folder_deleted(cls, val): + """ + Create an instance of this class set to the ``paper_folder_deleted`` tag + with value ``val``. + + :param PaperFolderDeletedType val: + :rtype: EventType + """ + return cls('paper_folder_deleted', val) + + @classmethod + def paper_folder_followed(cls, val): + """ + Create an instance of this class set to the ``paper_folder_followed`` + tag with value ``val``. + + :param PaperFolderFollowedType val: + :rtype: EventType + """ + return cls('paper_folder_followed', val) + + @classmethod + def paper_folder_team_invite(cls, val): + """ + Create an instance of this class set to the ``paper_folder_team_invite`` + tag with value ``val``. + + :param PaperFolderTeamInviteType val: + :rtype: EventType + """ + return cls('paper_folder_team_invite', val) + + @classmethod + def paper_published_link_change_permission(cls, val): + """ + Create an instance of this class set to the + ``paper_published_link_change_permission`` tag with value ``val``. + + :param PaperPublishedLinkChangePermissionType val: + :rtype: EventType + """ + return cls('paper_published_link_change_permission', val) + + @classmethod + def paper_published_link_create(cls, val): + """ + Create an instance of this class set to the + ``paper_published_link_create`` tag with value ``val``. + + :param PaperPublishedLinkCreateType val: + :rtype: EventType + """ + return cls('paper_published_link_create', val) + + @classmethod + def paper_published_link_disabled(cls, val): + """ + Create an instance of this class set to the + ``paper_published_link_disabled`` tag with value ``val``. + + :param PaperPublishedLinkDisabledType val: + :rtype: EventType + """ + return cls('paper_published_link_disabled', val) + + @classmethod + def paper_published_link_view(cls, val): + """ + Create an instance of this class set to the + ``paper_published_link_view`` tag with value ``val``. + + :param PaperPublishedLinkViewType val: + :rtype: EventType + """ + return cls('paper_published_link_view', val) + + @classmethod + def password_change(cls, val): + """ + Create an instance of this class set to the ``password_change`` tag with + value ``val``. + + :param PasswordChangeType val: + :rtype: EventType + """ + return cls('password_change', val) + + @classmethod + def password_reset(cls, val): + """ + Create an instance of this class set to the ``password_reset`` tag with + value ``val``. + + :param PasswordResetType val: + :rtype: EventType + """ + return cls('password_reset', val) + + @classmethod + def password_reset_all(cls, val): + """ + Create an instance of this class set to the ``password_reset_all`` tag + with value ``val``. + + :param PasswordResetAllType val: + :rtype: EventType + """ + return cls('password_reset_all', val) + + @classmethod + def emm_create_exceptions_report(cls, val): + """ + Create an instance of this class set to the + ``emm_create_exceptions_report`` tag with value ``val``. + + :param EmmCreateExceptionsReportType val: + :rtype: EventType + """ + return cls('emm_create_exceptions_report', val) + + @classmethod + def emm_create_usage_report(cls, val): + """ + Create an instance of this class set to the ``emm_create_usage_report`` + tag with value ``val``. + + :param EmmCreateUsageReportType val: + :rtype: EventType + """ + return cls('emm_create_usage_report', val) + + @classmethod + def export_members_report(cls, val): + """ + Create an instance of this class set to the ``export_members_report`` + tag with value ``val``. + + :param ExportMembersReportType val: + :rtype: EventType + """ + return cls('export_members_report', val) + + @classmethod + def export_members_report_fail(cls, val): + """ + Create an instance of this class set to the + ``export_members_report_fail`` tag with value ``val``. + + :param ExportMembersReportFailType val: + :rtype: EventType + """ + return cls('export_members_report_fail', val) + + @classmethod + def no_expiration_link_gen_create_report(cls, val): + """ + Create an instance of this class set to the + ``no_expiration_link_gen_create_report`` tag with value ``val``. + + :param NoExpirationLinkGenCreateReportType val: + :rtype: EventType + """ + return cls('no_expiration_link_gen_create_report', val) + + @classmethod + def no_expiration_link_gen_report_failed(cls, val): + """ + Create an instance of this class set to the + ``no_expiration_link_gen_report_failed`` tag with value ``val``. + + :param NoExpirationLinkGenReportFailedType val: + :rtype: EventType + """ + return cls('no_expiration_link_gen_report_failed', val) + + @classmethod + def no_password_link_gen_create_report(cls, val): + """ + Create an instance of this class set to the + ``no_password_link_gen_create_report`` tag with value ``val``. + + :param NoPasswordLinkGenCreateReportType val: + :rtype: EventType + """ + return cls('no_password_link_gen_create_report', val) + + @classmethod + def no_password_link_gen_report_failed(cls, val): + """ + Create an instance of this class set to the + ``no_password_link_gen_report_failed`` tag with value ``val``. + + :param NoPasswordLinkGenReportFailedType val: + :rtype: EventType + """ + return cls('no_password_link_gen_report_failed', val) + + @classmethod + def no_password_link_view_create_report(cls, val): + """ + Create an instance of this class set to the + ``no_password_link_view_create_report`` tag with value ``val``. + + :param NoPasswordLinkViewCreateReportType val: + :rtype: EventType + """ + return cls('no_password_link_view_create_report', val) + + @classmethod + def no_password_link_view_report_failed(cls, val): + """ + Create an instance of this class set to the + ``no_password_link_view_report_failed`` tag with value ``val``. + + :param NoPasswordLinkViewReportFailedType val: + :rtype: EventType + """ + return cls('no_password_link_view_report_failed', val) + + @classmethod + def outdated_link_view_create_report(cls, val): + """ + Create an instance of this class set to the + ``outdated_link_view_create_report`` tag with value ``val``. + + :param OutdatedLinkViewCreateReportType val: + :rtype: EventType + """ + return cls('outdated_link_view_create_report', val) + + @classmethod + def outdated_link_view_report_failed(cls, val): + """ + Create an instance of this class set to the + ``outdated_link_view_report_failed`` tag with value ``val``. + + :param OutdatedLinkViewReportFailedType val: + :rtype: EventType + """ + return cls('outdated_link_view_report_failed', val) + + @classmethod + def paper_admin_export_start(cls, val): + """ + Create an instance of this class set to the ``paper_admin_export_start`` + tag with value ``val``. + + :param PaperAdminExportStartType val: + :rtype: EventType + """ + return cls('paper_admin_export_start', val) + + @classmethod + def smart_sync_create_admin_privilege_report(cls, val): + """ + Create an instance of this class set to the + ``smart_sync_create_admin_privilege_report`` tag with value ``val``. + + :param SmartSyncCreateAdminPrivilegeReportType val: + :rtype: EventType + """ + return cls('smart_sync_create_admin_privilege_report', val) + + @classmethod + def team_activity_create_report(cls, val): + """ + Create an instance of this class set to the + ``team_activity_create_report`` tag with value ``val``. + + :param TeamActivityCreateReportType val: + :rtype: EventType + """ + return cls('team_activity_create_report', val) + + @classmethod + def team_activity_create_report_fail(cls, val): + """ + Create an instance of this class set to the + ``team_activity_create_report_fail`` tag with value ``val``. + + :param TeamActivityCreateReportFailType val: + :rtype: EventType + """ + return cls('team_activity_create_report_fail', val) + + @classmethod + def collection_share(cls, val): + """ + Create an instance of this class set to the ``collection_share`` tag + with value ``val``. + + :param CollectionShareType val: + :rtype: EventType + """ + return cls('collection_share', val) + + @classmethod + def file_transfers_file_add(cls, val): + """ + Create an instance of this class set to the ``file_transfers_file_add`` + tag with value ``val``. + + :param FileTransfersFileAddType val: + :rtype: EventType + """ + return cls('file_transfers_file_add', val) + + @classmethod + def file_transfers_transfer_delete(cls, val): + """ + Create an instance of this class set to the + ``file_transfers_transfer_delete`` tag with value ``val``. + + :param FileTransfersTransferDeleteType val: + :rtype: EventType + """ + return cls('file_transfers_transfer_delete', val) + + @classmethod + def file_transfers_transfer_download(cls, val): + """ + Create an instance of this class set to the + ``file_transfers_transfer_download`` tag with value ``val``. + + :param FileTransfersTransferDownloadType val: + :rtype: EventType + """ + return cls('file_transfers_transfer_download', val) + + @classmethod + def file_transfers_transfer_send(cls, val): + """ + Create an instance of this class set to the + ``file_transfers_transfer_send`` tag with value ``val``. + + :param FileTransfersTransferSendType val: + :rtype: EventType + """ + return cls('file_transfers_transfer_send', val) + + @classmethod + def file_transfers_transfer_view(cls, val): + """ + Create an instance of this class set to the + ``file_transfers_transfer_view`` tag with value ``val``. + + :param FileTransfersTransferViewType val: + :rtype: EventType + """ + return cls('file_transfers_transfer_view', val) + + @classmethod + def note_acl_invite_only(cls, val): + """ + Create an instance of this class set to the ``note_acl_invite_only`` tag + with value ``val``. + + :param NoteAclInviteOnlyType val: + :rtype: EventType + """ + return cls('note_acl_invite_only', val) + + @classmethod + def note_acl_link(cls, val): + """ + Create an instance of this class set to the ``note_acl_link`` tag with + value ``val``. + + :param NoteAclLinkType val: + :rtype: EventType + """ + return cls('note_acl_link', val) + + @classmethod + def note_acl_team_link(cls, val): + """ + Create an instance of this class set to the ``note_acl_team_link`` tag + with value ``val``. + + :param NoteAclTeamLinkType val: + :rtype: EventType + """ + return cls('note_acl_team_link', val) + + @classmethod + def note_shared(cls, val): + """ + Create an instance of this class set to the ``note_shared`` tag with + value ``val``. + + :param NoteSharedType val: + :rtype: EventType + """ + return cls('note_shared', val) + + @classmethod + def note_share_receive(cls, val): + """ + Create an instance of this class set to the ``note_share_receive`` tag + with value ``val``. + + :param NoteShareReceiveType val: + :rtype: EventType + """ + return cls('note_share_receive', val) + + @classmethod + def open_note_shared(cls, val): + """ + Create an instance of this class set to the ``open_note_shared`` tag + with value ``val``. + + :param OpenNoteSharedType val: + :rtype: EventType + """ + return cls('open_note_shared', val) + + @classmethod + def sf_add_group(cls, val): + """ + Create an instance of this class set to the ``sf_add_group`` tag with + value ``val``. + + :param SfAddGroupType val: + :rtype: EventType + """ + return cls('sf_add_group', val) + + @classmethod + def sf_allow_non_members_to_view_shared_links(cls, val): + """ + Create an instance of this class set to the + ``sf_allow_non_members_to_view_shared_links`` tag with value ``val``. + + :param SfAllowNonMembersToViewSharedLinksType val: + :rtype: EventType + """ + return cls('sf_allow_non_members_to_view_shared_links', val) + + @classmethod + def sf_external_invite_warn(cls, val): + """ + Create an instance of this class set to the ``sf_external_invite_warn`` + tag with value ``val``. + + :param SfExternalInviteWarnType val: + :rtype: EventType + """ + return cls('sf_external_invite_warn', val) + + @classmethod + def sf_fb_invite(cls, val): + """ + Create an instance of this class set to the ``sf_fb_invite`` tag with + value ``val``. + + :param SfFbInviteType val: + :rtype: EventType + """ + return cls('sf_fb_invite', val) + + @classmethod + def sf_fb_invite_change_role(cls, val): + """ + Create an instance of this class set to the ``sf_fb_invite_change_role`` + tag with value ``val``. + + :param SfFbInviteChangeRoleType val: + :rtype: EventType + """ + return cls('sf_fb_invite_change_role', val) + + @classmethod + def sf_fb_uninvite(cls, val): + """ + Create an instance of this class set to the ``sf_fb_uninvite`` tag with + value ``val``. + + :param SfFbUninviteType val: + :rtype: EventType + """ + return cls('sf_fb_uninvite', val) + + @classmethod + def sf_invite_group(cls, val): + """ + Create an instance of this class set to the ``sf_invite_group`` tag with + value ``val``. + + :param SfInviteGroupType val: + :rtype: EventType + """ + return cls('sf_invite_group', val) + + @classmethod + def sf_team_grant_access(cls, val): + """ + Create an instance of this class set to the ``sf_team_grant_access`` tag + with value ``val``. + + :param SfTeamGrantAccessType val: + :rtype: EventType + """ + return cls('sf_team_grant_access', val) + + @classmethod + def sf_team_invite(cls, val): + """ + Create an instance of this class set to the ``sf_team_invite`` tag with + value ``val``. + + :param SfTeamInviteType val: + :rtype: EventType + """ + return cls('sf_team_invite', val) + + @classmethod + def sf_team_invite_change_role(cls, val): + """ + Create an instance of this class set to the + ``sf_team_invite_change_role`` tag with value ``val``. + + :param SfTeamInviteChangeRoleType val: + :rtype: EventType + """ + return cls('sf_team_invite_change_role', val) + + @classmethod + def sf_team_join(cls, val): + """ + Create an instance of this class set to the ``sf_team_join`` tag with + value ``val``. + + :param SfTeamJoinType val: + :rtype: EventType + """ + return cls('sf_team_join', val) + + @classmethod + def sf_team_join_from_oob_link(cls, val): + """ + Create an instance of this class set to the + ``sf_team_join_from_oob_link`` tag with value ``val``. + + :param SfTeamJoinFromOobLinkType val: + :rtype: EventType + """ + return cls('sf_team_join_from_oob_link', val) + + @classmethod + def sf_team_uninvite(cls, val): + """ + Create an instance of this class set to the ``sf_team_uninvite`` tag + with value ``val``. + + :param SfTeamUninviteType val: + :rtype: EventType + """ + return cls('sf_team_uninvite', val) + + @classmethod + def shared_content_add_invitees(cls, val): + """ + Create an instance of this class set to the + ``shared_content_add_invitees`` tag with value ``val``. + + :param SharedContentAddInviteesType val: + :rtype: EventType + """ + return cls('shared_content_add_invitees', val) + + @classmethod + def shared_content_add_link_expiry(cls, val): + """ + Create an instance of this class set to the + ``shared_content_add_link_expiry`` tag with value ``val``. + + :param SharedContentAddLinkExpiryType val: + :rtype: EventType + """ + return cls('shared_content_add_link_expiry', val) + + @classmethod + def shared_content_add_link_password(cls, val): + """ + Create an instance of this class set to the + ``shared_content_add_link_password`` tag with value ``val``. + + :param SharedContentAddLinkPasswordType val: + :rtype: EventType + """ + return cls('shared_content_add_link_password', val) + + @classmethod + def shared_content_add_member(cls, val): + """ + Create an instance of this class set to the + ``shared_content_add_member`` tag with value ``val``. + + :param SharedContentAddMemberType val: + :rtype: EventType + """ + return cls('shared_content_add_member', val) + + @classmethod + def shared_content_change_downloads_policy(cls, val): + """ + Create an instance of this class set to the + ``shared_content_change_downloads_policy`` tag with value ``val``. + + :param SharedContentChangeDownloadsPolicyType val: + :rtype: EventType + """ + return cls('shared_content_change_downloads_policy', val) + + @classmethod + def shared_content_change_invitee_role(cls, val): + """ + Create an instance of this class set to the + ``shared_content_change_invitee_role`` tag with value ``val``. + + :param SharedContentChangeInviteeRoleType val: + :rtype: EventType + """ + return cls('shared_content_change_invitee_role', val) + + @classmethod + def shared_content_change_link_audience(cls, val): + """ + Create an instance of this class set to the + ``shared_content_change_link_audience`` tag with value ``val``. + + :param SharedContentChangeLinkAudienceType val: + :rtype: EventType + """ + return cls('shared_content_change_link_audience', val) + + @classmethod + def shared_content_change_link_expiry(cls, val): + """ + Create an instance of this class set to the + ``shared_content_change_link_expiry`` tag with value ``val``. + + :param SharedContentChangeLinkExpiryType val: + :rtype: EventType + """ + return cls('shared_content_change_link_expiry', val) + + @classmethod + def shared_content_change_link_password(cls, val): + """ + Create an instance of this class set to the + ``shared_content_change_link_password`` tag with value ``val``. + + :param SharedContentChangeLinkPasswordType val: + :rtype: EventType + """ + return cls('shared_content_change_link_password', val) + + @classmethod + def shared_content_change_member_role(cls, val): + """ + Create an instance of this class set to the + ``shared_content_change_member_role`` tag with value ``val``. + + :param SharedContentChangeMemberRoleType val: + :rtype: EventType + """ + return cls('shared_content_change_member_role', val) + + @classmethod + def shared_content_change_viewer_info_policy(cls, val): + """ + Create an instance of this class set to the + ``shared_content_change_viewer_info_policy`` tag with value ``val``. + + :param SharedContentChangeViewerInfoPolicyType val: + :rtype: EventType + """ + return cls('shared_content_change_viewer_info_policy', val) + + @classmethod + def shared_content_claim_invitation(cls, val): + """ + Create an instance of this class set to the + ``shared_content_claim_invitation`` tag with value ``val``. + + :param SharedContentClaimInvitationType val: + :rtype: EventType + """ + return cls('shared_content_claim_invitation', val) + + @classmethod + def shared_content_copy(cls, val): + """ + Create an instance of this class set to the ``shared_content_copy`` tag + with value ``val``. + + :param SharedContentCopyType val: + :rtype: EventType + """ + return cls('shared_content_copy', val) + + @classmethod + def shared_content_download(cls, val): + """ + Create an instance of this class set to the ``shared_content_download`` + tag with value ``val``. + + :param SharedContentDownloadType val: + :rtype: EventType + """ + return cls('shared_content_download', val) + + @classmethod + def shared_content_relinquish_membership(cls, val): + """ + Create an instance of this class set to the + ``shared_content_relinquish_membership`` tag with value ``val``. + + :param SharedContentRelinquishMembershipType val: + :rtype: EventType + """ + return cls('shared_content_relinquish_membership', val) + + @classmethod + def shared_content_remove_invitees(cls, val): + """ + Create an instance of this class set to the + ``shared_content_remove_invitees`` tag with value ``val``. + + :param SharedContentRemoveInviteesType val: + :rtype: EventType + """ + return cls('shared_content_remove_invitees', val) + + @classmethod + def shared_content_remove_link_expiry(cls, val): + """ + Create an instance of this class set to the + ``shared_content_remove_link_expiry`` tag with value ``val``. + + :param SharedContentRemoveLinkExpiryType val: + :rtype: EventType + """ + return cls('shared_content_remove_link_expiry', val) + + @classmethod + def shared_content_remove_link_password(cls, val): + """ + Create an instance of this class set to the + ``shared_content_remove_link_password`` tag with value ``val``. + + :param SharedContentRemoveLinkPasswordType val: + :rtype: EventType + """ + return cls('shared_content_remove_link_password', val) + + @classmethod + def shared_content_remove_member(cls, val): + """ + Create an instance of this class set to the + ``shared_content_remove_member`` tag with value ``val``. + + :param SharedContentRemoveMemberType val: + :rtype: EventType + """ + return cls('shared_content_remove_member', val) + + @classmethod + def shared_content_request_access(cls, val): + """ + Create an instance of this class set to the + ``shared_content_request_access`` tag with value ``val``. + + :param SharedContentRequestAccessType val: + :rtype: EventType + """ + return cls('shared_content_request_access', val) + + @classmethod + def shared_content_restore_invitees(cls, val): + """ + Create an instance of this class set to the + ``shared_content_restore_invitees`` tag with value ``val``. + + :param SharedContentRestoreInviteesType val: + :rtype: EventType + """ + return cls('shared_content_restore_invitees', val) + + @classmethod + def shared_content_restore_member(cls, val): + """ + Create an instance of this class set to the + ``shared_content_restore_member`` tag with value ``val``. + + :param SharedContentRestoreMemberType val: + :rtype: EventType + """ + return cls('shared_content_restore_member', val) + + @classmethod + def shared_content_unshare(cls, val): + """ + Create an instance of this class set to the ``shared_content_unshare`` + tag with value ``val``. + + :param SharedContentUnshareType val: + :rtype: EventType + """ + return cls('shared_content_unshare', val) + + @classmethod + def shared_content_view(cls, val): + """ + Create an instance of this class set to the ``shared_content_view`` tag + with value ``val``. + + :param SharedContentViewType val: + :rtype: EventType + """ + return cls('shared_content_view', val) + + @classmethod + def shared_folder_change_link_policy(cls, val): + """ + Create an instance of this class set to the + ``shared_folder_change_link_policy`` tag with value ``val``. + + :param SharedFolderChangeLinkPolicyType val: + :rtype: EventType + """ + return cls('shared_folder_change_link_policy', val) + + @classmethod + def shared_folder_change_members_inheritance_policy(cls, val): + """ + Create an instance of this class set to the + ``shared_folder_change_members_inheritance_policy`` tag with value + ``val``. + + :param SharedFolderChangeMembersInheritancePolicyType val: + :rtype: EventType + """ + return cls('shared_folder_change_members_inheritance_policy', val) + + @classmethod + def shared_folder_change_members_management_policy(cls, val): + """ + Create an instance of this class set to the + ``shared_folder_change_members_management_policy`` tag with value + ``val``. + + :param SharedFolderChangeMembersManagementPolicyType val: + :rtype: EventType + """ + return cls('shared_folder_change_members_management_policy', val) + + @classmethod + def shared_folder_change_members_policy(cls, val): + """ + Create an instance of this class set to the + ``shared_folder_change_members_policy`` tag with value ``val``. + + :param SharedFolderChangeMembersPolicyType val: + :rtype: EventType + """ + return cls('shared_folder_change_members_policy', val) + + @classmethod + def shared_folder_create(cls, val): + """ + Create an instance of this class set to the ``shared_folder_create`` tag + with value ``val``. + + :param SharedFolderCreateType val: + :rtype: EventType + """ + return cls('shared_folder_create', val) + + @classmethod + def shared_folder_decline_invitation(cls, val): + """ + Create an instance of this class set to the + ``shared_folder_decline_invitation`` tag with value ``val``. + + :param SharedFolderDeclineInvitationType val: + :rtype: EventType + """ + return cls('shared_folder_decline_invitation', val) + + @classmethod + def shared_folder_mount(cls, val): + """ + Create an instance of this class set to the ``shared_folder_mount`` tag + with value ``val``. + + :param SharedFolderMountType val: + :rtype: EventType + """ + return cls('shared_folder_mount', val) + + @classmethod + def shared_folder_nest(cls, val): + """ + Create an instance of this class set to the ``shared_folder_nest`` tag + with value ``val``. + + :param SharedFolderNestType val: + :rtype: EventType + """ + return cls('shared_folder_nest', val) + + @classmethod + def shared_folder_transfer_ownership(cls, val): + """ + Create an instance of this class set to the + ``shared_folder_transfer_ownership`` tag with value ``val``. + + :param SharedFolderTransferOwnershipType val: + :rtype: EventType + """ + return cls('shared_folder_transfer_ownership', val) + + @classmethod + def shared_folder_unmount(cls, val): + """ + Create an instance of this class set to the ``shared_folder_unmount`` + tag with value ``val``. + + :param SharedFolderUnmountType val: + :rtype: EventType + """ + return cls('shared_folder_unmount', val) + + @classmethod + def shared_link_add_expiry(cls, val): + """ + Create an instance of this class set to the ``shared_link_add_expiry`` + tag with value ``val``. + + :param SharedLinkAddExpiryType val: + :rtype: EventType + """ + return cls('shared_link_add_expiry', val) + + @classmethod + def shared_link_change_expiry(cls, val): + """ + Create an instance of this class set to the + ``shared_link_change_expiry`` tag with value ``val``. + + :param SharedLinkChangeExpiryType val: + :rtype: EventType + """ + return cls('shared_link_change_expiry', val) + + @classmethod + def shared_link_change_visibility(cls, val): + """ + Create an instance of this class set to the + ``shared_link_change_visibility`` tag with value ``val``. + + :param SharedLinkChangeVisibilityType val: + :rtype: EventType + """ + return cls('shared_link_change_visibility', val) + + @classmethod + def shared_link_copy(cls, val): + """ + Create an instance of this class set to the ``shared_link_copy`` tag + with value ``val``. + + :param SharedLinkCopyType val: + :rtype: EventType + """ + return cls('shared_link_copy', val) + + @classmethod + def shared_link_create(cls, val): + """ + Create an instance of this class set to the ``shared_link_create`` tag + with value ``val``. + + :param SharedLinkCreateType val: + :rtype: EventType + """ + return cls('shared_link_create', val) + + @classmethod + def shared_link_disable(cls, val): + """ + Create an instance of this class set to the ``shared_link_disable`` tag + with value ``val``. + + :param SharedLinkDisableType val: + :rtype: EventType + """ + return cls('shared_link_disable', val) + + @classmethod + def shared_link_download(cls, val): + """ + Create an instance of this class set to the ``shared_link_download`` tag + with value ``val``. + + :param SharedLinkDownloadType val: + :rtype: EventType + """ + return cls('shared_link_download', val) + + @classmethod + def shared_link_remove_expiry(cls, val): + """ + Create an instance of this class set to the + ``shared_link_remove_expiry`` tag with value ``val``. + + :param SharedLinkRemoveExpiryType val: + :rtype: EventType + """ + return cls('shared_link_remove_expiry', val) + + @classmethod + def shared_link_settings_add_expiration(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_add_expiration`` tag with value ``val``. + + :param SharedLinkSettingsAddExpirationType val: + :rtype: EventType + """ + return cls('shared_link_settings_add_expiration', val) + + @classmethod + def shared_link_settings_add_password(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_add_password`` tag with value ``val``. + + :param SharedLinkSettingsAddPasswordType val: + :rtype: EventType + """ + return cls('shared_link_settings_add_password', val) + + @classmethod + def shared_link_settings_allow_download_disabled(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_allow_download_disabled`` tag with value ``val``. + + :param SharedLinkSettingsAllowDownloadDisabledType val: + :rtype: EventType + """ + return cls('shared_link_settings_allow_download_disabled', val) + + @classmethod + def shared_link_settings_allow_download_enabled(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_allow_download_enabled`` tag with value ``val``. + + :param SharedLinkSettingsAllowDownloadEnabledType val: + :rtype: EventType + """ + return cls('shared_link_settings_allow_download_enabled', val) + + @classmethod + def shared_link_settings_change_audience(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_change_audience`` tag with value ``val``. + + :param SharedLinkSettingsChangeAudienceType val: + :rtype: EventType + """ + return cls('shared_link_settings_change_audience', val) + + @classmethod + def shared_link_settings_change_expiration(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_change_expiration`` tag with value ``val``. + + :param SharedLinkSettingsChangeExpirationType val: + :rtype: EventType + """ + return cls('shared_link_settings_change_expiration', val) + + @classmethod + def shared_link_settings_change_password(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_change_password`` tag with value ``val``. + + :param SharedLinkSettingsChangePasswordType val: + :rtype: EventType + """ + return cls('shared_link_settings_change_password', val) + + @classmethod + def shared_link_settings_remove_expiration(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_remove_expiration`` tag with value ``val``. + + :param SharedLinkSettingsRemoveExpirationType val: + :rtype: EventType + """ + return cls('shared_link_settings_remove_expiration', val) + + @classmethod + def shared_link_settings_remove_password(cls, val): + """ + Create an instance of this class set to the + ``shared_link_settings_remove_password`` tag with value ``val``. + + :param SharedLinkSettingsRemovePasswordType val: + :rtype: EventType + """ + return cls('shared_link_settings_remove_password', val) + + @classmethod + def shared_link_share(cls, val): + """ + Create an instance of this class set to the ``shared_link_share`` tag + with value ``val``. + + :param SharedLinkShareType val: + :rtype: EventType + """ + return cls('shared_link_share', val) + + @classmethod + def shared_link_view(cls, val): + """ + Create an instance of this class set to the ``shared_link_view`` tag + with value ``val``. + + :param SharedLinkViewType val: + :rtype: EventType + """ + return cls('shared_link_view', val) + + @classmethod + def shared_note_opened(cls, val): + """ + Create an instance of this class set to the ``shared_note_opened`` tag + with value ``val``. + + :param SharedNoteOpenedType val: + :rtype: EventType + """ + return cls('shared_note_opened', val) + + @classmethod + def shmodel_group_share(cls, val): + """ + Create an instance of this class set to the ``shmodel_group_share`` tag + with value ``val``. + + :param ShmodelGroupShareType val: + :rtype: EventType + """ + return cls('shmodel_group_share', val) + + @classmethod + def showcase_access_granted(cls, val): + """ + Create an instance of this class set to the ``showcase_access_granted`` + tag with value ``val``. + + :param ShowcaseAccessGrantedType val: + :rtype: EventType + """ + return cls('showcase_access_granted', val) + + @classmethod + def showcase_add_member(cls, val): + """ + Create an instance of this class set to the ``showcase_add_member`` tag + with value ``val``. + + :param ShowcaseAddMemberType val: + :rtype: EventType + """ + return cls('showcase_add_member', val) + + @classmethod + def showcase_archived(cls, val): + """ + Create an instance of this class set to the ``showcase_archived`` tag + with value ``val``. + + :param ShowcaseArchivedType val: + :rtype: EventType + """ + return cls('showcase_archived', val) + + @classmethod + def showcase_created(cls, val): + """ + Create an instance of this class set to the ``showcase_created`` tag + with value ``val``. + + :param ShowcaseCreatedType val: + :rtype: EventType + """ + return cls('showcase_created', val) + + @classmethod + def showcase_delete_comment(cls, val): + """ + Create an instance of this class set to the ``showcase_delete_comment`` + tag with value ``val``. + + :param ShowcaseDeleteCommentType val: + :rtype: EventType + """ + return cls('showcase_delete_comment', val) + + @classmethod + def showcase_edited(cls, val): + """ + Create an instance of this class set to the ``showcase_edited`` tag with + value ``val``. + + :param ShowcaseEditedType val: + :rtype: EventType + """ + return cls('showcase_edited', val) + + @classmethod + def showcase_edit_comment(cls, val): + """ + Create an instance of this class set to the ``showcase_edit_comment`` + tag with value ``val``. + + :param ShowcaseEditCommentType val: + :rtype: EventType + """ + return cls('showcase_edit_comment', val) + + @classmethod + def showcase_file_added(cls, val): + """ + Create an instance of this class set to the ``showcase_file_added`` tag + with value ``val``. + + :param ShowcaseFileAddedType val: + :rtype: EventType + """ + return cls('showcase_file_added', val) + + @classmethod + def showcase_file_download(cls, val): + """ + Create an instance of this class set to the ``showcase_file_download`` + tag with value ``val``. + + :param ShowcaseFileDownloadType val: + :rtype: EventType + """ + return cls('showcase_file_download', val) + + @classmethod + def showcase_file_removed(cls, val): + """ + Create an instance of this class set to the ``showcase_file_removed`` + tag with value ``val``. + + :param ShowcaseFileRemovedType val: + :rtype: EventType + """ + return cls('showcase_file_removed', val) + + @classmethod + def showcase_file_view(cls, val): + """ + Create an instance of this class set to the ``showcase_file_view`` tag + with value ``val``. + + :param ShowcaseFileViewType val: + :rtype: EventType + """ + return cls('showcase_file_view', val) + + @classmethod + def showcase_permanently_deleted(cls, val): + """ + Create an instance of this class set to the + ``showcase_permanently_deleted`` tag with value ``val``. + + :param ShowcasePermanentlyDeletedType val: + :rtype: EventType + """ + return cls('showcase_permanently_deleted', val) + + @classmethod + def showcase_post_comment(cls, val): + """ + Create an instance of this class set to the ``showcase_post_comment`` + tag with value ``val``. + + :param ShowcasePostCommentType val: + :rtype: EventType + """ + return cls('showcase_post_comment', val) + + @classmethod + def showcase_remove_member(cls, val): + """ + Create an instance of this class set to the ``showcase_remove_member`` + tag with value ``val``. + + :param ShowcaseRemoveMemberType val: + :rtype: EventType + """ + return cls('showcase_remove_member', val) + + @classmethod + def showcase_renamed(cls, val): + """ + Create an instance of this class set to the ``showcase_renamed`` tag + with value ``val``. + + :param ShowcaseRenamedType val: + :rtype: EventType + """ + return cls('showcase_renamed', val) + + @classmethod + def showcase_request_access(cls, val): + """ + Create an instance of this class set to the ``showcase_request_access`` + tag with value ``val``. + + :param ShowcaseRequestAccessType val: + :rtype: EventType + """ + return cls('showcase_request_access', val) + + @classmethod + def showcase_resolve_comment(cls, val): + """ + Create an instance of this class set to the ``showcase_resolve_comment`` + tag with value ``val``. + + :param ShowcaseResolveCommentType val: + :rtype: EventType + """ + return cls('showcase_resolve_comment', val) + + @classmethod + def showcase_restored(cls, val): + """ + Create an instance of this class set to the ``showcase_restored`` tag + with value ``val``. + + :param ShowcaseRestoredType val: + :rtype: EventType + """ + return cls('showcase_restored', val) + + @classmethod + def showcase_trashed(cls, val): + """ + Create an instance of this class set to the ``showcase_trashed`` tag + with value ``val``. + + :param ShowcaseTrashedType val: + :rtype: EventType + """ + return cls('showcase_trashed', val) + + @classmethod + def showcase_trashed_deprecated(cls, val): + """ + Create an instance of this class set to the + ``showcase_trashed_deprecated`` tag with value ``val``. + + :param ShowcaseTrashedDeprecatedType val: + :rtype: EventType + """ + return cls('showcase_trashed_deprecated', val) + + @classmethod + def showcase_unresolve_comment(cls, val): + """ + Create an instance of this class set to the + ``showcase_unresolve_comment`` tag with value ``val``. + + :param ShowcaseUnresolveCommentType val: + :rtype: EventType + """ + return cls('showcase_unresolve_comment', val) + + @classmethod + def showcase_untrashed(cls, val): + """ + Create an instance of this class set to the ``showcase_untrashed`` tag + with value ``val``. + + :param ShowcaseUntrashedType val: + :rtype: EventType + """ + return cls('showcase_untrashed', val) + + @classmethod + def showcase_untrashed_deprecated(cls, val): + """ + Create an instance of this class set to the + ``showcase_untrashed_deprecated`` tag with value ``val``. + + :param ShowcaseUntrashedDeprecatedType val: + :rtype: EventType + """ + return cls('showcase_untrashed_deprecated', val) + + @classmethod + def showcase_view(cls, val): + """ + Create an instance of this class set to the ``showcase_view`` tag with + value ``val``. + + :param ShowcaseViewType val: + :rtype: EventType + """ + return cls('showcase_view', val) + + @classmethod + def sso_add_cert(cls, val): + """ + Create an instance of this class set to the ``sso_add_cert`` tag with + value ``val``. + + :param SsoAddCertType val: + :rtype: EventType + """ + return cls('sso_add_cert', val) + + @classmethod + def sso_add_login_url(cls, val): + """ + Create an instance of this class set to the ``sso_add_login_url`` tag + with value ``val``. + + :param SsoAddLoginUrlType val: + :rtype: EventType + """ + return cls('sso_add_login_url', val) + + @classmethod + def sso_add_logout_url(cls, val): + """ + Create an instance of this class set to the ``sso_add_logout_url`` tag + with value ``val``. + + :param SsoAddLogoutUrlType val: + :rtype: EventType + """ + return cls('sso_add_logout_url', val) + + @classmethod + def sso_change_cert(cls, val): + """ + Create an instance of this class set to the ``sso_change_cert`` tag with + value ``val``. + + :param SsoChangeCertType val: + :rtype: EventType + """ + return cls('sso_change_cert', val) + + @classmethod + def sso_change_login_url(cls, val): + """ + Create an instance of this class set to the ``sso_change_login_url`` tag + with value ``val``. + + :param SsoChangeLoginUrlType val: + :rtype: EventType + """ + return cls('sso_change_login_url', val) + + @classmethod + def sso_change_logout_url(cls, val): + """ + Create an instance of this class set to the ``sso_change_logout_url`` + tag with value ``val``. + + :param SsoChangeLogoutUrlType val: + :rtype: EventType + """ + return cls('sso_change_logout_url', val) + + @classmethod + def sso_change_saml_identity_mode(cls, val): + """ + Create an instance of this class set to the + ``sso_change_saml_identity_mode`` tag with value ``val``. + + :param SsoChangeSamlIdentityModeType val: + :rtype: EventType + """ + return cls('sso_change_saml_identity_mode', val) + + @classmethod + def sso_remove_cert(cls, val): + """ + Create an instance of this class set to the ``sso_remove_cert`` tag with + value ``val``. + + :param SsoRemoveCertType val: + :rtype: EventType + """ + return cls('sso_remove_cert', val) + + @classmethod + def sso_remove_login_url(cls, val): + """ + Create an instance of this class set to the ``sso_remove_login_url`` tag + with value ``val``. + + :param SsoRemoveLoginUrlType val: + :rtype: EventType + """ + return cls('sso_remove_login_url', val) + + @classmethod + def sso_remove_logout_url(cls, val): + """ + Create an instance of this class set to the ``sso_remove_logout_url`` + tag with value ``val``. + + :param SsoRemoveLogoutUrlType val: + :rtype: EventType + """ + return cls('sso_remove_logout_url', val) + + @classmethod + def team_folder_change_status(cls, val): + """ + Create an instance of this class set to the + ``team_folder_change_status`` tag with value ``val``. + + :param TeamFolderChangeStatusType val: + :rtype: EventType + """ + return cls('team_folder_change_status', val) + + @classmethod + def team_folder_create(cls, val): + """ + Create an instance of this class set to the ``team_folder_create`` tag + with value ``val``. + + :param TeamFolderCreateType val: + :rtype: EventType + """ + return cls('team_folder_create', val) + + @classmethod + def team_folder_downgrade(cls, val): + """ + Create an instance of this class set to the ``team_folder_downgrade`` + tag with value ``val``. + + :param TeamFolderDowngradeType val: + :rtype: EventType + """ + return cls('team_folder_downgrade', val) + + @classmethod + def team_folder_permanently_delete(cls, val): + """ + Create an instance of this class set to the + ``team_folder_permanently_delete`` tag with value ``val``. + + :param TeamFolderPermanentlyDeleteType val: + :rtype: EventType + """ + return cls('team_folder_permanently_delete', val) + + @classmethod + def team_folder_rename(cls, val): + """ + Create an instance of this class set to the ``team_folder_rename`` tag + with value ``val``. + + :param TeamFolderRenameType val: + :rtype: EventType + """ + return cls('team_folder_rename', val) + + @classmethod + def team_selective_sync_settings_changed(cls, val): + """ + Create an instance of this class set to the + ``team_selective_sync_settings_changed`` tag with value ``val``. + + :param TeamSelectiveSyncSettingsChangedType val: + :rtype: EventType + """ + return cls('team_selective_sync_settings_changed', val) + + @classmethod + def account_capture_change_policy(cls, val): + """ + Create an instance of this class set to the + ``account_capture_change_policy`` tag with value ``val``. + + :param AccountCaptureChangePolicyType val: + :rtype: EventType + """ + return cls('account_capture_change_policy', val) + + @classmethod + def allow_download_disabled(cls, val): + """ + Create an instance of this class set to the ``allow_download_disabled`` + tag with value ``val``. + + :param AllowDownloadDisabledType val: + :rtype: EventType + """ + return cls('allow_download_disabled', val) + + @classmethod + def allow_download_enabled(cls, val): + """ + Create an instance of this class set to the ``allow_download_enabled`` + tag with value ``val``. + + :param AllowDownloadEnabledType val: + :rtype: EventType + """ + return cls('allow_download_enabled', val) + + @classmethod + def camera_uploads_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``camera_uploads_policy_changed`` tag with value ``val``. + + :param CameraUploadsPolicyChangedType val: + :rtype: EventType + """ + return cls('camera_uploads_policy_changed', val) + + @classmethod + def data_placement_restriction_change_policy(cls, val): + """ + Create an instance of this class set to the + ``data_placement_restriction_change_policy`` tag with value ``val``. + + :param DataPlacementRestrictionChangePolicyType val: + :rtype: EventType + """ + return cls('data_placement_restriction_change_policy', val) + + @classmethod + def data_placement_restriction_satisfy_policy(cls, val): + """ + Create an instance of this class set to the + ``data_placement_restriction_satisfy_policy`` tag with value ``val``. + + :param DataPlacementRestrictionSatisfyPolicyType val: + :rtype: EventType + """ + return cls('data_placement_restriction_satisfy_policy', val) + + @classmethod + def device_approvals_add_exception(cls, val): + """ + Create an instance of this class set to the + ``device_approvals_add_exception`` tag with value ``val``. + + :param DeviceApprovalsAddExceptionType val: + :rtype: EventType + """ + return cls('device_approvals_add_exception', val) + + @classmethod + def device_approvals_change_desktop_policy(cls, val): + """ + Create an instance of this class set to the + ``device_approvals_change_desktop_policy`` tag with value ``val``. + + :param DeviceApprovalsChangeDesktopPolicyType val: + :rtype: EventType + """ + return cls('device_approvals_change_desktop_policy', val) + + @classmethod + def device_approvals_change_mobile_policy(cls, val): + """ + Create an instance of this class set to the + ``device_approvals_change_mobile_policy`` tag with value ``val``. + + :param DeviceApprovalsChangeMobilePolicyType val: + :rtype: EventType + """ + return cls('device_approvals_change_mobile_policy', val) + + @classmethod + def device_approvals_change_overage_action(cls, val): + """ + Create an instance of this class set to the + ``device_approvals_change_overage_action`` tag with value ``val``. + + :param DeviceApprovalsChangeOverageActionType val: + :rtype: EventType + """ + return cls('device_approvals_change_overage_action', val) + + @classmethod + def device_approvals_change_unlink_action(cls, val): + """ + Create an instance of this class set to the + ``device_approvals_change_unlink_action`` tag with value ``val``. + + :param DeviceApprovalsChangeUnlinkActionType val: + :rtype: EventType + """ + return cls('device_approvals_change_unlink_action', val) + + @classmethod + def device_approvals_remove_exception(cls, val): + """ + Create an instance of this class set to the + ``device_approvals_remove_exception`` tag with value ``val``. + + :param DeviceApprovalsRemoveExceptionType val: + :rtype: EventType + """ + return cls('device_approvals_remove_exception', val) + + @classmethod + def directory_restrictions_add_members(cls, val): + """ + Create an instance of this class set to the + ``directory_restrictions_add_members`` tag with value ``val``. + + :param DirectoryRestrictionsAddMembersType val: + :rtype: EventType + """ + return cls('directory_restrictions_add_members', val) + + @classmethod + def directory_restrictions_remove_members(cls, val): + """ + Create an instance of this class set to the + ``directory_restrictions_remove_members`` tag with value ``val``. + + :param DirectoryRestrictionsRemoveMembersType val: + :rtype: EventType + """ + return cls('directory_restrictions_remove_members', val) + + @classmethod + def emm_add_exception(cls, val): + """ + Create an instance of this class set to the ``emm_add_exception`` tag + with value ``val``. + + :param EmmAddExceptionType val: + :rtype: EventType + """ + return cls('emm_add_exception', val) + + @classmethod + def emm_change_policy(cls, val): + """ + Create an instance of this class set to the ``emm_change_policy`` tag + with value ``val``. + + :param EmmChangePolicyType val: + :rtype: EventType + """ + return cls('emm_change_policy', val) + + @classmethod + def emm_remove_exception(cls, val): + """ + Create an instance of this class set to the ``emm_remove_exception`` tag + with value ``val``. + + :param EmmRemoveExceptionType val: + :rtype: EventType + """ + return cls('emm_remove_exception', val) + + @classmethod + def extended_version_history_change_policy(cls, val): + """ + Create an instance of this class set to the + ``extended_version_history_change_policy`` tag with value ``val``. + + :param ExtendedVersionHistoryChangePolicyType val: + :rtype: EventType + """ + return cls('extended_version_history_change_policy', val) + + @classmethod + def file_comments_change_policy(cls, val): + """ + Create an instance of this class set to the + ``file_comments_change_policy`` tag with value ``val``. + + :param FileCommentsChangePolicyType val: + :rtype: EventType + """ + return cls('file_comments_change_policy', val) + + @classmethod + def file_locking_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``file_locking_policy_changed`` tag with value ``val``. + + :param FileLockingPolicyChangedType val: + :rtype: EventType + """ + return cls('file_locking_policy_changed', val) + + @classmethod + def file_requests_change_policy(cls, val): + """ + Create an instance of this class set to the + ``file_requests_change_policy`` tag with value ``val``. + + :param FileRequestsChangePolicyType val: + :rtype: EventType + """ + return cls('file_requests_change_policy', val) + + @classmethod + def file_requests_emails_enabled(cls, val): + """ + Create an instance of this class set to the + ``file_requests_emails_enabled`` tag with value ``val``. + + :param FileRequestsEmailsEnabledType val: + :rtype: EventType + """ + return cls('file_requests_emails_enabled', val) + + @classmethod + def file_requests_emails_restricted_to_team_only(cls, val): + """ + Create an instance of this class set to the + ``file_requests_emails_restricted_to_team_only`` tag with value ``val``. + + :param FileRequestsEmailsRestrictedToTeamOnlyType val: + :rtype: EventType + """ + return cls('file_requests_emails_restricted_to_team_only', val) + + @classmethod + def file_transfers_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``file_transfers_policy_changed`` tag with value ``val``. + + :param FileTransfersPolicyChangedType val: + :rtype: EventType + """ + return cls('file_transfers_policy_changed', val) + + @classmethod + def google_sso_change_policy(cls, val): + """ + Create an instance of this class set to the ``google_sso_change_policy`` + tag with value ``val``. + + :param GoogleSsoChangePolicyType val: + :rtype: EventType + """ + return cls('google_sso_change_policy', val) + + @classmethod + def group_user_management_change_policy(cls, val): + """ + Create an instance of this class set to the + ``group_user_management_change_policy`` tag with value ``val``. + + :param GroupUserManagementChangePolicyType val: + :rtype: EventType + """ + return cls('group_user_management_change_policy', val) + + @classmethod + def integration_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``integration_policy_changed`` tag with value ``val``. + + :param IntegrationPolicyChangedType val: + :rtype: EventType + """ + return cls('integration_policy_changed', val) + + @classmethod + def member_requests_change_policy(cls, val): + """ + Create an instance of this class set to the + ``member_requests_change_policy`` tag with value ``val``. + + :param MemberRequestsChangePolicyType val: + :rtype: EventType + """ + return cls('member_requests_change_policy', val) + + @classmethod + def member_send_invite_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``member_send_invite_policy_changed`` tag with value ``val``. + + :param MemberSendInvitePolicyChangedType val: + :rtype: EventType + """ + return cls('member_send_invite_policy_changed', val) + + @classmethod + def member_space_limits_add_exception(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_add_exception`` tag with value ``val``. + + :param MemberSpaceLimitsAddExceptionType val: + :rtype: EventType + """ + return cls('member_space_limits_add_exception', val) + + @classmethod + def member_space_limits_change_caps_type_policy(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_change_caps_type_policy`` tag with value ``val``. + + :param MemberSpaceLimitsChangeCapsTypePolicyType val: + :rtype: EventType + """ + return cls('member_space_limits_change_caps_type_policy', val) + + @classmethod + def member_space_limits_change_policy(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_change_policy`` tag with value ``val``. + + :param MemberSpaceLimitsChangePolicyType val: + :rtype: EventType + """ + return cls('member_space_limits_change_policy', val) + + @classmethod + def member_space_limits_remove_exception(cls, val): + """ + Create an instance of this class set to the + ``member_space_limits_remove_exception`` tag with value ``val``. + + :param MemberSpaceLimitsRemoveExceptionType val: + :rtype: EventType + """ + return cls('member_space_limits_remove_exception', val) + + @classmethod + def member_suggestions_change_policy(cls, val): + """ + Create an instance of this class set to the + ``member_suggestions_change_policy`` tag with value ``val``. + + :param MemberSuggestionsChangePolicyType val: + :rtype: EventType + """ + return cls('member_suggestions_change_policy', val) + + @classmethod + def microsoft_office_addin_change_policy(cls, val): + """ + Create an instance of this class set to the + ``microsoft_office_addin_change_policy`` tag with value ``val``. + + :param MicrosoftOfficeAddinChangePolicyType val: + :rtype: EventType + """ + return cls('microsoft_office_addin_change_policy', val) + + @classmethod + def network_control_change_policy(cls, val): + """ + Create an instance of this class set to the + ``network_control_change_policy`` tag with value ``val``. + + :param NetworkControlChangePolicyType val: + :rtype: EventType + """ + return cls('network_control_change_policy', val) + + @classmethod + def paper_change_deployment_policy(cls, val): + """ + Create an instance of this class set to the + ``paper_change_deployment_policy`` tag with value ``val``. + + :param PaperChangeDeploymentPolicyType val: + :rtype: EventType + """ + return cls('paper_change_deployment_policy', val) + + @classmethod + def paper_change_member_link_policy(cls, val): + """ + Create an instance of this class set to the + ``paper_change_member_link_policy`` tag with value ``val``. + + :param PaperChangeMemberLinkPolicyType val: + :rtype: EventType + """ + return cls('paper_change_member_link_policy', val) + + @classmethod + def paper_change_member_policy(cls, val): + """ + Create an instance of this class set to the + ``paper_change_member_policy`` tag with value ``val``. + + :param PaperChangeMemberPolicyType val: + :rtype: EventType + """ + return cls('paper_change_member_policy', val) + + @classmethod + def paper_change_policy(cls, val): + """ + Create an instance of this class set to the ``paper_change_policy`` tag + with value ``val``. + + :param PaperChangePolicyType val: + :rtype: EventType + """ + return cls('paper_change_policy', val) + + @classmethod + def paper_default_folder_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``paper_default_folder_policy_changed`` tag with value ``val``. + + :param PaperDefaultFolderPolicyChangedType val: + :rtype: EventType + """ + return cls('paper_default_folder_policy_changed', val) + + @classmethod + def paper_desktop_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``paper_desktop_policy_changed`` tag with value ``val``. + + :param PaperDesktopPolicyChangedType val: + :rtype: EventType + """ + return cls('paper_desktop_policy_changed', val) + + @classmethod + def paper_enabled_users_group_addition(cls, val): + """ + Create an instance of this class set to the + ``paper_enabled_users_group_addition`` tag with value ``val``. + + :param PaperEnabledUsersGroupAdditionType val: + :rtype: EventType + """ + return cls('paper_enabled_users_group_addition', val) + + @classmethod + def paper_enabled_users_group_removal(cls, val): + """ + Create an instance of this class set to the + ``paper_enabled_users_group_removal`` tag with value ``val``. + + :param PaperEnabledUsersGroupRemovalType val: + :rtype: EventType + """ + return cls('paper_enabled_users_group_removal', val) + + @classmethod + def password_strength_requirements_change_policy(cls, val): + """ + Create an instance of this class set to the + ``password_strength_requirements_change_policy`` tag with value ``val``. + + :param PasswordStrengthRequirementsChangePolicyType val: + :rtype: EventType + """ + return cls('password_strength_requirements_change_policy', val) + + @classmethod + def permanent_delete_change_policy(cls, val): + """ + Create an instance of this class set to the + ``permanent_delete_change_policy`` tag with value ``val``. + + :param PermanentDeleteChangePolicyType val: + :rtype: EventType + """ + return cls('permanent_delete_change_policy', val) + + @classmethod + def reseller_support_change_policy(cls, val): + """ + Create an instance of this class set to the + ``reseller_support_change_policy`` tag with value ``val``. + + :param ResellerSupportChangePolicyType val: + :rtype: EventType + """ + return cls('reseller_support_change_policy', val) + + @classmethod + def rewind_policy_changed(cls, val): + """ + Create an instance of this class set to the ``rewind_policy_changed`` + tag with value ``val``. + + :param RewindPolicyChangedType val: + :rtype: EventType + """ + return cls('rewind_policy_changed', val) + + @classmethod + def sharing_change_folder_join_policy(cls, val): + """ + Create an instance of this class set to the + ``sharing_change_folder_join_policy`` tag with value ``val``. + + :param SharingChangeFolderJoinPolicyType val: + :rtype: EventType + """ + return cls('sharing_change_folder_join_policy', val) + + @classmethod + def sharing_change_link_policy(cls, val): + """ + Create an instance of this class set to the + ``sharing_change_link_policy`` tag with value ``val``. + + :param SharingChangeLinkPolicyType val: + :rtype: EventType + """ + return cls('sharing_change_link_policy', val) + + @classmethod + def sharing_change_member_policy(cls, val): + """ + Create an instance of this class set to the + ``sharing_change_member_policy`` tag with value ``val``. + + :param SharingChangeMemberPolicyType val: + :rtype: EventType + """ + return cls('sharing_change_member_policy', val) + + @classmethod + def showcase_change_download_policy(cls, val): + """ + Create an instance of this class set to the + ``showcase_change_download_policy`` tag with value ``val``. + + :param ShowcaseChangeDownloadPolicyType val: + :rtype: EventType + """ + return cls('showcase_change_download_policy', val) + + @classmethod + def showcase_change_enabled_policy(cls, val): + """ + Create an instance of this class set to the + ``showcase_change_enabled_policy`` tag with value ``val``. + + :param ShowcaseChangeEnabledPolicyType val: + :rtype: EventType + """ + return cls('showcase_change_enabled_policy', val) + + @classmethod + def showcase_change_external_sharing_policy(cls, val): + """ + Create an instance of this class set to the + ``showcase_change_external_sharing_policy`` tag with value ``val``. + + :param ShowcaseChangeExternalSharingPolicyType val: + :rtype: EventType + """ + return cls('showcase_change_external_sharing_policy', val) + + @classmethod + def smarter_smart_sync_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``smarter_smart_sync_policy_changed`` tag with value ``val``. + + :param SmarterSmartSyncPolicyChangedType val: + :rtype: EventType + """ + return cls('smarter_smart_sync_policy_changed', val) + + @classmethod + def smart_sync_change_policy(cls, val): + """ + Create an instance of this class set to the ``smart_sync_change_policy`` + tag with value ``val``. + + :param SmartSyncChangePolicyType val: + :rtype: EventType + """ + return cls('smart_sync_change_policy', val) + + @classmethod + def smart_sync_not_opt_out(cls, val): + """ + Create an instance of this class set to the ``smart_sync_not_opt_out`` + tag with value ``val``. + + :param SmartSyncNotOptOutType val: + :rtype: EventType + """ + return cls('smart_sync_not_opt_out', val) + + @classmethod + def smart_sync_opt_out(cls, val): + """ + Create an instance of this class set to the ``smart_sync_opt_out`` tag + with value ``val``. + + :param SmartSyncOptOutType val: + :rtype: EventType + """ + return cls('smart_sync_opt_out', val) + + @classmethod + def sso_change_policy(cls, val): + """ + Create an instance of this class set to the ``sso_change_policy`` tag + with value ``val``. + + :param SsoChangePolicyType val: + :rtype: EventType + """ + return cls('sso_change_policy', val) + + @classmethod + def team_extensions_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``team_extensions_policy_changed`` tag with value ``val``. + + :param TeamExtensionsPolicyChangedType val: + :rtype: EventType + """ + return cls('team_extensions_policy_changed', val) + + @classmethod + def team_selective_sync_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``team_selective_sync_policy_changed`` tag with value ``val``. + + :param TeamSelectiveSyncPolicyChangedType val: + :rtype: EventType + """ + return cls('team_selective_sync_policy_changed', val) + + @classmethod + def team_sharing_whitelist_subjects_changed(cls, val): + """ + Create an instance of this class set to the + ``team_sharing_whitelist_subjects_changed`` tag with value ``val``. + + :param TeamSharingWhitelistSubjectsChangedType val: + :rtype: EventType + """ + return cls('team_sharing_whitelist_subjects_changed', val) + + @classmethod + def tfa_add_exception(cls, val): + """ + Create an instance of this class set to the ``tfa_add_exception`` tag + with value ``val``. + + :param TfaAddExceptionType val: + :rtype: EventType + """ + return cls('tfa_add_exception', val) + + @classmethod + def tfa_change_policy(cls, val): + """ + Create an instance of this class set to the ``tfa_change_policy`` tag + with value ``val``. + + :param TfaChangePolicyType val: + :rtype: EventType + """ + return cls('tfa_change_policy', val) + + @classmethod + def tfa_remove_exception(cls, val): + """ + Create an instance of this class set to the ``tfa_remove_exception`` tag + with value ``val``. + + :param TfaRemoveExceptionType val: + :rtype: EventType + """ + return cls('tfa_remove_exception', val) + + @classmethod + def two_account_change_policy(cls, val): + """ + Create an instance of this class set to the + ``two_account_change_policy`` tag with value ``val``. + + :param TwoAccountChangePolicyType val: + :rtype: EventType + """ + return cls('two_account_change_policy', val) + + @classmethod + def viewer_info_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``viewer_info_policy_changed`` tag with value ``val``. + + :param ViewerInfoPolicyChangedType val: + :rtype: EventType + """ + return cls('viewer_info_policy_changed', val) + + @classmethod + def watermarking_policy_changed(cls, val): + """ + Create an instance of this class set to the + ``watermarking_policy_changed`` tag with value ``val``. + + :param WatermarkingPolicyChangedType val: + :rtype: EventType + """ + return cls('watermarking_policy_changed', val) + + @classmethod + def web_sessions_change_active_session_limit(cls, val): + """ + Create an instance of this class set to the + ``web_sessions_change_active_session_limit`` tag with value ``val``. + + :param WebSessionsChangeActiveSessionLimitType val: + :rtype: EventType + """ + return cls('web_sessions_change_active_session_limit', val) + + @classmethod + def web_sessions_change_fixed_length_policy(cls, val): + """ + Create an instance of this class set to the + ``web_sessions_change_fixed_length_policy`` tag with value ``val``. + + :param WebSessionsChangeFixedLengthPolicyType val: + :rtype: EventType + """ + return cls('web_sessions_change_fixed_length_policy', val) + + @classmethod + def web_sessions_change_idle_length_policy(cls, val): + """ + Create an instance of this class set to the + ``web_sessions_change_idle_length_policy`` tag with value ``val``. + + :param WebSessionsChangeIdleLengthPolicyType val: + :rtype: EventType + """ + return cls('web_sessions_change_idle_length_policy', val) + + @classmethod + def team_merge_from(cls, val): + """ + Create an instance of this class set to the ``team_merge_from`` tag with + value ``val``. + + :param TeamMergeFromType val: + :rtype: EventType + """ + return cls('team_merge_from', val) + + @classmethod + def team_merge_to(cls, val): + """ + Create an instance of this class set to the ``team_merge_to`` tag with + value ``val``. + + :param TeamMergeToType val: + :rtype: EventType + """ + return cls('team_merge_to', val) + + @classmethod + def team_profile_add_logo(cls, val): + """ + Create an instance of this class set to the ``team_profile_add_logo`` + tag with value ``val``. + + :param TeamProfileAddLogoType val: + :rtype: EventType + """ + return cls('team_profile_add_logo', val) + + @classmethod + def team_profile_change_default_language(cls, val): + """ + Create an instance of this class set to the + ``team_profile_change_default_language`` tag with value ``val``. + + :param TeamProfileChangeDefaultLanguageType val: + :rtype: EventType + """ + return cls('team_profile_change_default_language', val) + + @classmethod + def team_profile_change_logo(cls, val): + """ + Create an instance of this class set to the ``team_profile_change_logo`` + tag with value ``val``. + + :param TeamProfileChangeLogoType val: + :rtype: EventType + """ + return cls('team_profile_change_logo', val) + + @classmethod + def team_profile_change_name(cls, val): + """ + Create an instance of this class set to the ``team_profile_change_name`` + tag with value ``val``. + + :param TeamProfileChangeNameType val: + :rtype: EventType + """ + return cls('team_profile_change_name', val) + + @classmethod + def team_profile_remove_logo(cls, val): + """ + Create an instance of this class set to the ``team_profile_remove_logo`` + tag with value ``val``. + + :param TeamProfileRemoveLogoType val: + :rtype: EventType + """ + return cls('team_profile_remove_logo', val) + + @classmethod + def tfa_add_backup_phone(cls, val): + """ + Create an instance of this class set to the ``tfa_add_backup_phone`` tag + with value ``val``. + + :param TfaAddBackupPhoneType val: + :rtype: EventType + """ + return cls('tfa_add_backup_phone', val) + + @classmethod + def tfa_add_security_key(cls, val): + """ + Create an instance of this class set to the ``tfa_add_security_key`` tag + with value ``val``. + + :param TfaAddSecurityKeyType val: + :rtype: EventType + """ + return cls('tfa_add_security_key', val) + + @classmethod + def tfa_change_backup_phone(cls, val): + """ + Create an instance of this class set to the ``tfa_change_backup_phone`` + tag with value ``val``. + + :param TfaChangeBackupPhoneType val: + :rtype: EventType + """ + return cls('tfa_change_backup_phone', val) + + @classmethod + def tfa_change_status(cls, val): + """ + Create an instance of this class set to the ``tfa_change_status`` tag + with value ``val``. + + :param TfaChangeStatusType val: + :rtype: EventType + """ + return cls('tfa_change_status', val) + + @classmethod + def tfa_remove_backup_phone(cls, val): + """ + Create an instance of this class set to the ``tfa_remove_backup_phone`` + tag with value ``val``. + + :param TfaRemoveBackupPhoneType val: + :rtype: EventType + """ + return cls('tfa_remove_backup_phone', val) + + @classmethod + def tfa_remove_security_key(cls, val): + """ + Create an instance of this class set to the ``tfa_remove_security_key`` + tag with value ``val``. + + :param TfaRemoveSecurityKeyType val: + :rtype: EventType + """ + return cls('tfa_remove_security_key', val) + + @classmethod + def tfa_reset(cls, val): + """ + Create an instance of this class set to the ``tfa_reset`` tag with value + ``val``. + + :param TfaResetType val: + :rtype: EventType + """ + return cls('tfa_reset', val) + + @classmethod + def changed_enterprise_admin_role(cls, val): + """ + Create an instance of this class set to the + ``changed_enterprise_admin_role`` tag with value ``val``. + + :param ChangedEnterpriseAdminRoleType val: + :rtype: EventType + """ + return cls('changed_enterprise_admin_role', val) + + @classmethod + def changed_enterprise_connected_team_status(cls, val): + """ + Create an instance of this class set to the + ``changed_enterprise_connected_team_status`` tag with value ``val``. + + :param ChangedEnterpriseConnectedTeamStatusType val: + :rtype: EventType + """ + return cls('changed_enterprise_connected_team_status', val) + + @classmethod + def ended_enterprise_admin_session(cls, val): + """ + Create an instance of this class set to the + ``ended_enterprise_admin_session`` tag with value ``val``. + + :param EndedEnterpriseAdminSessionType val: + :rtype: EventType + """ + return cls('ended_enterprise_admin_session', val) + + @classmethod + def ended_enterprise_admin_session_deprecated(cls, val): + """ + Create an instance of this class set to the + ``ended_enterprise_admin_session_deprecated`` tag with value ``val``. + + :param EndedEnterpriseAdminSessionDeprecatedType val: + :rtype: EventType + """ + return cls('ended_enterprise_admin_session_deprecated', val) + + @classmethod + def enterprise_settings_locking(cls, val): + """ + Create an instance of this class set to the + ``enterprise_settings_locking`` tag with value ``val``. + + :param EnterpriseSettingsLockingType val: + :rtype: EventType + """ + return cls('enterprise_settings_locking', val) + + @classmethod + def guest_admin_change_status(cls, val): + """ + Create an instance of this class set to the + ``guest_admin_change_status`` tag with value ``val``. + + :param GuestAdminChangeStatusType val: + :rtype: EventType + """ + return cls('guest_admin_change_status', val) + + @classmethod + def started_enterprise_admin_session(cls, val): + """ + Create an instance of this class set to the + ``started_enterprise_admin_session`` tag with value ``val``. + + :param StartedEnterpriseAdminSessionType val: + :rtype: EventType + """ + return cls('started_enterprise_admin_session', val) + + @classmethod + def team_merge_request_accepted(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_accepted`` tag with value ``val``. + + :param TeamMergeRequestAcceptedType val: + :rtype: EventType + """ + return cls('team_merge_request_accepted', val) + + @classmethod + def team_merge_request_accepted_shown_to_primary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_accepted_shown_to_primary_team`` tag with value + ``val``. + + :param TeamMergeRequestAcceptedShownToPrimaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_accepted_shown_to_primary_team', val) + + @classmethod + def team_merge_request_accepted_shown_to_secondary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_accepted_shown_to_secondary_team`` tag with value + ``val``. + + :param TeamMergeRequestAcceptedShownToSecondaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_accepted_shown_to_secondary_team', val) + + @classmethod + def team_merge_request_auto_canceled(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_auto_canceled`` tag with value ``val``. + + :param TeamMergeRequestAutoCanceledType val: + :rtype: EventType + """ + return cls('team_merge_request_auto_canceled', val) + + @classmethod + def team_merge_request_canceled(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_canceled`` tag with value ``val``. + + :param TeamMergeRequestCanceledType val: + :rtype: EventType + """ + return cls('team_merge_request_canceled', val) + + @classmethod + def team_merge_request_canceled_shown_to_primary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_canceled_shown_to_primary_team`` tag with value + ``val``. + + :param TeamMergeRequestCanceledShownToPrimaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_canceled_shown_to_primary_team', val) + + @classmethod + def team_merge_request_canceled_shown_to_secondary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_canceled_shown_to_secondary_team`` tag with value + ``val``. + + :param TeamMergeRequestCanceledShownToSecondaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_canceled_shown_to_secondary_team', val) + + @classmethod + def team_merge_request_expired(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_expired`` tag with value ``val``. + + :param TeamMergeRequestExpiredType val: + :rtype: EventType + """ + return cls('team_merge_request_expired', val) + + @classmethod + def team_merge_request_expired_shown_to_primary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_expired_shown_to_primary_team`` tag with value + ``val``. + + :param TeamMergeRequestExpiredShownToPrimaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_expired_shown_to_primary_team', val) + + @classmethod + def team_merge_request_expired_shown_to_secondary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_expired_shown_to_secondary_team`` tag with value + ``val``. + + :param TeamMergeRequestExpiredShownToSecondaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_expired_shown_to_secondary_team', val) + + @classmethod + def team_merge_request_rejected_shown_to_primary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_rejected_shown_to_primary_team`` tag with value + ``val``. + + :param TeamMergeRequestRejectedShownToPrimaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_rejected_shown_to_primary_team', val) + + @classmethod + def team_merge_request_rejected_shown_to_secondary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_rejected_shown_to_secondary_team`` tag with value + ``val``. + + :param TeamMergeRequestRejectedShownToSecondaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_rejected_shown_to_secondary_team', val) + + @classmethod + def team_merge_request_reminder(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_reminder`` tag with value ``val``. + + :param TeamMergeRequestReminderType val: + :rtype: EventType + """ + return cls('team_merge_request_reminder', val) + + @classmethod + def team_merge_request_reminder_shown_to_primary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_reminder_shown_to_primary_team`` tag with value + ``val``. + + :param TeamMergeRequestReminderShownToPrimaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_reminder_shown_to_primary_team', val) + + @classmethod + def team_merge_request_reminder_shown_to_secondary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_reminder_shown_to_secondary_team`` tag with value + ``val``. + + :param TeamMergeRequestReminderShownToSecondaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_reminder_shown_to_secondary_team', val) + + @classmethod + def team_merge_request_revoked(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_revoked`` tag with value ``val``. + + :param TeamMergeRequestRevokedType val: + :rtype: EventType + """ + return cls('team_merge_request_revoked', val) + + @classmethod + def team_merge_request_sent_shown_to_primary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_sent_shown_to_primary_team`` tag with value + ``val``. + + :param TeamMergeRequestSentShownToPrimaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_sent_shown_to_primary_team', val) + + @classmethod + def team_merge_request_sent_shown_to_secondary_team(cls, val): + """ + Create an instance of this class set to the + ``team_merge_request_sent_shown_to_secondary_team`` tag with value + ``val``. + + :param TeamMergeRequestSentShownToSecondaryTeamType val: + :rtype: EventType + """ + return cls('team_merge_request_sent_shown_to_secondary_team', val) + + def is_app_link_team(self): + """ + Check if the union tag is ``app_link_team``. + + :rtype: bool + """ + return self._tag == 'app_link_team' + + def is_app_link_user(self): + """ + Check if the union tag is ``app_link_user``. + + :rtype: bool + """ + return self._tag == 'app_link_user' + + def is_app_unlink_team(self): + """ + Check if the union tag is ``app_unlink_team``. + + :rtype: bool + """ + return self._tag == 'app_unlink_team' + + def is_app_unlink_user(self): + """ + Check if the union tag is ``app_unlink_user``. + + :rtype: bool + """ + return self._tag == 'app_unlink_user' + + def is_integration_connected(self): + """ + Check if the union tag is ``integration_connected``. + + :rtype: bool + """ + return self._tag == 'integration_connected' + + def is_integration_disconnected(self): + """ + Check if the union tag is ``integration_disconnected``. + + :rtype: bool + """ + return self._tag == 'integration_disconnected' + + def is_file_add_comment(self): + """ + Check if the union tag is ``file_add_comment``. + + :rtype: bool + """ + return self._tag == 'file_add_comment' + + def is_file_change_comment_subscription(self): + """ + Check if the union tag is ``file_change_comment_subscription``. + + :rtype: bool + """ + return self._tag == 'file_change_comment_subscription' + + def is_file_delete_comment(self): + """ + Check if the union tag is ``file_delete_comment``. + + :rtype: bool + """ + return self._tag == 'file_delete_comment' + + def is_file_edit_comment(self): + """ + Check if the union tag is ``file_edit_comment``. + + :rtype: bool + """ + return self._tag == 'file_edit_comment' + + def is_file_like_comment(self): + """ + Check if the union tag is ``file_like_comment``. + + :rtype: bool + """ + return self._tag == 'file_like_comment' + + def is_file_resolve_comment(self): + """ + Check if the union tag is ``file_resolve_comment``. + + :rtype: bool + """ + return self._tag == 'file_resolve_comment' + + def is_file_unlike_comment(self): + """ + Check if the union tag is ``file_unlike_comment``. + + :rtype: bool + """ + return self._tag == 'file_unlike_comment' + + def is_file_unresolve_comment(self): + """ + Check if the union tag is ``file_unresolve_comment``. + + :rtype: bool + """ + return self._tag == 'file_unresolve_comment' + + def is_device_change_ip_desktop(self): + """ + Check if the union tag is ``device_change_ip_desktop``. + + :rtype: bool + """ + return self._tag == 'device_change_ip_desktop' + + def is_device_change_ip_mobile(self): + """ + Check if the union tag is ``device_change_ip_mobile``. + + :rtype: bool + """ + return self._tag == 'device_change_ip_mobile' + + def is_device_change_ip_web(self): + """ + Check if the union tag is ``device_change_ip_web``. + + :rtype: bool + """ + return self._tag == 'device_change_ip_web' + + def is_device_delete_on_unlink_fail(self): + """ + Check if the union tag is ``device_delete_on_unlink_fail``. + + :rtype: bool + """ + return self._tag == 'device_delete_on_unlink_fail' + + def is_device_delete_on_unlink_success(self): + """ + Check if the union tag is ``device_delete_on_unlink_success``. + + :rtype: bool + """ + return self._tag == 'device_delete_on_unlink_success' + + def is_device_link_fail(self): + """ + Check if the union tag is ``device_link_fail``. + + :rtype: bool + """ + return self._tag == 'device_link_fail' + + def is_device_link_success(self): + """ + Check if the union tag is ``device_link_success``. + + :rtype: bool + """ + return self._tag == 'device_link_success' + + def is_device_management_disabled(self): + """ + Check if the union tag is ``device_management_disabled``. + + :rtype: bool + """ + return self._tag == 'device_management_disabled' + + def is_device_management_enabled(self): + """ + Check if the union tag is ``device_management_enabled``. + + :rtype: bool + """ + return self._tag == 'device_management_enabled' + + def is_device_unlink(self): + """ + Check if the union tag is ``device_unlink``. + + :rtype: bool + """ + return self._tag == 'device_unlink' + + def is_emm_refresh_auth_token(self): + """ + Check if the union tag is ``emm_refresh_auth_token``. + + :rtype: bool + """ + return self._tag == 'emm_refresh_auth_token' + + def is_account_capture_change_availability(self): + """ + Check if the union tag is ``account_capture_change_availability``. + + :rtype: bool + """ + return self._tag == 'account_capture_change_availability' + + def is_account_capture_migrate_account(self): + """ + Check if the union tag is ``account_capture_migrate_account``. + + :rtype: bool + """ + return self._tag == 'account_capture_migrate_account' + + def is_account_capture_notification_emails_sent(self): + """ + Check if the union tag is ``account_capture_notification_emails_sent``. + + :rtype: bool + """ + return self._tag == 'account_capture_notification_emails_sent' + + def is_account_capture_relinquish_account(self): + """ + Check if the union tag is ``account_capture_relinquish_account``. + + :rtype: bool + """ + return self._tag == 'account_capture_relinquish_account' + + def is_disabled_domain_invites(self): + """ + Check if the union tag is ``disabled_domain_invites``. + + :rtype: bool + """ + return self._tag == 'disabled_domain_invites' + + def is_domain_invites_approve_request_to_join_team(self): + """ + Check if the union tag is ``domain_invites_approve_request_to_join_team``. + + :rtype: bool + """ + return self._tag == 'domain_invites_approve_request_to_join_team' + + def is_domain_invites_decline_request_to_join_team(self): + """ + Check if the union tag is ``domain_invites_decline_request_to_join_team``. + + :rtype: bool + """ + return self._tag == 'domain_invites_decline_request_to_join_team' + + def is_domain_invites_email_existing_users(self): + """ + Check if the union tag is ``domain_invites_email_existing_users``. + + :rtype: bool + """ + return self._tag == 'domain_invites_email_existing_users' + + def is_domain_invites_request_to_join_team(self): + """ + Check if the union tag is ``domain_invites_request_to_join_team``. + + :rtype: bool + """ + return self._tag == 'domain_invites_request_to_join_team' + + def is_domain_invites_set_invite_new_user_pref_to_no(self): + """ + Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_no``. + + :rtype: bool + """ + return self._tag == 'domain_invites_set_invite_new_user_pref_to_no' + + def is_domain_invites_set_invite_new_user_pref_to_yes(self): + """ + Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_yes``. + + :rtype: bool + """ + return self._tag == 'domain_invites_set_invite_new_user_pref_to_yes' + + def is_domain_verification_add_domain_fail(self): + """ + Check if the union tag is ``domain_verification_add_domain_fail``. + + :rtype: bool + """ + return self._tag == 'domain_verification_add_domain_fail' + + def is_domain_verification_add_domain_success(self): + """ + Check if the union tag is ``domain_verification_add_domain_success``. + + :rtype: bool + """ + return self._tag == 'domain_verification_add_domain_success' + + def is_domain_verification_remove_domain(self): + """ + Check if the union tag is ``domain_verification_remove_domain``. + + :rtype: bool + """ + return self._tag == 'domain_verification_remove_domain' + + def is_enabled_domain_invites(self): + """ + Check if the union tag is ``enabled_domain_invites``. + + :rtype: bool + """ + return self._tag == 'enabled_domain_invites' + + def is_create_folder(self): + """ + Check if the union tag is ``create_folder``. + + :rtype: bool + """ + return self._tag == 'create_folder' + + def is_file_add(self): + """ + Check if the union tag is ``file_add``. + + :rtype: bool + """ + return self._tag == 'file_add' + + def is_file_copy(self): + """ + Check if the union tag is ``file_copy``. + + :rtype: bool + """ + return self._tag == 'file_copy' + + def is_file_delete(self): + """ + Check if the union tag is ``file_delete``. + + :rtype: bool + """ + return self._tag == 'file_delete' + + def is_file_download(self): + """ + Check if the union tag is ``file_download``. + + :rtype: bool + """ + return self._tag == 'file_download' + + def is_file_edit(self): + """ + Check if the union tag is ``file_edit``. + + :rtype: bool + """ + return self._tag == 'file_edit' + + def is_file_get_copy_reference(self): + """ + Check if the union tag is ``file_get_copy_reference``. + + :rtype: bool + """ + return self._tag == 'file_get_copy_reference' + + def is_file_locking_lock_status_changed(self): + """ + Check if the union tag is ``file_locking_lock_status_changed``. + + :rtype: bool + """ + return self._tag == 'file_locking_lock_status_changed' + + def is_file_move(self): + """ + Check if the union tag is ``file_move``. + + :rtype: bool + """ + return self._tag == 'file_move' + + def is_file_permanently_delete(self): + """ + Check if the union tag is ``file_permanently_delete``. + + :rtype: bool + """ + return self._tag == 'file_permanently_delete' + + def is_file_preview(self): + """ + Check if the union tag is ``file_preview``. + + :rtype: bool + """ + return self._tag == 'file_preview' + + def is_file_rename(self): + """ + Check if the union tag is ``file_rename``. + + :rtype: bool + """ + return self._tag == 'file_rename' + + def is_file_restore(self): + """ + Check if the union tag is ``file_restore``. + + :rtype: bool + """ + return self._tag == 'file_restore' + + def is_file_revert(self): + """ + Check if the union tag is ``file_revert``. + + :rtype: bool + """ + return self._tag == 'file_revert' + + def is_file_rollback_changes(self): + """ + Check if the union tag is ``file_rollback_changes``. + + :rtype: bool + """ + return self._tag == 'file_rollback_changes' + + def is_file_save_copy_reference(self): + """ + Check if the union tag is ``file_save_copy_reference``. + + :rtype: bool + """ + return self._tag == 'file_save_copy_reference' + + def is_folder_overview_description_changed(self): + """ + Check if the union tag is ``folder_overview_description_changed``. + + :rtype: bool + """ + return self._tag == 'folder_overview_description_changed' + + def is_folder_overview_item_pinned(self): + """ + Check if the union tag is ``folder_overview_item_pinned``. + + :rtype: bool + """ + return self._tag == 'folder_overview_item_pinned' + + def is_folder_overview_item_unpinned(self): + """ + Check if the union tag is ``folder_overview_item_unpinned``. + + :rtype: bool + """ + return self._tag == 'folder_overview_item_unpinned' + + def is_rewind_folder(self): + """ + Check if the union tag is ``rewind_folder``. + + :rtype: bool + """ + return self._tag == 'rewind_folder' + + def is_file_request_change(self): + """ + Check if the union tag is ``file_request_change``. + + :rtype: bool + """ + return self._tag == 'file_request_change' + + def is_file_request_close(self): + """ + Check if the union tag is ``file_request_close``. + + :rtype: bool + """ + return self._tag == 'file_request_close' + + def is_file_request_create(self): + """ + Check if the union tag is ``file_request_create``. + + :rtype: bool + """ + return self._tag == 'file_request_create' + + def is_file_request_delete(self): + """ + Check if the union tag is ``file_request_delete``. + + :rtype: bool + """ + return self._tag == 'file_request_delete' + + def is_file_request_receive_file(self): + """ + Check if the union tag is ``file_request_receive_file``. + + :rtype: bool + """ + return self._tag == 'file_request_receive_file' + + def is_group_add_external_id(self): + """ + Check if the union tag is ``group_add_external_id``. + + :rtype: bool + """ + return self._tag == 'group_add_external_id' + + def is_group_add_member(self): + """ + Check if the union tag is ``group_add_member``. + + :rtype: bool + """ + return self._tag == 'group_add_member' + + def is_group_change_external_id(self): + """ + Check if the union tag is ``group_change_external_id``. + + :rtype: bool + """ + return self._tag == 'group_change_external_id' + + def is_group_change_management_type(self): + """ + Check if the union tag is ``group_change_management_type``. + + :rtype: bool + """ + return self._tag == 'group_change_management_type' + + def is_group_change_member_role(self): + """ + Check if the union tag is ``group_change_member_role``. + + :rtype: bool + """ + return self._tag == 'group_change_member_role' + + def is_group_create(self): + """ + Check if the union tag is ``group_create``. + + :rtype: bool + """ + return self._tag == 'group_create' + + def is_group_delete(self): + """ + Check if the union tag is ``group_delete``. + + :rtype: bool + """ + return self._tag == 'group_delete' + + def is_group_description_updated(self): + """ + Check if the union tag is ``group_description_updated``. + + :rtype: bool + """ + return self._tag == 'group_description_updated' + + def is_group_join_policy_updated(self): + """ + Check if the union tag is ``group_join_policy_updated``. + + :rtype: bool + """ + return self._tag == 'group_join_policy_updated' + + def is_group_moved(self): + """ + Check if the union tag is ``group_moved``. + + :rtype: bool + """ + return self._tag == 'group_moved' + + def is_group_remove_external_id(self): + """ + Check if the union tag is ``group_remove_external_id``. + + :rtype: bool + """ + return self._tag == 'group_remove_external_id' + + def is_group_remove_member(self): + """ + Check if the union tag is ``group_remove_member``. + + :rtype: bool + """ + return self._tag == 'group_remove_member' + + def is_group_rename(self): + """ + Check if the union tag is ``group_rename``. + + :rtype: bool + """ + return self._tag == 'group_rename' + + def is_legal_holds_activate_a_hold(self): + """ + Check if the union tag is ``legal_holds_activate_a_hold``. + + :rtype: bool + """ + return self._tag == 'legal_holds_activate_a_hold' + + def is_legal_holds_add_members(self): + """ + Check if the union tag is ``legal_holds_add_members``. + + :rtype: bool + """ + return self._tag == 'legal_holds_add_members' + + def is_legal_holds_change_hold_details(self): + """ + Check if the union tag is ``legal_holds_change_hold_details``. + + :rtype: bool + """ + return self._tag == 'legal_holds_change_hold_details' + + def is_legal_holds_change_hold_name(self): + """ + Check if the union tag is ``legal_holds_change_hold_name``. + + :rtype: bool + """ + return self._tag == 'legal_holds_change_hold_name' + + def is_legal_holds_export_a_hold(self): + """ + Check if the union tag is ``legal_holds_export_a_hold``. + + :rtype: bool + """ + return self._tag == 'legal_holds_export_a_hold' + + def is_legal_holds_export_cancelled(self): + """ + Check if the union tag is ``legal_holds_export_cancelled``. + + :rtype: bool + """ + return self._tag == 'legal_holds_export_cancelled' + + def is_legal_holds_export_downloaded(self): + """ + Check if the union tag is ``legal_holds_export_downloaded``. + + :rtype: bool + """ + return self._tag == 'legal_holds_export_downloaded' + + def is_legal_holds_export_removed(self): + """ + Check if the union tag is ``legal_holds_export_removed``. + + :rtype: bool + """ + return self._tag == 'legal_holds_export_removed' + + def is_legal_holds_release_a_hold(self): + """ + Check if the union tag is ``legal_holds_release_a_hold``. + + :rtype: bool + """ + return self._tag == 'legal_holds_release_a_hold' + + def is_legal_holds_remove_members(self): + """ + Check if the union tag is ``legal_holds_remove_members``. + + :rtype: bool + """ + return self._tag == 'legal_holds_remove_members' + + def is_legal_holds_report_a_hold(self): + """ + Check if the union tag is ``legal_holds_report_a_hold``. + + :rtype: bool + """ + return self._tag == 'legal_holds_report_a_hold' + + def is_account_lock_or_unlocked(self): + """ + Check if the union tag is ``account_lock_or_unlocked``. + + :rtype: bool + """ + return self._tag == 'account_lock_or_unlocked' + + def is_emm_error(self): + """ + Check if the union tag is ``emm_error``. + + :rtype: bool + """ + return self._tag == 'emm_error' + + def is_guest_admin_signed_in_via_trusted_teams(self): + """ + Check if the union tag is ``guest_admin_signed_in_via_trusted_teams``. + + :rtype: bool + """ + return self._tag == 'guest_admin_signed_in_via_trusted_teams' + + def is_guest_admin_signed_out_via_trusted_teams(self): + """ + Check if the union tag is ``guest_admin_signed_out_via_trusted_teams``. + + :rtype: bool + """ + return self._tag == 'guest_admin_signed_out_via_trusted_teams' + + def is_login_fail(self): + """ + Check if the union tag is ``login_fail``. + + :rtype: bool + """ + return self._tag == 'login_fail' + + def is_login_success(self): + """ + Check if the union tag is ``login_success``. + + :rtype: bool + """ + return self._tag == 'login_success' + + def is_logout(self): + """ + Check if the union tag is ``logout``. + + :rtype: bool + """ + return self._tag == 'logout' + + def is_reseller_support_session_end(self): + """ + Check if the union tag is ``reseller_support_session_end``. + + :rtype: bool + """ + return self._tag == 'reseller_support_session_end' + + def is_reseller_support_session_start(self): + """ + Check if the union tag is ``reseller_support_session_start``. + + :rtype: bool + """ + return self._tag == 'reseller_support_session_start' + + def is_sign_in_as_session_end(self): + """ + Check if the union tag is ``sign_in_as_session_end``. + + :rtype: bool + """ + return self._tag == 'sign_in_as_session_end' + + def is_sign_in_as_session_start(self): + """ + Check if the union tag is ``sign_in_as_session_start``. + + :rtype: bool + """ + return self._tag == 'sign_in_as_session_start' + + def is_sso_error(self): + """ + Check if the union tag is ``sso_error``. + + :rtype: bool + """ + return self._tag == 'sso_error' + + def is_create_team_invite_link(self): + """ + Check if the union tag is ``create_team_invite_link``. + + :rtype: bool + """ + return self._tag == 'create_team_invite_link' + + def is_delete_team_invite_link(self): + """ + Check if the union tag is ``delete_team_invite_link``. + + :rtype: bool + """ + return self._tag == 'delete_team_invite_link' + + def is_member_add_external_id(self): + """ + Check if the union tag is ``member_add_external_id``. + + :rtype: bool + """ + return self._tag == 'member_add_external_id' + + def is_member_add_name(self): + """ + Check if the union tag is ``member_add_name``. + + :rtype: bool + """ + return self._tag == 'member_add_name' + + def is_member_change_admin_role(self): + """ + Check if the union tag is ``member_change_admin_role``. + + :rtype: bool + """ + return self._tag == 'member_change_admin_role' + + def is_member_change_email(self): + """ + Check if the union tag is ``member_change_email``. + + :rtype: bool + """ + return self._tag == 'member_change_email' + + def is_member_change_external_id(self): + """ + Check if the union tag is ``member_change_external_id``. + + :rtype: bool + """ + return self._tag == 'member_change_external_id' + + def is_member_change_membership_type(self): + """ + Check if the union tag is ``member_change_membership_type``. + + :rtype: bool + """ + return self._tag == 'member_change_membership_type' + + def is_member_change_name(self): + """ + Check if the union tag is ``member_change_name``. + + :rtype: bool + """ + return self._tag == 'member_change_name' + + def is_member_change_status(self): + """ + Check if the union tag is ``member_change_status``. + + :rtype: bool + """ + return self._tag == 'member_change_status' + + def is_member_delete_manual_contacts(self): + """ + Check if the union tag is ``member_delete_manual_contacts``. + + :rtype: bool + """ + return self._tag == 'member_delete_manual_contacts' + + def is_member_delete_profile_photo(self): + """ + Check if the union tag is ``member_delete_profile_photo``. + + :rtype: bool + """ + return self._tag == 'member_delete_profile_photo' + + def is_member_permanently_delete_account_contents(self): + """ + Check if the union tag is ``member_permanently_delete_account_contents``. + + :rtype: bool + """ + return self._tag == 'member_permanently_delete_account_contents' + + def is_member_remove_external_id(self): + """ + Check if the union tag is ``member_remove_external_id``. + + :rtype: bool + """ + return self._tag == 'member_remove_external_id' + + def is_member_set_profile_photo(self): + """ + Check if the union tag is ``member_set_profile_photo``. + + :rtype: bool + """ + return self._tag == 'member_set_profile_photo' + + def is_member_space_limits_add_custom_quota(self): + """ + Check if the union tag is ``member_space_limits_add_custom_quota``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_add_custom_quota' + + def is_member_space_limits_change_custom_quota(self): + """ + Check if the union tag is ``member_space_limits_change_custom_quota``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_change_custom_quota' + + def is_member_space_limits_change_status(self): + """ + Check if the union tag is ``member_space_limits_change_status``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_change_status' + + def is_member_space_limits_remove_custom_quota(self): + """ + Check if the union tag is ``member_space_limits_remove_custom_quota``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_remove_custom_quota' + + def is_member_suggest(self): + """ + Check if the union tag is ``member_suggest``. + + :rtype: bool + """ + return self._tag == 'member_suggest' + + def is_member_transfer_account_contents(self): + """ + Check if the union tag is ``member_transfer_account_contents``. + + :rtype: bool + """ + return self._tag == 'member_transfer_account_contents' + + def is_pending_secondary_email_added(self): + """ + Check if the union tag is ``pending_secondary_email_added``. + + :rtype: bool + """ + return self._tag == 'pending_secondary_email_added' + + def is_secondary_email_deleted(self): + """ + Check if the union tag is ``secondary_email_deleted``. + + :rtype: bool + """ + return self._tag == 'secondary_email_deleted' + + def is_secondary_email_verified(self): + """ + Check if the union tag is ``secondary_email_verified``. + + :rtype: bool + """ + return self._tag == 'secondary_email_verified' + + def is_secondary_mails_policy_changed(self): + """ + Check if the union tag is ``secondary_mails_policy_changed``. + + :rtype: bool + """ + return self._tag == 'secondary_mails_policy_changed' + + def is_binder_add_page(self): + """ + Check if the union tag is ``binder_add_page``. + + :rtype: bool + """ + return self._tag == 'binder_add_page' + + def is_binder_add_section(self): + """ + Check if the union tag is ``binder_add_section``. + + :rtype: bool + """ + return self._tag == 'binder_add_section' + + def is_binder_remove_page(self): + """ + Check if the union tag is ``binder_remove_page``. + + :rtype: bool + """ + return self._tag == 'binder_remove_page' + + def is_binder_remove_section(self): + """ + Check if the union tag is ``binder_remove_section``. + + :rtype: bool + """ + return self._tag == 'binder_remove_section' + + def is_binder_rename_page(self): + """ + Check if the union tag is ``binder_rename_page``. + + :rtype: bool + """ + return self._tag == 'binder_rename_page' + + def is_binder_rename_section(self): + """ + Check if the union tag is ``binder_rename_section``. + + :rtype: bool + """ + return self._tag == 'binder_rename_section' + + def is_binder_reorder_page(self): + """ + Check if the union tag is ``binder_reorder_page``. + + :rtype: bool + """ + return self._tag == 'binder_reorder_page' + + def is_binder_reorder_section(self): + """ + Check if the union tag is ``binder_reorder_section``. + + :rtype: bool + """ + return self._tag == 'binder_reorder_section' + + def is_paper_content_add_member(self): + """ + Check if the union tag is ``paper_content_add_member``. + + :rtype: bool + """ + return self._tag == 'paper_content_add_member' + + def is_paper_content_add_to_folder(self): + """ + Check if the union tag is ``paper_content_add_to_folder``. + + :rtype: bool + """ + return self._tag == 'paper_content_add_to_folder' + + def is_paper_content_archive(self): + """ + Check if the union tag is ``paper_content_archive``. + + :rtype: bool + """ + return self._tag == 'paper_content_archive' + + def is_paper_content_create(self): + """ + Check if the union tag is ``paper_content_create``. + + :rtype: bool + """ + return self._tag == 'paper_content_create' + + def is_paper_content_permanently_delete(self): + """ + Check if the union tag is ``paper_content_permanently_delete``. + + :rtype: bool + """ + return self._tag == 'paper_content_permanently_delete' + + def is_paper_content_remove_from_folder(self): + """ + Check if the union tag is ``paper_content_remove_from_folder``. + + :rtype: bool + """ + return self._tag == 'paper_content_remove_from_folder' + + def is_paper_content_remove_member(self): + """ + Check if the union tag is ``paper_content_remove_member``. + + :rtype: bool + """ + return self._tag == 'paper_content_remove_member' + + def is_paper_content_rename(self): + """ + Check if the union tag is ``paper_content_rename``. + + :rtype: bool + """ + return self._tag == 'paper_content_rename' + + def is_paper_content_restore(self): + """ + Check if the union tag is ``paper_content_restore``. + + :rtype: bool + """ + return self._tag == 'paper_content_restore' + + def is_paper_doc_add_comment(self): + """ + Check if the union tag is ``paper_doc_add_comment``. + + :rtype: bool + """ + return self._tag == 'paper_doc_add_comment' + + def is_paper_doc_change_member_role(self): + """ + Check if the union tag is ``paper_doc_change_member_role``. + + :rtype: bool + """ + return self._tag == 'paper_doc_change_member_role' + + def is_paper_doc_change_sharing_policy(self): + """ + Check if the union tag is ``paper_doc_change_sharing_policy``. + + :rtype: bool + """ + return self._tag == 'paper_doc_change_sharing_policy' + + def is_paper_doc_change_subscription(self): + """ + Check if the union tag is ``paper_doc_change_subscription``. + + :rtype: bool + """ + return self._tag == 'paper_doc_change_subscription' + + def is_paper_doc_deleted(self): + """ + Check if the union tag is ``paper_doc_deleted``. + + :rtype: bool + """ + return self._tag == 'paper_doc_deleted' + + def is_paper_doc_delete_comment(self): + """ + Check if the union tag is ``paper_doc_delete_comment``. + + :rtype: bool + """ + return self._tag == 'paper_doc_delete_comment' + + def is_paper_doc_download(self): + """ + Check if the union tag is ``paper_doc_download``. + + :rtype: bool + """ + return self._tag == 'paper_doc_download' + + def is_paper_doc_edit(self): + """ + Check if the union tag is ``paper_doc_edit``. + + :rtype: bool + """ + return self._tag == 'paper_doc_edit' + + def is_paper_doc_edit_comment(self): + """ + Check if the union tag is ``paper_doc_edit_comment``. + + :rtype: bool + """ + return self._tag == 'paper_doc_edit_comment' + + def is_paper_doc_followed(self): + """ + Check if the union tag is ``paper_doc_followed``. + + :rtype: bool + """ + return self._tag == 'paper_doc_followed' + + def is_paper_doc_mention(self): + """ + Check if the union tag is ``paper_doc_mention``. + + :rtype: bool + """ + return self._tag == 'paper_doc_mention' + + def is_paper_doc_ownership_changed(self): + """ + Check if the union tag is ``paper_doc_ownership_changed``. + + :rtype: bool + """ + return self._tag == 'paper_doc_ownership_changed' + + def is_paper_doc_request_access(self): + """ + Check if the union tag is ``paper_doc_request_access``. + + :rtype: bool + """ + return self._tag == 'paper_doc_request_access' + + def is_paper_doc_resolve_comment(self): + """ + Check if the union tag is ``paper_doc_resolve_comment``. + + :rtype: bool + """ + return self._tag == 'paper_doc_resolve_comment' + + def is_paper_doc_revert(self): + """ + Check if the union tag is ``paper_doc_revert``. + + :rtype: bool + """ + return self._tag == 'paper_doc_revert' + + def is_paper_doc_slack_share(self): + """ + Check if the union tag is ``paper_doc_slack_share``. + + :rtype: bool + """ + return self._tag == 'paper_doc_slack_share' + + def is_paper_doc_team_invite(self): + """ + Check if the union tag is ``paper_doc_team_invite``. + + :rtype: bool + """ + return self._tag == 'paper_doc_team_invite' + + def is_paper_doc_trashed(self): + """ + Check if the union tag is ``paper_doc_trashed``. + + :rtype: bool + """ + return self._tag == 'paper_doc_trashed' + + def is_paper_doc_unresolve_comment(self): + """ + Check if the union tag is ``paper_doc_unresolve_comment``. + + :rtype: bool + """ + return self._tag == 'paper_doc_unresolve_comment' + + def is_paper_doc_untrashed(self): + """ + Check if the union tag is ``paper_doc_untrashed``. + + :rtype: bool + """ + return self._tag == 'paper_doc_untrashed' + + def is_paper_doc_view(self): + """ + Check if the union tag is ``paper_doc_view``. + + :rtype: bool + """ + return self._tag == 'paper_doc_view' + + def is_paper_external_view_allow(self): + """ + Check if the union tag is ``paper_external_view_allow``. + + :rtype: bool + """ + return self._tag == 'paper_external_view_allow' + + def is_paper_external_view_default_team(self): + """ + Check if the union tag is ``paper_external_view_default_team``. + + :rtype: bool + """ + return self._tag == 'paper_external_view_default_team' + + def is_paper_external_view_forbid(self): + """ + Check if the union tag is ``paper_external_view_forbid``. + + :rtype: bool + """ + return self._tag == 'paper_external_view_forbid' + + def is_paper_folder_change_subscription(self): + """ + Check if the union tag is ``paper_folder_change_subscription``. + + :rtype: bool + """ + return self._tag == 'paper_folder_change_subscription' + + def is_paper_folder_deleted(self): + """ + Check if the union tag is ``paper_folder_deleted``. + + :rtype: bool + """ + return self._tag == 'paper_folder_deleted' + + def is_paper_folder_followed(self): + """ + Check if the union tag is ``paper_folder_followed``. + + :rtype: bool + """ + return self._tag == 'paper_folder_followed' + + def is_paper_folder_team_invite(self): + """ + Check if the union tag is ``paper_folder_team_invite``. + + :rtype: bool + """ + return self._tag == 'paper_folder_team_invite' + + def is_paper_published_link_change_permission(self): + """ + Check if the union tag is ``paper_published_link_change_permission``. + + :rtype: bool + """ + return self._tag == 'paper_published_link_change_permission' + + def is_paper_published_link_create(self): + """ + Check if the union tag is ``paper_published_link_create``. + + :rtype: bool + """ + return self._tag == 'paper_published_link_create' + + def is_paper_published_link_disabled(self): + """ + Check if the union tag is ``paper_published_link_disabled``. + + :rtype: bool + """ + return self._tag == 'paper_published_link_disabled' + + def is_paper_published_link_view(self): + """ + Check if the union tag is ``paper_published_link_view``. + + :rtype: bool + """ + return self._tag == 'paper_published_link_view' + + def is_password_change(self): + """ + Check if the union tag is ``password_change``. + + :rtype: bool + """ + return self._tag == 'password_change' + + def is_password_reset(self): + """ + Check if the union tag is ``password_reset``. + + :rtype: bool + """ + return self._tag == 'password_reset' + + def is_password_reset_all(self): + """ + Check if the union tag is ``password_reset_all``. + + :rtype: bool + """ + return self._tag == 'password_reset_all' + + def is_emm_create_exceptions_report(self): + """ + Check if the union tag is ``emm_create_exceptions_report``. + + :rtype: bool + """ + return self._tag == 'emm_create_exceptions_report' + + def is_emm_create_usage_report(self): + """ + Check if the union tag is ``emm_create_usage_report``. + + :rtype: bool + """ + return self._tag == 'emm_create_usage_report' + + def is_export_members_report(self): + """ + Check if the union tag is ``export_members_report``. + + :rtype: bool + """ + return self._tag == 'export_members_report' + + def is_export_members_report_fail(self): + """ + Check if the union tag is ``export_members_report_fail``. + + :rtype: bool + """ + return self._tag == 'export_members_report_fail' + + def is_no_expiration_link_gen_create_report(self): + """ + Check if the union tag is ``no_expiration_link_gen_create_report``. + + :rtype: bool + """ + return self._tag == 'no_expiration_link_gen_create_report' + + def is_no_expiration_link_gen_report_failed(self): + """ + Check if the union tag is ``no_expiration_link_gen_report_failed``. + + :rtype: bool + """ + return self._tag == 'no_expiration_link_gen_report_failed' + + def is_no_password_link_gen_create_report(self): + """ + Check if the union tag is ``no_password_link_gen_create_report``. + + :rtype: bool + """ + return self._tag == 'no_password_link_gen_create_report' + + def is_no_password_link_gen_report_failed(self): + """ + Check if the union tag is ``no_password_link_gen_report_failed``. + + :rtype: bool + """ + return self._tag == 'no_password_link_gen_report_failed' + + def is_no_password_link_view_create_report(self): + """ + Check if the union tag is ``no_password_link_view_create_report``. + + :rtype: bool + """ + return self._tag == 'no_password_link_view_create_report' + + def is_no_password_link_view_report_failed(self): + """ + Check if the union tag is ``no_password_link_view_report_failed``. + + :rtype: bool + """ + return self._tag == 'no_password_link_view_report_failed' + + def is_outdated_link_view_create_report(self): + """ + Check if the union tag is ``outdated_link_view_create_report``. + + :rtype: bool + """ + return self._tag == 'outdated_link_view_create_report' + + def is_outdated_link_view_report_failed(self): + """ + Check if the union tag is ``outdated_link_view_report_failed``. + + :rtype: bool + """ + return self._tag == 'outdated_link_view_report_failed' + + def is_paper_admin_export_start(self): + """ + Check if the union tag is ``paper_admin_export_start``. + + :rtype: bool + """ + return self._tag == 'paper_admin_export_start' + + def is_smart_sync_create_admin_privilege_report(self): + """ + Check if the union tag is ``smart_sync_create_admin_privilege_report``. + + :rtype: bool + """ + return self._tag == 'smart_sync_create_admin_privilege_report' + + def is_team_activity_create_report(self): + """ + Check if the union tag is ``team_activity_create_report``. + + :rtype: bool + """ + return self._tag == 'team_activity_create_report' + + def is_team_activity_create_report_fail(self): + """ + Check if the union tag is ``team_activity_create_report_fail``. + + :rtype: bool + """ + return self._tag == 'team_activity_create_report_fail' + + def is_collection_share(self): + """ + Check if the union tag is ``collection_share``. + + :rtype: bool + """ + return self._tag == 'collection_share' + + def is_file_transfers_file_add(self): + """ + Check if the union tag is ``file_transfers_file_add``. + + :rtype: bool + """ + return self._tag == 'file_transfers_file_add' + + def is_file_transfers_transfer_delete(self): + """ + Check if the union tag is ``file_transfers_transfer_delete``. + + :rtype: bool + """ + return self._tag == 'file_transfers_transfer_delete' + + def is_file_transfers_transfer_download(self): + """ + Check if the union tag is ``file_transfers_transfer_download``. + + :rtype: bool + """ + return self._tag == 'file_transfers_transfer_download' + + def is_file_transfers_transfer_send(self): + """ + Check if the union tag is ``file_transfers_transfer_send``. + + :rtype: bool + """ + return self._tag == 'file_transfers_transfer_send' + + def is_file_transfers_transfer_view(self): + """ + Check if the union tag is ``file_transfers_transfer_view``. + + :rtype: bool + """ + return self._tag == 'file_transfers_transfer_view' + + def is_note_acl_invite_only(self): + """ + Check if the union tag is ``note_acl_invite_only``. + + :rtype: bool + """ + return self._tag == 'note_acl_invite_only' + + def is_note_acl_link(self): + """ + Check if the union tag is ``note_acl_link``. + + :rtype: bool + """ + return self._tag == 'note_acl_link' + + def is_note_acl_team_link(self): + """ + Check if the union tag is ``note_acl_team_link``. + + :rtype: bool + """ + return self._tag == 'note_acl_team_link' + + def is_note_shared(self): + """ + Check if the union tag is ``note_shared``. + + :rtype: bool + """ + return self._tag == 'note_shared' + + def is_note_share_receive(self): + """ + Check if the union tag is ``note_share_receive``. + + :rtype: bool + """ + return self._tag == 'note_share_receive' + + def is_open_note_shared(self): + """ + Check if the union tag is ``open_note_shared``. + + :rtype: bool + """ + return self._tag == 'open_note_shared' + + def is_sf_add_group(self): + """ + Check if the union tag is ``sf_add_group``. + + :rtype: bool + """ + return self._tag == 'sf_add_group' + + def is_sf_allow_non_members_to_view_shared_links(self): + """ + Check if the union tag is ``sf_allow_non_members_to_view_shared_links``. + + :rtype: bool + """ + return self._tag == 'sf_allow_non_members_to_view_shared_links' + + def is_sf_external_invite_warn(self): + """ + Check if the union tag is ``sf_external_invite_warn``. + + :rtype: bool + """ + return self._tag == 'sf_external_invite_warn' + + def is_sf_fb_invite(self): + """ + Check if the union tag is ``sf_fb_invite``. + + :rtype: bool + """ + return self._tag == 'sf_fb_invite' + + def is_sf_fb_invite_change_role(self): + """ + Check if the union tag is ``sf_fb_invite_change_role``. + + :rtype: bool + """ + return self._tag == 'sf_fb_invite_change_role' + + def is_sf_fb_uninvite(self): + """ + Check if the union tag is ``sf_fb_uninvite``. + + :rtype: bool + """ + return self._tag == 'sf_fb_uninvite' + + def is_sf_invite_group(self): + """ + Check if the union tag is ``sf_invite_group``. + + :rtype: bool + """ + return self._tag == 'sf_invite_group' + + def is_sf_team_grant_access(self): + """ + Check if the union tag is ``sf_team_grant_access``. + + :rtype: bool + """ + return self._tag == 'sf_team_grant_access' + + def is_sf_team_invite(self): + """ + Check if the union tag is ``sf_team_invite``. + + :rtype: bool + """ + return self._tag == 'sf_team_invite' + + def is_sf_team_invite_change_role(self): + """ + Check if the union tag is ``sf_team_invite_change_role``. + + :rtype: bool + """ + return self._tag == 'sf_team_invite_change_role' + + def is_sf_team_join(self): + """ + Check if the union tag is ``sf_team_join``. + + :rtype: bool + """ + return self._tag == 'sf_team_join' + + def is_sf_team_join_from_oob_link(self): + """ + Check if the union tag is ``sf_team_join_from_oob_link``. + + :rtype: bool + """ + return self._tag == 'sf_team_join_from_oob_link' + + def is_sf_team_uninvite(self): + """ + Check if the union tag is ``sf_team_uninvite``. + + :rtype: bool + """ + return self._tag == 'sf_team_uninvite' + + def is_shared_content_add_invitees(self): + """ + Check if the union tag is ``shared_content_add_invitees``. + + :rtype: bool + """ + return self._tag == 'shared_content_add_invitees' + + def is_shared_content_add_link_expiry(self): + """ + Check if the union tag is ``shared_content_add_link_expiry``. + + :rtype: bool + """ + return self._tag == 'shared_content_add_link_expiry' + + def is_shared_content_add_link_password(self): + """ + Check if the union tag is ``shared_content_add_link_password``. + + :rtype: bool + """ + return self._tag == 'shared_content_add_link_password' + + def is_shared_content_add_member(self): + """ + Check if the union tag is ``shared_content_add_member``. + + :rtype: bool + """ + return self._tag == 'shared_content_add_member' + + def is_shared_content_change_downloads_policy(self): + """ + Check if the union tag is ``shared_content_change_downloads_policy``. + + :rtype: bool + """ + return self._tag == 'shared_content_change_downloads_policy' + + def is_shared_content_change_invitee_role(self): + """ + Check if the union tag is ``shared_content_change_invitee_role``. + + :rtype: bool + """ + return self._tag == 'shared_content_change_invitee_role' + + def is_shared_content_change_link_audience(self): + """ + Check if the union tag is ``shared_content_change_link_audience``. + + :rtype: bool + """ + return self._tag == 'shared_content_change_link_audience' + + def is_shared_content_change_link_expiry(self): + """ + Check if the union tag is ``shared_content_change_link_expiry``. + + :rtype: bool + """ + return self._tag == 'shared_content_change_link_expiry' + + def is_shared_content_change_link_password(self): + """ + Check if the union tag is ``shared_content_change_link_password``. + + :rtype: bool + """ + return self._tag == 'shared_content_change_link_password' + + def is_shared_content_change_member_role(self): + """ + Check if the union tag is ``shared_content_change_member_role``. + + :rtype: bool + """ + return self._tag == 'shared_content_change_member_role' + + def is_shared_content_change_viewer_info_policy(self): + """ + Check if the union tag is ``shared_content_change_viewer_info_policy``. + + :rtype: bool + """ + return self._tag == 'shared_content_change_viewer_info_policy' + + def is_shared_content_claim_invitation(self): + """ + Check if the union tag is ``shared_content_claim_invitation``. + + :rtype: bool + """ + return self._tag == 'shared_content_claim_invitation' + + def is_shared_content_copy(self): + """ + Check if the union tag is ``shared_content_copy``. + + :rtype: bool + """ + return self._tag == 'shared_content_copy' + + def is_shared_content_download(self): + """ + Check if the union tag is ``shared_content_download``. + + :rtype: bool + """ + return self._tag == 'shared_content_download' + + def is_shared_content_relinquish_membership(self): + """ + Check if the union tag is ``shared_content_relinquish_membership``. + + :rtype: bool + """ + return self._tag == 'shared_content_relinquish_membership' + + def is_shared_content_remove_invitees(self): + """ + Check if the union tag is ``shared_content_remove_invitees``. + + :rtype: bool + """ + return self._tag == 'shared_content_remove_invitees' + + def is_shared_content_remove_link_expiry(self): + """ + Check if the union tag is ``shared_content_remove_link_expiry``. + + :rtype: bool + """ + return self._tag == 'shared_content_remove_link_expiry' + + def is_shared_content_remove_link_password(self): + """ + Check if the union tag is ``shared_content_remove_link_password``. + + :rtype: bool + """ + return self._tag == 'shared_content_remove_link_password' + + def is_shared_content_remove_member(self): + """ + Check if the union tag is ``shared_content_remove_member``. + + :rtype: bool + """ + return self._tag == 'shared_content_remove_member' + + def is_shared_content_request_access(self): + """ + Check if the union tag is ``shared_content_request_access``. + + :rtype: bool + """ + return self._tag == 'shared_content_request_access' + + def is_shared_content_restore_invitees(self): + """ + Check if the union tag is ``shared_content_restore_invitees``. + + :rtype: bool + """ + return self._tag == 'shared_content_restore_invitees' + + def is_shared_content_restore_member(self): + """ + Check if the union tag is ``shared_content_restore_member``. + + :rtype: bool + """ + return self._tag == 'shared_content_restore_member' + + def is_shared_content_unshare(self): + """ + Check if the union tag is ``shared_content_unshare``. + + :rtype: bool + """ + return self._tag == 'shared_content_unshare' + + def is_shared_content_view(self): + """ + Check if the union tag is ``shared_content_view``. + + :rtype: bool + """ + return self._tag == 'shared_content_view' + + def is_shared_folder_change_link_policy(self): + """ + Check if the union tag is ``shared_folder_change_link_policy``. + + :rtype: bool + """ + return self._tag == 'shared_folder_change_link_policy' + + def is_shared_folder_change_members_inheritance_policy(self): + """ + Check if the union tag is ``shared_folder_change_members_inheritance_policy``. + + :rtype: bool + """ + return self._tag == 'shared_folder_change_members_inheritance_policy' + + def is_shared_folder_change_members_management_policy(self): + """ + Check if the union tag is ``shared_folder_change_members_management_policy``. + + :rtype: bool + """ + return self._tag == 'shared_folder_change_members_management_policy' + + def is_shared_folder_change_members_policy(self): + """ + Check if the union tag is ``shared_folder_change_members_policy``. + + :rtype: bool + """ + return self._tag == 'shared_folder_change_members_policy' + + def is_shared_folder_create(self): + """ + Check if the union tag is ``shared_folder_create``. + + :rtype: bool + """ + return self._tag == 'shared_folder_create' + + def is_shared_folder_decline_invitation(self): + """ + Check if the union tag is ``shared_folder_decline_invitation``. + + :rtype: bool + """ + return self._tag == 'shared_folder_decline_invitation' + + def is_shared_folder_mount(self): + """ + Check if the union tag is ``shared_folder_mount``. + + :rtype: bool + """ + return self._tag == 'shared_folder_mount' + + def is_shared_folder_nest(self): + """ + Check if the union tag is ``shared_folder_nest``. + + :rtype: bool + """ + return self._tag == 'shared_folder_nest' + + def is_shared_folder_transfer_ownership(self): + """ + Check if the union tag is ``shared_folder_transfer_ownership``. + + :rtype: bool + """ + return self._tag == 'shared_folder_transfer_ownership' + + def is_shared_folder_unmount(self): + """ + Check if the union tag is ``shared_folder_unmount``. + + :rtype: bool + """ + return self._tag == 'shared_folder_unmount' + + def is_shared_link_add_expiry(self): + """ + Check if the union tag is ``shared_link_add_expiry``. + + :rtype: bool + """ + return self._tag == 'shared_link_add_expiry' + + def is_shared_link_change_expiry(self): + """ + Check if the union tag is ``shared_link_change_expiry``. + + :rtype: bool + """ + return self._tag == 'shared_link_change_expiry' + + def is_shared_link_change_visibility(self): + """ + Check if the union tag is ``shared_link_change_visibility``. + + :rtype: bool + """ + return self._tag == 'shared_link_change_visibility' + + def is_shared_link_copy(self): + """ + Check if the union tag is ``shared_link_copy``. + + :rtype: bool + """ + return self._tag == 'shared_link_copy' + + def is_shared_link_create(self): + """ + Check if the union tag is ``shared_link_create``. + + :rtype: bool + """ + return self._tag == 'shared_link_create' + + def is_shared_link_disable(self): + """ + Check if the union tag is ``shared_link_disable``. + + :rtype: bool + """ + return self._tag == 'shared_link_disable' + + def is_shared_link_download(self): + """ + Check if the union tag is ``shared_link_download``. + + :rtype: bool + """ + return self._tag == 'shared_link_download' + + def is_shared_link_remove_expiry(self): + """ + Check if the union tag is ``shared_link_remove_expiry``. + + :rtype: bool + """ + return self._tag == 'shared_link_remove_expiry' + + def is_shared_link_settings_add_expiration(self): + """ + Check if the union tag is ``shared_link_settings_add_expiration``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_add_expiration' + + def is_shared_link_settings_add_password(self): + """ + Check if the union tag is ``shared_link_settings_add_password``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_add_password' + + def is_shared_link_settings_allow_download_disabled(self): + """ + Check if the union tag is ``shared_link_settings_allow_download_disabled``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_allow_download_disabled' + + def is_shared_link_settings_allow_download_enabled(self): + """ + Check if the union tag is ``shared_link_settings_allow_download_enabled``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_allow_download_enabled' + + def is_shared_link_settings_change_audience(self): + """ + Check if the union tag is ``shared_link_settings_change_audience``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_change_audience' + + def is_shared_link_settings_change_expiration(self): + """ + Check if the union tag is ``shared_link_settings_change_expiration``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_change_expiration' + + def is_shared_link_settings_change_password(self): + """ + Check if the union tag is ``shared_link_settings_change_password``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_change_password' + + def is_shared_link_settings_remove_expiration(self): + """ + Check if the union tag is ``shared_link_settings_remove_expiration``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_remove_expiration' + + def is_shared_link_settings_remove_password(self): + """ + Check if the union tag is ``shared_link_settings_remove_password``. + + :rtype: bool + """ + return self._tag == 'shared_link_settings_remove_password' + + def is_shared_link_share(self): + """ + Check if the union tag is ``shared_link_share``. + + :rtype: bool + """ + return self._tag == 'shared_link_share' + + def is_shared_link_view(self): + """ + Check if the union tag is ``shared_link_view``. + + :rtype: bool + """ + return self._tag == 'shared_link_view' + + def is_shared_note_opened(self): + """ + Check if the union tag is ``shared_note_opened``. + + :rtype: bool + """ + return self._tag == 'shared_note_opened' + + def is_shmodel_group_share(self): + """ + Check if the union tag is ``shmodel_group_share``. + + :rtype: bool + """ + return self._tag == 'shmodel_group_share' + + def is_showcase_access_granted(self): + """ + Check if the union tag is ``showcase_access_granted``. + + :rtype: bool + """ + return self._tag == 'showcase_access_granted' + + def is_showcase_add_member(self): + """ + Check if the union tag is ``showcase_add_member``. + + :rtype: bool + """ + return self._tag == 'showcase_add_member' + + def is_showcase_archived(self): + """ + Check if the union tag is ``showcase_archived``. + + :rtype: bool + """ + return self._tag == 'showcase_archived' + + def is_showcase_created(self): + """ + Check if the union tag is ``showcase_created``. + + :rtype: bool + """ + return self._tag == 'showcase_created' + + def is_showcase_delete_comment(self): + """ + Check if the union tag is ``showcase_delete_comment``. + + :rtype: bool + """ + return self._tag == 'showcase_delete_comment' + + def is_showcase_edited(self): + """ + Check if the union tag is ``showcase_edited``. + + :rtype: bool + """ + return self._tag == 'showcase_edited' + + def is_showcase_edit_comment(self): + """ + Check if the union tag is ``showcase_edit_comment``. + + :rtype: bool + """ + return self._tag == 'showcase_edit_comment' + + def is_showcase_file_added(self): + """ + Check if the union tag is ``showcase_file_added``. + + :rtype: bool + """ + return self._tag == 'showcase_file_added' + + def is_showcase_file_download(self): + """ + Check if the union tag is ``showcase_file_download``. + + :rtype: bool + """ + return self._tag == 'showcase_file_download' + + def is_showcase_file_removed(self): + """ + Check if the union tag is ``showcase_file_removed``. + + :rtype: bool + """ + return self._tag == 'showcase_file_removed' + + def is_showcase_file_view(self): + """ + Check if the union tag is ``showcase_file_view``. + + :rtype: bool + """ + return self._tag == 'showcase_file_view' + + def is_showcase_permanently_deleted(self): + """ + Check if the union tag is ``showcase_permanently_deleted``. + + :rtype: bool + """ + return self._tag == 'showcase_permanently_deleted' + + def is_showcase_post_comment(self): + """ + Check if the union tag is ``showcase_post_comment``. + + :rtype: bool + """ + return self._tag == 'showcase_post_comment' + + def is_showcase_remove_member(self): + """ + Check if the union tag is ``showcase_remove_member``. + + :rtype: bool + """ + return self._tag == 'showcase_remove_member' + + def is_showcase_renamed(self): + """ + Check if the union tag is ``showcase_renamed``. + + :rtype: bool + """ + return self._tag == 'showcase_renamed' + + def is_showcase_request_access(self): + """ + Check if the union tag is ``showcase_request_access``. + + :rtype: bool + """ + return self._tag == 'showcase_request_access' + + def is_showcase_resolve_comment(self): + """ + Check if the union tag is ``showcase_resolve_comment``. + + :rtype: bool + """ + return self._tag == 'showcase_resolve_comment' + + def is_showcase_restored(self): + """ + Check if the union tag is ``showcase_restored``. + + :rtype: bool + """ + return self._tag == 'showcase_restored' + + def is_showcase_trashed(self): + """ + Check if the union tag is ``showcase_trashed``. + + :rtype: bool + """ + return self._tag == 'showcase_trashed' + + def is_showcase_trashed_deprecated(self): + """ + Check if the union tag is ``showcase_trashed_deprecated``. + + :rtype: bool + """ + return self._tag == 'showcase_trashed_deprecated' + + def is_showcase_unresolve_comment(self): + """ + Check if the union tag is ``showcase_unresolve_comment``. + + :rtype: bool + """ + return self._tag == 'showcase_unresolve_comment' + + def is_showcase_untrashed(self): + """ + Check if the union tag is ``showcase_untrashed``. + + :rtype: bool + """ + return self._tag == 'showcase_untrashed' + + def is_showcase_untrashed_deprecated(self): + """ + Check if the union tag is ``showcase_untrashed_deprecated``. + + :rtype: bool + """ + return self._tag == 'showcase_untrashed_deprecated' + + def is_showcase_view(self): + """ + Check if the union tag is ``showcase_view``. + + :rtype: bool + """ + return self._tag == 'showcase_view' + + def is_sso_add_cert(self): + """ + Check if the union tag is ``sso_add_cert``. + + :rtype: bool + """ + return self._tag == 'sso_add_cert' + + def is_sso_add_login_url(self): + """ + Check if the union tag is ``sso_add_login_url``. + + :rtype: bool + """ + return self._tag == 'sso_add_login_url' + + def is_sso_add_logout_url(self): + """ + Check if the union tag is ``sso_add_logout_url``. + + :rtype: bool + """ + return self._tag == 'sso_add_logout_url' + + def is_sso_change_cert(self): + """ + Check if the union tag is ``sso_change_cert``. + + :rtype: bool + """ + return self._tag == 'sso_change_cert' + + def is_sso_change_login_url(self): + """ + Check if the union tag is ``sso_change_login_url``. + + :rtype: bool + """ + return self._tag == 'sso_change_login_url' + + def is_sso_change_logout_url(self): + """ + Check if the union tag is ``sso_change_logout_url``. + + :rtype: bool + """ + return self._tag == 'sso_change_logout_url' + + def is_sso_change_saml_identity_mode(self): + """ + Check if the union tag is ``sso_change_saml_identity_mode``. + + :rtype: bool + """ + return self._tag == 'sso_change_saml_identity_mode' + + def is_sso_remove_cert(self): + """ + Check if the union tag is ``sso_remove_cert``. + + :rtype: bool + """ + return self._tag == 'sso_remove_cert' + + def is_sso_remove_login_url(self): + """ + Check if the union tag is ``sso_remove_login_url``. + + :rtype: bool + """ + return self._tag == 'sso_remove_login_url' + + def is_sso_remove_logout_url(self): + """ + Check if the union tag is ``sso_remove_logout_url``. + + :rtype: bool + """ + return self._tag == 'sso_remove_logout_url' + + def is_team_folder_change_status(self): + """ + Check if the union tag is ``team_folder_change_status``. + + :rtype: bool + """ + return self._tag == 'team_folder_change_status' + + def is_team_folder_create(self): + """ + Check if the union tag is ``team_folder_create``. + + :rtype: bool + """ + return self._tag == 'team_folder_create' + + def is_team_folder_downgrade(self): + """ + Check if the union tag is ``team_folder_downgrade``. + + :rtype: bool + """ + return self._tag == 'team_folder_downgrade' + + def is_team_folder_permanently_delete(self): + """ + Check if the union tag is ``team_folder_permanently_delete``. + + :rtype: bool + """ + return self._tag == 'team_folder_permanently_delete' + + def is_team_folder_rename(self): + """ + Check if the union tag is ``team_folder_rename``. + + :rtype: bool + """ + return self._tag == 'team_folder_rename' + + def is_team_selective_sync_settings_changed(self): + """ + Check if the union tag is ``team_selective_sync_settings_changed``. + + :rtype: bool + """ + return self._tag == 'team_selective_sync_settings_changed' + + def is_account_capture_change_policy(self): + """ + Check if the union tag is ``account_capture_change_policy``. + + :rtype: bool + """ + return self._tag == 'account_capture_change_policy' + + def is_allow_download_disabled(self): + """ + Check if the union tag is ``allow_download_disabled``. + + :rtype: bool + """ + return self._tag == 'allow_download_disabled' + + def is_allow_download_enabled(self): + """ + Check if the union tag is ``allow_download_enabled``. + + :rtype: bool + """ + return self._tag == 'allow_download_enabled' + + def is_camera_uploads_policy_changed(self): + """ + Check if the union tag is ``camera_uploads_policy_changed``. + + :rtype: bool + """ + return self._tag == 'camera_uploads_policy_changed' + + def is_data_placement_restriction_change_policy(self): + """ + Check if the union tag is ``data_placement_restriction_change_policy``. + + :rtype: bool + """ + return self._tag == 'data_placement_restriction_change_policy' + + def is_data_placement_restriction_satisfy_policy(self): + """ + Check if the union tag is ``data_placement_restriction_satisfy_policy``. + + :rtype: bool + """ + return self._tag == 'data_placement_restriction_satisfy_policy' + + def is_device_approvals_add_exception(self): + """ + Check if the union tag is ``device_approvals_add_exception``. + + :rtype: bool + """ + return self._tag == 'device_approvals_add_exception' + + def is_device_approvals_change_desktop_policy(self): + """ + Check if the union tag is ``device_approvals_change_desktop_policy``. + + :rtype: bool + """ + return self._tag == 'device_approvals_change_desktop_policy' + + def is_device_approvals_change_mobile_policy(self): + """ + Check if the union tag is ``device_approvals_change_mobile_policy``. + + :rtype: bool + """ + return self._tag == 'device_approvals_change_mobile_policy' + + def is_device_approvals_change_overage_action(self): + """ + Check if the union tag is ``device_approvals_change_overage_action``. + + :rtype: bool + """ + return self._tag == 'device_approvals_change_overage_action' + + def is_device_approvals_change_unlink_action(self): + """ + Check if the union tag is ``device_approvals_change_unlink_action``. + + :rtype: bool + """ + return self._tag == 'device_approvals_change_unlink_action' + + def is_device_approvals_remove_exception(self): + """ + Check if the union tag is ``device_approvals_remove_exception``. + + :rtype: bool + """ + return self._tag == 'device_approvals_remove_exception' + + def is_directory_restrictions_add_members(self): + """ + Check if the union tag is ``directory_restrictions_add_members``. + + :rtype: bool + """ + return self._tag == 'directory_restrictions_add_members' + + def is_directory_restrictions_remove_members(self): + """ + Check if the union tag is ``directory_restrictions_remove_members``. + + :rtype: bool + """ + return self._tag == 'directory_restrictions_remove_members' + + def is_emm_add_exception(self): + """ + Check if the union tag is ``emm_add_exception``. + + :rtype: bool + """ + return self._tag == 'emm_add_exception' + + def is_emm_change_policy(self): + """ + Check if the union tag is ``emm_change_policy``. + + :rtype: bool + """ + return self._tag == 'emm_change_policy' + + def is_emm_remove_exception(self): + """ + Check if the union tag is ``emm_remove_exception``. + + :rtype: bool + """ + return self._tag == 'emm_remove_exception' + + def is_extended_version_history_change_policy(self): + """ + Check if the union tag is ``extended_version_history_change_policy``. + + :rtype: bool + """ + return self._tag == 'extended_version_history_change_policy' + + def is_file_comments_change_policy(self): + """ + Check if the union tag is ``file_comments_change_policy``. + + :rtype: bool + """ + return self._tag == 'file_comments_change_policy' + + def is_file_locking_policy_changed(self): + """ + Check if the union tag is ``file_locking_policy_changed``. + + :rtype: bool + """ + return self._tag == 'file_locking_policy_changed' + + def is_file_requests_change_policy(self): + """ + Check if the union tag is ``file_requests_change_policy``. + + :rtype: bool + """ + return self._tag == 'file_requests_change_policy' + + def is_file_requests_emails_enabled(self): + """ + Check if the union tag is ``file_requests_emails_enabled``. + + :rtype: bool + """ + return self._tag == 'file_requests_emails_enabled' + + def is_file_requests_emails_restricted_to_team_only(self): + """ + Check if the union tag is ``file_requests_emails_restricted_to_team_only``. + + :rtype: bool + """ + return self._tag == 'file_requests_emails_restricted_to_team_only' + + def is_file_transfers_policy_changed(self): + """ + Check if the union tag is ``file_transfers_policy_changed``. + + :rtype: bool + """ + return self._tag == 'file_transfers_policy_changed' + + def is_google_sso_change_policy(self): + """ + Check if the union tag is ``google_sso_change_policy``. + + :rtype: bool + """ + return self._tag == 'google_sso_change_policy' + + def is_group_user_management_change_policy(self): + """ + Check if the union tag is ``group_user_management_change_policy``. + + :rtype: bool + """ + return self._tag == 'group_user_management_change_policy' + + def is_integration_policy_changed(self): + """ + Check if the union tag is ``integration_policy_changed``. + + :rtype: bool + """ + return self._tag == 'integration_policy_changed' + + def is_member_requests_change_policy(self): + """ + Check if the union tag is ``member_requests_change_policy``. + + :rtype: bool + """ + return self._tag == 'member_requests_change_policy' + + def is_member_send_invite_policy_changed(self): + """ + Check if the union tag is ``member_send_invite_policy_changed``. + + :rtype: bool + """ + return self._tag == 'member_send_invite_policy_changed' + + def is_member_space_limits_add_exception(self): + """ + Check if the union tag is ``member_space_limits_add_exception``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_add_exception' + + def is_member_space_limits_change_caps_type_policy(self): + """ + Check if the union tag is ``member_space_limits_change_caps_type_policy``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_change_caps_type_policy' + + def is_member_space_limits_change_policy(self): + """ + Check if the union tag is ``member_space_limits_change_policy``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_change_policy' + + def is_member_space_limits_remove_exception(self): + """ + Check if the union tag is ``member_space_limits_remove_exception``. + + :rtype: bool + """ + return self._tag == 'member_space_limits_remove_exception' + + def is_member_suggestions_change_policy(self): + """ + Check if the union tag is ``member_suggestions_change_policy``. + + :rtype: bool + """ + return self._tag == 'member_suggestions_change_policy' + + def is_microsoft_office_addin_change_policy(self): + """ + Check if the union tag is ``microsoft_office_addin_change_policy``. + + :rtype: bool + """ + return self._tag == 'microsoft_office_addin_change_policy' + + def is_network_control_change_policy(self): + """ + Check if the union tag is ``network_control_change_policy``. + + :rtype: bool + """ + return self._tag == 'network_control_change_policy' + + def is_paper_change_deployment_policy(self): + """ + Check if the union tag is ``paper_change_deployment_policy``. + + :rtype: bool + """ + return self._tag == 'paper_change_deployment_policy' + + def is_paper_change_member_link_policy(self): + """ + Check if the union tag is ``paper_change_member_link_policy``. + + :rtype: bool + """ + return self._tag == 'paper_change_member_link_policy' + + def is_paper_change_member_policy(self): + """ + Check if the union tag is ``paper_change_member_policy``. + + :rtype: bool + """ + return self._tag == 'paper_change_member_policy' + + def is_paper_change_policy(self): + """ + Check if the union tag is ``paper_change_policy``. + + :rtype: bool + """ + return self._tag == 'paper_change_policy' + + def is_paper_default_folder_policy_changed(self): + """ + Check if the union tag is ``paper_default_folder_policy_changed``. + + :rtype: bool + """ + return self._tag == 'paper_default_folder_policy_changed' + + def is_paper_desktop_policy_changed(self): + """ + Check if the union tag is ``paper_desktop_policy_changed``. + + :rtype: bool + """ + return self._tag == 'paper_desktop_policy_changed' + + def is_paper_enabled_users_group_addition(self): + """ + Check if the union tag is ``paper_enabled_users_group_addition``. + + :rtype: bool + """ + return self._tag == 'paper_enabled_users_group_addition' + + def is_paper_enabled_users_group_removal(self): + """ + Check if the union tag is ``paper_enabled_users_group_removal``. + + :rtype: bool + """ + return self._tag == 'paper_enabled_users_group_removal' + + def is_password_strength_requirements_change_policy(self): + """ + Check if the union tag is ``password_strength_requirements_change_policy``. + + :rtype: bool + """ + return self._tag == 'password_strength_requirements_change_policy' + + def is_permanent_delete_change_policy(self): + """ + Check if the union tag is ``permanent_delete_change_policy``. + + :rtype: bool + """ + return self._tag == 'permanent_delete_change_policy' + + def is_reseller_support_change_policy(self): + """ + Check if the union tag is ``reseller_support_change_policy``. + + :rtype: bool + """ + return self._tag == 'reseller_support_change_policy' + + def is_rewind_policy_changed(self): + """ + Check if the union tag is ``rewind_policy_changed``. + + :rtype: bool + """ + return self._tag == 'rewind_policy_changed' + + def is_sharing_change_folder_join_policy(self): + """ + Check if the union tag is ``sharing_change_folder_join_policy``. + + :rtype: bool + """ + return self._tag == 'sharing_change_folder_join_policy' + + def is_sharing_change_link_policy(self): + """ + Check if the union tag is ``sharing_change_link_policy``. + + :rtype: bool + """ + return self._tag == 'sharing_change_link_policy' + + def is_sharing_change_member_policy(self): + """ + Check if the union tag is ``sharing_change_member_policy``. + + :rtype: bool + """ + return self._tag == 'sharing_change_member_policy' + + def is_showcase_change_download_policy(self): + """ + Check if the union tag is ``showcase_change_download_policy``. + + :rtype: bool + """ + return self._tag == 'showcase_change_download_policy' + + def is_showcase_change_enabled_policy(self): + """ + Check if the union tag is ``showcase_change_enabled_policy``. + + :rtype: bool + """ + return self._tag == 'showcase_change_enabled_policy' + + def is_showcase_change_external_sharing_policy(self): + """ + Check if the union tag is ``showcase_change_external_sharing_policy``. + + :rtype: bool + """ + return self._tag == 'showcase_change_external_sharing_policy' + + def is_smarter_smart_sync_policy_changed(self): + """ + Check if the union tag is ``smarter_smart_sync_policy_changed``. + + :rtype: bool + """ + return self._tag == 'smarter_smart_sync_policy_changed' + + def is_smart_sync_change_policy(self): + """ + Check if the union tag is ``smart_sync_change_policy``. + + :rtype: bool + """ + return self._tag == 'smart_sync_change_policy' + + def is_smart_sync_not_opt_out(self): + """ + Check if the union tag is ``smart_sync_not_opt_out``. + + :rtype: bool + """ + return self._tag == 'smart_sync_not_opt_out' + + def is_smart_sync_opt_out(self): + """ + Check if the union tag is ``smart_sync_opt_out``. + + :rtype: bool + """ + return self._tag == 'smart_sync_opt_out' + + def is_sso_change_policy(self): + """ + Check if the union tag is ``sso_change_policy``. + + :rtype: bool + """ + return self._tag == 'sso_change_policy' + + def is_team_extensions_policy_changed(self): + """ + Check if the union tag is ``team_extensions_policy_changed``. + + :rtype: bool + """ + return self._tag == 'team_extensions_policy_changed' + + def is_team_selective_sync_policy_changed(self): + """ + Check if the union tag is ``team_selective_sync_policy_changed``. + + :rtype: bool + """ + return self._tag == 'team_selective_sync_policy_changed' + + def is_team_sharing_whitelist_subjects_changed(self): + """ + Check if the union tag is ``team_sharing_whitelist_subjects_changed``. + + :rtype: bool + """ + return self._tag == 'team_sharing_whitelist_subjects_changed' + + def is_tfa_add_exception(self): + """ + Check if the union tag is ``tfa_add_exception``. + + :rtype: bool + """ + return self._tag == 'tfa_add_exception' + + def is_tfa_change_policy(self): + """ + Check if the union tag is ``tfa_change_policy``. + + :rtype: bool + """ + return self._tag == 'tfa_change_policy' + + def is_tfa_remove_exception(self): + """ + Check if the union tag is ``tfa_remove_exception``. + + :rtype: bool + """ + return self._tag == 'tfa_remove_exception' + + def is_two_account_change_policy(self): + """ + Check if the union tag is ``two_account_change_policy``. + + :rtype: bool + """ + return self._tag == 'two_account_change_policy' + + def is_viewer_info_policy_changed(self): + """ + Check if the union tag is ``viewer_info_policy_changed``. + + :rtype: bool + """ + return self._tag == 'viewer_info_policy_changed' + + def is_watermarking_policy_changed(self): + """ + Check if the union tag is ``watermarking_policy_changed``. + + :rtype: bool + """ + return self._tag == 'watermarking_policy_changed' + + def is_web_sessions_change_active_session_limit(self): + """ + Check if the union tag is ``web_sessions_change_active_session_limit``. + + :rtype: bool + """ + return self._tag == 'web_sessions_change_active_session_limit' + + def is_web_sessions_change_fixed_length_policy(self): + """ + Check if the union tag is ``web_sessions_change_fixed_length_policy``. + + :rtype: bool + """ + return self._tag == 'web_sessions_change_fixed_length_policy' + + def is_web_sessions_change_idle_length_policy(self): + """ + Check if the union tag is ``web_sessions_change_idle_length_policy``. + + :rtype: bool + """ + return self._tag == 'web_sessions_change_idle_length_policy' + + def is_team_merge_from(self): + """ + Check if the union tag is ``team_merge_from``. + + :rtype: bool + """ + return self._tag == 'team_merge_from' + + def is_team_merge_to(self): + """ + Check if the union tag is ``team_merge_to``. + + :rtype: bool + """ + return self._tag == 'team_merge_to' + + def is_team_profile_add_logo(self): + """ + Check if the union tag is ``team_profile_add_logo``. + + :rtype: bool + """ + return self._tag == 'team_profile_add_logo' + + def is_team_profile_change_default_language(self): + """ + Check if the union tag is ``team_profile_change_default_language``. + + :rtype: bool + """ + return self._tag == 'team_profile_change_default_language' + + def is_team_profile_change_logo(self): + """ + Check if the union tag is ``team_profile_change_logo``. + + :rtype: bool + """ + return self._tag == 'team_profile_change_logo' + + def is_team_profile_change_name(self): + """ + Check if the union tag is ``team_profile_change_name``. + + :rtype: bool + """ + return self._tag == 'team_profile_change_name' + + def is_team_profile_remove_logo(self): + """ + Check if the union tag is ``team_profile_remove_logo``. + + :rtype: bool + """ + return self._tag == 'team_profile_remove_logo' + + def is_tfa_add_backup_phone(self): + """ + Check if the union tag is ``tfa_add_backup_phone``. + + :rtype: bool + """ + return self._tag == 'tfa_add_backup_phone' + + def is_tfa_add_security_key(self): + """ + Check if the union tag is ``tfa_add_security_key``. + + :rtype: bool + """ + return self._tag == 'tfa_add_security_key' + + def is_tfa_change_backup_phone(self): + """ + Check if the union tag is ``tfa_change_backup_phone``. + + :rtype: bool + """ + return self._tag == 'tfa_change_backup_phone' + + def is_tfa_change_status(self): + """ + Check if the union tag is ``tfa_change_status``. + + :rtype: bool + """ + return self._tag == 'tfa_change_status' + + def is_tfa_remove_backup_phone(self): + """ + Check if the union tag is ``tfa_remove_backup_phone``. + + :rtype: bool + """ + return self._tag == 'tfa_remove_backup_phone' + + def is_tfa_remove_security_key(self): + """ + Check if the union tag is ``tfa_remove_security_key``. + + :rtype: bool + """ + return self._tag == 'tfa_remove_security_key' + + def is_tfa_reset(self): + """ + Check if the union tag is ``tfa_reset``. + + :rtype: bool + """ + return self._tag == 'tfa_reset' + + def is_changed_enterprise_admin_role(self): + """ + Check if the union tag is ``changed_enterprise_admin_role``. + + :rtype: bool + """ + return self._tag == 'changed_enterprise_admin_role' + + def is_changed_enterprise_connected_team_status(self): + """ + Check if the union tag is ``changed_enterprise_connected_team_status``. + + :rtype: bool + """ + return self._tag == 'changed_enterprise_connected_team_status' + + def is_ended_enterprise_admin_session(self): + """ + Check if the union tag is ``ended_enterprise_admin_session``. + + :rtype: bool + """ + return self._tag == 'ended_enterprise_admin_session' + + def is_ended_enterprise_admin_session_deprecated(self): + """ + Check if the union tag is ``ended_enterprise_admin_session_deprecated``. + + :rtype: bool + """ + return self._tag == 'ended_enterprise_admin_session_deprecated' + + def is_enterprise_settings_locking(self): + """ + Check if the union tag is ``enterprise_settings_locking``. + + :rtype: bool + """ + return self._tag == 'enterprise_settings_locking' + + def is_guest_admin_change_status(self): + """ + Check if the union tag is ``guest_admin_change_status``. + + :rtype: bool + """ + return self._tag == 'guest_admin_change_status' + + def is_started_enterprise_admin_session(self): + """ + Check if the union tag is ``started_enterprise_admin_session``. + + :rtype: bool + """ + return self._tag == 'started_enterprise_admin_session' + + def is_team_merge_request_accepted(self): + """ + Check if the union tag is ``team_merge_request_accepted``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_accepted' + + def is_team_merge_request_accepted_shown_to_primary_team(self): + """ + Check if the union tag is ``team_merge_request_accepted_shown_to_primary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_accepted_shown_to_primary_team' + + def is_team_merge_request_accepted_shown_to_secondary_team(self): + """ + Check if the union tag is ``team_merge_request_accepted_shown_to_secondary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_accepted_shown_to_secondary_team' + + def is_team_merge_request_auto_canceled(self): + """ + Check if the union tag is ``team_merge_request_auto_canceled``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_auto_canceled' + + def is_team_merge_request_canceled(self): + """ + Check if the union tag is ``team_merge_request_canceled``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_canceled' + + def is_team_merge_request_canceled_shown_to_primary_team(self): + """ + Check if the union tag is ``team_merge_request_canceled_shown_to_primary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_canceled_shown_to_primary_team' + + def is_team_merge_request_canceled_shown_to_secondary_team(self): + """ + Check if the union tag is ``team_merge_request_canceled_shown_to_secondary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_canceled_shown_to_secondary_team' + + def is_team_merge_request_expired(self): + """ + Check if the union tag is ``team_merge_request_expired``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_expired' + + def is_team_merge_request_expired_shown_to_primary_team(self): + """ + Check if the union tag is ``team_merge_request_expired_shown_to_primary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_expired_shown_to_primary_team' + + def is_team_merge_request_expired_shown_to_secondary_team(self): + """ + Check if the union tag is ``team_merge_request_expired_shown_to_secondary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_expired_shown_to_secondary_team' + + def is_team_merge_request_rejected_shown_to_primary_team(self): + """ + Check if the union tag is ``team_merge_request_rejected_shown_to_primary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_rejected_shown_to_primary_team' + + def is_team_merge_request_rejected_shown_to_secondary_team(self): + """ + Check if the union tag is ``team_merge_request_rejected_shown_to_secondary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_rejected_shown_to_secondary_team' + + def is_team_merge_request_reminder(self): + """ + Check if the union tag is ``team_merge_request_reminder``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_reminder' + + def is_team_merge_request_reminder_shown_to_primary_team(self): + """ + Check if the union tag is ``team_merge_request_reminder_shown_to_primary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_reminder_shown_to_primary_team' + + def is_team_merge_request_reminder_shown_to_secondary_team(self): + """ + Check if the union tag is ``team_merge_request_reminder_shown_to_secondary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_reminder_shown_to_secondary_team' + + def is_team_merge_request_revoked(self): + """ + Check if the union tag is ``team_merge_request_revoked``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_revoked' + + def is_team_merge_request_sent_shown_to_primary_team(self): + """ + Check if the union tag is ``team_merge_request_sent_shown_to_primary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_sent_shown_to_primary_team' + + def is_team_merge_request_sent_shown_to_secondary_team(self): + """ + Check if the union tag is ``team_merge_request_sent_shown_to_secondary_team``. + + :rtype: bool + """ + return self._tag == 'team_merge_request_sent_shown_to_secondary_team' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_app_link_team(self): + """ + (apps) Linked app for team + + Only call this if :meth:`is_app_link_team` is true. + + :rtype: AppLinkTeamType + """ + if not self.is_app_link_team(): + raise AttributeError("tag 'app_link_team' not set") + return self._value + + def get_app_link_user(self): + """ + (apps) Linked app for member + + Only call this if :meth:`is_app_link_user` is true. + + :rtype: AppLinkUserType + """ + if not self.is_app_link_user(): + raise AttributeError("tag 'app_link_user' not set") + return self._value + + def get_app_unlink_team(self): + """ + (apps) Unlinked app for team + + Only call this if :meth:`is_app_unlink_team` is true. + + :rtype: AppUnlinkTeamType + """ + if not self.is_app_unlink_team(): + raise AttributeError("tag 'app_unlink_team' not set") + return self._value + + def get_app_unlink_user(self): + """ + (apps) Unlinked app for member + + Only call this if :meth:`is_app_unlink_user` is true. + + :rtype: AppUnlinkUserType + """ + if not self.is_app_unlink_user(): + raise AttributeError("tag 'app_unlink_user' not set") + return self._value + + def get_integration_connected(self): + """ + (apps) Connected integration for member + + Only call this if :meth:`is_integration_connected` is true. + + :rtype: IntegrationConnectedType + """ + if not self.is_integration_connected(): + raise AttributeError("tag 'integration_connected' not set") + return self._value + + def get_integration_disconnected(self): + """ + (apps) Disconnected integration for member + + Only call this if :meth:`is_integration_disconnected` is true. + + :rtype: IntegrationDisconnectedType + """ + if not self.is_integration_disconnected(): + raise AttributeError("tag 'integration_disconnected' not set") + return self._value + + def get_file_add_comment(self): + """ + (comments) Added file comment + + Only call this if :meth:`is_file_add_comment` is true. + + :rtype: FileAddCommentType + """ + if not self.is_file_add_comment(): + raise AttributeError("tag 'file_add_comment' not set") + return self._value + + def get_file_change_comment_subscription(self): + """ + (comments) Subscribed to or unsubscribed from comment notifications for + file + + Only call this if :meth:`is_file_change_comment_subscription` is true. + + :rtype: FileChangeCommentSubscriptionType + """ + if not self.is_file_change_comment_subscription(): + raise AttributeError("tag 'file_change_comment_subscription' not set") + return self._value + + def get_file_delete_comment(self): + """ + (comments) Deleted file comment + + Only call this if :meth:`is_file_delete_comment` is true. + + :rtype: FileDeleteCommentType + """ + if not self.is_file_delete_comment(): + raise AttributeError("tag 'file_delete_comment' not set") + return self._value + + def get_file_edit_comment(self): + """ + (comments) Edited file comment + + Only call this if :meth:`is_file_edit_comment` is true. + + :rtype: FileEditCommentType + """ + if not self.is_file_edit_comment(): + raise AttributeError("tag 'file_edit_comment' not set") + return self._value + + def get_file_like_comment(self): + """ + (comments) Liked file comment (deprecated, no longer logged) + + Only call this if :meth:`is_file_like_comment` is true. + + :rtype: FileLikeCommentType + """ + if not self.is_file_like_comment(): + raise AttributeError("tag 'file_like_comment' not set") + return self._value + + def get_file_resolve_comment(self): + """ + (comments) Resolved file comment + + Only call this if :meth:`is_file_resolve_comment` is true. + + :rtype: FileResolveCommentType + """ + if not self.is_file_resolve_comment(): + raise AttributeError("tag 'file_resolve_comment' not set") + return self._value + + def get_file_unlike_comment(self): + """ + (comments) Unliked file comment (deprecated, no longer logged) + + Only call this if :meth:`is_file_unlike_comment` is true. + + :rtype: FileUnlikeCommentType + """ + if not self.is_file_unlike_comment(): + raise AttributeError("tag 'file_unlike_comment' not set") + return self._value + + def get_file_unresolve_comment(self): + """ + (comments) Unresolved file comment + + Only call this if :meth:`is_file_unresolve_comment` is true. + + :rtype: FileUnresolveCommentType + """ + if not self.is_file_unresolve_comment(): + raise AttributeError("tag 'file_unresolve_comment' not set") + return self._value + + def get_device_change_ip_desktop(self): + """ + (devices) Changed IP address associated with active desktop session + + Only call this if :meth:`is_device_change_ip_desktop` is true. + + :rtype: DeviceChangeIpDesktopType + """ + if not self.is_device_change_ip_desktop(): + raise AttributeError("tag 'device_change_ip_desktop' not set") + return self._value + + def get_device_change_ip_mobile(self): + """ + (devices) Changed IP address associated with active mobile session + + Only call this if :meth:`is_device_change_ip_mobile` is true. + + :rtype: DeviceChangeIpMobileType + """ + if not self.is_device_change_ip_mobile(): + raise AttributeError("tag 'device_change_ip_mobile' not set") + return self._value + + def get_device_change_ip_web(self): + """ + (devices) Changed IP address associated with active web session + + Only call this if :meth:`is_device_change_ip_web` is true. + + :rtype: DeviceChangeIpWebType + """ + if not self.is_device_change_ip_web(): + raise AttributeError("tag 'device_change_ip_web' not set") + return self._value + + def get_device_delete_on_unlink_fail(self): + """ + (devices) Failed to delete all files from unlinked device + + Only call this if :meth:`is_device_delete_on_unlink_fail` is true. + + :rtype: DeviceDeleteOnUnlinkFailType + """ + if not self.is_device_delete_on_unlink_fail(): + raise AttributeError("tag 'device_delete_on_unlink_fail' not set") + return self._value + + def get_device_delete_on_unlink_success(self): + """ + (devices) Deleted all files from unlinked device + + Only call this if :meth:`is_device_delete_on_unlink_success` is true. + + :rtype: DeviceDeleteOnUnlinkSuccessType + """ + if not self.is_device_delete_on_unlink_success(): + raise AttributeError("tag 'device_delete_on_unlink_success' not set") + return self._value + + def get_device_link_fail(self): + """ + (devices) Failed to link device + + Only call this if :meth:`is_device_link_fail` is true. + + :rtype: DeviceLinkFailType + """ + if not self.is_device_link_fail(): + raise AttributeError("tag 'device_link_fail' not set") + return self._value + + def get_device_link_success(self): + """ + (devices) Linked device + + Only call this if :meth:`is_device_link_success` is true. + + :rtype: DeviceLinkSuccessType + """ + if not self.is_device_link_success(): + raise AttributeError("tag 'device_link_success' not set") + return self._value + + def get_device_management_disabled(self): + """ + (devices) Disabled device management (deprecated, no longer logged) + + Only call this if :meth:`is_device_management_disabled` is true. + + :rtype: DeviceManagementDisabledType + """ + if not self.is_device_management_disabled(): + raise AttributeError("tag 'device_management_disabled' not set") + return self._value + + def get_device_management_enabled(self): + """ + (devices) Enabled device management (deprecated, no longer logged) + + Only call this if :meth:`is_device_management_enabled` is true. + + :rtype: DeviceManagementEnabledType + """ + if not self.is_device_management_enabled(): + raise AttributeError("tag 'device_management_enabled' not set") + return self._value + + def get_device_unlink(self): + """ + (devices) Disconnected device + + Only call this if :meth:`is_device_unlink` is true. + + :rtype: DeviceUnlinkType + """ + if not self.is_device_unlink(): + raise AttributeError("tag 'device_unlink' not set") + return self._value + + def get_emm_refresh_auth_token(self): + """ + (devices) Refreshed auth token used for setting up EMM + + Only call this if :meth:`is_emm_refresh_auth_token` is true. + + :rtype: EmmRefreshAuthTokenType + """ + if not self.is_emm_refresh_auth_token(): + raise AttributeError("tag 'emm_refresh_auth_token' not set") + return self._value + + def get_account_capture_change_availability(self): + """ + (domains) Granted/revoked option to enable account capture on team + domains + + Only call this if :meth:`is_account_capture_change_availability` is true. + + :rtype: AccountCaptureChangeAvailabilityType + """ + if not self.is_account_capture_change_availability(): + raise AttributeError("tag 'account_capture_change_availability' not set") + return self._value + + def get_account_capture_migrate_account(self): + """ + (domains) Account-captured user migrated account to team + + Only call this if :meth:`is_account_capture_migrate_account` is true. + + :rtype: AccountCaptureMigrateAccountType + """ + if not self.is_account_capture_migrate_account(): + raise AttributeError("tag 'account_capture_migrate_account' not set") + return self._value + + def get_account_capture_notification_emails_sent(self): + """ + (domains) Sent account capture email to all unmanaged members + + Only call this if :meth:`is_account_capture_notification_emails_sent` is true. + + :rtype: AccountCaptureNotificationEmailsSentType + """ + if not self.is_account_capture_notification_emails_sent(): + raise AttributeError("tag 'account_capture_notification_emails_sent' not set") + return self._value + + def get_account_capture_relinquish_account(self): + """ + (domains) Account-captured user changed account email to personal email + + Only call this if :meth:`is_account_capture_relinquish_account` is true. + + :rtype: AccountCaptureRelinquishAccountType + """ + if not self.is_account_capture_relinquish_account(): + raise AttributeError("tag 'account_capture_relinquish_account' not set") + return self._value + + def get_disabled_domain_invites(self): + """ + (domains) Disabled domain invites (deprecated, no longer logged) + + Only call this if :meth:`is_disabled_domain_invites` is true. + + :rtype: DisabledDomainInvitesType + """ + if not self.is_disabled_domain_invites(): + raise AttributeError("tag 'disabled_domain_invites' not set") + return self._value + + def get_domain_invites_approve_request_to_join_team(self): + """ + (domains) Approved user's request to join team + + Only call this if :meth:`is_domain_invites_approve_request_to_join_team` is true. + + :rtype: DomainInvitesApproveRequestToJoinTeamType + """ + if not self.is_domain_invites_approve_request_to_join_team(): + raise AttributeError("tag 'domain_invites_approve_request_to_join_team' not set") + return self._value + + def get_domain_invites_decline_request_to_join_team(self): + """ + (domains) Declined user's request to join team + + Only call this if :meth:`is_domain_invites_decline_request_to_join_team` is true. + + :rtype: DomainInvitesDeclineRequestToJoinTeamType + """ + if not self.is_domain_invites_decline_request_to_join_team(): + raise AttributeError("tag 'domain_invites_decline_request_to_join_team' not set") + return self._value + + def get_domain_invites_email_existing_users(self): + """ + (domains) Sent domain invites to existing domain accounts (deprecated, + no longer logged) + + Only call this if :meth:`is_domain_invites_email_existing_users` is true. + + :rtype: DomainInvitesEmailExistingUsersType + """ + if not self.is_domain_invites_email_existing_users(): + raise AttributeError("tag 'domain_invites_email_existing_users' not set") + return self._value + + def get_domain_invites_request_to_join_team(self): + """ + (domains) Requested to join team + + Only call this if :meth:`is_domain_invites_request_to_join_team` is true. + + :rtype: DomainInvitesRequestToJoinTeamType + """ + if not self.is_domain_invites_request_to_join_team(): + raise AttributeError("tag 'domain_invites_request_to_join_team' not set") + return self._value + + def get_domain_invites_set_invite_new_user_pref_to_no(self): + """ + (domains) Disabled "Automatically invite new users" (deprecated, no + longer logged) + + Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_no` is true. + + :rtype: DomainInvitesSetInviteNewUserPrefToNoType + """ + if not self.is_domain_invites_set_invite_new_user_pref_to_no(): + raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_no' not set") + return self._value + + def get_domain_invites_set_invite_new_user_pref_to_yes(self): + """ + (domains) Enabled "Automatically invite new users" (deprecated, no + longer logged) + + Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_yes` is true. + + :rtype: DomainInvitesSetInviteNewUserPrefToYesType + """ + if not self.is_domain_invites_set_invite_new_user_pref_to_yes(): + raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_yes' not set") + return self._value + + def get_domain_verification_add_domain_fail(self): + """ + (domains) Failed to verify team domain + + Only call this if :meth:`is_domain_verification_add_domain_fail` is true. + + :rtype: DomainVerificationAddDomainFailType + """ + if not self.is_domain_verification_add_domain_fail(): + raise AttributeError("tag 'domain_verification_add_domain_fail' not set") + return self._value + + def get_domain_verification_add_domain_success(self): + """ + (domains) Verified team domain + + Only call this if :meth:`is_domain_verification_add_domain_success` is true. + + :rtype: DomainVerificationAddDomainSuccessType + """ + if not self.is_domain_verification_add_domain_success(): + raise AttributeError("tag 'domain_verification_add_domain_success' not set") + return self._value + + def get_domain_verification_remove_domain(self): + """ + (domains) Removed domain from list of verified team domains + + Only call this if :meth:`is_domain_verification_remove_domain` is true. + + :rtype: DomainVerificationRemoveDomainType + """ + if not self.is_domain_verification_remove_domain(): + raise AttributeError("tag 'domain_verification_remove_domain' not set") + return self._value + + def get_enabled_domain_invites(self): + """ + (domains) Enabled domain invites (deprecated, no longer logged) + + Only call this if :meth:`is_enabled_domain_invites` is true. + + :rtype: EnabledDomainInvitesType + """ + if not self.is_enabled_domain_invites(): + raise AttributeError("tag 'enabled_domain_invites' not set") + return self._value + + def get_create_folder(self): + """ + (file_operations) Created folders (deprecated, no longer logged) + + Only call this if :meth:`is_create_folder` is true. + + :rtype: CreateFolderType + """ + if not self.is_create_folder(): + raise AttributeError("tag 'create_folder' not set") + return self._value + + def get_file_add(self): + """ + (file_operations) Added files and/or folders + + Only call this if :meth:`is_file_add` is true. + + :rtype: FileAddType + """ + if not self.is_file_add(): + raise AttributeError("tag 'file_add' not set") + return self._value + + def get_file_copy(self): + """ + (file_operations) Copied files and/or folders + + Only call this if :meth:`is_file_copy` is true. + + :rtype: FileCopyType + """ + if not self.is_file_copy(): + raise AttributeError("tag 'file_copy' not set") + return self._value + + def get_file_delete(self): + """ + (file_operations) Deleted files and/or folders + + Only call this if :meth:`is_file_delete` is true. + + :rtype: FileDeleteType + """ + if not self.is_file_delete(): + raise AttributeError("tag 'file_delete' not set") + return self._value + + def get_file_download(self): + """ + (file_operations) Downloaded files and/or folders + + Only call this if :meth:`is_file_download` is true. + + :rtype: FileDownloadType + """ + if not self.is_file_download(): + raise AttributeError("tag 'file_download' not set") + return self._value + + def get_file_edit(self): + """ + (file_operations) Edited files + + Only call this if :meth:`is_file_edit` is true. + + :rtype: FileEditType + """ + if not self.is_file_edit(): + raise AttributeError("tag 'file_edit' not set") + return self._value + + def get_file_get_copy_reference(self): + """ + (file_operations) Created copy reference to file/folder + + Only call this if :meth:`is_file_get_copy_reference` is true. + + :rtype: FileGetCopyReferenceType + """ + if not self.is_file_get_copy_reference(): + raise AttributeError("tag 'file_get_copy_reference' not set") + return self._value + + def get_file_locking_lock_status_changed(self): + """ + (file_operations) Locked/unlocked editing for a file + + Only call this if :meth:`is_file_locking_lock_status_changed` is true. + + :rtype: FileLockingLockStatusChangedType + """ + if not self.is_file_locking_lock_status_changed(): + raise AttributeError("tag 'file_locking_lock_status_changed' not set") + return self._value + + def get_file_move(self): + """ + (file_operations) Moved files and/or folders + + Only call this if :meth:`is_file_move` is true. + + :rtype: FileMoveType + """ + if not self.is_file_move(): + raise AttributeError("tag 'file_move' not set") + return self._value + + def get_file_permanently_delete(self): + """ + (file_operations) Permanently deleted files and/or folders + + Only call this if :meth:`is_file_permanently_delete` is true. + + :rtype: FilePermanentlyDeleteType + """ + if not self.is_file_permanently_delete(): + raise AttributeError("tag 'file_permanently_delete' not set") + return self._value + + def get_file_preview(self): + """ + (file_operations) Previewed files and/or folders + + Only call this if :meth:`is_file_preview` is true. + + :rtype: FilePreviewType + """ + if not self.is_file_preview(): + raise AttributeError("tag 'file_preview' not set") + return self._value + + def get_file_rename(self): + """ + (file_operations) Renamed files and/or folders + + Only call this if :meth:`is_file_rename` is true. + + :rtype: FileRenameType + """ + if not self.is_file_rename(): + raise AttributeError("tag 'file_rename' not set") + return self._value + + def get_file_restore(self): + """ + (file_operations) Restored deleted files and/or folders + + Only call this if :meth:`is_file_restore` is true. + + :rtype: FileRestoreType + """ + if not self.is_file_restore(): + raise AttributeError("tag 'file_restore' not set") + return self._value + + def get_file_revert(self): + """ + (file_operations) Reverted files to previous version + + Only call this if :meth:`is_file_revert` is true. + + :rtype: FileRevertType + """ + if not self.is_file_revert(): + raise AttributeError("tag 'file_revert' not set") + return self._value + + def get_file_rollback_changes(self): + """ + (file_operations) Rolled back file actions + + Only call this if :meth:`is_file_rollback_changes` is true. + + :rtype: FileRollbackChangesType + """ + if not self.is_file_rollback_changes(): + raise AttributeError("tag 'file_rollback_changes' not set") + return self._value + + def get_file_save_copy_reference(self): + """ + (file_operations) Saved file/folder using copy reference + + Only call this if :meth:`is_file_save_copy_reference` is true. + + :rtype: FileSaveCopyReferenceType + """ + if not self.is_file_save_copy_reference(): + raise AttributeError("tag 'file_save_copy_reference' not set") + return self._value + + def get_folder_overview_description_changed(self): + """ + (file_operations) Updated folder overview + + Only call this if :meth:`is_folder_overview_description_changed` is true. + + :rtype: FolderOverviewDescriptionChangedType + """ + if not self.is_folder_overview_description_changed(): + raise AttributeError("tag 'folder_overview_description_changed' not set") + return self._value + + def get_folder_overview_item_pinned(self): + """ + (file_operations) Pinned item to folder overview + + Only call this if :meth:`is_folder_overview_item_pinned` is true. + + :rtype: FolderOverviewItemPinnedType + """ + if not self.is_folder_overview_item_pinned(): + raise AttributeError("tag 'folder_overview_item_pinned' not set") + return self._value + + def get_folder_overview_item_unpinned(self): + """ + (file_operations) Unpinned item from folder overview + + Only call this if :meth:`is_folder_overview_item_unpinned` is true. + + :rtype: FolderOverviewItemUnpinnedType + """ + if not self.is_folder_overview_item_unpinned(): + raise AttributeError("tag 'folder_overview_item_unpinned' not set") + return self._value + + def get_rewind_folder(self): + """ + (file_operations) Rewound a folder + + Only call this if :meth:`is_rewind_folder` is true. + + :rtype: RewindFolderType + """ + if not self.is_rewind_folder(): + raise AttributeError("tag 'rewind_folder' not set") + return self._value + + def get_file_request_change(self): + """ + (file_requests) Changed file request + + Only call this if :meth:`is_file_request_change` is true. + + :rtype: FileRequestChangeType + """ + if not self.is_file_request_change(): + raise AttributeError("tag 'file_request_change' not set") + return self._value + + def get_file_request_close(self): + """ + (file_requests) Closed file request + + Only call this if :meth:`is_file_request_close` is true. + + :rtype: FileRequestCloseType + """ + if not self.is_file_request_close(): + raise AttributeError("tag 'file_request_close' not set") + return self._value + + def get_file_request_create(self): + """ + (file_requests) Created file request + + Only call this if :meth:`is_file_request_create` is true. + + :rtype: FileRequestCreateType + """ + if not self.is_file_request_create(): + raise AttributeError("tag 'file_request_create' not set") + return self._value + + def get_file_request_delete(self): + """ + (file_requests) Delete file request + + Only call this if :meth:`is_file_request_delete` is true. + + :rtype: FileRequestDeleteType + """ + if not self.is_file_request_delete(): + raise AttributeError("tag 'file_request_delete' not set") + return self._value + + def get_file_request_receive_file(self): + """ + (file_requests) Received files for file request + + Only call this if :meth:`is_file_request_receive_file` is true. + + :rtype: FileRequestReceiveFileType + """ + if not self.is_file_request_receive_file(): + raise AttributeError("tag 'file_request_receive_file' not set") + return self._value + + def get_group_add_external_id(self): + """ + (groups) Added external ID for group + + Only call this if :meth:`is_group_add_external_id` is true. + + :rtype: GroupAddExternalIdType + """ + if not self.is_group_add_external_id(): + raise AttributeError("tag 'group_add_external_id' not set") + return self._value + + def get_group_add_member(self): + """ + (groups) Added team members to group + + Only call this if :meth:`is_group_add_member` is true. + + :rtype: GroupAddMemberType + """ + if not self.is_group_add_member(): + raise AttributeError("tag 'group_add_member' not set") + return self._value + + def get_group_change_external_id(self): + """ + (groups) Changed external ID for group + + Only call this if :meth:`is_group_change_external_id` is true. + + :rtype: GroupChangeExternalIdType + """ + if not self.is_group_change_external_id(): + raise AttributeError("tag 'group_change_external_id' not set") + return self._value + + def get_group_change_management_type(self): + """ + (groups) Changed group management type + + Only call this if :meth:`is_group_change_management_type` is true. + + :rtype: GroupChangeManagementTypeType + """ + if not self.is_group_change_management_type(): + raise AttributeError("tag 'group_change_management_type' not set") + return self._value + + def get_group_change_member_role(self): + """ + (groups) Changed manager permissions of group member + + Only call this if :meth:`is_group_change_member_role` is true. + + :rtype: GroupChangeMemberRoleType + """ + if not self.is_group_change_member_role(): + raise AttributeError("tag 'group_change_member_role' not set") + return self._value + + def get_group_create(self): + """ + (groups) Created group + + Only call this if :meth:`is_group_create` is true. + + :rtype: GroupCreateType + """ + if not self.is_group_create(): + raise AttributeError("tag 'group_create' not set") + return self._value + + def get_group_delete(self): + """ + (groups) Deleted group + + Only call this if :meth:`is_group_delete` is true. + + :rtype: GroupDeleteType + """ + if not self.is_group_delete(): + raise AttributeError("tag 'group_delete' not set") + return self._value + + def get_group_description_updated(self): + """ + (groups) Updated group (deprecated, no longer logged) + + Only call this if :meth:`is_group_description_updated` is true. + + :rtype: GroupDescriptionUpdatedType + """ + if not self.is_group_description_updated(): + raise AttributeError("tag 'group_description_updated' not set") + return self._value + + def get_group_join_policy_updated(self): + """ + (groups) Updated group join policy (deprecated, no longer logged) + + Only call this if :meth:`is_group_join_policy_updated` is true. + + :rtype: GroupJoinPolicyUpdatedType + """ + if not self.is_group_join_policy_updated(): + raise AttributeError("tag 'group_join_policy_updated' not set") + return self._value + + def get_group_moved(self): + """ + (groups) Moved group (deprecated, no longer logged) + + Only call this if :meth:`is_group_moved` is true. + + :rtype: GroupMovedType + """ + if not self.is_group_moved(): + raise AttributeError("tag 'group_moved' not set") + return self._value + + def get_group_remove_external_id(self): + """ + (groups) Removed external ID for group + + Only call this if :meth:`is_group_remove_external_id` is true. + + :rtype: GroupRemoveExternalIdType + """ + if not self.is_group_remove_external_id(): + raise AttributeError("tag 'group_remove_external_id' not set") + return self._value + + def get_group_remove_member(self): + """ + (groups) Removed team members from group + + Only call this if :meth:`is_group_remove_member` is true. + + :rtype: GroupRemoveMemberType + """ + if not self.is_group_remove_member(): + raise AttributeError("tag 'group_remove_member' not set") + return self._value + + def get_group_rename(self): + """ + (groups) Renamed group + + Only call this if :meth:`is_group_rename` is true. + + :rtype: GroupRenameType + """ + if not self.is_group_rename(): + raise AttributeError("tag 'group_rename' not set") + return self._value + + def get_legal_holds_activate_a_hold(self): + """ + (legal_holds) Activated a hold + + Only call this if :meth:`is_legal_holds_activate_a_hold` is true. + + :rtype: LegalHoldsActivateAHoldType + """ + if not self.is_legal_holds_activate_a_hold(): + raise AttributeError("tag 'legal_holds_activate_a_hold' not set") + return self._value + + def get_legal_holds_add_members(self): + """ + (legal_holds) Added members to a hold + + Only call this if :meth:`is_legal_holds_add_members` is true. + + :rtype: LegalHoldsAddMembersType + """ + if not self.is_legal_holds_add_members(): + raise AttributeError("tag 'legal_holds_add_members' not set") + return self._value + + def get_legal_holds_change_hold_details(self): + """ + (legal_holds) Edited details for a hold + + Only call this if :meth:`is_legal_holds_change_hold_details` is true. + + :rtype: LegalHoldsChangeHoldDetailsType + """ + if not self.is_legal_holds_change_hold_details(): + raise AttributeError("tag 'legal_holds_change_hold_details' not set") + return self._value + + def get_legal_holds_change_hold_name(self): + """ + (legal_holds) Renamed a hold + + Only call this if :meth:`is_legal_holds_change_hold_name` is true. + + :rtype: LegalHoldsChangeHoldNameType + """ + if not self.is_legal_holds_change_hold_name(): + raise AttributeError("tag 'legal_holds_change_hold_name' not set") + return self._value + + def get_legal_holds_export_a_hold(self): + """ + (legal_holds) Exported hold + + Only call this if :meth:`is_legal_holds_export_a_hold` is true. + + :rtype: LegalHoldsExportAHoldType + """ + if not self.is_legal_holds_export_a_hold(): + raise AttributeError("tag 'legal_holds_export_a_hold' not set") + return self._value + + def get_legal_holds_export_cancelled(self): + """ + (legal_holds) Canceled export for a hold + + Only call this if :meth:`is_legal_holds_export_cancelled` is true. + + :rtype: LegalHoldsExportCancelledType + """ + if not self.is_legal_holds_export_cancelled(): + raise AttributeError("tag 'legal_holds_export_cancelled' not set") + return self._value + + def get_legal_holds_export_downloaded(self): + """ + (legal_holds) Downloaded export for a hold + + Only call this if :meth:`is_legal_holds_export_downloaded` is true. + + :rtype: LegalHoldsExportDownloadedType + """ + if not self.is_legal_holds_export_downloaded(): + raise AttributeError("tag 'legal_holds_export_downloaded' not set") + return self._value + + def get_legal_holds_export_removed(self): + """ + (legal_holds) Removed export for a hold + + Only call this if :meth:`is_legal_holds_export_removed` is true. + + :rtype: LegalHoldsExportRemovedType + """ + if not self.is_legal_holds_export_removed(): + raise AttributeError("tag 'legal_holds_export_removed' not set") + return self._value + + def get_legal_holds_release_a_hold(self): + """ + (legal_holds) Released a hold + + Only call this if :meth:`is_legal_holds_release_a_hold` is true. + + :rtype: LegalHoldsReleaseAHoldType + """ + if not self.is_legal_holds_release_a_hold(): + raise AttributeError("tag 'legal_holds_release_a_hold' not set") + return self._value + + def get_legal_holds_remove_members(self): + """ + (legal_holds) Removed members from a hold + + Only call this if :meth:`is_legal_holds_remove_members` is true. + + :rtype: LegalHoldsRemoveMembersType + """ + if not self.is_legal_holds_remove_members(): + raise AttributeError("tag 'legal_holds_remove_members' not set") + return self._value + + def get_legal_holds_report_a_hold(self): + """ + (legal_holds) Created a summary report for a hold + + Only call this if :meth:`is_legal_holds_report_a_hold` is true. + + :rtype: LegalHoldsReportAHoldType + """ + if not self.is_legal_holds_report_a_hold(): + raise AttributeError("tag 'legal_holds_report_a_hold' not set") + return self._value + + def get_account_lock_or_unlocked(self): + """ + (logins) Unlocked/locked account after failed sign in attempts + + Only call this if :meth:`is_account_lock_or_unlocked` is true. + + :rtype: AccountLockOrUnlockedType + """ + if not self.is_account_lock_or_unlocked(): + raise AttributeError("tag 'account_lock_or_unlocked' not set") + return self._value + + def get_emm_error(self): + """ + (logins) Failed to sign in via EMM (deprecated, replaced by 'Failed to + sign in') + + Only call this if :meth:`is_emm_error` is true. + + :rtype: EmmErrorType + """ + if not self.is_emm_error(): + raise AttributeError("tag 'emm_error' not set") + return self._value + + def get_guest_admin_signed_in_via_trusted_teams(self): + """ + (logins) Started trusted team admin session + + Only call this if :meth:`is_guest_admin_signed_in_via_trusted_teams` is true. + + :rtype: GuestAdminSignedInViaTrustedTeamsType + """ + if not self.is_guest_admin_signed_in_via_trusted_teams(): + raise AttributeError("tag 'guest_admin_signed_in_via_trusted_teams' not set") + return self._value + + def get_guest_admin_signed_out_via_trusted_teams(self): + """ + (logins) Ended trusted team admin session + + Only call this if :meth:`is_guest_admin_signed_out_via_trusted_teams` is true. + + :rtype: GuestAdminSignedOutViaTrustedTeamsType + """ + if not self.is_guest_admin_signed_out_via_trusted_teams(): + raise AttributeError("tag 'guest_admin_signed_out_via_trusted_teams' not set") + return self._value + + def get_login_fail(self): + """ + (logins) Failed to sign in + + Only call this if :meth:`is_login_fail` is true. + + :rtype: LoginFailType + """ + if not self.is_login_fail(): + raise AttributeError("tag 'login_fail' not set") + return self._value + + def get_login_success(self): + """ + (logins) Signed in + + Only call this if :meth:`is_login_success` is true. + + :rtype: LoginSuccessType + """ + if not self.is_login_success(): + raise AttributeError("tag 'login_success' not set") + return self._value + + def get_logout(self): + """ + (logins) Signed out + + Only call this if :meth:`is_logout` is true. + + :rtype: LogoutType + """ + if not self.is_logout(): + raise AttributeError("tag 'logout' not set") + return self._value + + def get_reseller_support_session_end(self): + """ + (logins) Ended reseller support session + + Only call this if :meth:`is_reseller_support_session_end` is true. + + :rtype: ResellerSupportSessionEndType + """ + if not self.is_reseller_support_session_end(): + raise AttributeError("tag 'reseller_support_session_end' not set") + return self._value + + def get_reseller_support_session_start(self): + """ + (logins) Started reseller support session + + Only call this if :meth:`is_reseller_support_session_start` is true. + + :rtype: ResellerSupportSessionStartType + """ + if not self.is_reseller_support_session_start(): + raise AttributeError("tag 'reseller_support_session_start' not set") + return self._value + + def get_sign_in_as_session_end(self): + """ + (logins) Ended admin sign-in-as session + + Only call this if :meth:`is_sign_in_as_session_end` is true. + + :rtype: SignInAsSessionEndType + """ + if not self.is_sign_in_as_session_end(): + raise AttributeError("tag 'sign_in_as_session_end' not set") + return self._value + + def get_sign_in_as_session_start(self): + """ + (logins) Started admin sign-in-as session + + Only call this if :meth:`is_sign_in_as_session_start` is true. + + :rtype: SignInAsSessionStartType + """ + if not self.is_sign_in_as_session_start(): + raise AttributeError("tag 'sign_in_as_session_start' not set") + return self._value + + def get_sso_error(self): + """ + (logins) Failed to sign in via SSO (deprecated, replaced by 'Failed to + sign in') + + Only call this if :meth:`is_sso_error` is true. + + :rtype: SsoErrorType + """ + if not self.is_sso_error(): + raise AttributeError("tag 'sso_error' not set") + return self._value + + def get_create_team_invite_link(self): + """ + (members) Created team invite link + + Only call this if :meth:`is_create_team_invite_link` is true. + + :rtype: CreateTeamInviteLinkType + """ + if not self.is_create_team_invite_link(): + raise AttributeError("tag 'create_team_invite_link' not set") + return self._value + + def get_delete_team_invite_link(self): + """ + (members) Deleted team invite link + + Only call this if :meth:`is_delete_team_invite_link` is true. + + :rtype: DeleteTeamInviteLinkType + """ + if not self.is_delete_team_invite_link(): + raise AttributeError("tag 'delete_team_invite_link' not set") + return self._value + + def get_member_add_external_id(self): + """ + (members) Added an external ID for team member + + Only call this if :meth:`is_member_add_external_id` is true. + + :rtype: MemberAddExternalIdType + """ + if not self.is_member_add_external_id(): + raise AttributeError("tag 'member_add_external_id' not set") + return self._value + + def get_member_add_name(self): + """ + (members) Added team member name + + Only call this if :meth:`is_member_add_name` is true. + + :rtype: MemberAddNameType + """ + if not self.is_member_add_name(): + raise AttributeError("tag 'member_add_name' not set") + return self._value + + def get_member_change_admin_role(self): + """ + (members) Changed team member admin role + + Only call this if :meth:`is_member_change_admin_role` is true. + + :rtype: MemberChangeAdminRoleType + """ + if not self.is_member_change_admin_role(): + raise AttributeError("tag 'member_change_admin_role' not set") + return self._value + + def get_member_change_email(self): + """ + (members) Changed team member email + + Only call this if :meth:`is_member_change_email` is true. + + :rtype: MemberChangeEmailType + """ + if not self.is_member_change_email(): + raise AttributeError("tag 'member_change_email' not set") + return self._value + + def get_member_change_external_id(self): + """ (members) Changed the external ID for team member - :ivar MemberChangeMembershipTypeType - EventType.member_change_membership_type: (members) Changed membership - type (limited/full) of member (deprecated, no longer logged) - :ivar MemberChangeNameType EventType.member_change_name: (members) Changed - team member name - :ivar MemberChangeStatusType EventType.member_change_status: (members) - Changed member status (invited, joined, suspended, etc.) - :ivar MemberDeleteManualContactsType - EventType.member_delete_manual_contacts: (members) Cleared manually - added contacts - :ivar MemberPermanentlyDeleteAccountContentsType - EventType.member_permanently_delete_account_contents: (members) - Permanently deleted contents of deleted team member account - :ivar MemberRemoveExternalIdType EventType.member_remove_external_id: + + Only call this if :meth:`is_member_change_external_id` is true. + + :rtype: MemberChangeExternalIdType + """ + if not self.is_member_change_external_id(): + raise AttributeError("tag 'member_change_external_id' not set") + return self._value + + def get_member_change_membership_type(self): + """ + (members) Changed membership type (limited/full) of member (deprecated, + no longer logged) + + Only call this if :meth:`is_member_change_membership_type` is true. + + :rtype: MemberChangeMembershipTypeType + """ + if not self.is_member_change_membership_type(): + raise AttributeError("tag 'member_change_membership_type' not set") + return self._value + + def get_member_change_name(self): + """ + (members) Changed team member name + + Only call this if :meth:`is_member_change_name` is true. + + :rtype: MemberChangeNameType + """ + if not self.is_member_change_name(): + raise AttributeError("tag 'member_change_name' not set") + return self._value + + def get_member_change_status(self): + """ + (members) Changed member status (invited, joined, suspended, etc.) + + Only call this if :meth:`is_member_change_status` is true. + + :rtype: MemberChangeStatusType + """ + if not self.is_member_change_status(): + raise AttributeError("tag 'member_change_status' not set") + return self._value + + def get_member_delete_manual_contacts(self): + """ + (members) Cleared manually added contacts + + Only call this if :meth:`is_member_delete_manual_contacts` is true. + + :rtype: MemberDeleteManualContactsType + """ + if not self.is_member_delete_manual_contacts(): + raise AttributeError("tag 'member_delete_manual_contacts' not set") + return self._value + + def get_member_delete_profile_photo(self): + """ + (members) Deleted team member profile photo + + Only call this if :meth:`is_member_delete_profile_photo` is true. + + :rtype: MemberDeleteProfilePhotoType + """ + if not self.is_member_delete_profile_photo(): + raise AttributeError("tag 'member_delete_profile_photo' not set") + return self._value + + def get_member_permanently_delete_account_contents(self): + """ + (members) Permanently deleted contents of deleted team member account + + Only call this if :meth:`is_member_permanently_delete_account_contents` is true. + + :rtype: MemberPermanentlyDeleteAccountContentsType + """ + if not self.is_member_permanently_delete_account_contents(): + raise AttributeError("tag 'member_permanently_delete_account_contents' not set") + return self._value + + def get_member_remove_external_id(self): + """ (members) Removed the external ID for team member - :ivar MemberSpaceLimitsAddCustomQuotaType - EventType.member_space_limits_add_custom_quota: (members) Set custom - member space limit - :ivar MemberSpaceLimitsChangeCustomQuotaType - EventType.member_space_limits_change_custom_quota: (members) Changed - custom member space limit - :ivar MemberSpaceLimitsChangeStatusType - EventType.member_space_limits_change_status: (members) Changed space - limit status - :ivar MemberSpaceLimitsRemoveCustomQuotaType - EventType.member_space_limits_remove_custom_quota: (members) Removed - custom member space limit - :ivar MemberSuggestType EventType.member_suggest: (members) Suggested person - to add to team - :ivar MemberTransferAccountContentsType - EventType.member_transfer_account_contents: (members) Transferred - contents of deleted member account to another member - :ivar SecondaryMailsPolicyChangedType - EventType.secondary_mails_policy_changed: (members) Secondary mails - policy changed - :ivar PaperContentAddMemberType EventType.paper_content_add_member: (paper) - Added team member to Paper doc/folder - :ivar PaperContentAddToFolderType EventType.paper_content_add_to_folder: + + Only call this if :meth:`is_member_remove_external_id` is true. + + :rtype: MemberRemoveExternalIdType + """ + if not self.is_member_remove_external_id(): + raise AttributeError("tag 'member_remove_external_id' not set") + return self._value + + def get_member_set_profile_photo(self): + """ + (members) Set team member profile photo + + Only call this if :meth:`is_member_set_profile_photo` is true. + + :rtype: MemberSetProfilePhotoType + """ + if not self.is_member_set_profile_photo(): + raise AttributeError("tag 'member_set_profile_photo' not set") + return self._value + + def get_member_space_limits_add_custom_quota(self): + """ + (members) Set custom member space limit + + Only call this if :meth:`is_member_space_limits_add_custom_quota` is true. + + :rtype: MemberSpaceLimitsAddCustomQuotaType + """ + if not self.is_member_space_limits_add_custom_quota(): + raise AttributeError("tag 'member_space_limits_add_custom_quota' not set") + return self._value + + def get_member_space_limits_change_custom_quota(self): + """ + (members) Changed custom member space limit + + Only call this if :meth:`is_member_space_limits_change_custom_quota` is true. + + :rtype: MemberSpaceLimitsChangeCustomQuotaType + """ + if not self.is_member_space_limits_change_custom_quota(): + raise AttributeError("tag 'member_space_limits_change_custom_quota' not set") + return self._value + + def get_member_space_limits_change_status(self): + """ + (members) Changed space limit status + + Only call this if :meth:`is_member_space_limits_change_status` is true. + + :rtype: MemberSpaceLimitsChangeStatusType + """ + if not self.is_member_space_limits_change_status(): + raise AttributeError("tag 'member_space_limits_change_status' not set") + return self._value + + def get_member_space_limits_remove_custom_quota(self): + """ + (members) Removed custom member space limit + + Only call this if :meth:`is_member_space_limits_remove_custom_quota` is true. + + :rtype: MemberSpaceLimitsRemoveCustomQuotaType + """ + if not self.is_member_space_limits_remove_custom_quota(): + raise AttributeError("tag 'member_space_limits_remove_custom_quota' not set") + return self._value + + def get_member_suggest(self): + """ + (members) Suggested person to add to team + + Only call this if :meth:`is_member_suggest` is true. + + :rtype: MemberSuggestType + """ + if not self.is_member_suggest(): + raise AttributeError("tag 'member_suggest' not set") + return self._value + + def get_member_transfer_account_contents(self): + """ + (members) Transferred contents of deleted member account to another + member + + Only call this if :meth:`is_member_transfer_account_contents` is true. + + :rtype: MemberTransferAccountContentsType + """ + if not self.is_member_transfer_account_contents(): + raise AttributeError("tag 'member_transfer_account_contents' not set") + return self._value + + def get_pending_secondary_email_added(self): + """ + (members) Added pending secondary email + + Only call this if :meth:`is_pending_secondary_email_added` is true. + + :rtype: PendingSecondaryEmailAddedType + """ + if not self.is_pending_secondary_email_added(): + raise AttributeError("tag 'pending_secondary_email_added' not set") + return self._value + + def get_secondary_email_deleted(self): + """ + (members) Deleted secondary email + + Only call this if :meth:`is_secondary_email_deleted` is true. + + :rtype: SecondaryEmailDeletedType + """ + if not self.is_secondary_email_deleted(): + raise AttributeError("tag 'secondary_email_deleted' not set") + return self._value + + def get_secondary_email_verified(self): + """ + (members) Verified secondary email + + Only call this if :meth:`is_secondary_email_verified` is true. + + :rtype: SecondaryEmailVerifiedType + """ + if not self.is_secondary_email_verified(): + raise AttributeError("tag 'secondary_email_verified' not set") + return self._value + + def get_secondary_mails_policy_changed(self): + """ + (members) Secondary mails policy changed + + Only call this if :meth:`is_secondary_mails_policy_changed` is true. + + :rtype: SecondaryMailsPolicyChangedType + """ + if not self.is_secondary_mails_policy_changed(): + raise AttributeError("tag 'secondary_mails_policy_changed' not set") + return self._value + + def get_binder_add_page(self): + """ + (paper) Added Binder page (deprecated, replaced by 'Edited files') + + Only call this if :meth:`is_binder_add_page` is true. + + :rtype: BinderAddPageType + """ + if not self.is_binder_add_page(): + raise AttributeError("tag 'binder_add_page' not set") + return self._value + + def get_binder_add_section(self): + """ + (paper) Added Binder section (deprecated, replaced by 'Edited files') + + Only call this if :meth:`is_binder_add_section` is true. + + :rtype: BinderAddSectionType + """ + if not self.is_binder_add_section(): + raise AttributeError("tag 'binder_add_section' not set") + return self._value + + def get_binder_remove_page(self): + """ + (paper) Removed Binder page (deprecated, replaced by 'Edited files') + + Only call this if :meth:`is_binder_remove_page` is true. + + :rtype: BinderRemovePageType + """ + if not self.is_binder_remove_page(): + raise AttributeError("tag 'binder_remove_page' not set") + return self._value + + def get_binder_remove_section(self): + """ + (paper) Removed Binder section (deprecated, replaced by 'Edited files') + + Only call this if :meth:`is_binder_remove_section` is true. + + :rtype: BinderRemoveSectionType + """ + if not self.is_binder_remove_section(): + raise AttributeError("tag 'binder_remove_section' not set") + return self._value + + def get_binder_rename_page(self): + """ + (paper) Renamed Binder page (deprecated, replaced by 'Edited files') + + Only call this if :meth:`is_binder_rename_page` is true. + + :rtype: BinderRenamePageType + """ + if not self.is_binder_rename_page(): + raise AttributeError("tag 'binder_rename_page' not set") + return self._value + + def get_binder_rename_section(self): + """ + (paper) Renamed Binder section (deprecated, replaced by 'Edited files') + + Only call this if :meth:`is_binder_rename_section` is true. + + :rtype: BinderRenameSectionType + """ + if not self.is_binder_rename_section(): + raise AttributeError("tag 'binder_rename_section' not set") + return self._value + + def get_binder_reorder_page(self): + """ + (paper) Reordered Binder page (deprecated, replaced by 'Edited files') + + Only call this if :meth:`is_binder_reorder_page` is true. + + :rtype: BinderReorderPageType + """ + if not self.is_binder_reorder_page(): + raise AttributeError("tag 'binder_reorder_page' not set") + return self._value + + def get_binder_reorder_section(self): + """ + (paper) Reordered Binder section (deprecated, replaced by 'Edited + files') + + Only call this if :meth:`is_binder_reorder_section` is true. + + :rtype: BinderReorderSectionType + """ + if not self.is_binder_reorder_section(): + raise AttributeError("tag 'binder_reorder_section' not set") + return self._value + + def get_paper_content_add_member(self): + """ + (paper) Added users and/or groups to Paper doc/folder + + Only call this if :meth:`is_paper_content_add_member` is true. + + :rtype: PaperContentAddMemberType + """ + if not self.is_paper_content_add_member(): + raise AttributeError("tag 'paper_content_add_member' not set") + return self._value + + def get_paper_content_add_to_folder(self): + """ (paper) Added Paper doc/folder to folder - :ivar PaperContentArchiveType EventType.paper_content_archive: (paper) - Archived Paper doc/folder - :ivar PaperContentCreateType EventType.paper_content_create: (paper) Created - Paper doc/folder - :ivar PaperContentPermanentlyDeleteType - EventType.paper_content_permanently_delete: (paper) Permanently deleted - Paper doc/folder - :ivar PaperContentRemoveFromFolderType - EventType.paper_content_remove_from_folder: (paper) Removed Paper - doc/folder from folder - :ivar PaperContentRemoveMemberType EventType.paper_content_remove_member: - (paper) Removed team member from Paper doc/folder - :ivar PaperContentRenameType EventType.paper_content_rename: (paper) Renamed - Paper doc/folder - :ivar PaperContentRestoreType EventType.paper_content_restore: (paper) - Restored archived Paper doc/folder - :ivar PaperDocAddCommentType EventType.paper_doc_add_comment: (paper) Added - Paper doc comment - :ivar PaperDocChangeMemberRoleType EventType.paper_doc_change_member_role: - (paper) Changed team member permissions for Paper doc - :ivar PaperDocChangeSharingPolicyType - EventType.paper_doc_change_sharing_policy: (paper) Changed sharing - setting for Paper doc - :ivar PaperDocChangeSubscriptionType - EventType.paper_doc_change_subscription: (paper) Followed/unfollowed - Paper doc - :ivar PaperDocDeletedType EventType.paper_doc_deleted: (paper) Archived - Paper doc (deprecated, no longer logged) - :ivar PaperDocDeleteCommentType EventType.paper_doc_delete_comment: (paper) - Deleted Paper doc comment - :ivar PaperDocDownloadType EventType.paper_doc_download: (paper) Downloaded - Paper doc in specific format - :ivar PaperDocEditType EventType.paper_doc_edit: (paper) Edited Paper doc - :ivar PaperDocEditCommentType EventType.paper_doc_edit_comment: (paper) - Edited Paper doc comment - :ivar PaperDocFollowedType EventType.paper_doc_followed: (paper) Followed - Paper doc (deprecated, replaced by 'Followed/unfollowed Paper doc') - :ivar PaperDocMentionType EventType.paper_doc_mention: (paper) Mentioned - team member in Paper doc - :ivar PaperDocOwnershipChangedType EventType.paper_doc_ownership_changed: + + Only call this if :meth:`is_paper_content_add_to_folder` is true. + + :rtype: PaperContentAddToFolderType + """ + if not self.is_paper_content_add_to_folder(): + raise AttributeError("tag 'paper_content_add_to_folder' not set") + return self._value + + def get_paper_content_archive(self): + """ + (paper) Archived Paper doc/folder + + Only call this if :meth:`is_paper_content_archive` is true. + + :rtype: PaperContentArchiveType + """ + if not self.is_paper_content_archive(): + raise AttributeError("tag 'paper_content_archive' not set") + return self._value + + def get_paper_content_create(self): + """ + (paper) Created Paper doc/folder + + Only call this if :meth:`is_paper_content_create` is true. + + :rtype: PaperContentCreateType + """ + if not self.is_paper_content_create(): + raise AttributeError("tag 'paper_content_create' not set") + return self._value + + def get_paper_content_permanently_delete(self): + """ + (paper) Permanently deleted Paper doc/folder + + Only call this if :meth:`is_paper_content_permanently_delete` is true. + + :rtype: PaperContentPermanentlyDeleteType + """ + if not self.is_paper_content_permanently_delete(): + raise AttributeError("tag 'paper_content_permanently_delete' not set") + return self._value + + def get_paper_content_remove_from_folder(self): + """ + (paper) Removed Paper doc/folder from folder + + Only call this if :meth:`is_paper_content_remove_from_folder` is true. + + :rtype: PaperContentRemoveFromFolderType + """ + if not self.is_paper_content_remove_from_folder(): + raise AttributeError("tag 'paper_content_remove_from_folder' not set") + return self._value + + def get_paper_content_remove_member(self): + """ + (paper) Removed users and/or groups from Paper doc/folder + + Only call this if :meth:`is_paper_content_remove_member` is true. + + :rtype: PaperContentRemoveMemberType + """ + if not self.is_paper_content_remove_member(): + raise AttributeError("tag 'paper_content_remove_member' not set") + return self._value + + def get_paper_content_rename(self): + """ + (paper) Renamed Paper doc/folder + + Only call this if :meth:`is_paper_content_rename` is true. + + :rtype: PaperContentRenameType + """ + if not self.is_paper_content_rename(): + raise AttributeError("tag 'paper_content_rename' not set") + return self._value + + def get_paper_content_restore(self): + """ + (paper) Restored archived Paper doc/folder + + Only call this if :meth:`is_paper_content_restore` is true. + + :rtype: PaperContentRestoreType + """ + if not self.is_paper_content_restore(): + raise AttributeError("tag 'paper_content_restore' not set") + return self._value + + def get_paper_doc_add_comment(self): + """ + (paper) Added Paper doc comment + + Only call this if :meth:`is_paper_doc_add_comment` is true. + + :rtype: PaperDocAddCommentType + """ + if not self.is_paper_doc_add_comment(): + raise AttributeError("tag 'paper_doc_add_comment' not set") + return self._value + + def get_paper_doc_change_member_role(self): + """ + (paper) Changed member permissions for Paper doc + + Only call this if :meth:`is_paper_doc_change_member_role` is true. + + :rtype: PaperDocChangeMemberRoleType + """ + if not self.is_paper_doc_change_member_role(): + raise AttributeError("tag 'paper_doc_change_member_role' not set") + return self._value + + def get_paper_doc_change_sharing_policy(self): + """ + (paper) Changed sharing setting for Paper doc + + Only call this if :meth:`is_paper_doc_change_sharing_policy` is true. + + :rtype: PaperDocChangeSharingPolicyType + """ + if not self.is_paper_doc_change_sharing_policy(): + raise AttributeError("tag 'paper_doc_change_sharing_policy' not set") + return self._value + + def get_paper_doc_change_subscription(self): + """ + (paper) Followed/unfollowed Paper doc + + Only call this if :meth:`is_paper_doc_change_subscription` is true. + + :rtype: PaperDocChangeSubscriptionType + """ + if not self.is_paper_doc_change_subscription(): + raise AttributeError("tag 'paper_doc_change_subscription' not set") + return self._value + + def get_paper_doc_deleted(self): + """ + (paper) Archived Paper doc (deprecated, no longer logged) + + Only call this if :meth:`is_paper_doc_deleted` is true. + + :rtype: PaperDocDeletedType + """ + if not self.is_paper_doc_deleted(): + raise AttributeError("tag 'paper_doc_deleted' not set") + return self._value + + def get_paper_doc_delete_comment(self): + """ + (paper) Deleted Paper doc comment + + Only call this if :meth:`is_paper_doc_delete_comment` is true. + + :rtype: PaperDocDeleteCommentType + """ + if not self.is_paper_doc_delete_comment(): + raise AttributeError("tag 'paper_doc_delete_comment' not set") + return self._value + + def get_paper_doc_download(self): + """ + (paper) Downloaded Paper doc in specific format + + Only call this if :meth:`is_paper_doc_download` is true. + + :rtype: PaperDocDownloadType + """ + if not self.is_paper_doc_download(): + raise AttributeError("tag 'paper_doc_download' not set") + return self._value + + def get_paper_doc_edit(self): + """ + (paper) Edited Paper doc + + Only call this if :meth:`is_paper_doc_edit` is true. + + :rtype: PaperDocEditType + """ + if not self.is_paper_doc_edit(): + raise AttributeError("tag 'paper_doc_edit' not set") + return self._value + + def get_paper_doc_edit_comment(self): + """ + (paper) Edited Paper doc comment + + Only call this if :meth:`is_paper_doc_edit_comment` is true. + + :rtype: PaperDocEditCommentType + """ + if not self.is_paper_doc_edit_comment(): + raise AttributeError("tag 'paper_doc_edit_comment' not set") + return self._value + + def get_paper_doc_followed(self): + """ + (paper) Followed Paper doc (deprecated, replaced by 'Followed/unfollowed + Paper doc') + + Only call this if :meth:`is_paper_doc_followed` is true. + + :rtype: PaperDocFollowedType + """ + if not self.is_paper_doc_followed(): + raise AttributeError("tag 'paper_doc_followed' not set") + return self._value + + def get_paper_doc_mention(self): + """ + (paper) Mentioned user in Paper doc + + Only call this if :meth:`is_paper_doc_mention` is true. + + :rtype: PaperDocMentionType + """ + if not self.is_paper_doc_mention(): + raise AttributeError("tag 'paper_doc_mention' not set") + return self._value + + def get_paper_doc_ownership_changed(self): + """ (paper) Transferred ownership of Paper doc - :ivar PaperDocRequestAccessType EventType.paper_doc_request_access: (paper) - Requested access to Paper doc - :ivar PaperDocResolveCommentType EventType.paper_doc_resolve_comment: + + Only call this if :meth:`is_paper_doc_ownership_changed` is true. + + :rtype: PaperDocOwnershipChangedType + """ + if not self.is_paper_doc_ownership_changed(): + raise AttributeError("tag 'paper_doc_ownership_changed' not set") + return self._value + + def get_paper_doc_request_access(self): + """ + (paper) Requested access to Paper doc + + Only call this if :meth:`is_paper_doc_request_access` is true. + + :rtype: PaperDocRequestAccessType + """ + if not self.is_paper_doc_request_access(): + raise AttributeError("tag 'paper_doc_request_access' not set") + return self._value + + def get_paper_doc_resolve_comment(self): + """ (paper) Resolved Paper doc comment - :ivar PaperDocRevertType EventType.paper_doc_revert: (paper) Restored Paper - doc to previous version - :ivar PaperDocSlackShareType EventType.paper_doc_slack_share: (paper) Shared - Paper doc via Slack - :ivar PaperDocTeamInviteType EventType.paper_doc_team_invite: (paper) Shared - Paper doc with team member (deprecated, no longer logged) - :ivar PaperDocTrashedType EventType.paper_doc_trashed: (paper) Deleted Paper - doc - :ivar PaperDocUnresolveCommentType EventType.paper_doc_unresolve_comment: + + Only call this if :meth:`is_paper_doc_resolve_comment` is true. + + :rtype: PaperDocResolveCommentType + """ + if not self.is_paper_doc_resolve_comment(): + raise AttributeError("tag 'paper_doc_resolve_comment' not set") + return self._value + + def get_paper_doc_revert(self): + """ + (paper) Restored Paper doc to previous version + + Only call this if :meth:`is_paper_doc_revert` is true. + + :rtype: PaperDocRevertType + """ + if not self.is_paper_doc_revert(): + raise AttributeError("tag 'paper_doc_revert' not set") + return self._value + + def get_paper_doc_slack_share(self): + """ + (paper) Shared Paper doc via Slack + + Only call this if :meth:`is_paper_doc_slack_share` is true. + + :rtype: PaperDocSlackShareType + """ + if not self.is_paper_doc_slack_share(): + raise AttributeError("tag 'paper_doc_slack_share' not set") + return self._value + + def get_paper_doc_team_invite(self): + """ + (paper) Shared Paper doc with users and/or groups (deprecated, no longer + logged) + + Only call this if :meth:`is_paper_doc_team_invite` is true. + + :rtype: PaperDocTeamInviteType + """ + if not self.is_paper_doc_team_invite(): + raise AttributeError("tag 'paper_doc_team_invite' not set") + return self._value + + def get_paper_doc_trashed(self): + """ + (paper) Deleted Paper doc + + Only call this if :meth:`is_paper_doc_trashed` is true. + + :rtype: PaperDocTrashedType + """ + if not self.is_paper_doc_trashed(): + raise AttributeError("tag 'paper_doc_trashed' not set") + return self._value + + def get_paper_doc_unresolve_comment(self): + """ (paper) Unresolved Paper doc comment - :ivar PaperDocUntrashedType EventType.paper_doc_untrashed: (paper) Restored - Paper doc - :ivar PaperDocViewType EventType.paper_doc_view: (paper) Viewed Paper doc - :ivar PaperExternalViewAllowType EventType.paper_external_view_allow: + + Only call this if :meth:`is_paper_doc_unresolve_comment` is true. + + :rtype: PaperDocUnresolveCommentType + """ + if not self.is_paper_doc_unresolve_comment(): + raise AttributeError("tag 'paper_doc_unresolve_comment' not set") + return self._value + + def get_paper_doc_untrashed(self): + """ + (paper) Restored Paper doc + + Only call this if :meth:`is_paper_doc_untrashed` is true. + + :rtype: PaperDocUntrashedType + """ + if not self.is_paper_doc_untrashed(): + raise AttributeError("tag 'paper_doc_untrashed' not set") + return self._value + + def get_paper_doc_view(self): + """ + (paper) Viewed Paper doc + + Only call this if :meth:`is_paper_doc_view` is true. + + :rtype: PaperDocViewType + """ + if not self.is_paper_doc_view(): + raise AttributeError("tag 'paper_doc_view' not set") + return self._value + + def get_paper_external_view_allow(self): + """ (paper) Changed Paper external sharing setting to anyone (deprecated, no longer logged) - :ivar PaperExternalViewDefaultTeamType - EventType.paper_external_view_default_team: (paper) Changed Paper - external sharing setting to default team (deprecated, no longer logged) - :ivar PaperExternalViewForbidType EventType.paper_external_view_forbid: - (paper) Changed Paper external sharing setting to team-only (deprecated, - no longer logged) - :ivar PaperFolderChangeSubscriptionType - EventType.paper_folder_change_subscription: (paper) Followed/unfollowed - Paper folder - :ivar PaperFolderDeletedType EventType.paper_folder_deleted: (paper) - Archived Paper folder (deprecated, no longer logged) - :ivar PaperFolderFollowedType EventType.paper_folder_followed: (paper) - Followed Paper folder (deprecated, replaced by 'Followed/unfollowed - Paper folder') - :ivar PaperFolderTeamInviteType EventType.paper_folder_team_invite: (paper) - Shared Paper folder with member (deprecated, no longer logged) - :ivar PaperPublishedLinkCreateType EventType.paper_published_link_create: - (paper) Published doc - :ivar PaperPublishedLinkDisabledType - EventType.paper_published_link_disabled: (paper) Unpublished doc - :ivar PaperPublishedLinkViewType EventType.paper_published_link_view: - (paper) Viewed published doc - :ivar PasswordChangeType EventType.password_change: (passwords) Changed - password - :ivar PasswordResetType EventType.password_reset: (passwords) Reset password - :ivar PasswordResetAllType EventType.password_reset_all: (passwords) Reset - all team member passwords - :ivar EmmCreateExceptionsReportType EventType.emm_create_exceptions_report: - (reports) Created EMM-excluded users report - :ivar EmmCreateUsageReportType EventType.emm_create_usage_report: (reports) - Created EMM mobile app usage report - :ivar ExportMembersReportType EventType.export_members_report: (reports) - Created member data report - :ivar PaperAdminExportStartType EventType.paper_admin_export_start: - (reports) Exported all team Paper docs - :ivar SmartSyncCreateAdminPrivilegeReportType - EventType.smart_sync_create_admin_privilege_report: (reports) Created - Smart Sync non-admin devices report - :ivar TeamActivityCreateReportType EventType.team_activity_create_report: - (reports) Created team activity report - :ivar TeamActivityCreateReportFailType - EventType.team_activity_create_report_fail: (reports) Couldn't generate - team activity report - :ivar CollectionShareType EventType.collection_share: (sharing) Shared album - :ivar NoteAclInviteOnlyType EventType.note_acl_invite_only: (sharing) - Changed Paper doc to invite-only (deprecated, no longer logged) - :ivar NoteAclLinkType EventType.note_acl_link: (sharing) Changed Paper doc - to link-accessible (deprecated, no longer logged) - :ivar NoteAclTeamLinkType EventType.note_acl_team_link: (sharing) Changed - Paper doc to link-accessible for team (deprecated, no longer logged) - :ivar NoteSharedType EventType.note_shared: (sharing) Shared Paper doc + + Only call this if :meth:`is_paper_external_view_allow` is true. + + :rtype: PaperExternalViewAllowType + """ + if not self.is_paper_external_view_allow(): + raise AttributeError("tag 'paper_external_view_allow' not set") + return self._value + + def get_paper_external_view_default_team(self): + """ + (paper) Changed Paper external sharing setting to default team (deprecated, no longer logged) - :ivar NoteShareReceiveType EventType.note_share_receive: (sharing) Shared - received Paper doc (deprecated, no longer logged) - :ivar OpenNoteSharedType EventType.open_note_shared: (sharing) Opened shared - Paper doc (deprecated, no longer logged) - :ivar SfAddGroupType EventType.sf_add_group: (sharing) Added team to shared - folder (deprecated, no longer logged) - :ivar SfAllowNonMembersToViewSharedLinksType - EventType.sf_allow_non_members_to_view_shared_links: (sharing) Allowed - non-collaborators to view links to files in shared folder (deprecated, + + Only call this if :meth:`is_paper_external_view_default_team` is true. + + :rtype: PaperExternalViewDefaultTeamType + """ + if not self.is_paper_external_view_default_team(): + raise AttributeError("tag 'paper_external_view_default_team' not set") + return self._value + + def get_paper_external_view_forbid(self): + """ + (paper) Changed Paper external sharing setting to team-only (deprecated, no longer logged) - :ivar SfExternalInviteWarnType EventType.sf_external_invite_warn: (sharing) - Set team members to see warning before sharing folders outside team - (deprecated, no longer logged) - :ivar SfFbInviteType EventType.sf_fb_invite: (sharing) Invited Facebook - users to shared folder (deprecated, no longer logged) - :ivar SfFbInviteChangeRoleType EventType.sf_fb_invite_change_role: (sharing) - Changed Facebook user's role in shared folder (deprecated, no longer - logged) - :ivar SfFbUninviteType EventType.sf_fb_uninvite: (sharing) Uninvited - Facebook user from shared folder (deprecated, no longer logged) - :ivar SfInviteGroupType EventType.sf_invite_group: (sharing) Invited group - to shared folder (deprecated, no longer logged) - :ivar SfTeamGrantAccessType EventType.sf_team_grant_access: (sharing) - Granted access to shared folder (deprecated, no longer logged) - :ivar SfTeamInviteType EventType.sf_team_invite: (sharing) Invited team - members to shared folder (deprecated, replaced by 'Invited user to - Dropbox and added them to shared file/folder') - :ivar SfTeamInviteChangeRoleType EventType.sf_team_invite_change_role: - (sharing) Changed team member's role in shared folder (deprecated, no - longer logged) - :ivar SfTeamJoinType EventType.sf_team_join: (sharing) Joined team member's - shared folder (deprecated, no longer logged) - :ivar SfTeamJoinFromOobLinkType EventType.sf_team_join_from_oob_link: - (sharing) Joined team member's shared folder from link (deprecated, no - longer logged) - :ivar SfTeamUninviteType EventType.sf_team_uninvite: (sharing) Unshared - folder with team member (deprecated, replaced by 'Removed invitee from - shared file/folder before invite was accepted') - :ivar SharedContentAddInviteesType EventType.shared_content_add_invitees: - (sharing) Invited user to Dropbox and added them to shared file/folder - :ivar SharedContentAddLinkExpiryType - EventType.shared_content_add_link_expiry: (sharing) Added expiration - date to link for shared file/folder - :ivar SharedContentAddLinkPasswordType - EventType.shared_content_add_link_password: (sharing) Added password to - link for shared file/folder - :ivar SharedContentAddMemberType EventType.shared_content_add_member: - (sharing) Added users and/or groups to shared file/folder - :ivar SharedContentChangeDownloadsPolicyType - EventType.shared_content_change_downloads_policy: (sharing) Changed - whether members can download shared file/folder - :ivar SharedContentChangeInviteeRoleType - EventType.shared_content_change_invitee_role: (sharing) Changed access - type of invitee to shared file/folder before invite was accepted - :ivar SharedContentChangeLinkAudienceType - EventType.shared_content_change_link_audience: (sharing) Changed link - audience of shared file/folder - :ivar SharedContentChangeLinkExpiryType - EventType.shared_content_change_link_expiry: (sharing) Changed link - expiration of shared file/folder - :ivar SharedContentChangeLinkPasswordType - EventType.shared_content_change_link_password: (sharing) Changed link - password of shared file/folder - :ivar SharedContentChangeMemberRoleType - EventType.shared_content_change_member_role: (sharing) Changed access - type of shared file/folder member - :ivar SharedContentChangeViewerInfoPolicyType - EventType.shared_content_change_viewer_info_policy: (sharing) Changed - whether members can see who viewed shared file/folder - :ivar SharedContentClaimInvitationType - EventType.shared_content_claim_invitation: (sharing) Acquired membership - of shared file/folder by accepting invite - :ivar SharedContentCopyType EventType.shared_content_copy: (sharing) Copied - shared file/folder to own Dropbox - :ivar SharedContentDownloadType EventType.shared_content_download: (sharing) - Downloaded shared file/folder - :ivar SharedContentRelinquishMembershipType - EventType.shared_content_relinquish_membership: (sharing) Left shared - file/folder - :ivar SharedContentRemoveInviteesType - EventType.shared_content_remove_invitees: (sharing) Removed invitee from - shared file/folder before invite was accepted - :ivar SharedContentRemoveLinkExpiryType - EventType.shared_content_remove_link_expiry: (sharing) Removed link - expiration date of shared file/folder - :ivar SharedContentRemoveLinkPasswordType - EventType.shared_content_remove_link_password: (sharing) Removed link - password of shared file/folder - :ivar SharedContentRemoveMemberType EventType.shared_content_remove_member: - (sharing) Removed user/group from shared file/folder - :ivar SharedContentRequestAccessType - EventType.shared_content_request_access: (sharing) Requested access to - shared file/folder - :ivar SharedContentUnshareType EventType.shared_content_unshare: (sharing) - Unshared file/folder by clearing membership and turning off link - :ivar SharedContentViewType EventType.shared_content_view: (sharing) - Previewed shared file/folder - :ivar SharedFolderChangeLinkPolicyType - EventType.shared_folder_change_link_policy: (sharing) Changed who can - access shared folder via link - :ivar SharedFolderChangeMembersInheritancePolicyType - EventType.shared_folder_change_members_inheritance_policy: (sharing) - Changed whether shared folder inherits members from parent folder - :ivar SharedFolderChangeMembersManagementPolicyType - EventType.shared_folder_change_members_management_policy: (sharing) - Changed who can add/remove members of shared folder - :ivar SharedFolderChangeMembersPolicyType - EventType.shared_folder_change_members_policy: (sharing) Changed who can - become member of shared folder - :ivar SharedFolderCreateType EventType.shared_folder_create: (sharing) - Created shared folder - :ivar SharedFolderDeclineInvitationType - EventType.shared_folder_decline_invitation: (sharing) Declined team - member's invite to shared folder - :ivar SharedFolderMountType EventType.shared_folder_mount: (sharing) Added - shared folder to own Dropbox - :ivar SharedFolderNestType EventType.shared_folder_nest: (sharing) Changed - parent of shared folder - :ivar SharedFolderTransferOwnershipType - EventType.shared_folder_transfer_ownership: (sharing) Transferred - ownership of shared folder to another member - :ivar SharedFolderUnmountType EventType.shared_folder_unmount: (sharing) - Deleted shared folder from Dropbox - :ivar SharedLinkAddExpiryType EventType.shared_link_add_expiry: (sharing) - Added shared link expiration date - :ivar SharedLinkChangeExpiryType EventType.shared_link_change_expiry: - (sharing) Changed shared link expiration date - :ivar SharedLinkChangeVisibilityType - EventType.shared_link_change_visibility: (sharing) Changed visibility of - shared link - :ivar SharedLinkCopyType EventType.shared_link_copy: (sharing) Added - file/folder to Dropbox from shared link - :ivar SharedLinkCreateType EventType.shared_link_create: (sharing) Created - shared link - :ivar SharedLinkDisableType EventType.shared_link_disable: (sharing) Removed - shared link - :ivar SharedLinkDownloadType EventType.shared_link_download: (sharing) - Downloaded file/folder from shared link - :ivar SharedLinkRemoveExpiryType EventType.shared_link_remove_expiry: - (sharing) Removed shared link expiration date - :ivar SharedLinkShareType EventType.shared_link_share: (sharing) Added - members as audience of shared link - :ivar SharedLinkViewType EventType.shared_link_view: (sharing) Opened shared - link - :ivar SharedNoteOpenedType EventType.shared_note_opened: (sharing) Opened - shared Paper doc (deprecated, no longer logged) - :ivar ShmodelGroupShareType EventType.shmodel_group_share: (sharing) Shared - link with group (deprecated, no longer logged) - :ivar ShowcaseAccessGrantedType EventType.showcase_access_granted: - (showcase) Granted access to showcase - :ivar ShowcaseAddMemberType EventType.showcase_add_member: (showcase) Added - member to showcase - :ivar ShowcaseArchivedType EventType.showcase_archived: (showcase) Archived - showcase - :ivar ShowcaseCreatedType EventType.showcase_created: (showcase) Created - showcase - :ivar ShowcaseDeleteCommentType EventType.showcase_delete_comment: - (showcase) Deleted showcase comment - :ivar ShowcaseEditedType EventType.showcase_edited: (showcase) Edited - showcase - :ivar ShowcaseEditCommentType EventType.showcase_edit_comment: (showcase) - Edited showcase comment - :ivar ShowcaseFileAddedType EventType.showcase_file_added: (showcase) Added - file to showcase - :ivar ShowcaseFileDownloadType EventType.showcase_file_download: (showcase) - Downloaded file from showcase - :ivar ShowcaseFileRemovedType EventType.showcase_file_removed: (showcase) - Removed file from showcase - :ivar ShowcaseFileViewType EventType.showcase_file_view: (showcase) Viewed - file in showcase - :ivar ShowcasePermanentlyDeletedType EventType.showcase_permanently_deleted: - (showcase) Permanently deleted showcase - :ivar ShowcasePostCommentType EventType.showcase_post_comment: (showcase) - Added showcase comment - :ivar ShowcaseRemoveMemberType EventType.showcase_remove_member: (showcase) - Removed member from showcase - :ivar ShowcaseRenamedType EventType.showcase_renamed: (showcase) Renamed - showcase - :ivar ShowcaseRequestAccessType EventType.showcase_request_access: - (showcase) Requested access to showcase - :ivar ShowcaseResolveCommentType EventType.showcase_resolve_comment: - (showcase) Resolved showcase comment - :ivar ShowcaseRestoredType EventType.showcase_restored: (showcase) - Unarchived showcase - :ivar ShowcaseTrashedType EventType.showcase_trashed: (showcase) Deleted - showcase - :ivar ShowcaseTrashedDeprecatedType EventType.showcase_trashed_deprecated: - (showcase) Deleted showcase (old version) (deprecated, replaced by - 'Deleted showcase') - :ivar ShowcaseUnresolveCommentType EventType.showcase_unresolve_comment: - (showcase) Unresolved showcase comment - :ivar ShowcaseUntrashedType EventType.showcase_untrashed: (showcase) - Restored showcase - :ivar ShowcaseUntrashedDeprecatedType - EventType.showcase_untrashed_deprecated: (showcase) Restored showcase - (old version) (deprecated, replaced by 'Restored showcase') - :ivar ShowcaseViewType EventType.showcase_view: (showcase) Viewed showcase - :ivar SsoAddCertType EventType.sso_add_cert: (sso) Added X.509 certificate - for SSO - :ivar SsoAddLoginUrlType EventType.sso_add_login_url: (sso) Added sign-in - URL for SSO - :ivar SsoAddLogoutUrlType EventType.sso_add_logout_url: (sso) Added sign-out - URL for SSO - :ivar SsoChangeCertType EventType.sso_change_cert: (sso) Changed X.509 - certificate for SSO - :ivar SsoChangeLoginUrlType EventType.sso_change_login_url: (sso) Changed - sign-in URL for SSO - :ivar SsoChangeLogoutUrlType EventType.sso_change_logout_url: (sso) Changed - sign-out URL for SSO - :ivar SsoChangeSamlIdentityModeType EventType.sso_change_saml_identity_mode: - (sso) Changed SAML identity mode for SSO - :ivar SsoRemoveCertType EventType.sso_remove_cert: (sso) Removed X.509 - certificate for SSO - :ivar SsoRemoveLoginUrlType EventType.sso_remove_login_url: (sso) Removed - sign-in URL for SSO - :ivar SsoRemoveLogoutUrlType EventType.sso_remove_logout_url: (sso) Removed - sign-out URL for SSO - :ivar TeamFolderChangeStatusType EventType.team_folder_change_status: - (team_folders) Changed archival status of team folder - :ivar TeamFolderCreateType EventType.team_folder_create: (team_folders) - Created team folder in active status - :ivar TeamFolderDowngradeType EventType.team_folder_downgrade: - (team_folders) Downgraded team folder to regular shared folder - :ivar TeamFolderPermanentlyDeleteType - EventType.team_folder_permanently_delete: (team_folders) Permanently - deleted archived team folder - :ivar TeamFolderRenameType EventType.team_folder_rename: (team_folders) - Renamed active/archived team folder - :ivar TeamSelectiveSyncSettingsChangedType - EventType.team_selective_sync_settings_changed: (team_folders) Changed - sync default - :ivar AccountCaptureChangePolicyType - EventType.account_capture_change_policy: (team_policies) Changed account - capture setting on team domain - :ivar AllowDownloadDisabledType EventType.allow_download_disabled: - (team_policies) Disabled downloads (deprecated, no longer logged) - :ivar AllowDownloadEnabledType EventType.allow_download_enabled: - (team_policies) Enabled downloads (deprecated, no longer logged) - :ivar CameraUploadsPolicyChangedType - EventType.camera_uploads_policy_changed: (team_policies) Changed camera - uploads setting for team - :ivar DataPlacementRestrictionChangePolicyType - EventType.data_placement_restriction_change_policy: (team_policies) Set - restrictions on data center locations where team data resides - :ivar DataPlacementRestrictionSatisfyPolicyType - EventType.data_placement_restriction_satisfy_policy: (team_policies) - Completed restrictions on data center locations where team data resides - :ivar DeviceApprovalsChangeDesktopPolicyType - EventType.device_approvals_change_desktop_policy: (team_policies) - Set/removed limit on number of computers member can link to team Dropbox - account - :ivar DeviceApprovalsChangeMobilePolicyType - EventType.device_approvals_change_mobile_policy: (team_policies) - Set/removed limit on number of mobile devices member can link to team - Dropbox account - :ivar DeviceApprovalsChangeOverageActionType - EventType.device_approvals_change_overage_action: (team_policies) - Changed device approvals setting when member is over limit - :ivar DeviceApprovalsChangeUnlinkActionType - EventType.device_approvals_change_unlink_action: (team_policies) Changed - device approvals setting when member unlinks approved device - :ivar DirectoryRestrictionsAddMembersType - EventType.directory_restrictions_add_members: (team_policies) Added - members to directory restrictions list - :ivar DirectoryRestrictionsRemoveMembersType - EventType.directory_restrictions_remove_members: (team_policies) Removed - members from directory restrictions list - :ivar EmmAddExceptionType EventType.emm_add_exception: (team_policies) Added - members to EMM exception list - :ivar EmmChangePolicyType EventType.emm_change_policy: (team_policies) - Enabled/disabled enterprise mobility management for members - :ivar EmmRemoveExceptionType EventType.emm_remove_exception: (team_policies) - Removed members from EMM exception list - :ivar ExtendedVersionHistoryChangePolicyType - EventType.extended_version_history_change_policy: (team_policies) - Accepted/opted out of extended version history - :ivar FileCommentsChangePolicyType EventType.file_comments_change_policy: - (team_policies) Enabled/disabled commenting on team files - :ivar FileRequestsChangePolicyType EventType.file_requests_change_policy: - (team_policies) Enabled/disabled file requests - :ivar FileRequestsEmailsEnabledType EventType.file_requests_emails_enabled: - (team_policies) Enabled file request emails for everyone (deprecated, no - longer logged) - :ivar FileRequestsEmailsRestrictedToTeamOnlyType - EventType.file_requests_emails_restricted_to_team_only: (team_policies) - Enabled file request emails for team (deprecated, no longer logged) - :ivar GoogleSsoChangePolicyType EventType.google_sso_change_policy: - (team_policies) Enabled/disabled Google single sign-on for team - :ivar GroupUserManagementChangePolicyType - EventType.group_user_management_change_policy: (team_policies) Changed - who can create groups - :ivar IntegrationPolicyChangedType EventType.integration_policy_changed: - (team_policies) Changed integration policy for team - :ivar MemberRequestsChangePolicyType - EventType.member_requests_change_policy: (team_policies) Changed whether - users can find team when not invited - :ivar MemberSpaceLimitsAddExceptionType - EventType.member_space_limits_add_exception: (team_policies) Added - members to member space limit exception list - :ivar MemberSpaceLimitsChangeCapsTypePolicyType - EventType.member_space_limits_change_caps_type_policy: (team_policies) - Changed member space limit type for team - :ivar MemberSpaceLimitsChangePolicyType - EventType.member_space_limits_change_policy: (team_policies) Changed - team default member space limit - :ivar MemberSpaceLimitsRemoveExceptionType - EventType.member_space_limits_remove_exception: (team_policies) Removed - members from member space limit exception list - :ivar MemberSuggestionsChangePolicyType - EventType.member_suggestions_change_policy: (team_policies) - Enabled/disabled option for team members to suggest people to add to - team - :ivar MicrosoftOfficeAddinChangePolicyType - EventType.microsoft_office_addin_change_policy: (team_policies) - Enabled/disabled Microsoft Office add-in - :ivar NetworkControlChangePolicyType - EventType.network_control_change_policy: (team_policies) - Enabled/disabled network control - :ivar PaperChangeDeploymentPolicyType - EventType.paper_change_deployment_policy: (team_policies) Changed - whether Dropbox Paper, when enabled, is deployed to all members or to - specific members - :ivar PaperChangeMemberLinkPolicyType - EventType.paper_change_member_link_policy: (team_policies) Changed - whether non-members can view Paper docs with link (deprecated, no longer + + Only call this if :meth:`is_paper_external_view_forbid` is true. + + :rtype: PaperExternalViewForbidType + """ + if not self.is_paper_external_view_forbid(): + raise AttributeError("tag 'paper_external_view_forbid' not set") + return self._value + + def get_paper_folder_change_subscription(self): + """ + (paper) Followed/unfollowed Paper folder + + Only call this if :meth:`is_paper_folder_change_subscription` is true. + + :rtype: PaperFolderChangeSubscriptionType + """ + if not self.is_paper_folder_change_subscription(): + raise AttributeError("tag 'paper_folder_change_subscription' not set") + return self._value + + def get_paper_folder_deleted(self): + """ + (paper) Archived Paper folder (deprecated, no longer logged) + + Only call this if :meth:`is_paper_folder_deleted` is true. + + :rtype: PaperFolderDeletedType + """ + if not self.is_paper_folder_deleted(): + raise AttributeError("tag 'paper_folder_deleted' not set") + return self._value + + def get_paper_folder_followed(self): + """ + (paper) Followed Paper folder (deprecated, replaced by + 'Followed/unfollowed Paper folder') + + Only call this if :meth:`is_paper_folder_followed` is true. + + :rtype: PaperFolderFollowedType + """ + if not self.is_paper_folder_followed(): + raise AttributeError("tag 'paper_folder_followed' not set") + return self._value + + def get_paper_folder_team_invite(self): + """ + (paper) Shared Paper folder with users and/or groups (deprecated, no + longer logged) + + Only call this if :meth:`is_paper_folder_team_invite` is true. + + :rtype: PaperFolderTeamInviteType + """ + if not self.is_paper_folder_team_invite(): + raise AttributeError("tag 'paper_folder_team_invite' not set") + return self._value + + def get_paper_published_link_change_permission(self): + """ + (paper) Changed permissions for published doc + + Only call this if :meth:`is_paper_published_link_change_permission` is true. + + :rtype: PaperPublishedLinkChangePermissionType + """ + if not self.is_paper_published_link_change_permission(): + raise AttributeError("tag 'paper_published_link_change_permission' not set") + return self._value + + def get_paper_published_link_create(self): + """ + (paper) Published doc + + Only call this if :meth:`is_paper_published_link_create` is true. + + :rtype: PaperPublishedLinkCreateType + """ + if not self.is_paper_published_link_create(): + raise AttributeError("tag 'paper_published_link_create' not set") + return self._value + + def get_paper_published_link_disabled(self): + """ + (paper) Unpublished doc + + Only call this if :meth:`is_paper_published_link_disabled` is true. + + :rtype: PaperPublishedLinkDisabledType + """ + if not self.is_paper_published_link_disabled(): + raise AttributeError("tag 'paper_published_link_disabled' not set") + return self._value + + def get_paper_published_link_view(self): + """ + (paper) Viewed published doc + + Only call this if :meth:`is_paper_published_link_view` is true. + + :rtype: PaperPublishedLinkViewType + """ + if not self.is_paper_published_link_view(): + raise AttributeError("tag 'paper_published_link_view' not set") + return self._value + + def get_password_change(self): + """ + (passwords) Changed password + + Only call this if :meth:`is_password_change` is true. + + :rtype: PasswordChangeType + """ + if not self.is_password_change(): + raise AttributeError("tag 'password_change' not set") + return self._value + + def get_password_reset(self): + """ + (passwords) Reset password + + Only call this if :meth:`is_password_reset` is true. + + :rtype: PasswordResetType + """ + if not self.is_password_reset(): + raise AttributeError("tag 'password_reset' not set") + return self._value + + def get_password_reset_all(self): + """ + (passwords) Reset all team member passwords + + Only call this if :meth:`is_password_reset_all` is true. + + :rtype: PasswordResetAllType + """ + if not self.is_password_reset_all(): + raise AttributeError("tag 'password_reset_all' not set") + return self._value + + def get_emm_create_exceptions_report(self): + """ + (reports) Created EMM-excluded users report + + Only call this if :meth:`is_emm_create_exceptions_report` is true. + + :rtype: EmmCreateExceptionsReportType + """ + if not self.is_emm_create_exceptions_report(): + raise AttributeError("tag 'emm_create_exceptions_report' not set") + return self._value + + def get_emm_create_usage_report(self): + """ + (reports) Created EMM mobile app usage report + + Only call this if :meth:`is_emm_create_usage_report` is true. + + :rtype: EmmCreateUsageReportType + """ + if not self.is_emm_create_usage_report(): + raise AttributeError("tag 'emm_create_usage_report' not set") + return self._value + + def get_export_members_report(self): + """ + (reports) Created member data report + + Only call this if :meth:`is_export_members_report` is true. + + :rtype: ExportMembersReportType + """ + if not self.is_export_members_report(): + raise AttributeError("tag 'export_members_report' not set") + return self._value + + def get_export_members_report_fail(self): + """ + (reports) Failed to create members data report + + Only call this if :meth:`is_export_members_report_fail` is true. + + :rtype: ExportMembersReportFailType + """ + if not self.is_export_members_report_fail(): + raise AttributeError("tag 'export_members_report_fail' not set") + return self._value + + def get_no_expiration_link_gen_create_report(self): + """ + (reports) Report created: Links created with no expiration + + Only call this if :meth:`is_no_expiration_link_gen_create_report` is true. + + :rtype: NoExpirationLinkGenCreateReportType + """ + if not self.is_no_expiration_link_gen_create_report(): + raise AttributeError("tag 'no_expiration_link_gen_create_report' not set") + return self._value + + def get_no_expiration_link_gen_report_failed(self): + """ + (reports) Couldn't create report: Links created with no expiration + + Only call this if :meth:`is_no_expiration_link_gen_report_failed` is true. + + :rtype: NoExpirationLinkGenReportFailedType + """ + if not self.is_no_expiration_link_gen_report_failed(): + raise AttributeError("tag 'no_expiration_link_gen_report_failed' not set") + return self._value + + def get_no_password_link_gen_create_report(self): + """ + (reports) Report created: Links created without passwords + + Only call this if :meth:`is_no_password_link_gen_create_report` is true. + + :rtype: NoPasswordLinkGenCreateReportType + """ + if not self.is_no_password_link_gen_create_report(): + raise AttributeError("tag 'no_password_link_gen_create_report' not set") + return self._value + + def get_no_password_link_gen_report_failed(self): + """ + (reports) Couldn't create report: Links created without passwords + + Only call this if :meth:`is_no_password_link_gen_report_failed` is true. + + :rtype: NoPasswordLinkGenReportFailedType + """ + if not self.is_no_password_link_gen_report_failed(): + raise AttributeError("tag 'no_password_link_gen_report_failed' not set") + return self._value + + def get_no_password_link_view_create_report(self): + """ + (reports) Report created: Views of links without passwords + + Only call this if :meth:`is_no_password_link_view_create_report` is true. + + :rtype: NoPasswordLinkViewCreateReportType + """ + if not self.is_no_password_link_view_create_report(): + raise AttributeError("tag 'no_password_link_view_create_report' not set") + return self._value + + def get_no_password_link_view_report_failed(self): + """ + (reports) Couldn't create report: Views of links without passwords + + Only call this if :meth:`is_no_password_link_view_report_failed` is true. + + :rtype: NoPasswordLinkViewReportFailedType + """ + if not self.is_no_password_link_view_report_failed(): + raise AttributeError("tag 'no_password_link_view_report_failed' not set") + return self._value + + def get_outdated_link_view_create_report(self): + """ + (reports) Report created: Views of old links + + Only call this if :meth:`is_outdated_link_view_create_report` is true. + + :rtype: OutdatedLinkViewCreateReportType + """ + if not self.is_outdated_link_view_create_report(): + raise AttributeError("tag 'outdated_link_view_create_report' not set") + return self._value + + def get_outdated_link_view_report_failed(self): + """ + (reports) Couldn't create report: Views of old links + + Only call this if :meth:`is_outdated_link_view_report_failed` is true. + + :rtype: OutdatedLinkViewReportFailedType + """ + if not self.is_outdated_link_view_report_failed(): + raise AttributeError("tag 'outdated_link_view_report_failed' not set") + return self._value + + def get_paper_admin_export_start(self): + """ + (reports) Exported all team Paper docs + + Only call this if :meth:`is_paper_admin_export_start` is true. + + :rtype: PaperAdminExportStartType + """ + if not self.is_paper_admin_export_start(): + raise AttributeError("tag 'paper_admin_export_start' not set") + return self._value + + def get_smart_sync_create_admin_privilege_report(self): + """ + (reports) Created Smart Sync non-admin devices report + + Only call this if :meth:`is_smart_sync_create_admin_privilege_report` is true. + + :rtype: SmartSyncCreateAdminPrivilegeReportType + """ + if not self.is_smart_sync_create_admin_privilege_report(): + raise AttributeError("tag 'smart_sync_create_admin_privilege_report' not set") + return self._value + + def get_team_activity_create_report(self): + """ + (reports) Created team activity report + + Only call this if :meth:`is_team_activity_create_report` is true. + + :rtype: TeamActivityCreateReportType + """ + if not self.is_team_activity_create_report(): + raise AttributeError("tag 'team_activity_create_report' not set") + return self._value + + def get_team_activity_create_report_fail(self): + """ + (reports) Couldn't generate team activity report + + Only call this if :meth:`is_team_activity_create_report_fail` is true. + + :rtype: TeamActivityCreateReportFailType + """ + if not self.is_team_activity_create_report_fail(): + raise AttributeError("tag 'team_activity_create_report_fail' not set") + return self._value + + def get_collection_share(self): + """ + (sharing) Shared album + + Only call this if :meth:`is_collection_share` is true. + + :rtype: CollectionShareType + """ + if not self.is_collection_share(): + raise AttributeError("tag 'collection_share' not set") + return self._value + + def get_file_transfers_file_add(self): + """ + (sharing) Transfer files added + + Only call this if :meth:`is_file_transfers_file_add` is true. + + :rtype: FileTransfersFileAddType + """ + if not self.is_file_transfers_file_add(): + raise AttributeError("tag 'file_transfers_file_add' not set") + return self._value + + def get_file_transfers_transfer_delete(self): + """ + (sharing) Deleted transfer + + Only call this if :meth:`is_file_transfers_transfer_delete` is true. + + :rtype: FileTransfersTransferDeleteType + """ + if not self.is_file_transfers_transfer_delete(): + raise AttributeError("tag 'file_transfers_transfer_delete' not set") + return self._value + + def get_file_transfers_transfer_download(self): + """ + (sharing) Transfer downloaded + + Only call this if :meth:`is_file_transfers_transfer_download` is true. + + :rtype: FileTransfersTransferDownloadType + """ + if not self.is_file_transfers_transfer_download(): + raise AttributeError("tag 'file_transfers_transfer_download' not set") + return self._value + + def get_file_transfers_transfer_send(self): + """ + (sharing) Sent transfer + + Only call this if :meth:`is_file_transfers_transfer_send` is true. + + :rtype: FileTransfersTransferSendType + """ + if not self.is_file_transfers_transfer_send(): + raise AttributeError("tag 'file_transfers_transfer_send' not set") + return self._value + + def get_file_transfers_transfer_view(self): + """ + (sharing) Viewed transfer + + Only call this if :meth:`is_file_transfers_transfer_view` is true. + + :rtype: FileTransfersTransferViewType + """ + if not self.is_file_transfers_transfer_view(): + raise AttributeError("tag 'file_transfers_transfer_view' not set") + return self._value + + def get_note_acl_invite_only(self): + """ + (sharing) Changed Paper doc to invite-only (deprecated, no longer logged) - :ivar PaperChangeMemberPolicyType EventType.paper_change_member_policy: - (team_policies) Changed whether members can share Paper docs outside - team, and if docs are accessible only by team members or anyone by - default - :ivar PaperChangePolicyType EventType.paper_change_policy: (team_policies) - Enabled/disabled Dropbox Paper for team - :ivar PaperDefaultFolderPolicyChangedType - EventType.paper_default_folder_policy_changed: (team_policies) Changed - Paper Default Folder Policy setting for team - :ivar PaperDesktopPolicyChangedType EventType.paper_desktop_policy_changed: - (team_policies) Enabled/disabled Paper Desktop for team - :ivar PaperEnabledUsersGroupAdditionType - EventType.paper_enabled_users_group_addition: (team_policies) Added - users to Paper-enabled users list - :ivar PaperEnabledUsersGroupRemovalType - EventType.paper_enabled_users_group_removal: (team_policies) Removed - users from Paper-enabled users list - :ivar PermanentDeleteChangePolicyType - EventType.permanent_delete_change_policy: (team_policies) - Enabled/disabled ability of team members to permanently delete content - :ivar ResellerSupportChangePolicyType - EventType.reseller_support_change_policy: (team_policies) - Enabled/disabled reseller support - :ivar SharingChangeFolderJoinPolicyType - EventType.sharing_change_folder_join_policy: (team_policies) Changed - whether team members can join shared folders owned outside team - :ivar SharingChangeLinkPolicyType EventType.sharing_change_link_policy: - (team_policies) Changed whether members can share links outside team, - and if links are accessible only by team members or anyone by default - :ivar SharingChangeMemberPolicyType EventType.sharing_change_member_policy: - (team_policies) Changed whether members can share files/folders outside - team - :ivar ShowcaseChangeDownloadPolicyType - EventType.showcase_change_download_policy: (team_policies) - Enabled/disabled downloading files from Dropbox Showcase for team - :ivar ShowcaseChangeEnabledPolicyType - EventType.showcase_change_enabled_policy: (team_policies) - Enabled/disabled Dropbox Showcase for team - :ivar ShowcaseChangeExternalSharingPolicyType - EventType.showcase_change_external_sharing_policy: (team_policies) - Enabled/disabled sharing Dropbox Showcase externally for team - :ivar SmartSyncChangePolicyType EventType.smart_sync_change_policy: - (team_policies) Changed default Smart Sync setting for team members - :ivar SmartSyncNotOptOutType EventType.smart_sync_not_opt_out: - (team_policies) Opted team into Smart Sync - :ivar SmartSyncOptOutType EventType.smart_sync_opt_out: (team_policies) - Opted team out of Smart Sync - :ivar SsoChangePolicyType EventType.sso_change_policy: (team_policies) - Changed single sign-on setting for team - :ivar TeamExtensionsPolicyChangedType - EventType.team_extensions_policy_changed: (team_policies) Changed App - Integrations setting for team - :ivar TeamSelectiveSyncPolicyChangedType - EventType.team_selective_sync_policy_changed: (team_policies) - Enabled/disabled Team Selective Sync for team - :ivar TfaChangePolicyType EventType.tfa_change_policy: (team_policies) - Changed two-step verification setting for team - :ivar TwoAccountChangePolicyType EventType.two_account_change_policy: - (team_policies) Enabled/disabled option for members to link personal - Dropbox account and team account to same computer - :ivar ViewerInfoPolicyChangedType EventType.viewer_info_policy_changed: - (team_policies) Changed team policy for viewer info - :ivar WebSessionsChangeFixedLengthPolicyType - EventType.web_sessions_change_fixed_length_policy: (team_policies) - Changed how long members can stay signed in to Dropbox.com - :ivar WebSessionsChangeIdleLengthPolicyType - EventType.web_sessions_change_idle_length_policy: (team_policies) - Changed how long team members can be idle while signed in to Dropbox.com - :ivar TeamMergeFromType EventType.team_merge_from: (team_profile) Merged - another team into this team - :ivar TeamMergeToType EventType.team_merge_to: (team_profile) Merged this - team into another team - :ivar TeamProfileAddLogoType EventType.team_profile_add_logo: (team_profile) - Added team logo to display on shared link headers - :ivar TeamProfileChangeDefaultLanguageType - EventType.team_profile_change_default_language: (team_profile) Changed - default language for team - :ivar TeamProfileChangeLogoType EventType.team_profile_change_logo: - (team_profile) Changed team logo displayed on shared link headers - :ivar TeamProfileChangeNameType EventType.team_profile_change_name: - (team_profile) Changed team name - :ivar TeamProfileRemoveLogoType EventType.team_profile_remove_logo: - (team_profile) Removed team logo displayed on shared link headers - :ivar TfaAddBackupPhoneType EventType.tfa_add_backup_phone: (tfa) Added - backup phone for two-step verification - :ivar TfaAddSecurityKeyType EventType.tfa_add_security_key: (tfa) Added - security key for two-step verification - :ivar TfaChangeBackupPhoneType EventType.tfa_change_backup_phone: (tfa) - Changed backup phone for two-step verification - :ivar TfaChangeStatusType EventType.tfa_change_status: (tfa) - Enabled/disabled/changed two-step verification setting - :ivar TfaRemoveBackupPhoneType EventType.tfa_remove_backup_phone: (tfa) - Removed backup phone for two-step verification - :ivar TfaRemoveSecurityKeyType EventType.tfa_remove_security_key: (tfa) - Removed security key for two-step verification - :ivar TfaResetType EventType.tfa_reset: (tfa) Reset two-step verification - for team member - :ivar GuestAdminChangeStatusType EventType.guest_admin_change_status: - (trusted_teams) Changed guest team admin status - :ivar TeamMergeRequestAcceptedType EventType.team_merge_request_accepted: - (trusted_teams) Accepted a team merge request - :ivar TeamMergeRequestAcceptedShownToPrimaryTeamType - EventType.team_merge_request_accepted_shown_to_primary_team: - (trusted_teams) Accepted a team merge request (deprecated, replaced by - 'Accepted a team merge request') - :ivar TeamMergeRequestAcceptedShownToSecondaryTeamType - EventType.team_merge_request_accepted_shown_to_secondary_team: - (trusted_teams) Accepted a team merge request (deprecated, replaced by - 'Accepted a team merge request') - :ivar TeamMergeRequestAutoCanceledType - EventType.team_merge_request_auto_canceled: (trusted_teams) - Automatically canceled team merge request - :ivar TeamMergeRequestCanceledType EventType.team_merge_request_canceled: - (trusted_teams) Canceled a team merge request - :ivar TeamMergeRequestCanceledShownToPrimaryTeamType - EventType.team_merge_request_canceled_shown_to_primary_team: - (trusted_teams) Canceled a team merge request (deprecated, replaced by - 'Canceled a team merge request') - :ivar TeamMergeRequestCanceledShownToSecondaryTeamType - EventType.team_merge_request_canceled_shown_to_secondary_team: - (trusted_teams) Canceled a team merge request (deprecated, replaced by - 'Canceled a team merge request') - :ivar TeamMergeRequestExpiredType EventType.team_merge_request_expired: - (trusted_teams) Team merge request expired - :ivar TeamMergeRequestExpiredShownToPrimaryTeamType - EventType.team_merge_request_expired_shown_to_primary_team: - (trusted_teams) Team merge request expired (deprecated, replaced by - 'Team merge request expired') - :ivar TeamMergeRequestExpiredShownToSecondaryTeamType - EventType.team_merge_request_expired_shown_to_secondary_team: - (trusted_teams) Team merge request expired (deprecated, replaced by - 'Team merge request expired') - :ivar TeamMergeRequestRejectedShownToPrimaryTeamType - EventType.team_merge_request_rejected_shown_to_primary_team: - (trusted_teams) Rejected a team merge request (deprecated, no longer + + Only call this if :meth:`is_note_acl_invite_only` is true. + + :rtype: NoteAclInviteOnlyType + """ + if not self.is_note_acl_invite_only(): + raise AttributeError("tag 'note_acl_invite_only' not set") + return self._value + + def get_note_acl_link(self): + """ + (sharing) Changed Paper doc to link-accessible (deprecated, no longer + logged) + + Only call this if :meth:`is_note_acl_link` is true. + + :rtype: NoteAclLinkType + """ + if not self.is_note_acl_link(): + raise AttributeError("tag 'note_acl_link' not set") + return self._value + + def get_note_acl_team_link(self): + """ + (sharing) Changed Paper doc to link-accessible for team (deprecated, no + longer logged) + + Only call this if :meth:`is_note_acl_team_link` is true. + + :rtype: NoteAclTeamLinkType + """ + if not self.is_note_acl_team_link(): + raise AttributeError("tag 'note_acl_team_link' not set") + return self._value + + def get_note_shared(self): + """ + (sharing) Shared Paper doc (deprecated, no longer logged) + + Only call this if :meth:`is_note_shared` is true. + + :rtype: NoteSharedType + """ + if not self.is_note_shared(): + raise AttributeError("tag 'note_shared' not set") + return self._value + + def get_note_share_receive(self): + """ + (sharing) Shared received Paper doc (deprecated, no longer logged) + + Only call this if :meth:`is_note_share_receive` is true. + + :rtype: NoteShareReceiveType + """ + if not self.is_note_share_receive(): + raise AttributeError("tag 'note_share_receive' not set") + return self._value + + def get_open_note_shared(self): + """ + (sharing) Opened shared Paper doc (deprecated, no longer logged) + + Only call this if :meth:`is_open_note_shared` is true. + + :rtype: OpenNoteSharedType + """ + if not self.is_open_note_shared(): + raise AttributeError("tag 'open_note_shared' not set") + return self._value + + def get_sf_add_group(self): + """ + (sharing) Added team to shared folder (deprecated, no longer logged) + + Only call this if :meth:`is_sf_add_group` is true. + + :rtype: SfAddGroupType + """ + if not self.is_sf_add_group(): + raise AttributeError("tag 'sf_add_group' not set") + return self._value + + def get_sf_allow_non_members_to_view_shared_links(self): + """ + (sharing) Allowed non-collaborators to view links to files in shared + folder (deprecated, no longer logged) + + Only call this if :meth:`is_sf_allow_non_members_to_view_shared_links` is true. + + :rtype: SfAllowNonMembersToViewSharedLinksType + """ + if not self.is_sf_allow_non_members_to_view_shared_links(): + raise AttributeError("tag 'sf_allow_non_members_to_view_shared_links' not set") + return self._value + + def get_sf_external_invite_warn(self): + """ + (sharing) Set team members to see warning before sharing folders outside + team (deprecated, no longer logged) + + Only call this if :meth:`is_sf_external_invite_warn` is true. + + :rtype: SfExternalInviteWarnType + """ + if not self.is_sf_external_invite_warn(): + raise AttributeError("tag 'sf_external_invite_warn' not set") + return self._value + + def get_sf_fb_invite(self): + """ + (sharing) Invited Facebook users to shared folder (deprecated, no longer logged) - :ivar TeamMergeRequestRejectedShownToSecondaryTeamType - EventType.team_merge_request_rejected_shown_to_secondary_team: - (trusted_teams) Rejected a team merge request (deprecated, no longer + + Only call this if :meth:`is_sf_fb_invite` is true. + + :rtype: SfFbInviteType + """ + if not self.is_sf_fb_invite(): + raise AttributeError("tag 'sf_fb_invite' not set") + return self._value + + def get_sf_fb_invite_change_role(self): + """ + (sharing) Changed Facebook user's role in shared folder (deprecated, no + longer logged) + + Only call this if :meth:`is_sf_fb_invite_change_role` is true. + + :rtype: SfFbInviteChangeRoleType + """ + if not self.is_sf_fb_invite_change_role(): + raise AttributeError("tag 'sf_fb_invite_change_role' not set") + return self._value + + def get_sf_fb_uninvite(self): + """ + (sharing) Uninvited Facebook user from shared folder (deprecated, no + longer logged) + + Only call this if :meth:`is_sf_fb_uninvite` is true. + + :rtype: SfFbUninviteType + """ + if not self.is_sf_fb_uninvite(): + raise AttributeError("tag 'sf_fb_uninvite' not set") + return self._value + + def get_sf_invite_group(self): + """ + (sharing) Invited group to shared folder (deprecated, no longer logged) + + Only call this if :meth:`is_sf_invite_group` is true. + + :rtype: SfInviteGroupType + """ + if not self.is_sf_invite_group(): + raise AttributeError("tag 'sf_invite_group' not set") + return self._value + + def get_sf_team_grant_access(self): + """ + (sharing) Granted access to shared folder (deprecated, no longer logged) + + Only call this if :meth:`is_sf_team_grant_access` is true. + + :rtype: SfTeamGrantAccessType + """ + if not self.is_sf_team_grant_access(): + raise AttributeError("tag 'sf_team_grant_access' not set") + return self._value + + def get_sf_team_invite(self): + """ + (sharing) Invited team members to shared folder (deprecated, replaced by + 'Invited user to Dropbox and added them to shared file/folder') + + Only call this if :meth:`is_sf_team_invite` is true. + + :rtype: SfTeamInviteType + """ + if not self.is_sf_team_invite(): + raise AttributeError("tag 'sf_team_invite' not set") + return self._value + + def get_sf_team_invite_change_role(self): + """ + (sharing) Changed team member's role in shared folder (deprecated, no + longer logged) + + Only call this if :meth:`is_sf_team_invite_change_role` is true. + + :rtype: SfTeamInviteChangeRoleType + """ + if not self.is_sf_team_invite_change_role(): + raise AttributeError("tag 'sf_team_invite_change_role' not set") + return self._value + + def get_sf_team_join(self): + """ + (sharing) Joined team member's shared folder (deprecated, no longer logged) - :ivar TeamMergeRequestReminderType EventType.team_merge_request_reminder: - (trusted_teams) Sent a team merge request reminder - :ivar TeamMergeRequestReminderShownToPrimaryTeamType - EventType.team_merge_request_reminder_shown_to_primary_team: - (trusted_teams) Sent a team merge request reminder (deprecated, replaced - by 'Sent a team merge request reminder') - :ivar TeamMergeRequestReminderShownToSecondaryTeamType - EventType.team_merge_request_reminder_shown_to_secondary_team: - (trusted_teams) Sent a team merge request reminder (deprecated, replaced - by 'Sent a team merge request reminder') - :ivar TeamMergeRequestRevokedType EventType.team_merge_request_revoked: - (trusted_teams) Canceled the team merge - :ivar TeamMergeRequestSentShownToPrimaryTeamType - EventType.team_merge_request_sent_shown_to_primary_team: (trusted_teams) - Requested to merge their Dropbox team into yours - :ivar TeamMergeRequestSentShownToSecondaryTeamType - EventType.team_merge_request_sent_shown_to_secondary_team: - (trusted_teams) Requested to merge your team into another Dropbox team - """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + Only call this if :meth:`is_sf_team_join` is true. + + :rtype: SfTeamJoinType + """ + if not self.is_sf_team_join(): + raise AttributeError("tag 'sf_team_join' not set") + return self._value + + def get_sf_team_join_from_oob_link(self): + """ + (sharing) Joined team member's shared folder from link (deprecated, no + longer logged) + + Only call this if :meth:`is_sf_team_join_from_oob_link` is true. + + :rtype: SfTeamJoinFromOobLinkType + """ + if not self.is_sf_team_join_from_oob_link(): + raise AttributeError("tag 'sf_team_join_from_oob_link' not set") + return self._value + + def get_sf_team_uninvite(self): + """ + (sharing) Unshared folder with team member (deprecated, replaced by + 'Removed invitee from shared file/folder before invite was accepted') + + Only call this if :meth:`is_sf_team_uninvite` is true. + + :rtype: SfTeamUninviteType + """ + if not self.is_sf_team_uninvite(): + raise AttributeError("tag 'sf_team_uninvite' not set") + return self._value + + def get_shared_content_add_invitees(self): + """ + (sharing) Invited user to Dropbox and added them to shared file/folder + + Only call this if :meth:`is_shared_content_add_invitees` is true. + + :rtype: SharedContentAddInviteesType + """ + if not self.is_shared_content_add_invitees(): + raise AttributeError("tag 'shared_content_add_invitees' not set") + return self._value + + def get_shared_content_add_link_expiry(self): + """ + (sharing) Added expiration date to link for shared file/folder + (deprecated, no longer logged) + + Only call this if :meth:`is_shared_content_add_link_expiry` is true. + + :rtype: SharedContentAddLinkExpiryType + """ + if not self.is_shared_content_add_link_expiry(): + raise AttributeError("tag 'shared_content_add_link_expiry' not set") + return self._value + + def get_shared_content_add_link_password(self): + """ + (sharing) Added password to link for shared file/folder (deprecated, no + longer logged) + + Only call this if :meth:`is_shared_content_add_link_password` is true. + + :rtype: SharedContentAddLinkPasswordType + """ + if not self.is_shared_content_add_link_password(): + raise AttributeError("tag 'shared_content_add_link_password' not set") + return self._value + + def get_shared_content_add_member(self): + """ + (sharing) Added users and/or groups to shared file/folder + + Only call this if :meth:`is_shared_content_add_member` is true. + + :rtype: SharedContentAddMemberType + """ + if not self.is_shared_content_add_member(): + raise AttributeError("tag 'shared_content_add_member' not set") + return self._value + + def get_shared_content_change_downloads_policy(self): + """ + (sharing) Changed whether members can download shared file/folder + (deprecated, no longer logged) + + Only call this if :meth:`is_shared_content_change_downloads_policy` is true. + + :rtype: SharedContentChangeDownloadsPolicyType + """ + if not self.is_shared_content_change_downloads_policy(): + raise AttributeError("tag 'shared_content_change_downloads_policy' not set") + return self._value + + def get_shared_content_change_invitee_role(self): + """ + (sharing) Changed access type of invitee to shared file/folder before + invite was accepted + + Only call this if :meth:`is_shared_content_change_invitee_role` is true. + + :rtype: SharedContentChangeInviteeRoleType + """ + if not self.is_shared_content_change_invitee_role(): + raise AttributeError("tag 'shared_content_change_invitee_role' not set") + return self._value + + def get_shared_content_change_link_audience(self): + """ + (sharing) Changed link audience of shared file/folder (deprecated, no + longer logged) + + Only call this if :meth:`is_shared_content_change_link_audience` is true. + + :rtype: SharedContentChangeLinkAudienceType + """ + if not self.is_shared_content_change_link_audience(): + raise AttributeError("tag 'shared_content_change_link_audience' not set") + return self._value + + def get_shared_content_change_link_expiry(self): + """ + (sharing) Changed link expiration of shared file/folder (deprecated, no + longer logged) + + Only call this if :meth:`is_shared_content_change_link_expiry` is true. + + :rtype: SharedContentChangeLinkExpiryType + """ + if not self.is_shared_content_change_link_expiry(): + raise AttributeError("tag 'shared_content_change_link_expiry' not set") + return self._value + + def get_shared_content_change_link_password(self): + """ + (sharing) Changed link password of shared file/folder (deprecated, no + longer logged) + + Only call this if :meth:`is_shared_content_change_link_password` is true. + + :rtype: SharedContentChangeLinkPasswordType + """ + if not self.is_shared_content_change_link_password(): + raise AttributeError("tag 'shared_content_change_link_password' not set") + return self._value + + def get_shared_content_change_member_role(self): + """ + (sharing) Changed access type of shared file/folder member + + Only call this if :meth:`is_shared_content_change_member_role` is true. + + :rtype: SharedContentChangeMemberRoleType + """ + if not self.is_shared_content_change_member_role(): + raise AttributeError("tag 'shared_content_change_member_role' not set") + return self._value + + def get_shared_content_change_viewer_info_policy(self): + """ + (sharing) Changed whether members can see who viewed shared file/folder + + Only call this if :meth:`is_shared_content_change_viewer_info_policy` is true. + + :rtype: SharedContentChangeViewerInfoPolicyType + """ + if not self.is_shared_content_change_viewer_info_policy(): + raise AttributeError("tag 'shared_content_change_viewer_info_policy' not set") + return self._value + + def get_shared_content_claim_invitation(self): + """ + (sharing) Acquired membership of shared file/folder by accepting invite + + Only call this if :meth:`is_shared_content_claim_invitation` is true. + + :rtype: SharedContentClaimInvitationType + """ + if not self.is_shared_content_claim_invitation(): + raise AttributeError("tag 'shared_content_claim_invitation' not set") + return self._value + + def get_shared_content_copy(self): + """ + (sharing) Copied shared file/folder to own Dropbox + + Only call this if :meth:`is_shared_content_copy` is true. + + :rtype: SharedContentCopyType + """ + if not self.is_shared_content_copy(): + raise AttributeError("tag 'shared_content_copy' not set") + return self._value + + def get_shared_content_download(self): + """ + (sharing) Downloaded shared file/folder + + Only call this if :meth:`is_shared_content_download` is true. + + :rtype: SharedContentDownloadType + """ + if not self.is_shared_content_download(): + raise AttributeError("tag 'shared_content_download' not set") + return self._value + + def get_shared_content_relinquish_membership(self): + """ + (sharing) Left shared file/folder + + Only call this if :meth:`is_shared_content_relinquish_membership` is true. + + :rtype: SharedContentRelinquishMembershipType + """ + if not self.is_shared_content_relinquish_membership(): + raise AttributeError("tag 'shared_content_relinquish_membership' not set") + return self._value + + def get_shared_content_remove_invitees(self): + """ + (sharing) Removed invitee from shared file/folder before invite was + accepted + + Only call this if :meth:`is_shared_content_remove_invitees` is true. + + :rtype: SharedContentRemoveInviteesType + """ + if not self.is_shared_content_remove_invitees(): + raise AttributeError("tag 'shared_content_remove_invitees' not set") + return self._value + + def get_shared_content_remove_link_expiry(self): + """ + (sharing) Removed link expiration date of shared file/folder + (deprecated, no longer logged) + + Only call this if :meth:`is_shared_content_remove_link_expiry` is true. + + :rtype: SharedContentRemoveLinkExpiryType + """ + if not self.is_shared_content_remove_link_expiry(): + raise AttributeError("tag 'shared_content_remove_link_expiry' not set") + return self._value + + def get_shared_content_remove_link_password(self): + """ + (sharing) Removed link password of shared file/folder (deprecated, no + longer logged) + + Only call this if :meth:`is_shared_content_remove_link_password` is true. + + :rtype: SharedContentRemoveLinkPasswordType + """ + if not self.is_shared_content_remove_link_password(): + raise AttributeError("tag 'shared_content_remove_link_password' not set") + return self._value + + def get_shared_content_remove_member(self): + """ + (sharing) Removed user/group from shared file/folder + + Only call this if :meth:`is_shared_content_remove_member` is true. + + :rtype: SharedContentRemoveMemberType + """ + if not self.is_shared_content_remove_member(): + raise AttributeError("tag 'shared_content_remove_member' not set") + return self._value + + def get_shared_content_request_access(self): + """ + (sharing) Requested access to shared file/folder + + Only call this if :meth:`is_shared_content_request_access` is true. + + :rtype: SharedContentRequestAccessType + """ + if not self.is_shared_content_request_access(): + raise AttributeError("tag 'shared_content_request_access' not set") + return self._value + + def get_shared_content_restore_invitees(self): + """ + (sharing) Restored shared file/folder invitees + + Only call this if :meth:`is_shared_content_restore_invitees` is true. + + :rtype: SharedContentRestoreInviteesType + """ + if not self.is_shared_content_restore_invitees(): + raise AttributeError("tag 'shared_content_restore_invitees' not set") + return self._value + + def get_shared_content_restore_member(self): + """ + (sharing) Restored users and/or groups to membership of shared + file/folder + + Only call this if :meth:`is_shared_content_restore_member` is true. + + :rtype: SharedContentRestoreMemberType + """ + if not self.is_shared_content_restore_member(): + raise AttributeError("tag 'shared_content_restore_member' not set") + return self._value + + def get_shared_content_unshare(self): + """ + (sharing) Unshared file/folder by clearing membership + + Only call this if :meth:`is_shared_content_unshare` is true. + + :rtype: SharedContentUnshareType + """ + if not self.is_shared_content_unshare(): + raise AttributeError("tag 'shared_content_unshare' not set") + return self._value + + def get_shared_content_view(self): + """ + (sharing) Previewed shared file/folder + + Only call this if :meth:`is_shared_content_view` is true. + + :rtype: SharedContentViewType + """ + if not self.is_shared_content_view(): + raise AttributeError("tag 'shared_content_view' not set") + return self._value + + def get_shared_folder_change_link_policy(self): + """ + (sharing) Changed who can access shared folder via link + + Only call this if :meth:`is_shared_folder_change_link_policy` is true. + + :rtype: SharedFolderChangeLinkPolicyType + """ + if not self.is_shared_folder_change_link_policy(): + raise AttributeError("tag 'shared_folder_change_link_policy' not set") + return self._value + + def get_shared_folder_change_members_inheritance_policy(self): + """ + (sharing) Changed whether shared folder inherits members from parent + folder + + Only call this if :meth:`is_shared_folder_change_members_inheritance_policy` is true. + + :rtype: SharedFolderChangeMembersInheritancePolicyType + """ + if not self.is_shared_folder_change_members_inheritance_policy(): + raise AttributeError("tag 'shared_folder_change_members_inheritance_policy' not set") + return self._value + + def get_shared_folder_change_members_management_policy(self): + """ + (sharing) Changed who can add/remove members of shared folder + + Only call this if :meth:`is_shared_folder_change_members_management_policy` is true. + + :rtype: SharedFolderChangeMembersManagementPolicyType + """ + if not self.is_shared_folder_change_members_management_policy(): + raise AttributeError("tag 'shared_folder_change_members_management_policy' not set") + return self._value + + def get_shared_folder_change_members_policy(self): + """ + (sharing) Changed who can become member of shared folder + + Only call this if :meth:`is_shared_folder_change_members_policy` is true. + + :rtype: SharedFolderChangeMembersPolicyType + """ + if not self.is_shared_folder_change_members_policy(): + raise AttributeError("tag 'shared_folder_change_members_policy' not set") + return self._value + + def get_shared_folder_create(self): + """ + (sharing) Created shared folder + + Only call this if :meth:`is_shared_folder_create` is true. + + :rtype: SharedFolderCreateType + """ + if not self.is_shared_folder_create(): + raise AttributeError("tag 'shared_folder_create' not set") + return self._value + + def get_shared_folder_decline_invitation(self): + """ + (sharing) Declined team member's invite to shared folder + + Only call this if :meth:`is_shared_folder_decline_invitation` is true. + + :rtype: SharedFolderDeclineInvitationType + """ + if not self.is_shared_folder_decline_invitation(): + raise AttributeError("tag 'shared_folder_decline_invitation' not set") + return self._value + + def get_shared_folder_mount(self): + """ + (sharing) Added shared folder to own Dropbox - @classmethod - def app_link_team(cls, val): + Only call this if :meth:`is_shared_folder_mount` is true. + + :rtype: SharedFolderMountType """ - Create an instance of this class set to the ``app_link_team`` tag with - value ``val``. + if not self.is_shared_folder_mount(): + raise AttributeError("tag 'shared_folder_mount' not set") + return self._value - :param AppLinkTeamType val: - :rtype: EventType + def get_shared_folder_nest(self): """ - return cls('app_link_team', val) + (sharing) Changed parent of shared folder - @classmethod - def app_link_user(cls, val): + Only call this if :meth:`is_shared_folder_nest` is true. + + :rtype: SharedFolderNestType """ - Create an instance of this class set to the ``app_link_user`` tag with - value ``val``. + if not self.is_shared_folder_nest(): + raise AttributeError("tag 'shared_folder_nest' not set") + return self._value - :param AppLinkUserType val: - :rtype: EventType + def get_shared_folder_transfer_ownership(self): """ - return cls('app_link_user', val) + (sharing) Transferred ownership of shared folder to another member - @classmethod - def app_unlink_team(cls, val): + Only call this if :meth:`is_shared_folder_transfer_ownership` is true. + + :rtype: SharedFolderTransferOwnershipType """ - Create an instance of this class set to the ``app_unlink_team`` tag with - value ``val``. + if not self.is_shared_folder_transfer_ownership(): + raise AttributeError("tag 'shared_folder_transfer_ownership' not set") + return self._value - :param AppUnlinkTeamType val: - :rtype: EventType + def get_shared_folder_unmount(self): """ - return cls('app_unlink_team', val) + (sharing) Deleted shared folder from Dropbox - @classmethod - def app_unlink_user(cls, val): + Only call this if :meth:`is_shared_folder_unmount` is true. + + :rtype: SharedFolderUnmountType """ - Create an instance of this class set to the ``app_unlink_user`` tag with - value ``val``. + if not self.is_shared_folder_unmount(): + raise AttributeError("tag 'shared_folder_unmount' not set") + return self._value - :param AppUnlinkUserType val: - :rtype: EventType + def get_shared_link_add_expiry(self): """ - return cls('app_unlink_user', val) + (sharing) Added shared link expiration date - @classmethod - def integration_connected(cls, val): + Only call this if :meth:`is_shared_link_add_expiry` is true. + + :rtype: SharedLinkAddExpiryType """ - Create an instance of this class set to the ``integration_connected`` - tag with value ``val``. + if not self.is_shared_link_add_expiry(): + raise AttributeError("tag 'shared_link_add_expiry' not set") + return self._value - :param IntegrationConnectedType val: - :rtype: EventType + def get_shared_link_change_expiry(self): """ - return cls('integration_connected', val) + (sharing) Changed shared link expiration date - @classmethod - def integration_disconnected(cls, val): + Only call this if :meth:`is_shared_link_change_expiry` is true. + + :rtype: SharedLinkChangeExpiryType """ - Create an instance of this class set to the ``integration_disconnected`` - tag with value ``val``. + if not self.is_shared_link_change_expiry(): + raise AttributeError("tag 'shared_link_change_expiry' not set") + return self._value - :param IntegrationDisconnectedType val: - :rtype: EventType + def get_shared_link_change_visibility(self): """ - return cls('integration_disconnected', val) + (sharing) Changed visibility of shared link - @classmethod - def file_add_comment(cls, val): + Only call this if :meth:`is_shared_link_change_visibility` is true. + + :rtype: SharedLinkChangeVisibilityType """ - Create an instance of this class set to the ``file_add_comment`` tag - with value ``val``. + if not self.is_shared_link_change_visibility(): + raise AttributeError("tag 'shared_link_change_visibility' not set") + return self._value - :param FileAddCommentType val: - :rtype: EventType + def get_shared_link_copy(self): """ - return cls('file_add_comment', val) + (sharing) Added file/folder to Dropbox from shared link - @classmethod - def file_change_comment_subscription(cls, val): + Only call this if :meth:`is_shared_link_copy` is true. + + :rtype: SharedLinkCopyType """ - Create an instance of this class set to the - ``file_change_comment_subscription`` tag with value ``val``. + if not self.is_shared_link_copy(): + raise AttributeError("tag 'shared_link_copy' not set") + return self._value - :param FileChangeCommentSubscriptionType val: - :rtype: EventType + def get_shared_link_create(self): """ - return cls('file_change_comment_subscription', val) + (sharing) Created shared link - @classmethod - def file_delete_comment(cls, val): + Only call this if :meth:`is_shared_link_create` is true. + + :rtype: SharedLinkCreateType """ - Create an instance of this class set to the ``file_delete_comment`` tag - with value ``val``. + if not self.is_shared_link_create(): + raise AttributeError("tag 'shared_link_create' not set") + return self._value - :param FileDeleteCommentType val: - :rtype: EventType + def get_shared_link_disable(self): """ - return cls('file_delete_comment', val) + (sharing) Removed shared link - @classmethod - def file_edit_comment(cls, val): + Only call this if :meth:`is_shared_link_disable` is true. + + :rtype: SharedLinkDisableType """ - Create an instance of this class set to the ``file_edit_comment`` tag - with value ``val``. + if not self.is_shared_link_disable(): + raise AttributeError("tag 'shared_link_disable' not set") + return self._value - :param FileEditCommentType val: - :rtype: EventType + def get_shared_link_download(self): """ - return cls('file_edit_comment', val) + (sharing) Downloaded file/folder from shared link - @classmethod - def file_like_comment(cls, val): + Only call this if :meth:`is_shared_link_download` is true. + + :rtype: SharedLinkDownloadType """ - Create an instance of this class set to the ``file_like_comment`` tag - with value ``val``. + if not self.is_shared_link_download(): + raise AttributeError("tag 'shared_link_download' not set") + return self._value - :param FileLikeCommentType val: - :rtype: EventType + def get_shared_link_remove_expiry(self): """ - return cls('file_like_comment', val) + (sharing) Removed shared link expiration date - @classmethod - def file_resolve_comment(cls, val): + Only call this if :meth:`is_shared_link_remove_expiry` is true. + + :rtype: SharedLinkRemoveExpiryType """ - Create an instance of this class set to the ``file_resolve_comment`` tag - with value ``val``. + if not self.is_shared_link_remove_expiry(): + raise AttributeError("tag 'shared_link_remove_expiry' not set") + return self._value - :param FileResolveCommentType val: - :rtype: EventType + def get_shared_link_settings_add_expiration(self): """ - return cls('file_resolve_comment', val) + (sharing) Added an expiration date to the shared link - @classmethod - def file_unlike_comment(cls, val): + Only call this if :meth:`is_shared_link_settings_add_expiration` is true. + + :rtype: SharedLinkSettingsAddExpirationType """ - Create an instance of this class set to the ``file_unlike_comment`` tag - with value ``val``. + if not self.is_shared_link_settings_add_expiration(): + raise AttributeError("tag 'shared_link_settings_add_expiration' not set") + return self._value - :param FileUnlikeCommentType val: - :rtype: EventType + def get_shared_link_settings_add_password(self): """ - return cls('file_unlike_comment', val) + (sharing) Added a password to the shared link - @classmethod - def file_unresolve_comment(cls, val): + Only call this if :meth:`is_shared_link_settings_add_password` is true. + + :rtype: SharedLinkSettingsAddPasswordType """ - Create an instance of this class set to the ``file_unresolve_comment`` - tag with value ``val``. + if not self.is_shared_link_settings_add_password(): + raise AttributeError("tag 'shared_link_settings_add_password' not set") + return self._value - :param FileUnresolveCommentType val: - :rtype: EventType + def get_shared_link_settings_allow_download_disabled(self): """ - return cls('file_unresolve_comment', val) + (sharing) Disabled downloads - @classmethod - def device_change_ip_desktop(cls, val): + Only call this if :meth:`is_shared_link_settings_allow_download_disabled` is true. + + :rtype: SharedLinkSettingsAllowDownloadDisabledType """ - Create an instance of this class set to the ``device_change_ip_desktop`` - tag with value ``val``. + if not self.is_shared_link_settings_allow_download_disabled(): + raise AttributeError("tag 'shared_link_settings_allow_download_disabled' not set") + return self._value - :param DeviceChangeIpDesktopType val: - :rtype: EventType + def get_shared_link_settings_allow_download_enabled(self): """ - return cls('device_change_ip_desktop', val) + (sharing) Enabled downloads - @classmethod - def device_change_ip_mobile(cls, val): + Only call this if :meth:`is_shared_link_settings_allow_download_enabled` is true. + + :rtype: SharedLinkSettingsAllowDownloadEnabledType """ - Create an instance of this class set to the ``device_change_ip_mobile`` - tag with value ``val``. + if not self.is_shared_link_settings_allow_download_enabled(): + raise AttributeError("tag 'shared_link_settings_allow_download_enabled' not set") + return self._value - :param DeviceChangeIpMobileType val: - :rtype: EventType + def get_shared_link_settings_change_audience(self): """ - return cls('device_change_ip_mobile', val) + (sharing) Changed the audience of the shared link - @classmethod - def device_change_ip_web(cls, val): + Only call this if :meth:`is_shared_link_settings_change_audience` is true. + + :rtype: SharedLinkSettingsChangeAudienceType """ - Create an instance of this class set to the ``device_change_ip_web`` tag - with value ``val``. + if not self.is_shared_link_settings_change_audience(): + raise AttributeError("tag 'shared_link_settings_change_audience' not set") + return self._value - :param DeviceChangeIpWebType val: - :rtype: EventType + def get_shared_link_settings_change_expiration(self): """ - return cls('device_change_ip_web', val) + (sharing) Changed the expiration date of the shared link - @classmethod - def device_delete_on_unlink_fail(cls, val): + Only call this if :meth:`is_shared_link_settings_change_expiration` is true. + + :rtype: SharedLinkSettingsChangeExpirationType """ - Create an instance of this class set to the - ``device_delete_on_unlink_fail`` tag with value ``val``. + if not self.is_shared_link_settings_change_expiration(): + raise AttributeError("tag 'shared_link_settings_change_expiration' not set") + return self._value - :param DeviceDeleteOnUnlinkFailType val: - :rtype: EventType + def get_shared_link_settings_change_password(self): """ - return cls('device_delete_on_unlink_fail', val) + (sharing) Changed the password of the shared link - @classmethod - def device_delete_on_unlink_success(cls, val): + Only call this if :meth:`is_shared_link_settings_change_password` is true. + + :rtype: SharedLinkSettingsChangePasswordType """ - Create an instance of this class set to the - ``device_delete_on_unlink_success`` tag with value ``val``. + if not self.is_shared_link_settings_change_password(): + raise AttributeError("tag 'shared_link_settings_change_password' not set") + return self._value - :param DeviceDeleteOnUnlinkSuccessType val: - :rtype: EventType + def get_shared_link_settings_remove_expiration(self): """ - return cls('device_delete_on_unlink_success', val) + (sharing) Removed the expiration date from the shared link - @classmethod - def device_link_fail(cls, val): + Only call this if :meth:`is_shared_link_settings_remove_expiration` is true. + + :rtype: SharedLinkSettingsRemoveExpirationType """ - Create an instance of this class set to the ``device_link_fail`` tag - with value ``val``. + if not self.is_shared_link_settings_remove_expiration(): + raise AttributeError("tag 'shared_link_settings_remove_expiration' not set") + return self._value - :param DeviceLinkFailType val: - :rtype: EventType + def get_shared_link_settings_remove_password(self): """ - return cls('device_link_fail', val) + (sharing) Removed the password from the shared link - @classmethod - def device_link_success(cls, val): + Only call this if :meth:`is_shared_link_settings_remove_password` is true. + + :rtype: SharedLinkSettingsRemovePasswordType """ - Create an instance of this class set to the ``device_link_success`` tag - with value ``val``. + if not self.is_shared_link_settings_remove_password(): + raise AttributeError("tag 'shared_link_settings_remove_password' not set") + return self._value - :param DeviceLinkSuccessType val: - :rtype: EventType + def get_shared_link_share(self): """ - return cls('device_link_success', val) + (sharing) Added members as audience of shared link - @classmethod - def device_management_disabled(cls, val): + Only call this if :meth:`is_shared_link_share` is true. + + :rtype: SharedLinkShareType """ - Create an instance of this class set to the - ``device_management_disabled`` tag with value ``val``. + if not self.is_shared_link_share(): + raise AttributeError("tag 'shared_link_share' not set") + return self._value - :param DeviceManagementDisabledType val: - :rtype: EventType + def get_shared_link_view(self): """ - return cls('device_management_disabled', val) + (sharing) Opened shared link - @classmethod - def device_management_enabled(cls, val): + Only call this if :meth:`is_shared_link_view` is true. + + :rtype: SharedLinkViewType """ - Create an instance of this class set to the - ``device_management_enabled`` tag with value ``val``. + if not self.is_shared_link_view(): + raise AttributeError("tag 'shared_link_view' not set") + return self._value - :param DeviceManagementEnabledType val: - :rtype: EventType + def get_shared_note_opened(self): """ - return cls('device_management_enabled', val) + (sharing) Opened shared Paper doc (deprecated, no longer logged) - @classmethod - def device_unlink(cls, val): + Only call this if :meth:`is_shared_note_opened` is true. + + :rtype: SharedNoteOpenedType """ - Create an instance of this class set to the ``device_unlink`` tag with - value ``val``. + if not self.is_shared_note_opened(): + raise AttributeError("tag 'shared_note_opened' not set") + return self._value - :param DeviceUnlinkType val: - :rtype: EventType + def get_shmodel_group_share(self): """ - return cls('device_unlink', val) + (sharing) Shared link with group (deprecated, no longer logged) - @classmethod - def emm_refresh_auth_token(cls, val): + Only call this if :meth:`is_shmodel_group_share` is true. + + :rtype: ShmodelGroupShareType """ - Create an instance of this class set to the ``emm_refresh_auth_token`` - tag with value ``val``. + if not self.is_shmodel_group_share(): + raise AttributeError("tag 'shmodel_group_share' not set") + return self._value - :param EmmRefreshAuthTokenType val: - :rtype: EventType + def get_showcase_access_granted(self): """ - return cls('emm_refresh_auth_token', val) + (showcase) Granted access to showcase - @classmethod - def account_capture_change_availability(cls, val): + Only call this if :meth:`is_showcase_access_granted` is true. + + :rtype: ShowcaseAccessGrantedType """ - Create an instance of this class set to the - ``account_capture_change_availability`` tag with value ``val``. + if not self.is_showcase_access_granted(): + raise AttributeError("tag 'showcase_access_granted' not set") + return self._value - :param AccountCaptureChangeAvailabilityType val: - :rtype: EventType + def get_showcase_add_member(self): """ - return cls('account_capture_change_availability', val) + (showcase) Added member to showcase - @classmethod - def account_capture_migrate_account(cls, val): + Only call this if :meth:`is_showcase_add_member` is true. + + :rtype: ShowcaseAddMemberType """ - Create an instance of this class set to the - ``account_capture_migrate_account`` tag with value ``val``. + if not self.is_showcase_add_member(): + raise AttributeError("tag 'showcase_add_member' not set") + return self._value - :param AccountCaptureMigrateAccountType val: - :rtype: EventType + def get_showcase_archived(self): """ - return cls('account_capture_migrate_account', val) + (showcase) Archived showcase - @classmethod - def account_capture_notification_emails_sent(cls, val): + Only call this if :meth:`is_showcase_archived` is true. + + :rtype: ShowcaseArchivedType """ - Create an instance of this class set to the - ``account_capture_notification_emails_sent`` tag with value ``val``. + if not self.is_showcase_archived(): + raise AttributeError("tag 'showcase_archived' not set") + return self._value + + def get_showcase_created(self): + """ + (showcase) Created showcase + + Only call this if :meth:`is_showcase_created` is true. + + :rtype: ShowcaseCreatedType + """ + if not self.is_showcase_created(): + raise AttributeError("tag 'showcase_created' not set") + return self._value + + def get_showcase_delete_comment(self): + """ + (showcase) Deleted showcase comment + + Only call this if :meth:`is_showcase_delete_comment` is true. + + :rtype: ShowcaseDeleteCommentType + """ + if not self.is_showcase_delete_comment(): + raise AttributeError("tag 'showcase_delete_comment' not set") + return self._value + + def get_showcase_edited(self): + """ + (showcase) Edited showcase + + Only call this if :meth:`is_showcase_edited` is true. + + :rtype: ShowcaseEditedType + """ + if not self.is_showcase_edited(): + raise AttributeError("tag 'showcase_edited' not set") + return self._value + + def get_showcase_edit_comment(self): + """ + (showcase) Edited showcase comment + + Only call this if :meth:`is_showcase_edit_comment` is true. + + :rtype: ShowcaseEditCommentType + """ + if not self.is_showcase_edit_comment(): + raise AttributeError("tag 'showcase_edit_comment' not set") + return self._value + + def get_showcase_file_added(self): + """ + (showcase) Added file to showcase + + Only call this if :meth:`is_showcase_file_added` is true. + + :rtype: ShowcaseFileAddedType + """ + if not self.is_showcase_file_added(): + raise AttributeError("tag 'showcase_file_added' not set") + return self._value + + def get_showcase_file_download(self): + """ + (showcase) Downloaded file from showcase + + Only call this if :meth:`is_showcase_file_download` is true. + + :rtype: ShowcaseFileDownloadType + """ + if not self.is_showcase_file_download(): + raise AttributeError("tag 'showcase_file_download' not set") + return self._value + + def get_showcase_file_removed(self): + """ + (showcase) Removed file from showcase + + Only call this if :meth:`is_showcase_file_removed` is true. + + :rtype: ShowcaseFileRemovedType + """ + if not self.is_showcase_file_removed(): + raise AttributeError("tag 'showcase_file_removed' not set") + return self._value + + def get_showcase_file_view(self): + """ + (showcase) Viewed file in showcase + + Only call this if :meth:`is_showcase_file_view` is true. + + :rtype: ShowcaseFileViewType + """ + if not self.is_showcase_file_view(): + raise AttributeError("tag 'showcase_file_view' not set") + return self._value + + def get_showcase_permanently_deleted(self): + """ + (showcase) Permanently deleted showcase + + Only call this if :meth:`is_showcase_permanently_deleted` is true. + + :rtype: ShowcasePermanentlyDeletedType + """ + if not self.is_showcase_permanently_deleted(): + raise AttributeError("tag 'showcase_permanently_deleted' not set") + return self._value + + def get_showcase_post_comment(self): + """ + (showcase) Added showcase comment + + Only call this if :meth:`is_showcase_post_comment` is true. + + :rtype: ShowcasePostCommentType + """ + if not self.is_showcase_post_comment(): + raise AttributeError("tag 'showcase_post_comment' not set") + return self._value + + def get_showcase_remove_member(self): + """ + (showcase) Removed member from showcase + + Only call this if :meth:`is_showcase_remove_member` is true. + + :rtype: ShowcaseRemoveMemberType + """ + if not self.is_showcase_remove_member(): + raise AttributeError("tag 'showcase_remove_member' not set") + return self._value + + def get_showcase_renamed(self): + """ + (showcase) Renamed showcase + + Only call this if :meth:`is_showcase_renamed` is true. + + :rtype: ShowcaseRenamedType + """ + if not self.is_showcase_renamed(): + raise AttributeError("tag 'showcase_renamed' not set") + return self._value - :param AccountCaptureNotificationEmailsSentType val: - :rtype: EventType + def get_showcase_request_access(self): """ - return cls('account_capture_notification_emails_sent', val) + (showcase) Requested access to showcase - @classmethod - def account_capture_relinquish_account(cls, val): - """ - Create an instance of this class set to the - ``account_capture_relinquish_account`` tag with value ``val``. + Only call this if :meth:`is_showcase_request_access` is true. - :param AccountCaptureRelinquishAccountType val: - :rtype: EventType + :rtype: ShowcaseRequestAccessType """ - return cls('account_capture_relinquish_account', val) + if not self.is_showcase_request_access(): + raise AttributeError("tag 'showcase_request_access' not set") + return self._value - @classmethod - def disabled_domain_invites(cls, val): + def get_showcase_resolve_comment(self): """ - Create an instance of this class set to the ``disabled_domain_invites`` - tag with value ``val``. + (showcase) Resolved showcase comment - :param DisabledDomainInvitesType val: - :rtype: EventType - """ - return cls('disabled_domain_invites', val) + Only call this if :meth:`is_showcase_resolve_comment` is true. - @classmethod - def domain_invites_approve_request_to_join_team(cls, val): + :rtype: ShowcaseResolveCommentType """ - Create an instance of this class set to the - ``domain_invites_approve_request_to_join_team`` tag with value ``val``. + if not self.is_showcase_resolve_comment(): + raise AttributeError("tag 'showcase_resolve_comment' not set") + return self._value - :param DomainInvitesApproveRequestToJoinTeamType val: - :rtype: EventType + def get_showcase_restored(self): """ - return cls('domain_invites_approve_request_to_join_team', val) + (showcase) Unarchived showcase - @classmethod - def domain_invites_decline_request_to_join_team(cls, val): - """ - Create an instance of this class set to the - ``domain_invites_decline_request_to_join_team`` tag with value ``val``. + Only call this if :meth:`is_showcase_restored` is true. - :param DomainInvitesDeclineRequestToJoinTeamType val: - :rtype: EventType + :rtype: ShowcaseRestoredType """ - return cls('domain_invites_decline_request_to_join_team', val) + if not self.is_showcase_restored(): + raise AttributeError("tag 'showcase_restored' not set") + return self._value - @classmethod - def domain_invites_email_existing_users(cls, val): + def get_showcase_trashed(self): """ - Create an instance of this class set to the - ``domain_invites_email_existing_users`` tag with value ``val``. + (showcase) Deleted showcase - :param DomainInvitesEmailExistingUsersType val: - :rtype: EventType - """ - return cls('domain_invites_email_existing_users', val) + Only call this if :meth:`is_showcase_trashed` is true. - @classmethod - def domain_invites_request_to_join_team(cls, val): + :rtype: ShowcaseTrashedType """ - Create an instance of this class set to the - ``domain_invites_request_to_join_team`` tag with value ``val``. + if not self.is_showcase_trashed(): + raise AttributeError("tag 'showcase_trashed' not set") + return self._value - :param DomainInvitesRequestToJoinTeamType val: - :rtype: EventType + def get_showcase_trashed_deprecated(self): """ - return cls('domain_invites_request_to_join_team', val) + (showcase) Deleted showcase (old version) (deprecated, replaced by + 'Deleted showcase') - @classmethod - def domain_invites_set_invite_new_user_pref_to_no(cls, val): - """ - Create an instance of this class set to the - ``domain_invites_set_invite_new_user_pref_to_no`` tag with value - ``val``. + Only call this if :meth:`is_showcase_trashed_deprecated` is true. - :param DomainInvitesSetInviteNewUserPrefToNoType val: - :rtype: EventType + :rtype: ShowcaseTrashedDeprecatedType """ - return cls('domain_invites_set_invite_new_user_pref_to_no', val) + if not self.is_showcase_trashed_deprecated(): + raise AttributeError("tag 'showcase_trashed_deprecated' not set") + return self._value - @classmethod - def domain_invites_set_invite_new_user_pref_to_yes(cls, val): + def get_showcase_unresolve_comment(self): """ - Create an instance of this class set to the - ``domain_invites_set_invite_new_user_pref_to_yes`` tag with value - ``val``. + (showcase) Unresolved showcase comment - :param DomainInvitesSetInviteNewUserPrefToYesType val: - :rtype: EventType - """ - return cls('domain_invites_set_invite_new_user_pref_to_yes', val) + Only call this if :meth:`is_showcase_unresolve_comment` is true. - @classmethod - def domain_verification_add_domain_fail(cls, val): + :rtype: ShowcaseUnresolveCommentType """ - Create an instance of this class set to the - ``domain_verification_add_domain_fail`` tag with value ``val``. + if not self.is_showcase_unresolve_comment(): + raise AttributeError("tag 'showcase_unresolve_comment' not set") + return self._value - :param DomainVerificationAddDomainFailType val: - :rtype: EventType + def get_showcase_untrashed(self): """ - return cls('domain_verification_add_domain_fail', val) + (showcase) Restored showcase - @classmethod - def domain_verification_add_domain_success(cls, val): - """ - Create an instance of this class set to the - ``domain_verification_add_domain_success`` tag with value ``val``. + Only call this if :meth:`is_showcase_untrashed` is true. - :param DomainVerificationAddDomainSuccessType val: - :rtype: EventType + :rtype: ShowcaseUntrashedType """ - return cls('domain_verification_add_domain_success', val) + if not self.is_showcase_untrashed(): + raise AttributeError("tag 'showcase_untrashed' not set") + return self._value - @classmethod - def domain_verification_remove_domain(cls, val): + def get_showcase_untrashed_deprecated(self): """ - Create an instance of this class set to the - ``domain_verification_remove_domain`` tag with value ``val``. + (showcase) Restored showcase (old version) (deprecated, replaced by + 'Restored showcase') - :param DomainVerificationRemoveDomainType val: - :rtype: EventType - """ - return cls('domain_verification_remove_domain', val) + Only call this if :meth:`is_showcase_untrashed_deprecated` is true. - @classmethod - def enabled_domain_invites(cls, val): + :rtype: ShowcaseUntrashedDeprecatedType """ - Create an instance of this class set to the ``enabled_domain_invites`` - tag with value ``val``. + if not self.is_showcase_untrashed_deprecated(): + raise AttributeError("tag 'showcase_untrashed_deprecated' not set") + return self._value - :param EnabledDomainInvitesType val: - :rtype: EventType + def get_showcase_view(self): """ - return cls('enabled_domain_invites', val) + (showcase) Viewed showcase - @classmethod - def create_folder(cls, val): - """ - Create an instance of this class set to the ``create_folder`` tag with - value ``val``. + Only call this if :meth:`is_showcase_view` is true. - :param CreateFolderType val: - :rtype: EventType + :rtype: ShowcaseViewType """ - return cls('create_folder', val) + if not self.is_showcase_view(): + raise AttributeError("tag 'showcase_view' not set") + return self._value - @classmethod - def file_add(cls, val): + def get_sso_add_cert(self): """ - Create an instance of this class set to the ``file_add`` tag with value - ``val``. + (sso) Added X.509 certificate for SSO - :param FileAddType val: - :rtype: EventType - """ - return cls('file_add', val) + Only call this if :meth:`is_sso_add_cert` is true. - @classmethod - def file_copy(cls, val): + :rtype: SsoAddCertType """ - Create an instance of this class set to the ``file_copy`` tag with value - ``val``. + if not self.is_sso_add_cert(): + raise AttributeError("tag 'sso_add_cert' not set") + return self._value - :param FileCopyType val: - :rtype: EventType + def get_sso_add_login_url(self): """ - return cls('file_copy', val) + (sso) Added sign-in URL for SSO - @classmethod - def file_delete(cls, val): - """ - Create an instance of this class set to the ``file_delete`` tag with - value ``val``. + Only call this if :meth:`is_sso_add_login_url` is true. - :param FileDeleteType val: - :rtype: EventType + :rtype: SsoAddLoginUrlType """ - return cls('file_delete', val) + if not self.is_sso_add_login_url(): + raise AttributeError("tag 'sso_add_login_url' not set") + return self._value - @classmethod - def file_download(cls, val): + def get_sso_add_logout_url(self): """ - Create an instance of this class set to the ``file_download`` tag with - value ``val``. + (sso) Added sign-out URL for SSO - :param FileDownloadType val: - :rtype: EventType - """ - return cls('file_download', val) + Only call this if :meth:`is_sso_add_logout_url` is true. - @classmethod - def file_edit(cls, val): + :rtype: SsoAddLogoutUrlType """ - Create an instance of this class set to the ``file_edit`` tag with value - ``val``. + if not self.is_sso_add_logout_url(): + raise AttributeError("tag 'sso_add_logout_url' not set") + return self._value - :param FileEditType val: - :rtype: EventType + def get_sso_change_cert(self): """ - return cls('file_edit', val) + (sso) Changed X.509 certificate for SSO - @classmethod - def file_get_copy_reference(cls, val): - """ - Create an instance of this class set to the ``file_get_copy_reference`` - tag with value ``val``. + Only call this if :meth:`is_sso_change_cert` is true. - :param FileGetCopyReferenceType val: - :rtype: EventType + :rtype: SsoChangeCertType """ - return cls('file_get_copy_reference', val) + if not self.is_sso_change_cert(): + raise AttributeError("tag 'sso_change_cert' not set") + return self._value - @classmethod - def file_move(cls, val): + def get_sso_change_login_url(self): """ - Create an instance of this class set to the ``file_move`` tag with value - ``val``. + (sso) Changed sign-in URL for SSO - :param FileMoveType val: - :rtype: EventType - """ - return cls('file_move', val) + Only call this if :meth:`is_sso_change_login_url` is true. - @classmethod - def file_permanently_delete(cls, val): + :rtype: SsoChangeLoginUrlType """ - Create an instance of this class set to the ``file_permanently_delete`` - tag with value ``val``. + if not self.is_sso_change_login_url(): + raise AttributeError("tag 'sso_change_login_url' not set") + return self._value - :param FilePermanentlyDeleteType val: - :rtype: EventType + def get_sso_change_logout_url(self): """ - return cls('file_permanently_delete', val) + (sso) Changed sign-out URL for SSO - @classmethod - def file_preview(cls, val): + Only call this if :meth:`is_sso_change_logout_url` is true. + + :rtype: SsoChangeLogoutUrlType """ - Create an instance of this class set to the ``file_preview`` tag with - value ``val``. + if not self.is_sso_change_logout_url(): + raise AttributeError("tag 'sso_change_logout_url' not set") + return self._value - :param FilePreviewType val: - :rtype: EventType + def get_sso_change_saml_identity_mode(self): """ - return cls('file_preview', val) + (sso) Changed SAML identity mode for SSO - @classmethod - def file_rename(cls, val): + Only call this if :meth:`is_sso_change_saml_identity_mode` is true. + + :rtype: SsoChangeSamlIdentityModeType """ - Create an instance of this class set to the ``file_rename`` tag with - value ``val``. + if not self.is_sso_change_saml_identity_mode(): + raise AttributeError("tag 'sso_change_saml_identity_mode' not set") + return self._value - :param FileRenameType val: - :rtype: EventType + def get_sso_remove_cert(self): """ - return cls('file_rename', val) + (sso) Removed X.509 certificate for SSO - @classmethod - def file_restore(cls, val): + Only call this if :meth:`is_sso_remove_cert` is true. + + :rtype: SsoRemoveCertType """ - Create an instance of this class set to the ``file_restore`` tag with - value ``val``. + if not self.is_sso_remove_cert(): + raise AttributeError("tag 'sso_remove_cert' not set") + return self._value - :param FileRestoreType val: - :rtype: EventType + def get_sso_remove_login_url(self): """ - return cls('file_restore', val) + (sso) Removed sign-in URL for SSO - @classmethod - def file_revert(cls, val): + Only call this if :meth:`is_sso_remove_login_url` is true. + + :rtype: SsoRemoveLoginUrlType """ - Create an instance of this class set to the ``file_revert`` tag with - value ``val``. + if not self.is_sso_remove_login_url(): + raise AttributeError("tag 'sso_remove_login_url' not set") + return self._value - :param FileRevertType val: - :rtype: EventType + def get_sso_remove_logout_url(self): """ - return cls('file_revert', val) + (sso) Removed sign-out URL for SSO - @classmethod - def file_rollback_changes(cls, val): + Only call this if :meth:`is_sso_remove_logout_url` is true. + + :rtype: SsoRemoveLogoutUrlType """ - Create an instance of this class set to the ``file_rollback_changes`` - tag with value ``val``. + if not self.is_sso_remove_logout_url(): + raise AttributeError("tag 'sso_remove_logout_url' not set") + return self._value - :param FileRollbackChangesType val: - :rtype: EventType + def get_team_folder_change_status(self): """ - return cls('file_rollback_changes', val) + (team_folders) Changed archival status of team folder - @classmethod - def file_save_copy_reference(cls, val): + Only call this if :meth:`is_team_folder_change_status` is true. + + :rtype: TeamFolderChangeStatusType """ - Create an instance of this class set to the ``file_save_copy_reference`` - tag with value ``val``. + if not self.is_team_folder_change_status(): + raise AttributeError("tag 'team_folder_change_status' not set") + return self._value - :param FileSaveCopyReferenceType val: - :rtype: EventType + def get_team_folder_create(self): """ - return cls('file_save_copy_reference', val) + (team_folders) Created team folder in active status - @classmethod - def file_request_change(cls, val): + Only call this if :meth:`is_team_folder_create` is true. + + :rtype: TeamFolderCreateType """ - Create an instance of this class set to the ``file_request_change`` tag - with value ``val``. + if not self.is_team_folder_create(): + raise AttributeError("tag 'team_folder_create' not set") + return self._value - :param FileRequestChangeType val: - :rtype: EventType + def get_team_folder_downgrade(self): """ - return cls('file_request_change', val) + (team_folders) Downgraded team folder to regular shared folder - @classmethod - def file_request_close(cls, val): + Only call this if :meth:`is_team_folder_downgrade` is true. + + :rtype: TeamFolderDowngradeType """ - Create an instance of this class set to the ``file_request_close`` tag - with value ``val``. + if not self.is_team_folder_downgrade(): + raise AttributeError("tag 'team_folder_downgrade' not set") + return self._value - :param FileRequestCloseType val: - :rtype: EventType + def get_team_folder_permanently_delete(self): """ - return cls('file_request_close', val) + (team_folders) Permanently deleted archived team folder - @classmethod - def file_request_create(cls, val): + Only call this if :meth:`is_team_folder_permanently_delete` is true. + + :rtype: TeamFolderPermanentlyDeleteType """ - Create an instance of this class set to the ``file_request_create`` tag - with value ``val``. + if not self.is_team_folder_permanently_delete(): + raise AttributeError("tag 'team_folder_permanently_delete' not set") + return self._value - :param FileRequestCreateType val: - :rtype: EventType + def get_team_folder_rename(self): """ - return cls('file_request_create', val) + (team_folders) Renamed active/archived team folder - @classmethod - def file_request_delete(cls, val): + Only call this if :meth:`is_team_folder_rename` is true. + + :rtype: TeamFolderRenameType """ - Create an instance of this class set to the ``file_request_delete`` tag - with value ``val``. + if not self.is_team_folder_rename(): + raise AttributeError("tag 'team_folder_rename' not set") + return self._value - :param FileRequestDeleteType val: - :rtype: EventType + def get_team_selective_sync_settings_changed(self): """ - return cls('file_request_delete', val) + (team_folders) Changed sync default - @classmethod - def file_request_receive_file(cls, val): + Only call this if :meth:`is_team_selective_sync_settings_changed` is true. + + :rtype: TeamSelectiveSyncSettingsChangedType """ - Create an instance of this class set to the - ``file_request_receive_file`` tag with value ``val``. + if not self.is_team_selective_sync_settings_changed(): + raise AttributeError("tag 'team_selective_sync_settings_changed' not set") + return self._value - :param FileRequestReceiveFileType val: - :rtype: EventType + def get_account_capture_change_policy(self): """ - return cls('file_request_receive_file', val) + (team_policies) Changed account capture setting on team domain - @classmethod - def group_add_external_id(cls, val): + Only call this if :meth:`is_account_capture_change_policy` is true. + + :rtype: AccountCaptureChangePolicyType """ - Create an instance of this class set to the ``group_add_external_id`` - tag with value ``val``. + if not self.is_account_capture_change_policy(): + raise AttributeError("tag 'account_capture_change_policy' not set") + return self._value - :param GroupAddExternalIdType val: - :rtype: EventType + def get_allow_download_disabled(self): """ - return cls('group_add_external_id', val) + (team_policies) Disabled downloads (deprecated, no longer logged) - @classmethod - def group_add_member(cls, val): + Only call this if :meth:`is_allow_download_disabled` is true. + + :rtype: AllowDownloadDisabledType """ - Create an instance of this class set to the ``group_add_member`` tag - with value ``val``. + if not self.is_allow_download_disabled(): + raise AttributeError("tag 'allow_download_disabled' not set") + return self._value - :param GroupAddMemberType val: - :rtype: EventType + def get_allow_download_enabled(self): """ - return cls('group_add_member', val) + (team_policies) Enabled downloads (deprecated, no longer logged) - @classmethod - def group_change_external_id(cls, val): + Only call this if :meth:`is_allow_download_enabled` is true. + + :rtype: AllowDownloadEnabledType """ - Create an instance of this class set to the ``group_change_external_id`` - tag with value ``val``. + if not self.is_allow_download_enabled(): + raise AttributeError("tag 'allow_download_enabled' not set") + return self._value - :param GroupChangeExternalIdType val: - :rtype: EventType + def get_camera_uploads_policy_changed(self): """ - return cls('group_change_external_id', val) + (team_policies) Changed camera uploads setting for team - @classmethod - def group_change_management_type(cls, val): + Only call this if :meth:`is_camera_uploads_policy_changed` is true. + + :rtype: CameraUploadsPolicyChangedType """ - Create an instance of this class set to the - ``group_change_management_type`` tag with value ``val``. + if not self.is_camera_uploads_policy_changed(): + raise AttributeError("tag 'camera_uploads_policy_changed' not set") + return self._value - :param GroupChangeManagementTypeType val: - :rtype: EventType + def get_data_placement_restriction_change_policy(self): """ - return cls('group_change_management_type', val) + (team_policies) Set restrictions on data center locations where team + data resides - @classmethod - def group_change_member_role(cls, val): + Only call this if :meth:`is_data_placement_restriction_change_policy` is true. + + :rtype: DataPlacementRestrictionChangePolicyType """ - Create an instance of this class set to the ``group_change_member_role`` - tag with value ``val``. + if not self.is_data_placement_restriction_change_policy(): + raise AttributeError("tag 'data_placement_restriction_change_policy' not set") + return self._value - :param GroupChangeMemberRoleType val: - :rtype: EventType + def get_data_placement_restriction_satisfy_policy(self): """ - return cls('group_change_member_role', val) + (team_policies) Completed restrictions on data center locations where + team data resides + + Only call this if :meth:`is_data_placement_restriction_satisfy_policy` is true. - @classmethod - def group_create(cls, val): + :rtype: DataPlacementRestrictionSatisfyPolicyType """ - Create an instance of this class set to the ``group_create`` tag with - value ``val``. + if not self.is_data_placement_restriction_satisfy_policy(): + raise AttributeError("tag 'data_placement_restriction_satisfy_policy' not set") + return self._value - :param GroupCreateType val: - :rtype: EventType + def get_device_approvals_add_exception(self): """ - return cls('group_create', val) + (team_policies) Added members to device approvals exception list - @classmethod - def group_delete(cls, val): - """ - Create an instance of this class set to the ``group_delete`` tag with - value ``val``. + Only call this if :meth:`is_device_approvals_add_exception` is true. - :param GroupDeleteType val: - :rtype: EventType + :rtype: DeviceApprovalsAddExceptionType """ - return cls('group_delete', val) + if not self.is_device_approvals_add_exception(): + raise AttributeError("tag 'device_approvals_add_exception' not set") + return self._value - @classmethod - def group_description_updated(cls, val): + def get_device_approvals_change_desktop_policy(self): """ - Create an instance of this class set to the - ``group_description_updated`` tag with value ``val``. + (team_policies) Set/removed limit on number of computers member can link + to team Dropbox account - :param GroupDescriptionUpdatedType val: - :rtype: EventType - """ - return cls('group_description_updated', val) + Only call this if :meth:`is_device_approvals_change_desktop_policy` is true. - @classmethod - def group_join_policy_updated(cls, val): + :rtype: DeviceApprovalsChangeDesktopPolicyType """ - Create an instance of this class set to the - ``group_join_policy_updated`` tag with value ``val``. + if not self.is_device_approvals_change_desktop_policy(): + raise AttributeError("tag 'device_approvals_change_desktop_policy' not set") + return self._value - :param GroupJoinPolicyUpdatedType val: - :rtype: EventType + def get_device_approvals_change_mobile_policy(self): """ - return cls('group_join_policy_updated', val) + (team_policies) Set/removed limit on number of mobile devices member can + link to team Dropbox account - @classmethod - def group_moved(cls, val): - """ - Create an instance of this class set to the ``group_moved`` tag with - value ``val``. + Only call this if :meth:`is_device_approvals_change_mobile_policy` is true. - :param GroupMovedType val: - :rtype: EventType + :rtype: DeviceApprovalsChangeMobilePolicyType """ - return cls('group_moved', val) + if not self.is_device_approvals_change_mobile_policy(): + raise AttributeError("tag 'device_approvals_change_mobile_policy' not set") + return self._value - @classmethod - def group_remove_external_id(cls, val): + def get_device_approvals_change_overage_action(self): """ - Create an instance of this class set to the ``group_remove_external_id`` - tag with value ``val``. + (team_policies) Changed device approvals setting when member is over + limit - :param GroupRemoveExternalIdType val: - :rtype: EventType - """ - return cls('group_remove_external_id', val) + Only call this if :meth:`is_device_approvals_change_overage_action` is true. - @classmethod - def group_remove_member(cls, val): + :rtype: DeviceApprovalsChangeOverageActionType """ - Create an instance of this class set to the ``group_remove_member`` tag - with value ``val``. + if not self.is_device_approvals_change_overage_action(): + raise AttributeError("tag 'device_approvals_change_overage_action' not set") + return self._value - :param GroupRemoveMemberType val: - :rtype: EventType + def get_device_approvals_change_unlink_action(self): """ - return cls('group_remove_member', val) + (team_policies) Changed device approvals setting when member unlinks + approved device - @classmethod - def group_rename(cls, val): - """ - Create an instance of this class set to the ``group_rename`` tag with - value ``val``. + Only call this if :meth:`is_device_approvals_change_unlink_action` is true. - :param GroupRenameType val: - :rtype: EventType + :rtype: DeviceApprovalsChangeUnlinkActionType """ - return cls('group_rename', val) + if not self.is_device_approvals_change_unlink_action(): + raise AttributeError("tag 'device_approvals_change_unlink_action' not set") + return self._value - @classmethod - def emm_error(cls, val): + def get_device_approvals_remove_exception(self): """ - Create an instance of this class set to the ``emm_error`` tag with value - ``val``. + (team_policies) Removed members from device approvals exception list - :param EmmErrorType val: - :rtype: EventType - """ - return cls('emm_error', val) + Only call this if :meth:`is_device_approvals_remove_exception` is true. - @classmethod - def guest_admin_signed_in_via_trusted_teams(cls, val): + :rtype: DeviceApprovalsRemoveExceptionType """ - Create an instance of this class set to the - ``guest_admin_signed_in_via_trusted_teams`` tag with value ``val``. + if not self.is_device_approvals_remove_exception(): + raise AttributeError("tag 'device_approvals_remove_exception' not set") + return self._value - :param GuestAdminSignedInViaTrustedTeamsType val: - :rtype: EventType + def get_directory_restrictions_add_members(self): """ - return cls('guest_admin_signed_in_via_trusted_teams', val) + (team_policies) Added members to directory restrictions list - @classmethod - def guest_admin_signed_out_via_trusted_teams(cls, val): - """ - Create an instance of this class set to the - ``guest_admin_signed_out_via_trusted_teams`` tag with value ``val``. + Only call this if :meth:`is_directory_restrictions_add_members` is true. - :param GuestAdminSignedOutViaTrustedTeamsType val: - :rtype: EventType + :rtype: DirectoryRestrictionsAddMembersType """ - return cls('guest_admin_signed_out_via_trusted_teams', val) + if not self.is_directory_restrictions_add_members(): + raise AttributeError("tag 'directory_restrictions_add_members' not set") + return self._value - @classmethod - def login_fail(cls, val): + def get_directory_restrictions_remove_members(self): """ - Create an instance of this class set to the ``login_fail`` tag with - value ``val``. + (team_policies) Removed members from directory restrictions list - :param LoginFailType val: - :rtype: EventType - """ - return cls('login_fail', val) + Only call this if :meth:`is_directory_restrictions_remove_members` is true. - @classmethod - def login_success(cls, val): + :rtype: DirectoryRestrictionsRemoveMembersType """ - Create an instance of this class set to the ``login_success`` tag with - value ``val``. + if not self.is_directory_restrictions_remove_members(): + raise AttributeError("tag 'directory_restrictions_remove_members' not set") + return self._value - :param LoginSuccessType val: - :rtype: EventType + def get_emm_add_exception(self): """ - return cls('login_success', val) + (team_policies) Added members to EMM exception list - @classmethod - def logout(cls, val): - """ - Create an instance of this class set to the ``logout`` tag with value - ``val``. + Only call this if :meth:`is_emm_add_exception` is true. - :param LogoutType val: - :rtype: EventType + :rtype: EmmAddExceptionType """ - return cls('logout', val) + if not self.is_emm_add_exception(): + raise AttributeError("tag 'emm_add_exception' not set") + return self._value - @classmethod - def reseller_support_session_end(cls, val): + def get_emm_change_policy(self): """ - Create an instance of this class set to the - ``reseller_support_session_end`` tag with value ``val``. + (team_policies) Enabled/disabled enterprise mobility management for + members - :param ResellerSupportSessionEndType val: - :rtype: EventType - """ - return cls('reseller_support_session_end', val) + Only call this if :meth:`is_emm_change_policy` is true. - @classmethod - def reseller_support_session_start(cls, val): + :rtype: EmmChangePolicyType """ - Create an instance of this class set to the - ``reseller_support_session_start`` tag with value ``val``. + if not self.is_emm_change_policy(): + raise AttributeError("tag 'emm_change_policy' not set") + return self._value - :param ResellerSupportSessionStartType val: - :rtype: EventType + def get_emm_remove_exception(self): """ - return cls('reseller_support_session_start', val) + (team_policies) Removed members from EMM exception list - @classmethod - def sign_in_as_session_end(cls, val): - """ - Create an instance of this class set to the ``sign_in_as_session_end`` - tag with value ``val``. + Only call this if :meth:`is_emm_remove_exception` is true. - :param SignInAsSessionEndType val: - :rtype: EventType + :rtype: EmmRemoveExceptionType """ - return cls('sign_in_as_session_end', val) + if not self.is_emm_remove_exception(): + raise AttributeError("tag 'emm_remove_exception' not set") + return self._value - @classmethod - def sign_in_as_session_start(cls, val): + def get_extended_version_history_change_policy(self): """ - Create an instance of this class set to the ``sign_in_as_session_start`` - tag with value ``val``. + (team_policies) Accepted/opted out of extended version history - :param SignInAsSessionStartType val: - :rtype: EventType - """ - return cls('sign_in_as_session_start', val) + Only call this if :meth:`is_extended_version_history_change_policy` is true. - @classmethod - def sso_error(cls, val): + :rtype: ExtendedVersionHistoryChangePolicyType """ - Create an instance of this class set to the ``sso_error`` tag with value - ``val``. + if not self.is_extended_version_history_change_policy(): + raise AttributeError("tag 'extended_version_history_change_policy' not set") + return self._value - :param SsoErrorType val: - :rtype: EventType + def get_file_comments_change_policy(self): """ - return cls('sso_error', val) + (team_policies) Enabled/disabled commenting on team files - @classmethod - def member_add_external_id(cls, val): - """ - Create an instance of this class set to the ``member_add_external_id`` - tag with value ``val``. + Only call this if :meth:`is_file_comments_change_policy` is true. - :param MemberAddExternalIdType val: - :rtype: EventType + :rtype: FileCommentsChangePolicyType """ - return cls('member_add_external_id', val) + if not self.is_file_comments_change_policy(): + raise AttributeError("tag 'file_comments_change_policy' not set") + return self._value - @classmethod - def member_add_name(cls, val): + def get_file_locking_policy_changed(self): """ - Create an instance of this class set to the ``member_add_name`` tag with - value ``val``. + (team_policies) Changed file locking policy for team - :param MemberAddNameType val: - :rtype: EventType - """ - return cls('member_add_name', val) + Only call this if :meth:`is_file_locking_policy_changed` is true. - @classmethod - def member_change_admin_role(cls, val): + :rtype: FileLockingPolicyChangedType """ - Create an instance of this class set to the ``member_change_admin_role`` - tag with value ``val``. + if not self.is_file_locking_policy_changed(): + raise AttributeError("tag 'file_locking_policy_changed' not set") + return self._value - :param MemberChangeAdminRoleType val: - :rtype: EventType + def get_file_requests_change_policy(self): """ - return cls('member_change_admin_role', val) + (team_policies) Enabled/disabled file requests - @classmethod - def member_change_email(cls, val): - """ - Create an instance of this class set to the ``member_change_email`` tag - with value ``val``. + Only call this if :meth:`is_file_requests_change_policy` is true. - :param MemberChangeEmailType val: - :rtype: EventType + :rtype: FileRequestsChangePolicyType """ - return cls('member_change_email', val) + if not self.is_file_requests_change_policy(): + raise AttributeError("tag 'file_requests_change_policy' not set") + return self._value - @classmethod - def member_change_external_id(cls, val): + def get_file_requests_emails_enabled(self): """ - Create an instance of this class set to the - ``member_change_external_id`` tag with value ``val``. + (team_policies) Enabled file request emails for everyone (deprecated, no + longer logged) - :param MemberChangeExternalIdType val: - :rtype: EventType - """ - return cls('member_change_external_id', val) + Only call this if :meth:`is_file_requests_emails_enabled` is true. - @classmethod - def member_change_membership_type(cls, val): + :rtype: FileRequestsEmailsEnabledType """ - Create an instance of this class set to the - ``member_change_membership_type`` tag with value ``val``. + if not self.is_file_requests_emails_enabled(): + raise AttributeError("tag 'file_requests_emails_enabled' not set") + return self._value - :param MemberChangeMembershipTypeType val: - :rtype: EventType + def get_file_requests_emails_restricted_to_team_only(self): """ - return cls('member_change_membership_type', val) + (team_policies) Enabled file request emails for team (deprecated, no + longer logged) - @classmethod - def member_change_name(cls, val): - """ - Create an instance of this class set to the ``member_change_name`` tag - with value ``val``. + Only call this if :meth:`is_file_requests_emails_restricted_to_team_only` is true. - :param MemberChangeNameType val: - :rtype: EventType + :rtype: FileRequestsEmailsRestrictedToTeamOnlyType """ - return cls('member_change_name', val) + if not self.is_file_requests_emails_restricted_to_team_only(): + raise AttributeError("tag 'file_requests_emails_restricted_to_team_only' not set") + return self._value - @classmethod - def member_change_status(cls, val): + def get_file_transfers_policy_changed(self): """ - Create an instance of this class set to the ``member_change_status`` tag - with value ``val``. + (team_policies) Changed file transfers policy for team - :param MemberChangeStatusType val: - :rtype: EventType - """ - return cls('member_change_status', val) + Only call this if :meth:`is_file_transfers_policy_changed` is true. - @classmethod - def member_delete_manual_contacts(cls, val): + :rtype: FileTransfersPolicyChangedType """ - Create an instance of this class set to the - ``member_delete_manual_contacts`` tag with value ``val``. + if not self.is_file_transfers_policy_changed(): + raise AttributeError("tag 'file_transfers_policy_changed' not set") + return self._value - :param MemberDeleteManualContactsType val: - :rtype: EventType + def get_google_sso_change_policy(self): """ - return cls('member_delete_manual_contacts', val) + (team_policies) Enabled/disabled Google single sign-on for team - @classmethod - def member_permanently_delete_account_contents(cls, val): - """ - Create an instance of this class set to the - ``member_permanently_delete_account_contents`` tag with value ``val``. + Only call this if :meth:`is_google_sso_change_policy` is true. - :param MemberPermanentlyDeleteAccountContentsType val: - :rtype: EventType + :rtype: GoogleSsoChangePolicyType """ - return cls('member_permanently_delete_account_contents', val) + if not self.is_google_sso_change_policy(): + raise AttributeError("tag 'google_sso_change_policy' not set") + return self._value - @classmethod - def member_remove_external_id(cls, val): + def get_group_user_management_change_policy(self): """ - Create an instance of this class set to the - ``member_remove_external_id`` tag with value ``val``. + (team_policies) Changed who can create groups - :param MemberRemoveExternalIdType val: - :rtype: EventType - """ - return cls('member_remove_external_id', val) + Only call this if :meth:`is_group_user_management_change_policy` is true. - @classmethod - def member_space_limits_add_custom_quota(cls, val): + :rtype: GroupUserManagementChangePolicyType """ - Create an instance of this class set to the - ``member_space_limits_add_custom_quota`` tag with value ``val``. + if not self.is_group_user_management_change_policy(): + raise AttributeError("tag 'group_user_management_change_policy' not set") + return self._value - :param MemberSpaceLimitsAddCustomQuotaType val: - :rtype: EventType + def get_integration_policy_changed(self): """ - return cls('member_space_limits_add_custom_quota', val) + (team_policies) Changed integration policy for team - @classmethod - def member_space_limits_change_custom_quota(cls, val): - """ - Create an instance of this class set to the - ``member_space_limits_change_custom_quota`` tag with value ``val``. + Only call this if :meth:`is_integration_policy_changed` is true. - :param MemberSpaceLimitsChangeCustomQuotaType val: - :rtype: EventType + :rtype: IntegrationPolicyChangedType """ - return cls('member_space_limits_change_custom_quota', val) + if not self.is_integration_policy_changed(): + raise AttributeError("tag 'integration_policy_changed' not set") + return self._value - @classmethod - def member_space_limits_change_status(cls, val): + def get_member_requests_change_policy(self): """ - Create an instance of this class set to the - ``member_space_limits_change_status`` tag with value ``val``. + (team_policies) Changed whether users can find team when not invited - :param MemberSpaceLimitsChangeStatusType val: - :rtype: EventType - """ - return cls('member_space_limits_change_status', val) + Only call this if :meth:`is_member_requests_change_policy` is true. - @classmethod - def member_space_limits_remove_custom_quota(cls, val): + :rtype: MemberRequestsChangePolicyType """ - Create an instance of this class set to the - ``member_space_limits_remove_custom_quota`` tag with value ``val``. + if not self.is_member_requests_change_policy(): + raise AttributeError("tag 'member_requests_change_policy' not set") + return self._value - :param MemberSpaceLimitsRemoveCustomQuotaType val: - :rtype: EventType + def get_member_send_invite_policy_changed(self): """ - return cls('member_space_limits_remove_custom_quota', val) + (team_policies) Changed member send invite policy for team - @classmethod - def member_suggest(cls, val): - """ - Create an instance of this class set to the ``member_suggest`` tag with - value ``val``. + Only call this if :meth:`is_member_send_invite_policy_changed` is true. - :param MemberSuggestType val: - :rtype: EventType + :rtype: MemberSendInvitePolicyChangedType """ - return cls('member_suggest', val) + if not self.is_member_send_invite_policy_changed(): + raise AttributeError("tag 'member_send_invite_policy_changed' not set") + return self._value - @classmethod - def member_transfer_account_contents(cls, val): + def get_member_space_limits_add_exception(self): """ - Create an instance of this class set to the - ``member_transfer_account_contents`` tag with value ``val``. + (team_policies) Added members to member space limit exception list - :param MemberTransferAccountContentsType val: - :rtype: EventType - """ - return cls('member_transfer_account_contents', val) + Only call this if :meth:`is_member_space_limits_add_exception` is true. - @classmethod - def secondary_mails_policy_changed(cls, val): + :rtype: MemberSpaceLimitsAddExceptionType """ - Create an instance of this class set to the - ``secondary_mails_policy_changed`` tag with value ``val``. + if not self.is_member_space_limits_add_exception(): + raise AttributeError("tag 'member_space_limits_add_exception' not set") + return self._value - :param SecondaryMailsPolicyChangedType val: - :rtype: EventType + def get_member_space_limits_change_caps_type_policy(self): """ - return cls('secondary_mails_policy_changed', val) + (team_policies) Changed member space limit type for team - @classmethod - def paper_content_add_member(cls, val): - """ - Create an instance of this class set to the ``paper_content_add_member`` - tag with value ``val``. + Only call this if :meth:`is_member_space_limits_change_caps_type_policy` is true. - :param PaperContentAddMemberType val: - :rtype: EventType + :rtype: MemberSpaceLimitsChangeCapsTypePolicyType """ - return cls('paper_content_add_member', val) + if not self.is_member_space_limits_change_caps_type_policy(): + raise AttributeError("tag 'member_space_limits_change_caps_type_policy' not set") + return self._value - @classmethod - def paper_content_add_to_folder(cls, val): + def get_member_space_limits_change_policy(self): """ - Create an instance of this class set to the - ``paper_content_add_to_folder`` tag with value ``val``. + (team_policies) Changed team default member space limit - :param PaperContentAddToFolderType val: - :rtype: EventType - """ - return cls('paper_content_add_to_folder', val) + Only call this if :meth:`is_member_space_limits_change_policy` is true. - @classmethod - def paper_content_archive(cls, val): + :rtype: MemberSpaceLimitsChangePolicyType """ - Create an instance of this class set to the ``paper_content_archive`` - tag with value ``val``. + if not self.is_member_space_limits_change_policy(): + raise AttributeError("tag 'member_space_limits_change_policy' not set") + return self._value - :param PaperContentArchiveType val: - :rtype: EventType + def get_member_space_limits_remove_exception(self): """ - return cls('paper_content_archive', val) + (team_policies) Removed members from member space limit exception list - @classmethod - def paper_content_create(cls, val): + Only call this if :meth:`is_member_space_limits_remove_exception` is true. + + :rtype: MemberSpaceLimitsRemoveExceptionType """ - Create an instance of this class set to the ``paper_content_create`` tag - with value ``val``. + if not self.is_member_space_limits_remove_exception(): + raise AttributeError("tag 'member_space_limits_remove_exception' not set") + return self._value - :param PaperContentCreateType val: - :rtype: EventType + def get_member_suggestions_change_policy(self): """ - return cls('paper_content_create', val) + (team_policies) Enabled/disabled option for team members to suggest + people to add to team - @classmethod - def paper_content_permanently_delete(cls, val): + Only call this if :meth:`is_member_suggestions_change_policy` is true. + + :rtype: MemberSuggestionsChangePolicyType """ - Create an instance of this class set to the - ``paper_content_permanently_delete`` tag with value ``val``. + if not self.is_member_suggestions_change_policy(): + raise AttributeError("tag 'member_suggestions_change_policy' not set") + return self._value - :param PaperContentPermanentlyDeleteType val: - :rtype: EventType + def get_microsoft_office_addin_change_policy(self): """ - return cls('paper_content_permanently_delete', val) + (team_policies) Enabled/disabled Microsoft Office add-in - @classmethod - def paper_content_remove_from_folder(cls, val): + Only call this if :meth:`is_microsoft_office_addin_change_policy` is true. + + :rtype: MicrosoftOfficeAddinChangePolicyType """ - Create an instance of this class set to the - ``paper_content_remove_from_folder`` tag with value ``val``. + if not self.is_microsoft_office_addin_change_policy(): + raise AttributeError("tag 'microsoft_office_addin_change_policy' not set") + return self._value - :param PaperContentRemoveFromFolderType val: - :rtype: EventType + def get_network_control_change_policy(self): """ - return cls('paper_content_remove_from_folder', val) + (team_policies) Enabled/disabled network control - @classmethod - def paper_content_remove_member(cls, val): - """ - Create an instance of this class set to the - ``paper_content_remove_member`` tag with value ``val``. + Only call this if :meth:`is_network_control_change_policy` is true. - :param PaperContentRemoveMemberType val: - :rtype: EventType + :rtype: NetworkControlChangePolicyType """ - return cls('paper_content_remove_member', val) + if not self.is_network_control_change_policy(): + raise AttributeError("tag 'network_control_change_policy' not set") + return self._value - @classmethod - def paper_content_rename(cls, val): + def get_paper_change_deployment_policy(self): """ - Create an instance of this class set to the ``paper_content_rename`` tag - with value ``val``. + (team_policies) Changed whether Dropbox Paper, when enabled, is deployed + to all members or to specific members - :param PaperContentRenameType val: - :rtype: EventType - """ - return cls('paper_content_rename', val) + Only call this if :meth:`is_paper_change_deployment_policy` is true. - @classmethod - def paper_content_restore(cls, val): + :rtype: PaperChangeDeploymentPolicyType """ - Create an instance of this class set to the ``paper_content_restore`` - tag with value ``val``. + if not self.is_paper_change_deployment_policy(): + raise AttributeError("tag 'paper_change_deployment_policy' not set") + return self._value - :param PaperContentRestoreType val: - :rtype: EventType + def get_paper_change_member_link_policy(self): """ - return cls('paper_content_restore', val) + (team_policies) Changed whether non-members can view Paper docs with + link (deprecated, no longer logged) - @classmethod - def paper_doc_add_comment(cls, val): - """ - Create an instance of this class set to the ``paper_doc_add_comment`` - tag with value ``val``. + Only call this if :meth:`is_paper_change_member_link_policy` is true. - :param PaperDocAddCommentType val: - :rtype: EventType + :rtype: PaperChangeMemberLinkPolicyType """ - return cls('paper_doc_add_comment', val) + if not self.is_paper_change_member_link_policy(): + raise AttributeError("tag 'paper_change_member_link_policy' not set") + return self._value - @classmethod - def paper_doc_change_member_role(cls, val): + def get_paper_change_member_policy(self): """ - Create an instance of this class set to the - ``paper_doc_change_member_role`` tag with value ``val``. + (team_policies) Changed whether members can share Paper docs outside + team, and if docs are accessible only by team members or anyone by + default - :param PaperDocChangeMemberRoleType val: - :rtype: EventType - """ - return cls('paper_doc_change_member_role', val) + Only call this if :meth:`is_paper_change_member_policy` is true. - @classmethod - def paper_doc_change_sharing_policy(cls, val): + :rtype: PaperChangeMemberPolicyType """ - Create an instance of this class set to the - ``paper_doc_change_sharing_policy`` tag with value ``val``. + if not self.is_paper_change_member_policy(): + raise AttributeError("tag 'paper_change_member_policy' not set") + return self._value - :param PaperDocChangeSharingPolicyType val: - :rtype: EventType + def get_paper_change_policy(self): """ - return cls('paper_doc_change_sharing_policy', val) + (team_policies) Enabled/disabled Dropbox Paper for team - @classmethod - def paper_doc_change_subscription(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_change_subscription`` tag with value ``val``. + Only call this if :meth:`is_paper_change_policy` is true. - :param PaperDocChangeSubscriptionType val: - :rtype: EventType + :rtype: PaperChangePolicyType """ - return cls('paper_doc_change_subscription', val) + if not self.is_paper_change_policy(): + raise AttributeError("tag 'paper_change_policy' not set") + return self._value - @classmethod - def paper_doc_deleted(cls, val): + def get_paper_default_folder_policy_changed(self): """ - Create an instance of this class set to the ``paper_doc_deleted`` tag - with value ``val``. + (team_policies) Changed Paper Default Folder Policy setting for team - :param PaperDocDeletedType val: - :rtype: EventType - """ - return cls('paper_doc_deleted', val) + Only call this if :meth:`is_paper_default_folder_policy_changed` is true. - @classmethod - def paper_doc_delete_comment(cls, val): + :rtype: PaperDefaultFolderPolicyChangedType """ - Create an instance of this class set to the ``paper_doc_delete_comment`` - tag with value ``val``. + if not self.is_paper_default_folder_policy_changed(): + raise AttributeError("tag 'paper_default_folder_policy_changed' not set") + return self._value - :param PaperDocDeleteCommentType val: - :rtype: EventType + def get_paper_desktop_policy_changed(self): """ - return cls('paper_doc_delete_comment', val) + (team_policies) Enabled/disabled Paper Desktop for team - @classmethod - def paper_doc_download(cls, val): - """ - Create an instance of this class set to the ``paper_doc_download`` tag - with value ``val``. + Only call this if :meth:`is_paper_desktop_policy_changed` is true. - :param PaperDocDownloadType val: - :rtype: EventType + :rtype: PaperDesktopPolicyChangedType """ - return cls('paper_doc_download', val) + if not self.is_paper_desktop_policy_changed(): + raise AttributeError("tag 'paper_desktop_policy_changed' not set") + return self._value - @classmethod - def paper_doc_edit(cls, val): + def get_paper_enabled_users_group_addition(self): """ - Create an instance of this class set to the ``paper_doc_edit`` tag with - value ``val``. + (team_policies) Added users to Paper-enabled users list - :param PaperDocEditType val: - :rtype: EventType - """ - return cls('paper_doc_edit', val) + Only call this if :meth:`is_paper_enabled_users_group_addition` is true. - @classmethod - def paper_doc_edit_comment(cls, val): + :rtype: PaperEnabledUsersGroupAdditionType """ - Create an instance of this class set to the ``paper_doc_edit_comment`` - tag with value ``val``. + if not self.is_paper_enabled_users_group_addition(): + raise AttributeError("tag 'paper_enabled_users_group_addition' not set") + return self._value - :param PaperDocEditCommentType val: - :rtype: EventType + def get_paper_enabled_users_group_removal(self): """ - return cls('paper_doc_edit_comment', val) + (team_policies) Removed users from Paper-enabled users list - @classmethod - def paper_doc_followed(cls, val): - """ - Create an instance of this class set to the ``paper_doc_followed`` tag - with value ``val``. + Only call this if :meth:`is_paper_enabled_users_group_removal` is true. - :param PaperDocFollowedType val: - :rtype: EventType + :rtype: PaperEnabledUsersGroupRemovalType """ - return cls('paper_doc_followed', val) + if not self.is_paper_enabled_users_group_removal(): + raise AttributeError("tag 'paper_enabled_users_group_removal' not set") + return self._value - @classmethod - def paper_doc_mention(cls, val): + def get_password_strength_requirements_change_policy(self): """ - Create an instance of this class set to the ``paper_doc_mention`` tag - with value ``val``. + (team_policies) Changed team password strength requirements - :param PaperDocMentionType val: - :rtype: EventType - """ - return cls('paper_doc_mention', val) + Only call this if :meth:`is_password_strength_requirements_change_policy` is true. - @classmethod - def paper_doc_ownership_changed(cls, val): + :rtype: PasswordStrengthRequirementsChangePolicyType """ - Create an instance of this class set to the - ``paper_doc_ownership_changed`` tag with value ``val``. + if not self.is_password_strength_requirements_change_policy(): + raise AttributeError("tag 'password_strength_requirements_change_policy' not set") + return self._value - :param PaperDocOwnershipChangedType val: - :rtype: EventType + def get_permanent_delete_change_policy(self): """ - return cls('paper_doc_ownership_changed', val) + (team_policies) Enabled/disabled ability of team members to permanently + delete content - @classmethod - def paper_doc_request_access(cls, val): - """ - Create an instance of this class set to the ``paper_doc_request_access`` - tag with value ``val``. + Only call this if :meth:`is_permanent_delete_change_policy` is true. - :param PaperDocRequestAccessType val: - :rtype: EventType + :rtype: PermanentDeleteChangePolicyType """ - return cls('paper_doc_request_access', val) + if not self.is_permanent_delete_change_policy(): + raise AttributeError("tag 'permanent_delete_change_policy' not set") + return self._value - @classmethod - def paper_doc_resolve_comment(cls, val): + def get_reseller_support_change_policy(self): """ - Create an instance of this class set to the - ``paper_doc_resolve_comment`` tag with value ``val``. + (team_policies) Enabled/disabled reseller support - :param PaperDocResolveCommentType val: - :rtype: EventType - """ - return cls('paper_doc_resolve_comment', val) + Only call this if :meth:`is_reseller_support_change_policy` is true. - @classmethod - def paper_doc_revert(cls, val): + :rtype: ResellerSupportChangePolicyType """ - Create an instance of this class set to the ``paper_doc_revert`` tag - with value ``val``. + if not self.is_reseller_support_change_policy(): + raise AttributeError("tag 'reseller_support_change_policy' not set") + return self._value - :param PaperDocRevertType val: - :rtype: EventType + def get_rewind_policy_changed(self): """ - return cls('paper_doc_revert', val) + (team_policies) Changed Rewind policy for team - @classmethod - def paper_doc_slack_share(cls, val): - """ - Create an instance of this class set to the ``paper_doc_slack_share`` - tag with value ``val``. + Only call this if :meth:`is_rewind_policy_changed` is true. - :param PaperDocSlackShareType val: - :rtype: EventType + :rtype: RewindPolicyChangedType """ - return cls('paper_doc_slack_share', val) + if not self.is_rewind_policy_changed(): + raise AttributeError("tag 'rewind_policy_changed' not set") + return self._value - @classmethod - def paper_doc_team_invite(cls, val): + def get_sharing_change_folder_join_policy(self): """ - Create an instance of this class set to the ``paper_doc_team_invite`` - tag with value ``val``. + (team_policies) Changed whether team members can join shared folders + owned outside team - :param PaperDocTeamInviteType val: - :rtype: EventType - """ - return cls('paper_doc_team_invite', val) + Only call this if :meth:`is_sharing_change_folder_join_policy` is true. - @classmethod - def paper_doc_trashed(cls, val): + :rtype: SharingChangeFolderJoinPolicyType """ - Create an instance of this class set to the ``paper_doc_trashed`` tag - with value ``val``. + if not self.is_sharing_change_folder_join_policy(): + raise AttributeError("tag 'sharing_change_folder_join_policy' not set") + return self._value - :param PaperDocTrashedType val: - :rtype: EventType + def get_sharing_change_link_policy(self): """ - return cls('paper_doc_trashed', val) + (team_policies) Changed whether members can share links outside team, + and if links are accessible only by team members or anyone by default - @classmethod - def paper_doc_unresolve_comment(cls, val): - """ - Create an instance of this class set to the - ``paper_doc_unresolve_comment`` tag with value ``val``. + Only call this if :meth:`is_sharing_change_link_policy` is true. - :param PaperDocUnresolveCommentType val: - :rtype: EventType + :rtype: SharingChangeLinkPolicyType """ - return cls('paper_doc_unresolve_comment', val) + if not self.is_sharing_change_link_policy(): + raise AttributeError("tag 'sharing_change_link_policy' not set") + return self._value - @classmethod - def paper_doc_untrashed(cls, val): + def get_sharing_change_member_policy(self): """ - Create an instance of this class set to the ``paper_doc_untrashed`` tag - with value ``val``. + (team_policies) Changed whether members can share files/folders outside + team - :param PaperDocUntrashedType val: - :rtype: EventType - """ - return cls('paper_doc_untrashed', val) + Only call this if :meth:`is_sharing_change_member_policy` is true. - @classmethod - def paper_doc_view(cls, val): + :rtype: SharingChangeMemberPolicyType """ - Create an instance of this class set to the ``paper_doc_view`` tag with - value ``val``. + if not self.is_sharing_change_member_policy(): + raise AttributeError("tag 'sharing_change_member_policy' not set") + return self._value - :param PaperDocViewType val: - :rtype: EventType + def get_showcase_change_download_policy(self): """ - return cls('paper_doc_view', val) + (team_policies) Enabled/disabled downloading files from Dropbox Showcase + for team - @classmethod - def paper_external_view_allow(cls, val): - """ - Create an instance of this class set to the - ``paper_external_view_allow`` tag with value ``val``. + Only call this if :meth:`is_showcase_change_download_policy` is true. - :param PaperExternalViewAllowType val: - :rtype: EventType + :rtype: ShowcaseChangeDownloadPolicyType """ - return cls('paper_external_view_allow', val) + if not self.is_showcase_change_download_policy(): + raise AttributeError("tag 'showcase_change_download_policy' not set") + return self._value - @classmethod - def paper_external_view_default_team(cls, val): + def get_showcase_change_enabled_policy(self): """ - Create an instance of this class set to the - ``paper_external_view_default_team`` tag with value ``val``. + (team_policies) Enabled/disabled Dropbox Showcase for team - :param PaperExternalViewDefaultTeamType val: - :rtype: EventType - """ - return cls('paper_external_view_default_team', val) + Only call this if :meth:`is_showcase_change_enabled_policy` is true. - @classmethod - def paper_external_view_forbid(cls, val): + :rtype: ShowcaseChangeEnabledPolicyType """ - Create an instance of this class set to the - ``paper_external_view_forbid`` tag with value ``val``. + if not self.is_showcase_change_enabled_policy(): + raise AttributeError("tag 'showcase_change_enabled_policy' not set") + return self._value - :param PaperExternalViewForbidType val: - :rtype: EventType + def get_showcase_change_external_sharing_policy(self): """ - return cls('paper_external_view_forbid', val) + (team_policies) Enabled/disabled sharing Dropbox Showcase externally for + team - @classmethod - def paper_folder_change_subscription(cls, val): - """ - Create an instance of this class set to the - ``paper_folder_change_subscription`` tag with value ``val``. + Only call this if :meth:`is_showcase_change_external_sharing_policy` is true. - :param PaperFolderChangeSubscriptionType val: - :rtype: EventType + :rtype: ShowcaseChangeExternalSharingPolicyType """ - return cls('paper_folder_change_subscription', val) + if not self.is_showcase_change_external_sharing_policy(): + raise AttributeError("tag 'showcase_change_external_sharing_policy' not set") + return self._value - @classmethod - def paper_folder_deleted(cls, val): + def get_smarter_smart_sync_policy_changed(self): """ - Create an instance of this class set to the ``paper_folder_deleted`` tag - with value ``val``. + (team_policies) Changed automatic Smart Sync setting for team - :param PaperFolderDeletedType val: - :rtype: EventType - """ - return cls('paper_folder_deleted', val) + Only call this if :meth:`is_smarter_smart_sync_policy_changed` is true. - @classmethod - def paper_folder_followed(cls, val): + :rtype: SmarterSmartSyncPolicyChangedType """ - Create an instance of this class set to the ``paper_folder_followed`` - tag with value ``val``. + if not self.is_smarter_smart_sync_policy_changed(): + raise AttributeError("tag 'smarter_smart_sync_policy_changed' not set") + return self._value - :param PaperFolderFollowedType val: - :rtype: EventType + def get_smart_sync_change_policy(self): """ - return cls('paper_folder_followed', val) + (team_policies) Changed default Smart Sync setting for team members - @classmethod - def paper_folder_team_invite(cls, val): - """ - Create an instance of this class set to the ``paper_folder_team_invite`` - tag with value ``val``. + Only call this if :meth:`is_smart_sync_change_policy` is true. - :param PaperFolderTeamInviteType val: - :rtype: EventType + :rtype: SmartSyncChangePolicyType """ - return cls('paper_folder_team_invite', val) + if not self.is_smart_sync_change_policy(): + raise AttributeError("tag 'smart_sync_change_policy' not set") + return self._value - @classmethod - def paper_published_link_create(cls, val): + def get_smart_sync_not_opt_out(self): """ - Create an instance of this class set to the - ``paper_published_link_create`` tag with value ``val``. + (team_policies) Opted team into Smart Sync - :param PaperPublishedLinkCreateType val: - :rtype: EventType - """ - return cls('paper_published_link_create', val) + Only call this if :meth:`is_smart_sync_not_opt_out` is true. - @classmethod - def paper_published_link_disabled(cls, val): + :rtype: SmartSyncNotOptOutType """ - Create an instance of this class set to the - ``paper_published_link_disabled`` tag with value ``val``. + if not self.is_smart_sync_not_opt_out(): + raise AttributeError("tag 'smart_sync_not_opt_out' not set") + return self._value - :param PaperPublishedLinkDisabledType val: - :rtype: EventType + def get_smart_sync_opt_out(self): """ - return cls('paper_published_link_disabled', val) + (team_policies) Opted team out of Smart Sync - @classmethod - def paper_published_link_view(cls, val): - """ - Create an instance of this class set to the - ``paper_published_link_view`` tag with value ``val``. + Only call this if :meth:`is_smart_sync_opt_out` is true. - :param PaperPublishedLinkViewType val: - :rtype: EventType + :rtype: SmartSyncOptOutType """ - return cls('paper_published_link_view', val) + if not self.is_smart_sync_opt_out(): + raise AttributeError("tag 'smart_sync_opt_out' not set") + return self._value - @classmethod - def password_change(cls, val): + def get_sso_change_policy(self): """ - Create an instance of this class set to the ``password_change`` tag with - value ``val``. + (team_policies) Changed single sign-on setting for team - :param PasswordChangeType val: - :rtype: EventType + Only call this if :meth:`is_sso_change_policy` is true. + + :rtype: SsoChangePolicyType """ - return cls('password_change', val) + if not self.is_sso_change_policy(): + raise AttributeError("tag 'sso_change_policy' not set") + return self._value - @classmethod - def password_reset(cls, val): + def get_team_extensions_policy_changed(self): """ - Create an instance of this class set to the ``password_reset`` tag with - value ``val``. + (team_policies) Changed App Integrations setting for team - :param PasswordResetType val: - :rtype: EventType + Only call this if :meth:`is_team_extensions_policy_changed` is true. + + :rtype: TeamExtensionsPolicyChangedType """ - return cls('password_reset', val) + if not self.is_team_extensions_policy_changed(): + raise AttributeError("tag 'team_extensions_policy_changed' not set") + return self._value - @classmethod - def password_reset_all(cls, val): + def get_team_selective_sync_policy_changed(self): """ - Create an instance of this class set to the ``password_reset_all`` tag - with value ``val``. + (team_policies) Enabled/disabled Team Selective Sync for team - :param PasswordResetAllType val: - :rtype: EventType + Only call this if :meth:`is_team_selective_sync_policy_changed` is true. + + :rtype: TeamSelectiveSyncPolicyChangedType """ - return cls('password_reset_all', val) + if not self.is_team_selective_sync_policy_changed(): + raise AttributeError("tag 'team_selective_sync_policy_changed' not set") + return self._value - @classmethod - def emm_create_exceptions_report(cls, val): + def get_team_sharing_whitelist_subjects_changed(self): """ - Create an instance of this class set to the - ``emm_create_exceptions_report`` tag with value ``val``. + (team_policies) Edited the approved list for sharing externally - :param EmmCreateExceptionsReportType val: - :rtype: EventType + Only call this if :meth:`is_team_sharing_whitelist_subjects_changed` is true. + + :rtype: TeamSharingWhitelistSubjectsChangedType """ - return cls('emm_create_exceptions_report', val) + if not self.is_team_sharing_whitelist_subjects_changed(): + raise AttributeError("tag 'team_sharing_whitelist_subjects_changed' not set") + return self._value - @classmethod - def emm_create_usage_report(cls, val): + def get_tfa_add_exception(self): """ - Create an instance of this class set to the ``emm_create_usage_report`` - tag with value ``val``. + (team_policies) Added members to two factor authentication exception + list - :param EmmCreateUsageReportType val: - :rtype: EventType + Only call this if :meth:`is_tfa_add_exception` is true. + + :rtype: TfaAddExceptionType """ - return cls('emm_create_usage_report', val) + if not self.is_tfa_add_exception(): + raise AttributeError("tag 'tfa_add_exception' not set") + return self._value - @classmethod - def export_members_report(cls, val): + def get_tfa_change_policy(self): """ - Create an instance of this class set to the ``export_members_report`` - tag with value ``val``. + (team_policies) Changed two-step verification setting for team - :param ExportMembersReportType val: - :rtype: EventType + Only call this if :meth:`is_tfa_change_policy` is true. + + :rtype: TfaChangePolicyType """ - return cls('export_members_report', val) + if not self.is_tfa_change_policy(): + raise AttributeError("tag 'tfa_change_policy' not set") + return self._value - @classmethod - def paper_admin_export_start(cls, val): + def get_tfa_remove_exception(self): """ - Create an instance of this class set to the ``paper_admin_export_start`` - tag with value ``val``. + (team_policies) Removed members from two factor authentication exception + list - :param PaperAdminExportStartType val: - :rtype: EventType + Only call this if :meth:`is_tfa_remove_exception` is true. + + :rtype: TfaRemoveExceptionType """ - return cls('paper_admin_export_start', val) + if not self.is_tfa_remove_exception(): + raise AttributeError("tag 'tfa_remove_exception' not set") + return self._value - @classmethod - def smart_sync_create_admin_privilege_report(cls, val): + def get_two_account_change_policy(self): """ - Create an instance of this class set to the - ``smart_sync_create_admin_privilege_report`` tag with value ``val``. + (team_policies) Enabled/disabled option for members to link personal + Dropbox account and team account to same computer + + Only call this if :meth:`is_two_account_change_policy` is true. - :param SmartSyncCreateAdminPrivilegeReportType val: - :rtype: EventType + :rtype: TwoAccountChangePolicyType """ - return cls('smart_sync_create_admin_privilege_report', val) + if not self.is_two_account_change_policy(): + raise AttributeError("tag 'two_account_change_policy' not set") + return self._value - @classmethod - def team_activity_create_report(cls, val): + def get_viewer_info_policy_changed(self): """ - Create an instance of this class set to the - ``team_activity_create_report`` tag with value ``val``. + (team_policies) Changed team policy for viewer info - :param TeamActivityCreateReportType val: - :rtype: EventType - """ - return cls('team_activity_create_report', val) + Only call this if :meth:`is_viewer_info_policy_changed` is true. - @classmethod - def team_activity_create_report_fail(cls, val): + :rtype: ViewerInfoPolicyChangedType """ - Create an instance of this class set to the - ``team_activity_create_report_fail`` tag with value ``val``. + if not self.is_viewer_info_policy_changed(): + raise AttributeError("tag 'viewer_info_policy_changed' not set") + return self._value - :param TeamActivityCreateReportFailType val: - :rtype: EventType + def get_watermarking_policy_changed(self): """ - return cls('team_activity_create_report_fail', val) + (team_policies) Changed watermarking policy for team - @classmethod - def collection_share(cls, val): + Only call this if :meth:`is_watermarking_policy_changed` is true. + + :rtype: WatermarkingPolicyChangedType """ - Create an instance of this class set to the ``collection_share`` tag - with value ``val``. + if not self.is_watermarking_policy_changed(): + raise AttributeError("tag 'watermarking_policy_changed' not set") + return self._value - :param CollectionShareType val: - :rtype: EventType + def get_web_sessions_change_active_session_limit(self): """ - return cls('collection_share', val) + (team_policies) Changed limit on active sessions per member - @classmethod - def note_acl_invite_only(cls, val): + Only call this if :meth:`is_web_sessions_change_active_session_limit` is true. + + :rtype: WebSessionsChangeActiveSessionLimitType """ - Create an instance of this class set to the ``note_acl_invite_only`` tag - with value ``val``. + if not self.is_web_sessions_change_active_session_limit(): + raise AttributeError("tag 'web_sessions_change_active_session_limit' not set") + return self._value - :param NoteAclInviteOnlyType val: - :rtype: EventType + def get_web_sessions_change_fixed_length_policy(self): """ - return cls('note_acl_invite_only', val) + (team_policies) Changed how long members can stay signed in to + Dropbox.com - @classmethod - def note_acl_link(cls, val): + Only call this if :meth:`is_web_sessions_change_fixed_length_policy` is true. + + :rtype: WebSessionsChangeFixedLengthPolicyType """ - Create an instance of this class set to the ``note_acl_link`` tag with - value ``val``. + if not self.is_web_sessions_change_fixed_length_policy(): + raise AttributeError("tag 'web_sessions_change_fixed_length_policy' not set") + return self._value - :param NoteAclLinkType val: - :rtype: EventType + def get_web_sessions_change_idle_length_policy(self): """ - return cls('note_acl_link', val) + (team_policies) Changed how long team members can be idle while signed + in to Dropbox.com - @classmethod - def note_acl_team_link(cls, val): + Only call this if :meth:`is_web_sessions_change_idle_length_policy` is true. + + :rtype: WebSessionsChangeIdleLengthPolicyType """ - Create an instance of this class set to the ``note_acl_team_link`` tag - with value ``val``. + if not self.is_web_sessions_change_idle_length_policy(): + raise AttributeError("tag 'web_sessions_change_idle_length_policy' not set") + return self._value - :param NoteAclTeamLinkType val: - :rtype: EventType + def get_team_merge_from(self): """ - return cls('note_acl_team_link', val) + (team_profile) Merged another team into this team - @classmethod - def note_shared(cls, val): + Only call this if :meth:`is_team_merge_from` is true. + + :rtype: TeamMergeFromType """ - Create an instance of this class set to the ``note_shared`` tag with - value ``val``. + if not self.is_team_merge_from(): + raise AttributeError("tag 'team_merge_from' not set") + return self._value - :param NoteSharedType val: - :rtype: EventType + def get_team_merge_to(self): """ - return cls('note_shared', val) + (team_profile) Merged this team into another team - @classmethod - def note_share_receive(cls, val): + Only call this if :meth:`is_team_merge_to` is true. + + :rtype: TeamMergeToType """ - Create an instance of this class set to the ``note_share_receive`` tag - with value ``val``. + if not self.is_team_merge_to(): + raise AttributeError("tag 'team_merge_to' not set") + return self._value - :param NoteShareReceiveType val: - :rtype: EventType + def get_team_profile_add_logo(self): """ - return cls('note_share_receive', val) + (team_profile) Added team logo to display on shared link headers - @classmethod - def open_note_shared(cls, val): + Only call this if :meth:`is_team_profile_add_logo` is true. + + :rtype: TeamProfileAddLogoType """ - Create an instance of this class set to the ``open_note_shared`` tag - with value ``val``. + if not self.is_team_profile_add_logo(): + raise AttributeError("tag 'team_profile_add_logo' not set") + return self._value - :param OpenNoteSharedType val: - :rtype: EventType + def get_team_profile_change_default_language(self): """ - return cls('open_note_shared', val) + (team_profile) Changed default language for team - @classmethod - def sf_add_group(cls, val): + Only call this if :meth:`is_team_profile_change_default_language` is true. + + :rtype: TeamProfileChangeDefaultLanguageType """ - Create an instance of this class set to the ``sf_add_group`` tag with - value ``val``. + if not self.is_team_profile_change_default_language(): + raise AttributeError("tag 'team_profile_change_default_language' not set") + return self._value - :param SfAddGroupType val: - :rtype: EventType + def get_team_profile_change_logo(self): """ - return cls('sf_add_group', val) + (team_profile) Changed team logo displayed on shared link headers - @classmethod - def sf_allow_non_members_to_view_shared_links(cls, val): + Only call this if :meth:`is_team_profile_change_logo` is true. + + :rtype: TeamProfileChangeLogoType """ - Create an instance of this class set to the - ``sf_allow_non_members_to_view_shared_links`` tag with value ``val``. + if not self.is_team_profile_change_logo(): + raise AttributeError("tag 'team_profile_change_logo' not set") + return self._value - :param SfAllowNonMembersToViewSharedLinksType val: - :rtype: EventType + def get_team_profile_change_name(self): """ - return cls('sf_allow_non_members_to_view_shared_links', val) + (team_profile) Changed team name - @classmethod - def sf_external_invite_warn(cls, val): + Only call this if :meth:`is_team_profile_change_name` is true. + + :rtype: TeamProfileChangeNameType """ - Create an instance of this class set to the ``sf_external_invite_warn`` - tag with value ``val``. + if not self.is_team_profile_change_name(): + raise AttributeError("tag 'team_profile_change_name' not set") + return self._value - :param SfExternalInviteWarnType val: - :rtype: EventType + def get_team_profile_remove_logo(self): """ - return cls('sf_external_invite_warn', val) + (team_profile) Removed team logo displayed on shared link headers - @classmethod - def sf_fb_invite(cls, val): + Only call this if :meth:`is_team_profile_remove_logo` is true. + + :rtype: TeamProfileRemoveLogoType """ - Create an instance of this class set to the ``sf_fb_invite`` tag with - value ``val``. + if not self.is_team_profile_remove_logo(): + raise AttributeError("tag 'team_profile_remove_logo' not set") + return self._value - :param SfFbInviteType val: - :rtype: EventType + def get_tfa_add_backup_phone(self): """ - return cls('sf_fb_invite', val) + (tfa) Added backup phone for two-step verification - @classmethod - def sf_fb_invite_change_role(cls, val): + Only call this if :meth:`is_tfa_add_backup_phone` is true. + + :rtype: TfaAddBackupPhoneType """ - Create an instance of this class set to the ``sf_fb_invite_change_role`` - tag with value ``val``. + if not self.is_tfa_add_backup_phone(): + raise AttributeError("tag 'tfa_add_backup_phone' not set") + return self._value - :param SfFbInviteChangeRoleType val: - :rtype: EventType + def get_tfa_add_security_key(self): """ - return cls('sf_fb_invite_change_role', val) + (tfa) Added security key for two-step verification - @classmethod - def sf_fb_uninvite(cls, val): + Only call this if :meth:`is_tfa_add_security_key` is true. + + :rtype: TfaAddSecurityKeyType """ - Create an instance of this class set to the ``sf_fb_uninvite`` tag with - value ``val``. + if not self.is_tfa_add_security_key(): + raise AttributeError("tag 'tfa_add_security_key' not set") + return self._value - :param SfFbUninviteType val: - :rtype: EventType + def get_tfa_change_backup_phone(self): """ - return cls('sf_fb_uninvite', val) + (tfa) Changed backup phone for two-step verification - @classmethod - def sf_invite_group(cls, val): + Only call this if :meth:`is_tfa_change_backup_phone` is true. + + :rtype: TfaChangeBackupPhoneType """ - Create an instance of this class set to the ``sf_invite_group`` tag with - value ``val``. + if not self.is_tfa_change_backup_phone(): + raise AttributeError("tag 'tfa_change_backup_phone' not set") + return self._value - :param SfInviteGroupType val: - :rtype: EventType + def get_tfa_change_status(self): """ - return cls('sf_invite_group', val) + (tfa) Enabled/disabled/changed two-step verification setting - @classmethod - def sf_team_grant_access(cls, val): + Only call this if :meth:`is_tfa_change_status` is true. + + :rtype: TfaChangeStatusType """ - Create an instance of this class set to the ``sf_team_grant_access`` tag - with value ``val``. + if not self.is_tfa_change_status(): + raise AttributeError("tag 'tfa_change_status' not set") + return self._value - :param SfTeamGrantAccessType val: - :rtype: EventType + def get_tfa_remove_backup_phone(self): """ - return cls('sf_team_grant_access', val) + (tfa) Removed backup phone for two-step verification - @classmethod - def sf_team_invite(cls, val): + Only call this if :meth:`is_tfa_remove_backup_phone` is true. + + :rtype: TfaRemoveBackupPhoneType """ - Create an instance of this class set to the ``sf_team_invite`` tag with - value ``val``. + if not self.is_tfa_remove_backup_phone(): + raise AttributeError("tag 'tfa_remove_backup_phone' not set") + return self._value - :param SfTeamInviteType val: - :rtype: EventType + def get_tfa_remove_security_key(self): """ - return cls('sf_team_invite', val) + (tfa) Removed security key for two-step verification - @classmethod - def sf_team_invite_change_role(cls, val): + Only call this if :meth:`is_tfa_remove_security_key` is true. + + :rtype: TfaRemoveSecurityKeyType """ - Create an instance of this class set to the - ``sf_team_invite_change_role`` tag with value ``val``. + if not self.is_tfa_remove_security_key(): + raise AttributeError("tag 'tfa_remove_security_key' not set") + return self._value - :param SfTeamInviteChangeRoleType val: - :rtype: EventType + def get_tfa_reset(self): """ - return cls('sf_team_invite_change_role', val) + (tfa) Reset two-step verification for team member - @classmethod - def sf_team_join(cls, val): + Only call this if :meth:`is_tfa_reset` is true. + + :rtype: TfaResetType """ - Create an instance of this class set to the ``sf_team_join`` tag with - value ``val``. + if not self.is_tfa_reset(): + raise AttributeError("tag 'tfa_reset' not set") + return self._value - :param SfTeamJoinType val: - :rtype: EventType + def get_changed_enterprise_admin_role(self): """ - return cls('sf_team_join', val) + (trusted_teams) Changed enterprise admin role - @classmethod - def sf_team_join_from_oob_link(cls, val): + Only call this if :meth:`is_changed_enterprise_admin_role` is true. + + :rtype: ChangedEnterpriseAdminRoleType """ - Create an instance of this class set to the - ``sf_team_join_from_oob_link`` tag with value ``val``. + if not self.is_changed_enterprise_admin_role(): + raise AttributeError("tag 'changed_enterprise_admin_role' not set") + return self._value - :param SfTeamJoinFromOobLinkType val: - :rtype: EventType + def get_changed_enterprise_connected_team_status(self): """ - return cls('sf_team_join_from_oob_link', val) + (trusted_teams) Changed enterprise-connected team status - @classmethod - def sf_team_uninvite(cls, val): + Only call this if :meth:`is_changed_enterprise_connected_team_status` is true. + + :rtype: ChangedEnterpriseConnectedTeamStatusType """ - Create an instance of this class set to the ``sf_team_uninvite`` tag - with value ``val``. + if not self.is_changed_enterprise_connected_team_status(): + raise AttributeError("tag 'changed_enterprise_connected_team_status' not set") + return self._value - :param SfTeamUninviteType val: - :rtype: EventType + def get_ended_enterprise_admin_session(self): """ - return cls('sf_team_uninvite', val) + (trusted_teams) Ended enterprise admin session - @classmethod - def shared_content_add_invitees(cls, val): + Only call this if :meth:`is_ended_enterprise_admin_session` is true. + + :rtype: EndedEnterpriseAdminSessionType """ - Create an instance of this class set to the - ``shared_content_add_invitees`` tag with value ``val``. + if not self.is_ended_enterprise_admin_session(): + raise AttributeError("tag 'ended_enterprise_admin_session' not set") + return self._value - :param SharedContentAddInviteesType val: - :rtype: EventType + def get_ended_enterprise_admin_session_deprecated(self): """ - return cls('shared_content_add_invitees', val) + (trusted_teams) Ended enterprise admin session (deprecated, replaced by + 'Ended enterprise admin session') - @classmethod - def shared_content_add_link_expiry(cls, val): + Only call this if :meth:`is_ended_enterprise_admin_session_deprecated` is true. + + :rtype: EndedEnterpriseAdminSessionDeprecatedType """ - Create an instance of this class set to the - ``shared_content_add_link_expiry`` tag with value ``val``. + if not self.is_ended_enterprise_admin_session_deprecated(): + raise AttributeError("tag 'ended_enterprise_admin_session_deprecated' not set") + return self._value - :param SharedContentAddLinkExpiryType val: - :rtype: EventType + def get_enterprise_settings_locking(self): """ - return cls('shared_content_add_link_expiry', val) + (trusted_teams) Changed who can update a setting - @classmethod - def shared_content_add_link_password(cls, val): + Only call this if :meth:`is_enterprise_settings_locking` is true. + + :rtype: EnterpriseSettingsLockingType """ - Create an instance of this class set to the - ``shared_content_add_link_password`` tag with value ``val``. + if not self.is_enterprise_settings_locking(): + raise AttributeError("tag 'enterprise_settings_locking' not set") + return self._value - :param SharedContentAddLinkPasswordType val: - :rtype: EventType + def get_guest_admin_change_status(self): """ - return cls('shared_content_add_link_password', val) + (trusted_teams) Changed guest team admin status - @classmethod - def shared_content_add_member(cls, val): + Only call this if :meth:`is_guest_admin_change_status` is true. + + :rtype: GuestAdminChangeStatusType """ - Create an instance of this class set to the - ``shared_content_add_member`` tag with value ``val``. + if not self.is_guest_admin_change_status(): + raise AttributeError("tag 'guest_admin_change_status' not set") + return self._value - :param SharedContentAddMemberType val: - :rtype: EventType + def get_started_enterprise_admin_session(self): """ - return cls('shared_content_add_member', val) + (trusted_teams) Started enterprise admin session - @classmethod - def shared_content_change_downloads_policy(cls, val): + Only call this if :meth:`is_started_enterprise_admin_session` is true. + + :rtype: StartedEnterpriseAdminSessionType """ - Create an instance of this class set to the - ``shared_content_change_downloads_policy`` tag with value ``val``. + if not self.is_started_enterprise_admin_session(): + raise AttributeError("tag 'started_enterprise_admin_session' not set") + return self._value - :param SharedContentChangeDownloadsPolicyType val: - :rtype: EventType + def get_team_merge_request_accepted(self): """ - return cls('shared_content_change_downloads_policy', val) + (trusted_teams) Accepted a team merge request - @classmethod - def shared_content_change_invitee_role(cls, val): + Only call this if :meth:`is_team_merge_request_accepted` is true. + + :rtype: TeamMergeRequestAcceptedType """ - Create an instance of this class set to the - ``shared_content_change_invitee_role`` tag with value ``val``. + if not self.is_team_merge_request_accepted(): + raise AttributeError("tag 'team_merge_request_accepted' not set") + return self._value - :param SharedContentChangeInviteeRoleType val: - :rtype: EventType + def get_team_merge_request_accepted_shown_to_primary_team(self): """ - return cls('shared_content_change_invitee_role', val) + (trusted_teams) Accepted a team merge request (deprecated, replaced by + 'Accepted a team merge request') - @classmethod - def shared_content_change_link_audience(cls, val): + Only call this if :meth:`is_team_merge_request_accepted_shown_to_primary_team` is true. + + :rtype: TeamMergeRequestAcceptedShownToPrimaryTeamType """ - Create an instance of this class set to the - ``shared_content_change_link_audience`` tag with value ``val``. + if not self.is_team_merge_request_accepted_shown_to_primary_team(): + raise AttributeError("tag 'team_merge_request_accepted_shown_to_primary_team' not set") + return self._value - :param SharedContentChangeLinkAudienceType val: - :rtype: EventType + def get_team_merge_request_accepted_shown_to_secondary_team(self): """ - return cls('shared_content_change_link_audience', val) + (trusted_teams) Accepted a team merge request (deprecated, replaced by + 'Accepted a team merge request') - @classmethod - def shared_content_change_link_expiry(cls, val): + Only call this if :meth:`is_team_merge_request_accepted_shown_to_secondary_team` is true. + + :rtype: TeamMergeRequestAcceptedShownToSecondaryTeamType """ - Create an instance of this class set to the - ``shared_content_change_link_expiry`` tag with value ``val``. + if not self.is_team_merge_request_accepted_shown_to_secondary_team(): + raise AttributeError("tag 'team_merge_request_accepted_shown_to_secondary_team' not set") + return self._value - :param SharedContentChangeLinkExpiryType val: - :rtype: EventType + def get_team_merge_request_auto_canceled(self): """ - return cls('shared_content_change_link_expiry', val) + (trusted_teams) Automatically canceled team merge request - @classmethod - def shared_content_change_link_password(cls, val): + Only call this if :meth:`is_team_merge_request_auto_canceled` is true. + + :rtype: TeamMergeRequestAutoCanceledType """ - Create an instance of this class set to the - ``shared_content_change_link_password`` tag with value ``val``. + if not self.is_team_merge_request_auto_canceled(): + raise AttributeError("tag 'team_merge_request_auto_canceled' not set") + return self._value - :param SharedContentChangeLinkPasswordType val: - :rtype: EventType + def get_team_merge_request_canceled(self): """ - return cls('shared_content_change_link_password', val) + (trusted_teams) Canceled a team merge request - @classmethod - def shared_content_change_member_role(cls, val): + Only call this if :meth:`is_team_merge_request_canceled` is true. + + :rtype: TeamMergeRequestCanceledType """ - Create an instance of this class set to the - ``shared_content_change_member_role`` tag with value ``val``. + if not self.is_team_merge_request_canceled(): + raise AttributeError("tag 'team_merge_request_canceled' not set") + return self._value - :param SharedContentChangeMemberRoleType val: - :rtype: EventType + def get_team_merge_request_canceled_shown_to_primary_team(self): """ - return cls('shared_content_change_member_role', val) + (trusted_teams) Canceled a team merge request (deprecated, replaced by + 'Canceled a team merge request') - @classmethod - def shared_content_change_viewer_info_policy(cls, val): + Only call this if :meth:`is_team_merge_request_canceled_shown_to_primary_team` is true. + + :rtype: TeamMergeRequestCanceledShownToPrimaryTeamType """ - Create an instance of this class set to the - ``shared_content_change_viewer_info_policy`` tag with value ``val``. + if not self.is_team_merge_request_canceled_shown_to_primary_team(): + raise AttributeError("tag 'team_merge_request_canceled_shown_to_primary_team' not set") + return self._value - :param SharedContentChangeViewerInfoPolicyType val: - :rtype: EventType + def get_team_merge_request_canceled_shown_to_secondary_team(self): """ - return cls('shared_content_change_viewer_info_policy', val) + (trusted_teams) Canceled a team merge request (deprecated, replaced by + 'Canceled a team merge request') - @classmethod - def shared_content_claim_invitation(cls, val): + Only call this if :meth:`is_team_merge_request_canceled_shown_to_secondary_team` is true. + + :rtype: TeamMergeRequestCanceledShownToSecondaryTeamType """ - Create an instance of this class set to the - ``shared_content_claim_invitation`` tag with value ``val``. + if not self.is_team_merge_request_canceled_shown_to_secondary_team(): + raise AttributeError("tag 'team_merge_request_canceled_shown_to_secondary_team' not set") + return self._value - :param SharedContentClaimInvitationType val: - :rtype: EventType + def get_team_merge_request_expired(self): """ - return cls('shared_content_claim_invitation', val) + (trusted_teams) Team merge request expired - @classmethod - def shared_content_copy(cls, val): + Only call this if :meth:`is_team_merge_request_expired` is true. + + :rtype: TeamMergeRequestExpiredType """ - Create an instance of this class set to the ``shared_content_copy`` tag - with value ``val``. + if not self.is_team_merge_request_expired(): + raise AttributeError("tag 'team_merge_request_expired' not set") + return self._value - :param SharedContentCopyType val: - :rtype: EventType + def get_team_merge_request_expired_shown_to_primary_team(self): """ - return cls('shared_content_copy', val) + (trusted_teams) Team merge request expired (deprecated, replaced by + 'Team merge request expired') - @classmethod - def shared_content_download(cls, val): + Only call this if :meth:`is_team_merge_request_expired_shown_to_primary_team` is true. + + :rtype: TeamMergeRequestExpiredShownToPrimaryTeamType """ - Create an instance of this class set to the ``shared_content_download`` - tag with value ``val``. + if not self.is_team_merge_request_expired_shown_to_primary_team(): + raise AttributeError("tag 'team_merge_request_expired_shown_to_primary_team' not set") + return self._value - :param SharedContentDownloadType val: - :rtype: EventType + def get_team_merge_request_expired_shown_to_secondary_team(self): """ - return cls('shared_content_download', val) + (trusted_teams) Team merge request expired (deprecated, replaced by + 'Team merge request expired') - @classmethod - def shared_content_relinquish_membership(cls, val): + Only call this if :meth:`is_team_merge_request_expired_shown_to_secondary_team` is true. + + :rtype: TeamMergeRequestExpiredShownToSecondaryTeamType """ - Create an instance of this class set to the - ``shared_content_relinquish_membership`` tag with value ``val``. + if not self.is_team_merge_request_expired_shown_to_secondary_team(): + raise AttributeError("tag 'team_merge_request_expired_shown_to_secondary_team' not set") + return self._value - :param SharedContentRelinquishMembershipType val: - :rtype: EventType + def get_team_merge_request_rejected_shown_to_primary_team(self): """ - return cls('shared_content_relinquish_membership', val) + (trusted_teams) Rejected a team merge request (deprecated, no longer + logged) - @classmethod - def shared_content_remove_invitees(cls, val): - """ - Create an instance of this class set to the - ``shared_content_remove_invitees`` tag with value ``val``. + Only call this if :meth:`is_team_merge_request_rejected_shown_to_primary_team` is true. - :param SharedContentRemoveInviteesType val: - :rtype: EventType + :rtype: TeamMergeRequestRejectedShownToPrimaryTeamType """ - return cls('shared_content_remove_invitees', val) + if not self.is_team_merge_request_rejected_shown_to_primary_team(): + raise AttributeError("tag 'team_merge_request_rejected_shown_to_primary_team' not set") + return self._value - @classmethod - def shared_content_remove_link_expiry(cls, val): + def get_team_merge_request_rejected_shown_to_secondary_team(self): """ - Create an instance of this class set to the - ``shared_content_remove_link_expiry`` tag with value ``val``. + (trusted_teams) Rejected a team merge request (deprecated, no longer + logged) - :param SharedContentRemoveLinkExpiryType val: - :rtype: EventType - """ - return cls('shared_content_remove_link_expiry', val) + Only call this if :meth:`is_team_merge_request_rejected_shown_to_secondary_team` is true. - @classmethod - def shared_content_remove_link_password(cls, val): + :rtype: TeamMergeRequestRejectedShownToSecondaryTeamType """ - Create an instance of this class set to the - ``shared_content_remove_link_password`` tag with value ``val``. + if not self.is_team_merge_request_rejected_shown_to_secondary_team(): + raise AttributeError("tag 'team_merge_request_rejected_shown_to_secondary_team' not set") + return self._value - :param SharedContentRemoveLinkPasswordType val: - :rtype: EventType + def get_team_merge_request_reminder(self): """ - return cls('shared_content_remove_link_password', val) + (trusted_teams) Sent a team merge request reminder - @classmethod - def shared_content_remove_member(cls, val): - """ - Create an instance of this class set to the - ``shared_content_remove_member`` tag with value ``val``. + Only call this if :meth:`is_team_merge_request_reminder` is true. - :param SharedContentRemoveMemberType val: - :rtype: EventType + :rtype: TeamMergeRequestReminderType """ - return cls('shared_content_remove_member', val) + if not self.is_team_merge_request_reminder(): + raise AttributeError("tag 'team_merge_request_reminder' not set") + return self._value - @classmethod - def shared_content_request_access(cls, val): + def get_team_merge_request_reminder_shown_to_primary_team(self): """ - Create an instance of this class set to the - ``shared_content_request_access`` tag with value ``val``. + (trusted_teams) Sent a team merge request reminder (deprecated, replaced + by 'Sent a team merge request reminder') - :param SharedContentRequestAccessType val: - :rtype: EventType - """ - return cls('shared_content_request_access', val) + Only call this if :meth:`is_team_merge_request_reminder_shown_to_primary_team` is true. - @classmethod - def shared_content_unshare(cls, val): + :rtype: TeamMergeRequestReminderShownToPrimaryTeamType """ - Create an instance of this class set to the ``shared_content_unshare`` - tag with value ``val``. + if not self.is_team_merge_request_reminder_shown_to_primary_team(): + raise AttributeError("tag 'team_merge_request_reminder_shown_to_primary_team' not set") + return self._value - :param SharedContentUnshareType val: - :rtype: EventType + def get_team_merge_request_reminder_shown_to_secondary_team(self): """ - return cls('shared_content_unshare', val) + (trusted_teams) Sent a team merge request reminder (deprecated, replaced + by 'Sent a team merge request reminder') - @classmethod - def shared_content_view(cls, val): - """ - Create an instance of this class set to the ``shared_content_view`` tag - with value ``val``. + Only call this if :meth:`is_team_merge_request_reminder_shown_to_secondary_team` is true. - :param SharedContentViewType val: - :rtype: EventType + :rtype: TeamMergeRequestReminderShownToSecondaryTeamType """ - return cls('shared_content_view', val) + if not self.is_team_merge_request_reminder_shown_to_secondary_team(): + raise AttributeError("tag 'team_merge_request_reminder_shown_to_secondary_team' not set") + return self._value - @classmethod - def shared_folder_change_link_policy(cls, val): + def get_team_merge_request_revoked(self): """ - Create an instance of this class set to the - ``shared_folder_change_link_policy`` tag with value ``val``. + (trusted_teams) Canceled the team merge - :param SharedFolderChangeLinkPolicyType val: - :rtype: EventType - """ - return cls('shared_folder_change_link_policy', val) + Only call this if :meth:`is_team_merge_request_revoked` is true. - @classmethod - def shared_folder_change_members_inheritance_policy(cls, val): + :rtype: TeamMergeRequestRevokedType """ - Create an instance of this class set to the - ``shared_folder_change_members_inheritance_policy`` tag with value - ``val``. + if not self.is_team_merge_request_revoked(): + raise AttributeError("tag 'team_merge_request_revoked' not set") + return self._value - :param SharedFolderChangeMembersInheritancePolicyType val: - :rtype: EventType + def get_team_merge_request_sent_shown_to_primary_team(self): """ - return cls('shared_folder_change_members_inheritance_policy', val) + (trusted_teams) Requested to merge their Dropbox team into yours - @classmethod - def shared_folder_change_members_management_policy(cls, val): - """ - Create an instance of this class set to the - ``shared_folder_change_members_management_policy`` tag with value - ``val``. + Only call this if :meth:`is_team_merge_request_sent_shown_to_primary_team` is true. - :param SharedFolderChangeMembersManagementPolicyType val: - :rtype: EventType + :rtype: TeamMergeRequestSentShownToPrimaryTeamType """ - return cls('shared_folder_change_members_management_policy', val) + if not self.is_team_merge_request_sent_shown_to_primary_team(): + raise AttributeError("tag 'team_merge_request_sent_shown_to_primary_team' not set") + return self._value - @classmethod - def shared_folder_change_members_policy(cls, val): + def get_team_merge_request_sent_shown_to_secondary_team(self): """ - Create an instance of this class set to the - ``shared_folder_change_members_policy`` tag with value ``val``. + (trusted_teams) Requested to merge your team into another Dropbox team - :param SharedFolderChangeMembersPolicyType val: - :rtype: EventType - """ - return cls('shared_folder_change_members_policy', val) + Only call this if :meth:`is_team_merge_request_sent_shown_to_secondary_team` is true. - @classmethod - def shared_folder_create(cls, val): + :rtype: TeamMergeRequestSentShownToSecondaryTeamType """ - Create an instance of this class set to the ``shared_folder_create`` tag - with value ``val``. + if not self.is_team_merge_request_sent_shown_to_secondary_team(): + raise AttributeError("tag 'team_merge_request_sent_shown_to_secondary_team' not set") + return self._value - :param SharedFolderCreateType val: - :rtype: EventType - """ - return cls('shared_folder_create', val) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EventType, self)._process_custom_annotations(annotation_type, field_path, processor) - @classmethod - def shared_folder_decline_invitation(cls, val): - """ - Create an instance of this class set to the - ``shared_folder_decline_invitation`` tag with value ``val``. + def __repr__(self): + return 'EventType(%r, %r)' % (self._tag, self._value) - :param SharedFolderDeclineInvitationType val: - :rtype: EventType - """ - return cls('shared_folder_decline_invitation', val) +EventType_validator = bv.Union(EventType) - @classmethod - def shared_folder_mount(cls, val): - """ - Create an instance of this class set to the ``shared_folder_mount`` tag - with value ``val``. +class EventTypeArg(bb.Union): + """ + The type of the event. - :param SharedFolderMountType val: - :rtype: EventType - """ - return cls('shared_folder_mount', val) + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - @classmethod - def shared_folder_nest(cls, val): - """ - Create an instance of this class set to the ``shared_folder_nest`` tag - with value ``val``. + :ivar team_log.EventTypeArg.app_link_team: (apps) Linked app for team + :ivar team_log.EventTypeArg.app_link_user: (apps) Linked app for member + :ivar team_log.EventTypeArg.app_unlink_team: (apps) Unlinked app for team + :ivar team_log.EventTypeArg.app_unlink_user: (apps) Unlinked app for member + :ivar team_log.EventTypeArg.integration_connected: (apps) Connected + integration for member + :ivar team_log.EventTypeArg.integration_disconnected: (apps) Disconnected + integration for member + :ivar team_log.EventTypeArg.file_add_comment: (comments) Added file comment + :ivar team_log.EventTypeArg.file_change_comment_subscription: (comments) + Subscribed to or unsubscribed from comment notifications for file + :ivar team_log.EventTypeArg.file_delete_comment: (comments) Deleted file + comment + :ivar team_log.EventTypeArg.file_edit_comment: (comments) Edited file + comment + :ivar team_log.EventTypeArg.file_like_comment: (comments) Liked file comment + (deprecated, no longer logged) + :ivar team_log.EventTypeArg.file_resolve_comment: (comments) Resolved file + comment + :ivar team_log.EventTypeArg.file_unlike_comment: (comments) Unliked file + comment (deprecated, no longer logged) + :ivar team_log.EventTypeArg.file_unresolve_comment: (comments) Unresolved + file comment + :ivar team_log.EventTypeArg.device_change_ip_desktop: (devices) Changed IP + address associated with active desktop session + :ivar team_log.EventTypeArg.device_change_ip_mobile: (devices) Changed IP + address associated with active mobile session + :ivar team_log.EventTypeArg.device_change_ip_web: (devices) Changed IP + address associated with active web session + :ivar team_log.EventTypeArg.device_delete_on_unlink_fail: (devices) Failed + to delete all files from unlinked device + :ivar team_log.EventTypeArg.device_delete_on_unlink_success: (devices) + Deleted all files from unlinked device + :ivar team_log.EventTypeArg.device_link_fail: (devices) Failed to link + device + :ivar team_log.EventTypeArg.device_link_success: (devices) Linked device + :ivar team_log.EventTypeArg.device_management_disabled: (devices) Disabled + device management (deprecated, no longer logged) + :ivar team_log.EventTypeArg.device_management_enabled: (devices) Enabled + device management (deprecated, no longer logged) + :ivar team_log.EventTypeArg.device_unlink: (devices) Disconnected device + :ivar team_log.EventTypeArg.emm_refresh_auth_token: (devices) Refreshed auth + token used for setting up EMM + :ivar team_log.EventTypeArg.account_capture_change_availability: (domains) + Granted/revoked option to enable account capture on team domains + :ivar team_log.EventTypeArg.account_capture_migrate_account: (domains) + Account-captured user migrated account to team + :ivar team_log.EventTypeArg.account_capture_notification_emails_sent: + (domains) Sent account capture email to all unmanaged members + :ivar team_log.EventTypeArg.account_capture_relinquish_account: (domains) + Account-captured user changed account email to personal email + :ivar team_log.EventTypeArg.disabled_domain_invites: (domains) Disabled + domain invites (deprecated, no longer logged) + :ivar team_log.EventTypeArg.domain_invites_approve_request_to_join_team: + (domains) Approved user's request to join team + :ivar team_log.EventTypeArg.domain_invites_decline_request_to_join_team: + (domains) Declined user's request to join team + :ivar team_log.EventTypeArg.domain_invites_email_existing_users: (domains) + Sent domain invites to existing domain accounts (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.domain_invites_request_to_join_team: (domains) + Requested to join team + :ivar team_log.EventTypeArg.domain_invites_set_invite_new_user_pref_to_no: + (domains) Disabled "Automatically invite new users" (deprecated, no + longer logged) + :ivar team_log.EventTypeArg.domain_invites_set_invite_new_user_pref_to_yes: + (domains) Enabled "Automatically invite new users" (deprecated, no + longer logged) + :ivar team_log.EventTypeArg.domain_verification_add_domain_fail: (domains) + Failed to verify team domain + :ivar team_log.EventTypeArg.domain_verification_add_domain_success: + (domains) Verified team domain + :ivar team_log.EventTypeArg.domain_verification_remove_domain: (domains) + Removed domain from list of verified team domains + :ivar team_log.EventTypeArg.enabled_domain_invites: (domains) Enabled domain + invites (deprecated, no longer logged) + :ivar team_log.EventTypeArg.create_folder: (file_operations) Created folders + (deprecated, no longer logged) + :ivar team_log.EventTypeArg.file_add: (file_operations) Added files and/or + folders + :ivar team_log.EventTypeArg.file_copy: (file_operations) Copied files and/or + folders + :ivar team_log.EventTypeArg.file_delete: (file_operations) Deleted files + and/or folders + :ivar team_log.EventTypeArg.file_download: (file_operations) Downloaded + files and/or folders + :ivar team_log.EventTypeArg.file_edit: (file_operations) Edited files + :ivar team_log.EventTypeArg.file_get_copy_reference: (file_operations) + Created copy reference to file/folder + :ivar team_log.EventTypeArg.file_locking_lock_status_changed: + (file_operations) Locked/unlocked editing for a file + :ivar team_log.EventTypeArg.file_move: (file_operations) Moved files and/or + folders + :ivar team_log.EventTypeArg.file_permanently_delete: (file_operations) + Permanently deleted files and/or folders + :ivar team_log.EventTypeArg.file_preview: (file_operations) Previewed files + and/or folders + :ivar team_log.EventTypeArg.file_rename: (file_operations) Renamed files + and/or folders + :ivar team_log.EventTypeArg.file_restore: (file_operations) Restored deleted + files and/or folders + :ivar team_log.EventTypeArg.file_revert: (file_operations) Reverted files to + previous version + :ivar team_log.EventTypeArg.file_rollback_changes: (file_operations) Rolled + back file actions + :ivar team_log.EventTypeArg.file_save_copy_reference: (file_operations) + Saved file/folder using copy reference + :ivar team_log.EventTypeArg.folder_overview_description_changed: + (file_operations) Updated folder overview + :ivar team_log.EventTypeArg.folder_overview_item_pinned: (file_operations) + Pinned item to folder overview + :ivar team_log.EventTypeArg.folder_overview_item_unpinned: (file_operations) + Unpinned item from folder overview + :ivar team_log.EventTypeArg.rewind_folder: (file_operations) Rewound a + folder + :ivar team_log.EventTypeArg.file_request_change: (file_requests) Changed + file request + :ivar team_log.EventTypeArg.file_request_close: (file_requests) Closed file + request + :ivar team_log.EventTypeArg.file_request_create: (file_requests) Created + file request + :ivar team_log.EventTypeArg.file_request_delete: (file_requests) Delete file + request + :ivar team_log.EventTypeArg.file_request_receive_file: (file_requests) + Received files for file request + :ivar team_log.EventTypeArg.group_add_external_id: (groups) Added external + ID for group + :ivar team_log.EventTypeArg.group_add_member: (groups) Added team members to + group + :ivar team_log.EventTypeArg.group_change_external_id: (groups) Changed + external ID for group + :ivar team_log.EventTypeArg.group_change_management_type: (groups) Changed + group management type + :ivar team_log.EventTypeArg.group_change_member_role: (groups) Changed + manager permissions of group member + :ivar team_log.EventTypeArg.group_create: (groups) Created group + :ivar team_log.EventTypeArg.group_delete: (groups) Deleted group + :ivar team_log.EventTypeArg.group_description_updated: (groups) Updated + group (deprecated, no longer logged) + :ivar team_log.EventTypeArg.group_join_policy_updated: (groups) Updated + group join policy (deprecated, no longer logged) + :ivar team_log.EventTypeArg.group_moved: (groups) Moved group (deprecated, + no longer logged) + :ivar team_log.EventTypeArg.group_remove_external_id: (groups) Removed + external ID for group + :ivar team_log.EventTypeArg.group_remove_member: (groups) Removed team + members from group + :ivar team_log.EventTypeArg.group_rename: (groups) Renamed group + :ivar team_log.EventTypeArg.legal_holds_activate_a_hold: (legal_holds) + Activated a hold + :ivar team_log.EventTypeArg.legal_holds_add_members: (legal_holds) Added + members to a hold + :ivar team_log.EventTypeArg.legal_holds_change_hold_details: (legal_holds) + Edited details for a hold + :ivar team_log.EventTypeArg.legal_holds_change_hold_name: (legal_holds) + Renamed a hold + :ivar team_log.EventTypeArg.legal_holds_export_a_hold: (legal_holds) + Exported hold + :ivar team_log.EventTypeArg.legal_holds_export_cancelled: (legal_holds) + Canceled export for a hold + :ivar team_log.EventTypeArg.legal_holds_export_downloaded: (legal_holds) + Downloaded export for a hold + :ivar team_log.EventTypeArg.legal_holds_export_removed: (legal_holds) + Removed export for a hold + :ivar team_log.EventTypeArg.legal_holds_release_a_hold: (legal_holds) + Released a hold + :ivar team_log.EventTypeArg.legal_holds_remove_members: (legal_holds) + Removed members from a hold + :ivar team_log.EventTypeArg.legal_holds_report_a_hold: (legal_holds) Created + a summary report for a hold + :ivar team_log.EventTypeArg.account_lock_or_unlocked: (logins) + Unlocked/locked account after failed sign in attempts + :ivar team_log.EventTypeArg.emm_error: (logins) Failed to sign in via EMM + (deprecated, replaced by 'Failed to sign in') + :ivar team_log.EventTypeArg.guest_admin_signed_in_via_trusted_teams: + (logins) Started trusted team admin session + :ivar team_log.EventTypeArg.guest_admin_signed_out_via_trusted_teams: + (logins) Ended trusted team admin session + :ivar team_log.EventTypeArg.login_fail: (logins) Failed to sign in + :ivar team_log.EventTypeArg.login_success: (logins) Signed in + :ivar team_log.EventTypeArg.logout: (logins) Signed out + :ivar team_log.EventTypeArg.reseller_support_session_end: (logins) Ended + reseller support session + :ivar team_log.EventTypeArg.reseller_support_session_start: (logins) Started + reseller support session + :ivar team_log.EventTypeArg.sign_in_as_session_end: (logins) Ended admin + sign-in-as session + :ivar team_log.EventTypeArg.sign_in_as_session_start: (logins) Started admin + sign-in-as session + :ivar team_log.EventTypeArg.sso_error: (logins) Failed to sign in via SSO + (deprecated, replaced by 'Failed to sign in') + :ivar team_log.EventTypeArg.create_team_invite_link: (members) Created team + invite link + :ivar team_log.EventTypeArg.delete_team_invite_link: (members) Deleted team + invite link + :ivar team_log.EventTypeArg.member_add_external_id: (members) Added an + external ID for team member + :ivar team_log.EventTypeArg.member_add_name: (members) Added team member + name + :ivar team_log.EventTypeArg.member_change_admin_role: (members) Changed team + member admin role + :ivar team_log.EventTypeArg.member_change_email: (members) Changed team + member email + :ivar team_log.EventTypeArg.member_change_external_id: (members) Changed the + external ID for team member + :ivar team_log.EventTypeArg.member_change_membership_type: (members) Changed + membership type (limited/full) of member (deprecated, no longer logged) + :ivar team_log.EventTypeArg.member_change_name: (members) Changed team + member name + :ivar team_log.EventTypeArg.member_change_status: (members) Changed member + status (invited, joined, suspended, etc.) + :ivar team_log.EventTypeArg.member_delete_manual_contacts: (members) Cleared + manually added contacts + :ivar team_log.EventTypeArg.member_delete_profile_photo: (members) Deleted + team member profile photo + :ivar team_log.EventTypeArg.member_permanently_delete_account_contents: + (members) Permanently deleted contents of deleted team member account + :ivar team_log.EventTypeArg.member_remove_external_id: (members) Removed the + external ID for team member + :ivar team_log.EventTypeArg.member_set_profile_photo: (members) Set team + member profile photo + :ivar team_log.EventTypeArg.member_space_limits_add_custom_quota: (members) + Set custom member space limit + :ivar team_log.EventTypeArg.member_space_limits_change_custom_quota: + (members) Changed custom member space limit + :ivar team_log.EventTypeArg.member_space_limits_change_status: (members) + Changed space limit status + :ivar team_log.EventTypeArg.member_space_limits_remove_custom_quota: + (members) Removed custom member space limit + :ivar team_log.EventTypeArg.member_suggest: (members) Suggested person to + add to team + :ivar team_log.EventTypeArg.member_transfer_account_contents: (members) + Transferred contents of deleted member account to another member + :ivar team_log.EventTypeArg.pending_secondary_email_added: (members) Added + pending secondary email + :ivar team_log.EventTypeArg.secondary_email_deleted: (members) Deleted + secondary email + :ivar team_log.EventTypeArg.secondary_email_verified: (members) Verified + secondary email + :ivar team_log.EventTypeArg.secondary_mails_policy_changed: (members) + Secondary mails policy changed + :ivar team_log.EventTypeArg.binder_add_page: (paper) Added Binder page + (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.binder_add_section: (paper) Added Binder section + (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.binder_remove_page: (paper) Removed Binder page + (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.binder_remove_section: (paper) Removed Binder + section (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.binder_rename_page: (paper) Renamed Binder page + (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.binder_rename_section: (paper) Renamed Binder + section (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.binder_reorder_page: (paper) Reordered Binder + page (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.binder_reorder_section: (paper) Reordered Binder + section (deprecated, replaced by 'Edited files') + :ivar team_log.EventTypeArg.paper_content_add_member: (paper) Added users + and/or groups to Paper doc/folder + :ivar team_log.EventTypeArg.paper_content_add_to_folder: (paper) Added Paper + doc/folder to folder + :ivar team_log.EventTypeArg.paper_content_archive: (paper) Archived Paper + doc/folder + :ivar team_log.EventTypeArg.paper_content_create: (paper) Created Paper + doc/folder + :ivar team_log.EventTypeArg.paper_content_permanently_delete: (paper) + Permanently deleted Paper doc/folder + :ivar team_log.EventTypeArg.paper_content_remove_from_folder: (paper) + Removed Paper doc/folder from folder + :ivar team_log.EventTypeArg.paper_content_remove_member: (paper) Removed + users and/or groups from Paper doc/folder + :ivar team_log.EventTypeArg.paper_content_rename: (paper) Renamed Paper + doc/folder + :ivar team_log.EventTypeArg.paper_content_restore: (paper) Restored archived + Paper doc/folder + :ivar team_log.EventTypeArg.paper_doc_add_comment: (paper) Added Paper doc + comment + :ivar team_log.EventTypeArg.paper_doc_change_member_role: (paper) Changed + member permissions for Paper doc + :ivar team_log.EventTypeArg.paper_doc_change_sharing_policy: (paper) Changed + sharing setting for Paper doc + :ivar team_log.EventTypeArg.paper_doc_change_subscription: (paper) + Followed/unfollowed Paper doc + :ivar team_log.EventTypeArg.paper_doc_deleted: (paper) Archived Paper doc + (deprecated, no longer logged) + :ivar team_log.EventTypeArg.paper_doc_delete_comment: (paper) Deleted Paper + doc comment + :ivar team_log.EventTypeArg.paper_doc_download: (paper) Downloaded Paper doc + in specific format + :ivar team_log.EventTypeArg.paper_doc_edit: (paper) Edited Paper doc + :ivar team_log.EventTypeArg.paper_doc_edit_comment: (paper) Edited Paper doc + comment + :ivar team_log.EventTypeArg.paper_doc_followed: (paper) Followed Paper doc + (deprecated, replaced by 'Followed/unfollowed Paper doc') + :ivar team_log.EventTypeArg.paper_doc_mention: (paper) Mentioned user in + Paper doc + :ivar team_log.EventTypeArg.paper_doc_ownership_changed: (paper) Transferred + ownership of Paper doc + :ivar team_log.EventTypeArg.paper_doc_request_access: (paper) Requested + access to Paper doc + :ivar team_log.EventTypeArg.paper_doc_resolve_comment: (paper) Resolved + Paper doc comment + :ivar team_log.EventTypeArg.paper_doc_revert: (paper) Restored Paper doc to + previous version + :ivar team_log.EventTypeArg.paper_doc_slack_share: (paper) Shared Paper doc + via Slack + :ivar team_log.EventTypeArg.paper_doc_team_invite: (paper) Shared Paper doc + with users and/or groups (deprecated, no longer logged) + :ivar team_log.EventTypeArg.paper_doc_trashed: (paper) Deleted Paper doc + :ivar team_log.EventTypeArg.paper_doc_unresolve_comment: (paper) Unresolved + Paper doc comment + :ivar team_log.EventTypeArg.paper_doc_untrashed: (paper) Restored Paper doc + :ivar team_log.EventTypeArg.paper_doc_view: (paper) Viewed Paper doc + :ivar team_log.EventTypeArg.paper_external_view_allow: (paper) Changed Paper + external sharing setting to anyone (deprecated, no longer logged) + :ivar team_log.EventTypeArg.paper_external_view_default_team: (paper) + Changed Paper external sharing setting to default team (deprecated, no + longer logged) + :ivar team_log.EventTypeArg.paper_external_view_forbid: (paper) Changed + Paper external sharing setting to team-only (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.paper_folder_change_subscription: (paper) + Followed/unfollowed Paper folder + :ivar team_log.EventTypeArg.paper_folder_deleted: (paper) Archived Paper + folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.paper_folder_followed: (paper) Followed Paper + folder (deprecated, replaced by 'Followed/unfollowed Paper folder') + :ivar team_log.EventTypeArg.paper_folder_team_invite: (paper) Shared Paper + folder with users and/or groups (deprecated, no longer logged) + :ivar team_log.EventTypeArg.paper_published_link_change_permission: (paper) + Changed permissions for published doc + :ivar team_log.EventTypeArg.paper_published_link_create: (paper) Published + doc + :ivar team_log.EventTypeArg.paper_published_link_disabled: (paper) + Unpublished doc + :ivar team_log.EventTypeArg.paper_published_link_view: (paper) Viewed + published doc + :ivar team_log.EventTypeArg.password_change: (passwords) Changed password + :ivar team_log.EventTypeArg.password_reset: (passwords) Reset password + :ivar team_log.EventTypeArg.password_reset_all: (passwords) Reset all team + member passwords + :ivar team_log.EventTypeArg.emm_create_exceptions_report: (reports) Created + EMM-excluded users report + :ivar team_log.EventTypeArg.emm_create_usage_report: (reports) Created EMM + mobile app usage report + :ivar team_log.EventTypeArg.export_members_report: (reports) Created member + data report + :ivar team_log.EventTypeArg.export_members_report_fail: (reports) Failed to + create members data report + :ivar team_log.EventTypeArg.no_expiration_link_gen_create_report: (reports) + Report created: Links created with no expiration + :ivar team_log.EventTypeArg.no_expiration_link_gen_report_failed: (reports) + Couldn't create report: Links created with no expiration + :ivar team_log.EventTypeArg.no_password_link_gen_create_report: (reports) + Report created: Links created without passwords + :ivar team_log.EventTypeArg.no_password_link_gen_report_failed: (reports) + Couldn't create report: Links created without passwords + :ivar team_log.EventTypeArg.no_password_link_view_create_report: (reports) + Report created: Views of links without passwords + :ivar team_log.EventTypeArg.no_password_link_view_report_failed: (reports) + Couldn't create report: Views of links without passwords + :ivar team_log.EventTypeArg.outdated_link_view_create_report: (reports) + Report created: Views of old links + :ivar team_log.EventTypeArg.outdated_link_view_report_failed: (reports) + Couldn't create report: Views of old links + :ivar team_log.EventTypeArg.paper_admin_export_start: (reports) Exported all + team Paper docs + :ivar team_log.EventTypeArg.smart_sync_create_admin_privilege_report: + (reports) Created Smart Sync non-admin devices report + :ivar team_log.EventTypeArg.team_activity_create_report: (reports) Created + team activity report + :ivar team_log.EventTypeArg.team_activity_create_report_fail: (reports) + Couldn't generate team activity report + :ivar team_log.EventTypeArg.collection_share: (sharing) Shared album + :ivar team_log.EventTypeArg.file_transfers_file_add: (sharing) Transfer + files added + :ivar team_log.EventTypeArg.file_transfers_transfer_delete: (sharing) + Deleted transfer + :ivar team_log.EventTypeArg.file_transfers_transfer_download: (sharing) + Transfer downloaded + :ivar team_log.EventTypeArg.file_transfers_transfer_send: (sharing) Sent + transfer + :ivar team_log.EventTypeArg.file_transfers_transfer_view: (sharing) Viewed + transfer + :ivar team_log.EventTypeArg.note_acl_invite_only: (sharing) Changed Paper + doc to invite-only (deprecated, no longer logged) + :ivar team_log.EventTypeArg.note_acl_link: (sharing) Changed Paper doc to + link-accessible (deprecated, no longer logged) + :ivar team_log.EventTypeArg.note_acl_team_link: (sharing) Changed Paper doc + to link-accessible for team (deprecated, no longer logged) + :ivar team_log.EventTypeArg.note_shared: (sharing) Shared Paper doc + (deprecated, no longer logged) + :ivar team_log.EventTypeArg.note_share_receive: (sharing) Shared received + Paper doc (deprecated, no longer logged) + :ivar team_log.EventTypeArg.open_note_shared: (sharing) Opened shared Paper + doc (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_add_group: (sharing) Added team to shared + folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_allow_non_members_to_view_shared_links: + (sharing) Allowed non-collaborators to view links to files in shared + folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_external_invite_warn: (sharing) Set team + members to see warning before sharing folders outside team (deprecated, + no longer logged) + :ivar team_log.EventTypeArg.sf_fb_invite: (sharing) Invited Facebook users + to shared folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_fb_invite_change_role: (sharing) Changed + Facebook user's role in shared folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_fb_uninvite: (sharing) Uninvited Facebook + user from shared folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_invite_group: (sharing) Invited group to + shared folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_team_grant_access: (sharing) Granted access + to shared folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_team_invite: (sharing) Invited team members + to shared folder (deprecated, replaced by 'Invited user to Dropbox and + added them to shared file/folder') + :ivar team_log.EventTypeArg.sf_team_invite_change_role: (sharing) Changed + team member's role in shared folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_team_join: (sharing) Joined team member's + shared folder (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_team_join_from_oob_link: (sharing) Joined + team member's shared folder from link (deprecated, no longer logged) + :ivar team_log.EventTypeArg.sf_team_uninvite: (sharing) Unshared folder with + team member (deprecated, replaced by 'Removed invitee from shared + file/folder before invite was accepted') + :ivar team_log.EventTypeArg.shared_content_add_invitees: (sharing) Invited + user to Dropbox and added them to shared file/folder + :ivar team_log.EventTypeArg.shared_content_add_link_expiry: (sharing) Added + expiration date to link for shared file/folder (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.shared_content_add_link_password: (sharing) + Added password to link for shared file/folder (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.shared_content_add_member: (sharing) Added users + and/or groups to shared file/folder + :ivar team_log.EventTypeArg.shared_content_change_downloads_policy: + (sharing) Changed whether members can download shared file/folder + (deprecated, no longer logged) + :ivar team_log.EventTypeArg.shared_content_change_invitee_role: (sharing) + Changed access type of invitee to shared file/folder before invite was + accepted + :ivar team_log.EventTypeArg.shared_content_change_link_audience: (sharing) + Changed link audience of shared file/folder (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.shared_content_change_link_expiry: (sharing) + Changed link expiration of shared file/folder (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.shared_content_change_link_password: (sharing) + Changed link password of shared file/folder (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.shared_content_change_member_role: (sharing) + Changed access type of shared file/folder member + :ivar team_log.EventTypeArg.shared_content_change_viewer_info_policy: + (sharing) Changed whether members can see who viewed shared file/folder + :ivar team_log.EventTypeArg.shared_content_claim_invitation: (sharing) + Acquired membership of shared file/folder by accepting invite + :ivar team_log.EventTypeArg.shared_content_copy: (sharing) Copied shared + file/folder to own Dropbox + :ivar team_log.EventTypeArg.shared_content_download: (sharing) Downloaded + shared file/folder + :ivar team_log.EventTypeArg.shared_content_relinquish_membership: (sharing) + Left shared file/folder + :ivar team_log.EventTypeArg.shared_content_remove_invitees: (sharing) + Removed invitee from shared file/folder before invite was accepted + :ivar team_log.EventTypeArg.shared_content_remove_link_expiry: (sharing) + Removed link expiration date of shared file/folder (deprecated, no + longer logged) + :ivar team_log.EventTypeArg.shared_content_remove_link_password: (sharing) + Removed link password of shared file/folder (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.shared_content_remove_member: (sharing) Removed + user/group from shared file/folder + :ivar team_log.EventTypeArg.shared_content_request_access: (sharing) + Requested access to shared file/folder + :ivar team_log.EventTypeArg.shared_content_restore_invitees: (sharing) + Restored shared file/folder invitees + :ivar team_log.EventTypeArg.shared_content_restore_member: (sharing) + Restored users and/or groups to membership of shared file/folder + :ivar team_log.EventTypeArg.shared_content_unshare: (sharing) Unshared + file/folder by clearing membership + :ivar team_log.EventTypeArg.shared_content_view: (sharing) Previewed shared + file/folder + :ivar team_log.EventTypeArg.shared_folder_change_link_policy: (sharing) + Changed who can access shared folder via link + :ivar team_log.EventTypeArg.shared_folder_change_members_inheritance_policy: + (sharing) Changed whether shared folder inherits members from parent + folder + :ivar team_log.EventTypeArg.shared_folder_change_members_management_policy: + (sharing) Changed who can add/remove members of shared folder + :ivar team_log.EventTypeArg.shared_folder_change_members_policy: (sharing) + Changed who can become member of shared folder + :ivar team_log.EventTypeArg.shared_folder_create: (sharing) Created shared + folder + :ivar team_log.EventTypeArg.shared_folder_decline_invitation: (sharing) + Declined team member's invite to shared folder + :ivar team_log.EventTypeArg.shared_folder_mount: (sharing) Added shared + folder to own Dropbox + :ivar team_log.EventTypeArg.shared_folder_nest: (sharing) Changed parent of + shared folder + :ivar team_log.EventTypeArg.shared_folder_transfer_ownership: (sharing) + Transferred ownership of shared folder to another member + :ivar team_log.EventTypeArg.shared_folder_unmount: (sharing) Deleted shared + folder from Dropbox + :ivar team_log.EventTypeArg.shared_link_add_expiry: (sharing) Added shared + link expiration date + :ivar team_log.EventTypeArg.shared_link_change_expiry: (sharing) Changed + shared link expiration date + :ivar team_log.EventTypeArg.shared_link_change_visibility: (sharing) Changed + visibility of shared link + :ivar team_log.EventTypeArg.shared_link_copy: (sharing) Added file/folder to + Dropbox from shared link + :ivar team_log.EventTypeArg.shared_link_create: (sharing) Created shared + link + :ivar team_log.EventTypeArg.shared_link_disable: (sharing) Removed shared + link + :ivar team_log.EventTypeArg.shared_link_download: (sharing) Downloaded + file/folder from shared link + :ivar team_log.EventTypeArg.shared_link_remove_expiry: (sharing) Removed + shared link expiration date + :ivar team_log.EventTypeArg.shared_link_settings_add_expiration: (sharing) + Added an expiration date to the shared link + :ivar team_log.EventTypeArg.shared_link_settings_add_password: (sharing) + Added a password to the shared link + :ivar team_log.EventTypeArg.shared_link_settings_allow_download_disabled: + (sharing) Disabled downloads + :ivar team_log.EventTypeArg.shared_link_settings_allow_download_enabled: + (sharing) Enabled downloads + :ivar team_log.EventTypeArg.shared_link_settings_change_audience: (sharing) + Changed the audience of the shared link + :ivar team_log.EventTypeArg.shared_link_settings_change_expiration: + (sharing) Changed the expiration date of the shared link + :ivar team_log.EventTypeArg.shared_link_settings_change_password: (sharing) + Changed the password of the shared link + :ivar team_log.EventTypeArg.shared_link_settings_remove_expiration: + (sharing) Removed the expiration date from the shared link + :ivar team_log.EventTypeArg.shared_link_settings_remove_password: (sharing) + Removed the password from the shared link + :ivar team_log.EventTypeArg.shared_link_share: (sharing) Added members as + audience of shared link + :ivar team_log.EventTypeArg.shared_link_view: (sharing) Opened shared link + :ivar team_log.EventTypeArg.shared_note_opened: (sharing) Opened shared + Paper doc (deprecated, no longer logged) + :ivar team_log.EventTypeArg.shmodel_group_share: (sharing) Shared link with + group (deprecated, no longer logged) + :ivar team_log.EventTypeArg.showcase_access_granted: (showcase) Granted + access to showcase + :ivar team_log.EventTypeArg.showcase_add_member: (showcase) Added member to + showcase + :ivar team_log.EventTypeArg.showcase_archived: (showcase) Archived showcase + :ivar team_log.EventTypeArg.showcase_created: (showcase) Created showcase + :ivar team_log.EventTypeArg.showcase_delete_comment: (showcase) Deleted + showcase comment + :ivar team_log.EventTypeArg.showcase_edited: (showcase) Edited showcase + :ivar team_log.EventTypeArg.showcase_edit_comment: (showcase) Edited + showcase comment + :ivar team_log.EventTypeArg.showcase_file_added: (showcase) Added file to + showcase + :ivar team_log.EventTypeArg.showcase_file_download: (showcase) Downloaded + file from showcase + :ivar team_log.EventTypeArg.showcase_file_removed: (showcase) Removed file + from showcase + :ivar team_log.EventTypeArg.showcase_file_view: (showcase) Viewed file in + showcase + :ivar team_log.EventTypeArg.showcase_permanently_deleted: (showcase) + Permanently deleted showcase + :ivar team_log.EventTypeArg.showcase_post_comment: (showcase) Added showcase + comment + :ivar team_log.EventTypeArg.showcase_remove_member: (showcase) Removed + member from showcase + :ivar team_log.EventTypeArg.showcase_renamed: (showcase) Renamed showcase + :ivar team_log.EventTypeArg.showcase_request_access: (showcase) Requested + access to showcase + :ivar team_log.EventTypeArg.showcase_resolve_comment: (showcase) Resolved + showcase comment + :ivar team_log.EventTypeArg.showcase_restored: (showcase) Unarchived + showcase + :ivar team_log.EventTypeArg.showcase_trashed: (showcase) Deleted showcase + :ivar team_log.EventTypeArg.showcase_trashed_deprecated: (showcase) Deleted + showcase (old version) (deprecated, replaced by 'Deleted showcase') + :ivar team_log.EventTypeArg.showcase_unresolve_comment: (showcase) + Unresolved showcase comment + :ivar team_log.EventTypeArg.showcase_untrashed: (showcase) Restored showcase + :ivar team_log.EventTypeArg.showcase_untrashed_deprecated: (showcase) + Restored showcase (old version) (deprecated, replaced by 'Restored + showcase') + :ivar team_log.EventTypeArg.showcase_view: (showcase) Viewed showcase + :ivar team_log.EventTypeArg.sso_add_cert: (sso) Added X.509 certificate for + SSO + :ivar team_log.EventTypeArg.sso_add_login_url: (sso) Added sign-in URL for + SSO + :ivar team_log.EventTypeArg.sso_add_logout_url: (sso) Added sign-out URL for + SSO + :ivar team_log.EventTypeArg.sso_change_cert: (sso) Changed X.509 certificate + for SSO + :ivar team_log.EventTypeArg.sso_change_login_url: (sso) Changed sign-in URL + for SSO + :ivar team_log.EventTypeArg.sso_change_logout_url: (sso) Changed sign-out + URL for SSO + :ivar team_log.EventTypeArg.sso_change_saml_identity_mode: (sso) Changed + SAML identity mode for SSO + :ivar team_log.EventTypeArg.sso_remove_cert: (sso) Removed X.509 certificate + for SSO + :ivar team_log.EventTypeArg.sso_remove_login_url: (sso) Removed sign-in URL + for SSO + :ivar team_log.EventTypeArg.sso_remove_logout_url: (sso) Removed sign-out + URL for SSO + :ivar team_log.EventTypeArg.team_folder_change_status: (team_folders) + Changed archival status of team folder + :ivar team_log.EventTypeArg.team_folder_create: (team_folders) Created team + folder in active status + :ivar team_log.EventTypeArg.team_folder_downgrade: (team_folders) Downgraded + team folder to regular shared folder + :ivar team_log.EventTypeArg.team_folder_permanently_delete: (team_folders) + Permanently deleted archived team folder + :ivar team_log.EventTypeArg.team_folder_rename: (team_folders) Renamed + active/archived team folder + :ivar team_log.EventTypeArg.team_selective_sync_settings_changed: + (team_folders) Changed sync default + :ivar team_log.EventTypeArg.account_capture_change_policy: (team_policies) + Changed account capture setting on team domain + :ivar team_log.EventTypeArg.allow_download_disabled: (team_policies) + Disabled downloads (deprecated, no longer logged) + :ivar team_log.EventTypeArg.allow_download_enabled: (team_policies) Enabled + downloads (deprecated, no longer logged) + :ivar team_log.EventTypeArg.camera_uploads_policy_changed: (team_policies) + Changed camera uploads setting for team + :ivar team_log.EventTypeArg.data_placement_restriction_change_policy: + (team_policies) Set restrictions on data center locations where team + data resides + :ivar team_log.EventTypeArg.data_placement_restriction_satisfy_policy: + (team_policies) Completed restrictions on data center locations where + team data resides + :ivar team_log.EventTypeArg.device_approvals_add_exception: (team_policies) + Added members to device approvals exception list + :ivar team_log.EventTypeArg.device_approvals_change_desktop_policy: + (team_policies) Set/removed limit on number of computers member can link + to team Dropbox account + :ivar team_log.EventTypeArg.device_approvals_change_mobile_policy: + (team_policies) Set/removed limit on number of mobile devices member can + link to team Dropbox account + :ivar team_log.EventTypeArg.device_approvals_change_overage_action: + (team_policies) Changed device approvals setting when member is over + limit + :ivar team_log.EventTypeArg.device_approvals_change_unlink_action: + (team_policies) Changed device approvals setting when member unlinks + approved device + :ivar team_log.EventTypeArg.device_approvals_remove_exception: + (team_policies) Removed members from device approvals exception list + :ivar team_log.EventTypeArg.directory_restrictions_add_members: + (team_policies) Added members to directory restrictions list + :ivar team_log.EventTypeArg.directory_restrictions_remove_members: + (team_policies) Removed members from directory restrictions list + :ivar team_log.EventTypeArg.emm_add_exception: (team_policies) Added members + to EMM exception list + :ivar team_log.EventTypeArg.emm_change_policy: (team_policies) + Enabled/disabled enterprise mobility management for members + :ivar team_log.EventTypeArg.emm_remove_exception: (team_policies) Removed + members from EMM exception list + :ivar team_log.EventTypeArg.extended_version_history_change_policy: + (team_policies) Accepted/opted out of extended version history + :ivar team_log.EventTypeArg.file_comments_change_policy: (team_policies) + Enabled/disabled commenting on team files + :ivar team_log.EventTypeArg.file_locking_policy_changed: (team_policies) + Changed file locking policy for team + :ivar team_log.EventTypeArg.file_requests_change_policy: (team_policies) + Enabled/disabled file requests + :ivar team_log.EventTypeArg.file_requests_emails_enabled: (team_policies) + Enabled file request emails for everyone (deprecated, no longer logged) + :ivar team_log.EventTypeArg.file_requests_emails_restricted_to_team_only: + (team_policies) Enabled file request emails for team (deprecated, no + longer logged) + :ivar team_log.EventTypeArg.file_transfers_policy_changed: (team_policies) + Changed file transfers policy for team + :ivar team_log.EventTypeArg.google_sso_change_policy: (team_policies) + Enabled/disabled Google single sign-on for team + :ivar team_log.EventTypeArg.group_user_management_change_policy: + (team_policies) Changed who can create groups + :ivar team_log.EventTypeArg.integration_policy_changed: (team_policies) + Changed integration policy for team + :ivar team_log.EventTypeArg.member_requests_change_policy: (team_policies) + Changed whether users can find team when not invited + :ivar team_log.EventTypeArg.member_send_invite_policy_changed: + (team_policies) Changed member send invite policy for team + :ivar team_log.EventTypeArg.member_space_limits_add_exception: + (team_policies) Added members to member space limit exception list + :ivar team_log.EventTypeArg.member_space_limits_change_caps_type_policy: + (team_policies) Changed member space limit type for team + :ivar team_log.EventTypeArg.member_space_limits_change_policy: + (team_policies) Changed team default member space limit + :ivar team_log.EventTypeArg.member_space_limits_remove_exception: + (team_policies) Removed members from member space limit exception list + :ivar team_log.EventTypeArg.member_suggestions_change_policy: + (team_policies) Enabled/disabled option for team members to suggest + people to add to team + :ivar team_log.EventTypeArg.microsoft_office_addin_change_policy: + (team_policies) Enabled/disabled Microsoft Office add-in + :ivar team_log.EventTypeArg.network_control_change_policy: (team_policies) + Enabled/disabled network control + :ivar team_log.EventTypeArg.paper_change_deployment_policy: (team_policies) + Changed whether Dropbox Paper, when enabled, is deployed to all members + or to specific members + :ivar team_log.EventTypeArg.paper_change_member_link_policy: (team_policies) + Changed whether non-members can view Paper docs with link (deprecated, + no longer logged) + :ivar team_log.EventTypeArg.paper_change_member_policy: (team_policies) + Changed whether members can share Paper docs outside team, and if docs + are accessible only by team members or anyone by default + :ivar team_log.EventTypeArg.paper_change_policy: (team_policies) + Enabled/disabled Dropbox Paper for team + :ivar team_log.EventTypeArg.paper_default_folder_policy_changed: + (team_policies) Changed Paper Default Folder Policy setting for team + :ivar team_log.EventTypeArg.paper_desktop_policy_changed: (team_policies) + Enabled/disabled Paper Desktop for team + :ivar team_log.EventTypeArg.paper_enabled_users_group_addition: + (team_policies) Added users to Paper-enabled users list + :ivar team_log.EventTypeArg.paper_enabled_users_group_removal: + (team_policies) Removed users from Paper-enabled users list + :ivar team_log.EventTypeArg.password_strength_requirements_change_policy: + (team_policies) Changed team password strength requirements + :ivar team_log.EventTypeArg.permanent_delete_change_policy: (team_policies) + Enabled/disabled ability of team members to permanently delete content + :ivar team_log.EventTypeArg.reseller_support_change_policy: (team_policies) + Enabled/disabled reseller support + :ivar team_log.EventTypeArg.rewind_policy_changed: (team_policies) Changed + Rewind policy for team + :ivar team_log.EventTypeArg.sharing_change_folder_join_policy: + (team_policies) Changed whether team members can join shared folders + owned outside team + :ivar team_log.EventTypeArg.sharing_change_link_policy: (team_policies) + Changed whether members can share links outside team, and if links are + accessible only by team members or anyone by default + :ivar team_log.EventTypeArg.sharing_change_member_policy: (team_policies) + Changed whether members can share files/folders outside team + :ivar team_log.EventTypeArg.showcase_change_download_policy: (team_policies) + Enabled/disabled downloading files from Dropbox Showcase for team + :ivar team_log.EventTypeArg.showcase_change_enabled_policy: (team_policies) + Enabled/disabled Dropbox Showcase for team + :ivar team_log.EventTypeArg.showcase_change_external_sharing_policy: + (team_policies) Enabled/disabled sharing Dropbox Showcase externally for + team + :ivar team_log.EventTypeArg.smarter_smart_sync_policy_changed: + (team_policies) Changed automatic Smart Sync setting for team + :ivar team_log.EventTypeArg.smart_sync_change_policy: (team_policies) + Changed default Smart Sync setting for team members + :ivar team_log.EventTypeArg.smart_sync_not_opt_out: (team_policies) Opted + team into Smart Sync + :ivar team_log.EventTypeArg.smart_sync_opt_out: (team_policies) Opted team + out of Smart Sync + :ivar team_log.EventTypeArg.sso_change_policy: (team_policies) Changed + single sign-on setting for team + :ivar team_log.EventTypeArg.team_extensions_policy_changed: (team_policies) + Changed App Integrations setting for team + :ivar team_log.EventTypeArg.team_selective_sync_policy_changed: + (team_policies) Enabled/disabled Team Selective Sync for team + :ivar team_log.EventTypeArg.team_sharing_whitelist_subjects_changed: + (team_policies) Edited the approved list for sharing externally + :ivar team_log.EventTypeArg.tfa_add_exception: (team_policies) Added members + to two factor authentication exception list + :ivar team_log.EventTypeArg.tfa_change_policy: (team_policies) Changed + two-step verification setting for team + :ivar team_log.EventTypeArg.tfa_remove_exception: (team_policies) Removed + members from two factor authentication exception list + :ivar team_log.EventTypeArg.two_account_change_policy: (team_policies) + Enabled/disabled option for members to link personal Dropbox account and + team account to same computer + :ivar team_log.EventTypeArg.viewer_info_policy_changed: (team_policies) + Changed team policy for viewer info + :ivar team_log.EventTypeArg.watermarking_policy_changed: (team_policies) + Changed watermarking policy for team + :ivar team_log.EventTypeArg.web_sessions_change_active_session_limit: + (team_policies) Changed limit on active sessions per member + :ivar team_log.EventTypeArg.web_sessions_change_fixed_length_policy: + (team_policies) Changed how long members can stay signed in to + Dropbox.com + :ivar team_log.EventTypeArg.web_sessions_change_idle_length_policy: + (team_policies) Changed how long team members can be idle while signed + in to Dropbox.com + :ivar team_log.EventTypeArg.team_merge_from: (team_profile) Merged another + team into this team + :ivar team_log.EventTypeArg.team_merge_to: (team_profile) Merged this team + into another team + :ivar team_log.EventTypeArg.team_profile_add_logo: (team_profile) Added team + logo to display on shared link headers + :ivar team_log.EventTypeArg.team_profile_change_default_language: + (team_profile) Changed default language for team + :ivar team_log.EventTypeArg.team_profile_change_logo: (team_profile) Changed + team logo displayed on shared link headers + :ivar team_log.EventTypeArg.team_profile_change_name: (team_profile) Changed + team name + :ivar team_log.EventTypeArg.team_profile_remove_logo: (team_profile) Removed + team logo displayed on shared link headers + :ivar team_log.EventTypeArg.tfa_add_backup_phone: (tfa) Added backup phone + for two-step verification + :ivar team_log.EventTypeArg.tfa_add_security_key: (tfa) Added security key + for two-step verification + :ivar team_log.EventTypeArg.tfa_change_backup_phone: (tfa) Changed backup + phone for two-step verification + :ivar team_log.EventTypeArg.tfa_change_status: (tfa) + Enabled/disabled/changed two-step verification setting + :ivar team_log.EventTypeArg.tfa_remove_backup_phone: (tfa) Removed backup + phone for two-step verification + :ivar team_log.EventTypeArg.tfa_remove_security_key: (tfa) Removed security + key for two-step verification + :ivar team_log.EventTypeArg.tfa_reset: (tfa) Reset two-step verification for + team member + :ivar team_log.EventTypeArg.changed_enterprise_admin_role: (trusted_teams) + Changed enterprise admin role + :ivar team_log.EventTypeArg.changed_enterprise_connected_team_status: + (trusted_teams) Changed enterprise-connected team status + :ivar team_log.EventTypeArg.ended_enterprise_admin_session: (trusted_teams) + Ended enterprise admin session + :ivar team_log.EventTypeArg.ended_enterprise_admin_session_deprecated: + (trusted_teams) Ended enterprise admin session (deprecated, replaced by + 'Ended enterprise admin session') + :ivar team_log.EventTypeArg.enterprise_settings_locking: (trusted_teams) + Changed who can update a setting + :ivar team_log.EventTypeArg.guest_admin_change_status: (trusted_teams) + Changed guest team admin status + :ivar team_log.EventTypeArg.started_enterprise_admin_session: + (trusted_teams) Started enterprise admin session + :ivar team_log.EventTypeArg.team_merge_request_accepted: (trusted_teams) + Accepted a team merge request + :ivar + team_log.EventTypeArg.team_merge_request_accepted_shown_to_primary_team: + (trusted_teams) Accepted a team merge request (deprecated, replaced by + 'Accepted a team merge request') + :ivar + team_log.EventTypeArg.team_merge_request_accepted_shown_to_secondary_team: + (trusted_teams) Accepted a team merge request (deprecated, replaced by + 'Accepted a team merge request') + :ivar team_log.EventTypeArg.team_merge_request_auto_canceled: + (trusted_teams) Automatically canceled team merge request + :ivar team_log.EventTypeArg.team_merge_request_canceled: (trusted_teams) + Canceled a team merge request + :ivar + team_log.EventTypeArg.team_merge_request_canceled_shown_to_primary_team: + (trusted_teams) Canceled a team merge request (deprecated, replaced by + 'Canceled a team merge request') + :ivar + team_log.EventTypeArg.team_merge_request_canceled_shown_to_secondary_team: + (trusted_teams) Canceled a team merge request (deprecated, replaced by + 'Canceled a team merge request') + :ivar team_log.EventTypeArg.team_merge_request_expired: (trusted_teams) Team + merge request expired + :ivar + team_log.EventTypeArg.team_merge_request_expired_shown_to_primary_team: + (trusted_teams) Team merge request expired (deprecated, replaced by + 'Team merge request expired') + :ivar + team_log.EventTypeArg.team_merge_request_expired_shown_to_secondary_team: + (trusted_teams) Team merge request expired (deprecated, replaced by + 'Team merge request expired') + :ivar + team_log.EventTypeArg.team_merge_request_rejected_shown_to_primary_team: + (trusted_teams) Rejected a team merge request (deprecated, no longer + logged) + :ivar + team_log.EventTypeArg.team_merge_request_rejected_shown_to_secondary_team: + (trusted_teams) Rejected a team merge request (deprecated, no longer + logged) + :ivar team_log.EventTypeArg.team_merge_request_reminder: (trusted_teams) + Sent a team merge request reminder + :ivar + team_log.EventTypeArg.team_merge_request_reminder_shown_to_primary_team: + (trusted_teams) Sent a team merge request reminder (deprecated, replaced + by 'Sent a team merge request reminder') + :ivar + team_log.EventTypeArg.team_merge_request_reminder_shown_to_secondary_team: + (trusted_teams) Sent a team merge request reminder (deprecated, replaced + by 'Sent a team merge request reminder') + :ivar team_log.EventTypeArg.team_merge_request_revoked: (trusted_teams) + Canceled the team merge + :ivar team_log.EventTypeArg.team_merge_request_sent_shown_to_primary_team: + (trusted_teams) Requested to merge their Dropbox team into yours + :ivar team_log.EventTypeArg.team_merge_request_sent_shown_to_secondary_team: + (trusted_teams) Requested to merge your team into another Dropbox team + """ - :param SharedFolderNestType val: - :rtype: EventType - """ - return cls('shared_folder_nest', val) + _catch_all = 'other' + # Attribute is overwritten below the class definition + app_link_team = None + # Attribute is overwritten below the class definition + app_link_user = None + # Attribute is overwritten below the class definition + app_unlink_team = None + # Attribute is overwritten below the class definition + app_unlink_user = None + # Attribute is overwritten below the class definition + integration_connected = None + # Attribute is overwritten below the class definition + integration_disconnected = None + # Attribute is overwritten below the class definition + file_add_comment = None + # Attribute is overwritten below the class definition + file_change_comment_subscription = None + # Attribute is overwritten below the class definition + file_delete_comment = None + # Attribute is overwritten below the class definition + file_edit_comment = None + # Attribute is overwritten below the class definition + file_like_comment = None + # Attribute is overwritten below the class definition + file_resolve_comment = None + # Attribute is overwritten below the class definition + file_unlike_comment = None + # Attribute is overwritten below the class definition + file_unresolve_comment = None + # Attribute is overwritten below the class definition + device_change_ip_desktop = None + # Attribute is overwritten below the class definition + device_change_ip_mobile = None + # Attribute is overwritten below the class definition + device_change_ip_web = None + # Attribute is overwritten below the class definition + device_delete_on_unlink_fail = None + # Attribute is overwritten below the class definition + device_delete_on_unlink_success = None + # Attribute is overwritten below the class definition + device_link_fail = None + # Attribute is overwritten below the class definition + device_link_success = None + # Attribute is overwritten below the class definition + device_management_disabled = None + # Attribute is overwritten below the class definition + device_management_enabled = None + # Attribute is overwritten below the class definition + device_unlink = None + # Attribute is overwritten below the class definition + emm_refresh_auth_token = None + # Attribute is overwritten below the class definition + account_capture_change_availability = None + # Attribute is overwritten below the class definition + account_capture_migrate_account = None + # Attribute is overwritten below the class definition + account_capture_notification_emails_sent = None + # Attribute is overwritten below the class definition + account_capture_relinquish_account = None + # Attribute is overwritten below the class definition + disabled_domain_invites = None + # Attribute is overwritten below the class definition + domain_invites_approve_request_to_join_team = None + # Attribute is overwritten below the class definition + domain_invites_decline_request_to_join_team = None + # Attribute is overwritten below the class definition + domain_invites_email_existing_users = None + # Attribute is overwritten below the class definition + domain_invites_request_to_join_team = None + # Attribute is overwritten below the class definition + domain_invites_set_invite_new_user_pref_to_no = None + # Attribute is overwritten below the class definition + domain_invites_set_invite_new_user_pref_to_yes = None + # Attribute is overwritten below the class definition + domain_verification_add_domain_fail = None + # Attribute is overwritten below the class definition + domain_verification_add_domain_success = None + # Attribute is overwritten below the class definition + domain_verification_remove_domain = None + # Attribute is overwritten below the class definition + enabled_domain_invites = None + # Attribute is overwritten below the class definition + create_folder = None + # Attribute is overwritten below the class definition + file_add = None + # Attribute is overwritten below the class definition + file_copy = None + # Attribute is overwritten below the class definition + file_delete = None + # Attribute is overwritten below the class definition + file_download = None + # Attribute is overwritten below the class definition + file_edit = None + # Attribute is overwritten below the class definition + file_get_copy_reference = None + # Attribute is overwritten below the class definition + file_locking_lock_status_changed = None + # Attribute is overwritten below the class definition + file_move = None + # Attribute is overwritten below the class definition + file_permanently_delete = None + # Attribute is overwritten below the class definition + file_preview = None + # Attribute is overwritten below the class definition + file_rename = None + # Attribute is overwritten below the class definition + file_restore = None + # Attribute is overwritten below the class definition + file_revert = None + # Attribute is overwritten below the class definition + file_rollback_changes = None + # Attribute is overwritten below the class definition + file_save_copy_reference = None + # Attribute is overwritten below the class definition + folder_overview_description_changed = None + # Attribute is overwritten below the class definition + folder_overview_item_pinned = None + # Attribute is overwritten below the class definition + folder_overview_item_unpinned = None + # Attribute is overwritten below the class definition + rewind_folder = None + # Attribute is overwritten below the class definition + file_request_change = None + # Attribute is overwritten below the class definition + file_request_close = None + # Attribute is overwritten below the class definition + file_request_create = None + # Attribute is overwritten below the class definition + file_request_delete = None + # Attribute is overwritten below the class definition + file_request_receive_file = None + # Attribute is overwritten below the class definition + group_add_external_id = None + # Attribute is overwritten below the class definition + group_add_member = None + # Attribute is overwritten below the class definition + group_change_external_id = None + # Attribute is overwritten below the class definition + group_change_management_type = None + # Attribute is overwritten below the class definition + group_change_member_role = None + # Attribute is overwritten below the class definition + group_create = None + # Attribute is overwritten below the class definition + group_delete = None + # Attribute is overwritten below the class definition + group_description_updated = None + # Attribute is overwritten below the class definition + group_join_policy_updated = None + # Attribute is overwritten below the class definition + group_moved = None + # Attribute is overwritten below the class definition + group_remove_external_id = None + # Attribute is overwritten below the class definition + group_remove_member = None + # Attribute is overwritten below the class definition + group_rename = None + # Attribute is overwritten below the class definition + legal_holds_activate_a_hold = None + # Attribute is overwritten below the class definition + legal_holds_add_members = None + # Attribute is overwritten below the class definition + legal_holds_change_hold_details = None + # Attribute is overwritten below the class definition + legal_holds_change_hold_name = None + # Attribute is overwritten below the class definition + legal_holds_export_a_hold = None + # Attribute is overwritten below the class definition + legal_holds_export_cancelled = None + # Attribute is overwritten below the class definition + legal_holds_export_downloaded = None + # Attribute is overwritten below the class definition + legal_holds_export_removed = None + # Attribute is overwritten below the class definition + legal_holds_release_a_hold = None + # Attribute is overwritten below the class definition + legal_holds_remove_members = None + # Attribute is overwritten below the class definition + legal_holds_report_a_hold = None + # Attribute is overwritten below the class definition + account_lock_or_unlocked = None + # Attribute is overwritten below the class definition + emm_error = None + # Attribute is overwritten below the class definition + guest_admin_signed_in_via_trusted_teams = None + # Attribute is overwritten below the class definition + guest_admin_signed_out_via_trusted_teams = None + # Attribute is overwritten below the class definition + login_fail = None + # Attribute is overwritten below the class definition + login_success = None + # Attribute is overwritten below the class definition + logout = None + # Attribute is overwritten below the class definition + reseller_support_session_end = None + # Attribute is overwritten below the class definition + reseller_support_session_start = None + # Attribute is overwritten below the class definition + sign_in_as_session_end = None + # Attribute is overwritten below the class definition + sign_in_as_session_start = None + # Attribute is overwritten below the class definition + sso_error = None + # Attribute is overwritten below the class definition + create_team_invite_link = None + # Attribute is overwritten below the class definition + delete_team_invite_link = None + # Attribute is overwritten below the class definition + member_add_external_id = None + # Attribute is overwritten below the class definition + member_add_name = None + # Attribute is overwritten below the class definition + member_change_admin_role = None + # Attribute is overwritten below the class definition + member_change_email = None + # Attribute is overwritten below the class definition + member_change_external_id = None + # Attribute is overwritten below the class definition + member_change_membership_type = None + # Attribute is overwritten below the class definition + member_change_name = None + # Attribute is overwritten below the class definition + member_change_status = None + # Attribute is overwritten below the class definition + member_delete_manual_contacts = None + # Attribute is overwritten below the class definition + member_delete_profile_photo = None + # Attribute is overwritten below the class definition + member_permanently_delete_account_contents = None + # Attribute is overwritten below the class definition + member_remove_external_id = None + # Attribute is overwritten below the class definition + member_set_profile_photo = None + # Attribute is overwritten below the class definition + member_space_limits_add_custom_quota = None + # Attribute is overwritten below the class definition + member_space_limits_change_custom_quota = None + # Attribute is overwritten below the class definition + member_space_limits_change_status = None + # Attribute is overwritten below the class definition + member_space_limits_remove_custom_quota = None + # Attribute is overwritten below the class definition + member_suggest = None + # Attribute is overwritten below the class definition + member_transfer_account_contents = None + # Attribute is overwritten below the class definition + pending_secondary_email_added = None + # Attribute is overwritten below the class definition + secondary_email_deleted = None + # Attribute is overwritten below the class definition + secondary_email_verified = None + # Attribute is overwritten below the class definition + secondary_mails_policy_changed = None + # Attribute is overwritten below the class definition + binder_add_page = None + # Attribute is overwritten below the class definition + binder_add_section = None + # Attribute is overwritten below the class definition + binder_remove_page = None + # Attribute is overwritten below the class definition + binder_remove_section = None + # Attribute is overwritten below the class definition + binder_rename_page = None + # Attribute is overwritten below the class definition + binder_rename_section = None + # Attribute is overwritten below the class definition + binder_reorder_page = None + # Attribute is overwritten below the class definition + binder_reorder_section = None + # Attribute is overwritten below the class definition + paper_content_add_member = None + # Attribute is overwritten below the class definition + paper_content_add_to_folder = None + # Attribute is overwritten below the class definition + paper_content_archive = None + # Attribute is overwritten below the class definition + paper_content_create = None + # Attribute is overwritten below the class definition + paper_content_permanently_delete = None + # Attribute is overwritten below the class definition + paper_content_remove_from_folder = None + # Attribute is overwritten below the class definition + paper_content_remove_member = None + # Attribute is overwritten below the class definition + paper_content_rename = None + # Attribute is overwritten below the class definition + paper_content_restore = None + # Attribute is overwritten below the class definition + paper_doc_add_comment = None + # Attribute is overwritten below the class definition + paper_doc_change_member_role = None + # Attribute is overwritten below the class definition + paper_doc_change_sharing_policy = None + # Attribute is overwritten below the class definition + paper_doc_change_subscription = None + # Attribute is overwritten below the class definition + paper_doc_deleted = None + # Attribute is overwritten below the class definition + paper_doc_delete_comment = None + # Attribute is overwritten below the class definition + paper_doc_download = None + # Attribute is overwritten below the class definition + paper_doc_edit = None + # Attribute is overwritten below the class definition + paper_doc_edit_comment = None + # Attribute is overwritten below the class definition + paper_doc_followed = None + # Attribute is overwritten below the class definition + paper_doc_mention = None + # Attribute is overwritten below the class definition + paper_doc_ownership_changed = None + # Attribute is overwritten below the class definition + paper_doc_request_access = None + # Attribute is overwritten below the class definition + paper_doc_resolve_comment = None + # Attribute is overwritten below the class definition + paper_doc_revert = None + # Attribute is overwritten below the class definition + paper_doc_slack_share = None + # Attribute is overwritten below the class definition + paper_doc_team_invite = None + # Attribute is overwritten below the class definition + paper_doc_trashed = None + # Attribute is overwritten below the class definition + paper_doc_unresolve_comment = None + # Attribute is overwritten below the class definition + paper_doc_untrashed = None + # Attribute is overwritten below the class definition + paper_doc_view = None + # Attribute is overwritten below the class definition + paper_external_view_allow = None + # Attribute is overwritten below the class definition + paper_external_view_default_team = None + # Attribute is overwritten below the class definition + paper_external_view_forbid = None + # Attribute is overwritten below the class definition + paper_folder_change_subscription = None + # Attribute is overwritten below the class definition + paper_folder_deleted = None + # Attribute is overwritten below the class definition + paper_folder_followed = None + # Attribute is overwritten below the class definition + paper_folder_team_invite = None + # Attribute is overwritten below the class definition + paper_published_link_change_permission = None + # Attribute is overwritten below the class definition + paper_published_link_create = None + # Attribute is overwritten below the class definition + paper_published_link_disabled = None + # Attribute is overwritten below the class definition + paper_published_link_view = None + # Attribute is overwritten below the class definition + password_change = None + # Attribute is overwritten below the class definition + password_reset = None + # Attribute is overwritten below the class definition + password_reset_all = None + # Attribute is overwritten below the class definition + emm_create_exceptions_report = None + # Attribute is overwritten below the class definition + emm_create_usage_report = None + # Attribute is overwritten below the class definition + export_members_report = None + # Attribute is overwritten below the class definition + export_members_report_fail = None + # Attribute is overwritten below the class definition + no_expiration_link_gen_create_report = None + # Attribute is overwritten below the class definition + no_expiration_link_gen_report_failed = None + # Attribute is overwritten below the class definition + no_password_link_gen_create_report = None + # Attribute is overwritten below the class definition + no_password_link_gen_report_failed = None + # Attribute is overwritten below the class definition + no_password_link_view_create_report = None + # Attribute is overwritten below the class definition + no_password_link_view_report_failed = None + # Attribute is overwritten below the class definition + outdated_link_view_create_report = None + # Attribute is overwritten below the class definition + outdated_link_view_report_failed = None + # Attribute is overwritten below the class definition + paper_admin_export_start = None + # Attribute is overwritten below the class definition + smart_sync_create_admin_privilege_report = None + # Attribute is overwritten below the class definition + team_activity_create_report = None + # Attribute is overwritten below the class definition + team_activity_create_report_fail = None + # Attribute is overwritten below the class definition + collection_share = None + # Attribute is overwritten below the class definition + file_transfers_file_add = None + # Attribute is overwritten below the class definition + file_transfers_transfer_delete = None + # Attribute is overwritten below the class definition + file_transfers_transfer_download = None + # Attribute is overwritten below the class definition + file_transfers_transfer_send = None + # Attribute is overwritten below the class definition + file_transfers_transfer_view = None + # Attribute is overwritten below the class definition + note_acl_invite_only = None + # Attribute is overwritten below the class definition + note_acl_link = None + # Attribute is overwritten below the class definition + note_acl_team_link = None + # Attribute is overwritten below the class definition + note_shared = None + # Attribute is overwritten below the class definition + note_share_receive = None + # Attribute is overwritten below the class definition + open_note_shared = None + # Attribute is overwritten below the class definition + sf_add_group = None + # Attribute is overwritten below the class definition + sf_allow_non_members_to_view_shared_links = None + # Attribute is overwritten below the class definition + sf_external_invite_warn = None + # Attribute is overwritten below the class definition + sf_fb_invite = None + # Attribute is overwritten below the class definition + sf_fb_invite_change_role = None + # Attribute is overwritten below the class definition + sf_fb_uninvite = None + # Attribute is overwritten below the class definition + sf_invite_group = None + # Attribute is overwritten below the class definition + sf_team_grant_access = None + # Attribute is overwritten below the class definition + sf_team_invite = None + # Attribute is overwritten below the class definition + sf_team_invite_change_role = None + # Attribute is overwritten below the class definition + sf_team_join = None + # Attribute is overwritten below the class definition + sf_team_join_from_oob_link = None + # Attribute is overwritten below the class definition + sf_team_uninvite = None + # Attribute is overwritten below the class definition + shared_content_add_invitees = None + # Attribute is overwritten below the class definition + shared_content_add_link_expiry = None + # Attribute is overwritten below the class definition + shared_content_add_link_password = None + # Attribute is overwritten below the class definition + shared_content_add_member = None + # Attribute is overwritten below the class definition + shared_content_change_downloads_policy = None + # Attribute is overwritten below the class definition + shared_content_change_invitee_role = None + # Attribute is overwritten below the class definition + shared_content_change_link_audience = None + # Attribute is overwritten below the class definition + shared_content_change_link_expiry = None + # Attribute is overwritten below the class definition + shared_content_change_link_password = None + # Attribute is overwritten below the class definition + shared_content_change_member_role = None + # Attribute is overwritten below the class definition + shared_content_change_viewer_info_policy = None + # Attribute is overwritten below the class definition + shared_content_claim_invitation = None + # Attribute is overwritten below the class definition + shared_content_copy = None + # Attribute is overwritten below the class definition + shared_content_download = None + # Attribute is overwritten below the class definition + shared_content_relinquish_membership = None + # Attribute is overwritten below the class definition + shared_content_remove_invitees = None + # Attribute is overwritten below the class definition + shared_content_remove_link_expiry = None + # Attribute is overwritten below the class definition + shared_content_remove_link_password = None + # Attribute is overwritten below the class definition + shared_content_remove_member = None + # Attribute is overwritten below the class definition + shared_content_request_access = None + # Attribute is overwritten below the class definition + shared_content_restore_invitees = None + # Attribute is overwritten below the class definition + shared_content_restore_member = None + # Attribute is overwritten below the class definition + shared_content_unshare = None + # Attribute is overwritten below the class definition + shared_content_view = None + # Attribute is overwritten below the class definition + shared_folder_change_link_policy = None + # Attribute is overwritten below the class definition + shared_folder_change_members_inheritance_policy = None + # Attribute is overwritten below the class definition + shared_folder_change_members_management_policy = None + # Attribute is overwritten below the class definition + shared_folder_change_members_policy = None + # Attribute is overwritten below the class definition + shared_folder_create = None + # Attribute is overwritten below the class definition + shared_folder_decline_invitation = None + # Attribute is overwritten below the class definition + shared_folder_mount = None + # Attribute is overwritten below the class definition + shared_folder_nest = None + # Attribute is overwritten below the class definition + shared_folder_transfer_ownership = None + # Attribute is overwritten below the class definition + shared_folder_unmount = None + # Attribute is overwritten below the class definition + shared_link_add_expiry = None + # Attribute is overwritten below the class definition + shared_link_change_expiry = None + # Attribute is overwritten below the class definition + shared_link_change_visibility = None + # Attribute is overwritten below the class definition + shared_link_copy = None + # Attribute is overwritten below the class definition + shared_link_create = None + # Attribute is overwritten below the class definition + shared_link_disable = None + # Attribute is overwritten below the class definition + shared_link_download = None + # Attribute is overwritten below the class definition + shared_link_remove_expiry = None + # Attribute is overwritten below the class definition + shared_link_settings_add_expiration = None + # Attribute is overwritten below the class definition + shared_link_settings_add_password = None + # Attribute is overwritten below the class definition + shared_link_settings_allow_download_disabled = None + # Attribute is overwritten below the class definition + shared_link_settings_allow_download_enabled = None + # Attribute is overwritten below the class definition + shared_link_settings_change_audience = None + # Attribute is overwritten below the class definition + shared_link_settings_change_expiration = None + # Attribute is overwritten below the class definition + shared_link_settings_change_password = None + # Attribute is overwritten below the class definition + shared_link_settings_remove_expiration = None + # Attribute is overwritten below the class definition + shared_link_settings_remove_password = None + # Attribute is overwritten below the class definition + shared_link_share = None + # Attribute is overwritten below the class definition + shared_link_view = None + # Attribute is overwritten below the class definition + shared_note_opened = None + # Attribute is overwritten below the class definition + shmodel_group_share = None + # Attribute is overwritten below the class definition + showcase_access_granted = None + # Attribute is overwritten below the class definition + showcase_add_member = None + # Attribute is overwritten below the class definition + showcase_archived = None + # Attribute is overwritten below the class definition + showcase_created = None + # Attribute is overwritten below the class definition + showcase_delete_comment = None + # Attribute is overwritten below the class definition + showcase_edited = None + # Attribute is overwritten below the class definition + showcase_edit_comment = None + # Attribute is overwritten below the class definition + showcase_file_added = None + # Attribute is overwritten below the class definition + showcase_file_download = None + # Attribute is overwritten below the class definition + showcase_file_removed = None + # Attribute is overwritten below the class definition + showcase_file_view = None + # Attribute is overwritten below the class definition + showcase_permanently_deleted = None + # Attribute is overwritten below the class definition + showcase_post_comment = None + # Attribute is overwritten below the class definition + showcase_remove_member = None + # Attribute is overwritten below the class definition + showcase_renamed = None + # Attribute is overwritten below the class definition + showcase_request_access = None + # Attribute is overwritten below the class definition + showcase_resolve_comment = None + # Attribute is overwritten below the class definition + showcase_restored = None + # Attribute is overwritten below the class definition + showcase_trashed = None + # Attribute is overwritten below the class definition + showcase_trashed_deprecated = None + # Attribute is overwritten below the class definition + showcase_unresolve_comment = None + # Attribute is overwritten below the class definition + showcase_untrashed = None + # Attribute is overwritten below the class definition + showcase_untrashed_deprecated = None + # Attribute is overwritten below the class definition + showcase_view = None + # Attribute is overwritten below the class definition + sso_add_cert = None + # Attribute is overwritten below the class definition + sso_add_login_url = None + # Attribute is overwritten below the class definition + sso_add_logout_url = None + # Attribute is overwritten below the class definition + sso_change_cert = None + # Attribute is overwritten below the class definition + sso_change_login_url = None + # Attribute is overwritten below the class definition + sso_change_logout_url = None + # Attribute is overwritten below the class definition + sso_change_saml_identity_mode = None + # Attribute is overwritten below the class definition + sso_remove_cert = None + # Attribute is overwritten below the class definition + sso_remove_login_url = None + # Attribute is overwritten below the class definition + sso_remove_logout_url = None + # Attribute is overwritten below the class definition + team_folder_change_status = None + # Attribute is overwritten below the class definition + team_folder_create = None + # Attribute is overwritten below the class definition + team_folder_downgrade = None + # Attribute is overwritten below the class definition + team_folder_permanently_delete = None + # Attribute is overwritten below the class definition + team_folder_rename = None + # Attribute is overwritten below the class definition + team_selective_sync_settings_changed = None + # Attribute is overwritten below the class definition + account_capture_change_policy = None + # Attribute is overwritten below the class definition + allow_download_disabled = None + # Attribute is overwritten below the class definition + allow_download_enabled = None + # Attribute is overwritten below the class definition + camera_uploads_policy_changed = None + # Attribute is overwritten below the class definition + data_placement_restriction_change_policy = None + # Attribute is overwritten below the class definition + data_placement_restriction_satisfy_policy = None + # Attribute is overwritten below the class definition + device_approvals_add_exception = None + # Attribute is overwritten below the class definition + device_approvals_change_desktop_policy = None + # Attribute is overwritten below the class definition + device_approvals_change_mobile_policy = None + # Attribute is overwritten below the class definition + device_approvals_change_overage_action = None + # Attribute is overwritten below the class definition + device_approvals_change_unlink_action = None + # Attribute is overwritten below the class definition + device_approvals_remove_exception = None + # Attribute is overwritten below the class definition + directory_restrictions_add_members = None + # Attribute is overwritten below the class definition + directory_restrictions_remove_members = None + # Attribute is overwritten below the class definition + emm_add_exception = None + # Attribute is overwritten below the class definition + emm_change_policy = None + # Attribute is overwritten below the class definition + emm_remove_exception = None + # Attribute is overwritten below the class definition + extended_version_history_change_policy = None + # Attribute is overwritten below the class definition + file_comments_change_policy = None + # Attribute is overwritten below the class definition + file_locking_policy_changed = None + # Attribute is overwritten below the class definition + file_requests_change_policy = None + # Attribute is overwritten below the class definition + file_requests_emails_enabled = None + # Attribute is overwritten below the class definition + file_requests_emails_restricted_to_team_only = None + # Attribute is overwritten below the class definition + file_transfers_policy_changed = None + # Attribute is overwritten below the class definition + google_sso_change_policy = None + # Attribute is overwritten below the class definition + group_user_management_change_policy = None + # Attribute is overwritten below the class definition + integration_policy_changed = None + # Attribute is overwritten below the class definition + member_requests_change_policy = None + # Attribute is overwritten below the class definition + member_send_invite_policy_changed = None + # Attribute is overwritten below the class definition + member_space_limits_add_exception = None + # Attribute is overwritten below the class definition + member_space_limits_change_caps_type_policy = None + # Attribute is overwritten below the class definition + member_space_limits_change_policy = None + # Attribute is overwritten below the class definition + member_space_limits_remove_exception = None + # Attribute is overwritten below the class definition + member_suggestions_change_policy = None + # Attribute is overwritten below the class definition + microsoft_office_addin_change_policy = None + # Attribute is overwritten below the class definition + network_control_change_policy = None + # Attribute is overwritten below the class definition + paper_change_deployment_policy = None + # Attribute is overwritten below the class definition + paper_change_member_link_policy = None + # Attribute is overwritten below the class definition + paper_change_member_policy = None + # Attribute is overwritten below the class definition + paper_change_policy = None + # Attribute is overwritten below the class definition + paper_default_folder_policy_changed = None + # Attribute is overwritten below the class definition + paper_desktop_policy_changed = None + # Attribute is overwritten below the class definition + paper_enabled_users_group_addition = None + # Attribute is overwritten below the class definition + paper_enabled_users_group_removal = None + # Attribute is overwritten below the class definition + password_strength_requirements_change_policy = None + # Attribute is overwritten below the class definition + permanent_delete_change_policy = None + # Attribute is overwritten below the class definition + reseller_support_change_policy = None + # Attribute is overwritten below the class definition + rewind_policy_changed = None + # Attribute is overwritten below the class definition + sharing_change_folder_join_policy = None + # Attribute is overwritten below the class definition + sharing_change_link_policy = None + # Attribute is overwritten below the class definition + sharing_change_member_policy = None + # Attribute is overwritten below the class definition + showcase_change_download_policy = None + # Attribute is overwritten below the class definition + showcase_change_enabled_policy = None + # Attribute is overwritten below the class definition + showcase_change_external_sharing_policy = None + # Attribute is overwritten below the class definition + smarter_smart_sync_policy_changed = None + # Attribute is overwritten below the class definition + smart_sync_change_policy = None + # Attribute is overwritten below the class definition + smart_sync_not_opt_out = None + # Attribute is overwritten below the class definition + smart_sync_opt_out = None + # Attribute is overwritten below the class definition + sso_change_policy = None + # Attribute is overwritten below the class definition + team_extensions_policy_changed = None + # Attribute is overwritten below the class definition + team_selective_sync_policy_changed = None + # Attribute is overwritten below the class definition + team_sharing_whitelist_subjects_changed = None + # Attribute is overwritten below the class definition + tfa_add_exception = None + # Attribute is overwritten below the class definition + tfa_change_policy = None + # Attribute is overwritten below the class definition + tfa_remove_exception = None + # Attribute is overwritten below the class definition + two_account_change_policy = None + # Attribute is overwritten below the class definition + viewer_info_policy_changed = None + # Attribute is overwritten below the class definition + watermarking_policy_changed = None + # Attribute is overwritten below the class definition + web_sessions_change_active_session_limit = None + # Attribute is overwritten below the class definition + web_sessions_change_fixed_length_policy = None + # Attribute is overwritten below the class definition + web_sessions_change_idle_length_policy = None + # Attribute is overwritten below the class definition + team_merge_from = None + # Attribute is overwritten below the class definition + team_merge_to = None + # Attribute is overwritten below the class definition + team_profile_add_logo = None + # Attribute is overwritten below the class definition + team_profile_change_default_language = None + # Attribute is overwritten below the class definition + team_profile_change_logo = None + # Attribute is overwritten below the class definition + team_profile_change_name = None + # Attribute is overwritten below the class definition + team_profile_remove_logo = None + # Attribute is overwritten below the class definition + tfa_add_backup_phone = None + # Attribute is overwritten below the class definition + tfa_add_security_key = None + # Attribute is overwritten below the class definition + tfa_change_backup_phone = None + # Attribute is overwritten below the class definition + tfa_change_status = None + # Attribute is overwritten below the class definition + tfa_remove_backup_phone = None + # Attribute is overwritten below the class definition + tfa_remove_security_key = None + # Attribute is overwritten below the class definition + tfa_reset = None + # Attribute is overwritten below the class definition + changed_enterprise_admin_role = None + # Attribute is overwritten below the class definition + changed_enterprise_connected_team_status = None + # Attribute is overwritten below the class definition + ended_enterprise_admin_session = None + # Attribute is overwritten below the class definition + ended_enterprise_admin_session_deprecated = None + # Attribute is overwritten below the class definition + enterprise_settings_locking = None + # Attribute is overwritten below the class definition + guest_admin_change_status = None + # Attribute is overwritten below the class definition + started_enterprise_admin_session = None + # Attribute is overwritten below the class definition + team_merge_request_accepted = None + # Attribute is overwritten below the class definition + team_merge_request_accepted_shown_to_primary_team = None + # Attribute is overwritten below the class definition + team_merge_request_accepted_shown_to_secondary_team = None + # Attribute is overwritten below the class definition + team_merge_request_auto_canceled = None + # Attribute is overwritten below the class definition + team_merge_request_canceled = None + # Attribute is overwritten below the class definition + team_merge_request_canceled_shown_to_primary_team = None + # Attribute is overwritten below the class definition + team_merge_request_canceled_shown_to_secondary_team = None + # Attribute is overwritten below the class definition + team_merge_request_expired = None + # Attribute is overwritten below the class definition + team_merge_request_expired_shown_to_primary_team = None + # Attribute is overwritten below the class definition + team_merge_request_expired_shown_to_secondary_team = None + # Attribute is overwritten below the class definition + team_merge_request_rejected_shown_to_primary_team = None + # Attribute is overwritten below the class definition + team_merge_request_rejected_shown_to_secondary_team = None + # Attribute is overwritten below the class definition + team_merge_request_reminder = None + # Attribute is overwritten below the class definition + team_merge_request_reminder_shown_to_primary_team = None + # Attribute is overwritten below the class definition + team_merge_request_reminder_shown_to_secondary_team = None + # Attribute is overwritten below the class definition + team_merge_request_revoked = None + # Attribute is overwritten below the class definition + team_merge_request_sent_shown_to_primary_team = None + # Attribute is overwritten below the class definition + team_merge_request_sent_shown_to_secondary_team = None + # Attribute is overwritten below the class definition + other = None - @classmethod - def shared_folder_transfer_ownership(cls, val): + def is_app_link_team(self): """ - Create an instance of this class set to the - ``shared_folder_transfer_ownership`` tag with value ``val``. + Check if the union tag is ``app_link_team``. - :param SharedFolderTransferOwnershipType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_folder_transfer_ownership', val) + return self._tag == 'app_link_team' - @classmethod - def shared_folder_unmount(cls, val): + def is_app_link_user(self): """ - Create an instance of this class set to the ``shared_folder_unmount`` - tag with value ``val``. + Check if the union tag is ``app_link_user``. - :param SharedFolderUnmountType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_folder_unmount', val) + return self._tag == 'app_link_user' - @classmethod - def shared_link_add_expiry(cls, val): + def is_app_unlink_team(self): """ - Create an instance of this class set to the ``shared_link_add_expiry`` - tag with value ``val``. + Check if the union tag is ``app_unlink_team``. - :param SharedLinkAddExpiryType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_add_expiry', val) + return self._tag == 'app_unlink_team' - @classmethod - def shared_link_change_expiry(cls, val): + def is_app_unlink_user(self): """ - Create an instance of this class set to the - ``shared_link_change_expiry`` tag with value ``val``. + Check if the union tag is ``app_unlink_user``. - :param SharedLinkChangeExpiryType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_change_expiry', val) + return self._tag == 'app_unlink_user' - @classmethod - def shared_link_change_visibility(cls, val): + def is_integration_connected(self): """ - Create an instance of this class set to the - ``shared_link_change_visibility`` tag with value ``val``. + Check if the union tag is ``integration_connected``. - :param SharedLinkChangeVisibilityType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_change_visibility', val) + return self._tag == 'integration_connected' - @classmethod - def shared_link_copy(cls, val): + def is_integration_disconnected(self): """ - Create an instance of this class set to the ``shared_link_copy`` tag - with value ``val``. + Check if the union tag is ``integration_disconnected``. - :param SharedLinkCopyType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_copy', val) + return self._tag == 'integration_disconnected' - @classmethod - def shared_link_create(cls, val): + def is_file_add_comment(self): """ - Create an instance of this class set to the ``shared_link_create`` tag - with value ``val``. + Check if the union tag is ``file_add_comment``. - :param SharedLinkCreateType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_create', val) + return self._tag == 'file_add_comment' - @classmethod - def shared_link_disable(cls, val): + def is_file_change_comment_subscription(self): """ - Create an instance of this class set to the ``shared_link_disable`` tag - with value ``val``. + Check if the union tag is ``file_change_comment_subscription``. - :param SharedLinkDisableType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_disable', val) + return self._tag == 'file_change_comment_subscription' - @classmethod - def shared_link_download(cls, val): + def is_file_delete_comment(self): """ - Create an instance of this class set to the ``shared_link_download`` tag - with value ``val``. + Check if the union tag is ``file_delete_comment``. - :param SharedLinkDownloadType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_download', val) + return self._tag == 'file_delete_comment' - @classmethod - def shared_link_remove_expiry(cls, val): + def is_file_edit_comment(self): """ - Create an instance of this class set to the - ``shared_link_remove_expiry`` tag with value ``val``. + Check if the union tag is ``file_edit_comment``. - :param SharedLinkRemoveExpiryType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_remove_expiry', val) + return self._tag == 'file_edit_comment' - @classmethod - def shared_link_share(cls, val): + def is_file_like_comment(self): """ - Create an instance of this class set to the ``shared_link_share`` tag - with value ``val``. + Check if the union tag is ``file_like_comment``. - :param SharedLinkShareType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_share', val) + return self._tag == 'file_like_comment' - @classmethod - def shared_link_view(cls, val): + def is_file_resolve_comment(self): """ - Create an instance of this class set to the ``shared_link_view`` tag - with value ``val``. + Check if the union tag is ``file_resolve_comment``. - :param SharedLinkViewType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_link_view', val) + return self._tag == 'file_resolve_comment' - @classmethod - def shared_note_opened(cls, val): + def is_file_unlike_comment(self): """ - Create an instance of this class set to the ``shared_note_opened`` tag - with value ``val``. + Check if the union tag is ``file_unlike_comment``. - :param SharedNoteOpenedType val: - :rtype: EventType + :rtype: bool """ - return cls('shared_note_opened', val) + return self._tag == 'file_unlike_comment' - @classmethod - def shmodel_group_share(cls, val): + def is_file_unresolve_comment(self): """ - Create an instance of this class set to the ``shmodel_group_share`` tag - with value ``val``. + Check if the union tag is ``file_unresolve_comment``. - :param ShmodelGroupShareType val: - :rtype: EventType + :rtype: bool """ - return cls('shmodel_group_share', val) + return self._tag == 'file_unresolve_comment' - @classmethod - def showcase_access_granted(cls, val): + def is_device_change_ip_desktop(self): """ - Create an instance of this class set to the ``showcase_access_granted`` - tag with value ``val``. + Check if the union tag is ``device_change_ip_desktop``. - :param ShowcaseAccessGrantedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_access_granted', val) + return self._tag == 'device_change_ip_desktop' - @classmethod - def showcase_add_member(cls, val): + def is_device_change_ip_mobile(self): """ - Create an instance of this class set to the ``showcase_add_member`` tag - with value ``val``. + Check if the union tag is ``device_change_ip_mobile``. - :param ShowcaseAddMemberType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_add_member', val) + return self._tag == 'device_change_ip_mobile' - @classmethod - def showcase_archived(cls, val): + def is_device_change_ip_web(self): """ - Create an instance of this class set to the ``showcase_archived`` tag - with value ``val``. + Check if the union tag is ``device_change_ip_web``. - :param ShowcaseArchivedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_archived', val) + return self._tag == 'device_change_ip_web' - @classmethod - def showcase_created(cls, val): + def is_device_delete_on_unlink_fail(self): """ - Create an instance of this class set to the ``showcase_created`` tag - with value ``val``. + Check if the union tag is ``device_delete_on_unlink_fail``. - :param ShowcaseCreatedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_created', val) + return self._tag == 'device_delete_on_unlink_fail' - @classmethod - def showcase_delete_comment(cls, val): + def is_device_delete_on_unlink_success(self): """ - Create an instance of this class set to the ``showcase_delete_comment`` - tag with value ``val``. + Check if the union tag is ``device_delete_on_unlink_success``. - :param ShowcaseDeleteCommentType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_delete_comment', val) + return self._tag == 'device_delete_on_unlink_success' - @classmethod - def showcase_edited(cls, val): + def is_device_link_fail(self): """ - Create an instance of this class set to the ``showcase_edited`` tag with - value ``val``. + Check if the union tag is ``device_link_fail``. - :param ShowcaseEditedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_edited', val) + return self._tag == 'device_link_fail' - @classmethod - def showcase_edit_comment(cls, val): + def is_device_link_success(self): """ - Create an instance of this class set to the ``showcase_edit_comment`` - tag with value ``val``. + Check if the union tag is ``device_link_success``. - :param ShowcaseEditCommentType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_edit_comment', val) + return self._tag == 'device_link_success' - @classmethod - def showcase_file_added(cls, val): + def is_device_management_disabled(self): """ - Create an instance of this class set to the ``showcase_file_added`` tag - with value ``val``. + Check if the union tag is ``device_management_disabled``. - :param ShowcaseFileAddedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_file_added', val) + return self._tag == 'device_management_disabled' - @classmethod - def showcase_file_download(cls, val): + def is_device_management_enabled(self): """ - Create an instance of this class set to the ``showcase_file_download`` - tag with value ``val``. + Check if the union tag is ``device_management_enabled``. - :param ShowcaseFileDownloadType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_file_download', val) + return self._tag == 'device_management_enabled' - @classmethod - def showcase_file_removed(cls, val): + def is_device_unlink(self): """ - Create an instance of this class set to the ``showcase_file_removed`` - tag with value ``val``. + Check if the union tag is ``device_unlink``. - :param ShowcaseFileRemovedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_file_removed', val) + return self._tag == 'device_unlink' - @classmethod - def showcase_file_view(cls, val): + def is_emm_refresh_auth_token(self): """ - Create an instance of this class set to the ``showcase_file_view`` tag - with value ``val``. + Check if the union tag is ``emm_refresh_auth_token``. - :param ShowcaseFileViewType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_file_view', val) + return self._tag == 'emm_refresh_auth_token' - @classmethod - def showcase_permanently_deleted(cls, val): + def is_account_capture_change_availability(self): """ - Create an instance of this class set to the - ``showcase_permanently_deleted`` tag with value ``val``. + Check if the union tag is ``account_capture_change_availability``. - :param ShowcasePermanentlyDeletedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_permanently_deleted', val) + return self._tag == 'account_capture_change_availability' - @classmethod - def showcase_post_comment(cls, val): + def is_account_capture_migrate_account(self): """ - Create an instance of this class set to the ``showcase_post_comment`` - tag with value ``val``. + Check if the union tag is ``account_capture_migrate_account``. - :param ShowcasePostCommentType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_post_comment', val) + return self._tag == 'account_capture_migrate_account' - @classmethod - def showcase_remove_member(cls, val): + def is_account_capture_notification_emails_sent(self): """ - Create an instance of this class set to the ``showcase_remove_member`` - tag with value ``val``. + Check if the union tag is ``account_capture_notification_emails_sent``. - :param ShowcaseRemoveMemberType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_remove_member', val) + return self._tag == 'account_capture_notification_emails_sent' - @classmethod - def showcase_renamed(cls, val): + def is_account_capture_relinquish_account(self): """ - Create an instance of this class set to the ``showcase_renamed`` tag - with value ``val``. + Check if the union tag is ``account_capture_relinquish_account``. - :param ShowcaseRenamedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_renamed', val) + return self._tag == 'account_capture_relinquish_account' - @classmethod - def showcase_request_access(cls, val): + def is_disabled_domain_invites(self): """ - Create an instance of this class set to the ``showcase_request_access`` - tag with value ``val``. + Check if the union tag is ``disabled_domain_invites``. - :param ShowcaseRequestAccessType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_request_access', val) + return self._tag == 'disabled_domain_invites' - @classmethod - def showcase_resolve_comment(cls, val): + def is_domain_invites_approve_request_to_join_team(self): """ - Create an instance of this class set to the ``showcase_resolve_comment`` - tag with value ``val``. + Check if the union tag is ``domain_invites_approve_request_to_join_team``. - :param ShowcaseResolveCommentType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_resolve_comment', val) + return self._tag == 'domain_invites_approve_request_to_join_team' - @classmethod - def showcase_restored(cls, val): + def is_domain_invites_decline_request_to_join_team(self): """ - Create an instance of this class set to the ``showcase_restored`` tag - with value ``val``. + Check if the union tag is ``domain_invites_decline_request_to_join_team``. - :param ShowcaseRestoredType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_restored', val) + return self._tag == 'domain_invites_decline_request_to_join_team' - @classmethod - def showcase_trashed(cls, val): + def is_domain_invites_email_existing_users(self): """ - Create an instance of this class set to the ``showcase_trashed`` tag - with value ``val``. + Check if the union tag is ``domain_invites_email_existing_users``. - :param ShowcaseTrashedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_trashed', val) + return self._tag == 'domain_invites_email_existing_users' - @classmethod - def showcase_trashed_deprecated(cls, val): + def is_domain_invites_request_to_join_team(self): """ - Create an instance of this class set to the - ``showcase_trashed_deprecated`` tag with value ``val``. + Check if the union tag is ``domain_invites_request_to_join_team``. - :param ShowcaseTrashedDeprecatedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_trashed_deprecated', val) + return self._tag == 'domain_invites_request_to_join_team' - @classmethod - def showcase_unresolve_comment(cls, val): + def is_domain_invites_set_invite_new_user_pref_to_no(self): """ - Create an instance of this class set to the - ``showcase_unresolve_comment`` tag with value ``val``. + Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_no``. - :param ShowcaseUnresolveCommentType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_unresolve_comment', val) + return self._tag == 'domain_invites_set_invite_new_user_pref_to_no' - @classmethod - def showcase_untrashed(cls, val): + def is_domain_invites_set_invite_new_user_pref_to_yes(self): """ - Create an instance of this class set to the ``showcase_untrashed`` tag - with value ``val``. + Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_yes``. - :param ShowcaseUntrashedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_untrashed', val) + return self._tag == 'domain_invites_set_invite_new_user_pref_to_yes' - @classmethod - def showcase_untrashed_deprecated(cls, val): + def is_domain_verification_add_domain_fail(self): """ - Create an instance of this class set to the - ``showcase_untrashed_deprecated`` tag with value ``val``. + Check if the union tag is ``domain_verification_add_domain_fail``. - :param ShowcaseUntrashedDeprecatedType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_untrashed_deprecated', val) + return self._tag == 'domain_verification_add_domain_fail' - @classmethod - def showcase_view(cls, val): + def is_domain_verification_add_domain_success(self): """ - Create an instance of this class set to the ``showcase_view`` tag with - value ``val``. + Check if the union tag is ``domain_verification_add_domain_success``. - :param ShowcaseViewType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_view', val) + return self._tag == 'domain_verification_add_domain_success' - @classmethod - def sso_add_cert(cls, val): + def is_domain_verification_remove_domain(self): """ - Create an instance of this class set to the ``sso_add_cert`` tag with - value ``val``. + Check if the union tag is ``domain_verification_remove_domain``. - :param SsoAddCertType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_add_cert', val) + return self._tag == 'domain_verification_remove_domain' - @classmethod - def sso_add_login_url(cls, val): + def is_enabled_domain_invites(self): """ - Create an instance of this class set to the ``sso_add_login_url`` tag - with value ``val``. + Check if the union tag is ``enabled_domain_invites``. - :param SsoAddLoginUrlType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_add_login_url', val) + return self._tag == 'enabled_domain_invites' - @classmethod - def sso_add_logout_url(cls, val): + def is_create_folder(self): """ - Create an instance of this class set to the ``sso_add_logout_url`` tag - with value ``val``. + Check if the union tag is ``create_folder``. - :param SsoAddLogoutUrlType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_add_logout_url', val) + return self._tag == 'create_folder' - @classmethod - def sso_change_cert(cls, val): + def is_file_add(self): """ - Create an instance of this class set to the ``sso_change_cert`` tag with - value ``val``. + Check if the union tag is ``file_add``. - :param SsoChangeCertType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_change_cert', val) + return self._tag == 'file_add' - @classmethod - def sso_change_login_url(cls, val): + def is_file_copy(self): """ - Create an instance of this class set to the ``sso_change_login_url`` tag - with value ``val``. + Check if the union tag is ``file_copy``. - :param SsoChangeLoginUrlType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_change_login_url', val) + return self._tag == 'file_copy' - @classmethod - def sso_change_logout_url(cls, val): + def is_file_delete(self): """ - Create an instance of this class set to the ``sso_change_logout_url`` - tag with value ``val``. + Check if the union tag is ``file_delete``. - :param SsoChangeLogoutUrlType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_change_logout_url', val) + return self._tag == 'file_delete' - @classmethod - def sso_change_saml_identity_mode(cls, val): + def is_file_download(self): """ - Create an instance of this class set to the - ``sso_change_saml_identity_mode`` tag with value ``val``. + Check if the union tag is ``file_download``. - :param SsoChangeSamlIdentityModeType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_change_saml_identity_mode', val) + return self._tag == 'file_download' - @classmethod - def sso_remove_cert(cls, val): + def is_file_edit(self): """ - Create an instance of this class set to the ``sso_remove_cert`` tag with - value ``val``. + Check if the union tag is ``file_edit``. - :param SsoRemoveCertType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_remove_cert', val) + return self._tag == 'file_edit' - @classmethod - def sso_remove_login_url(cls, val): + def is_file_get_copy_reference(self): """ - Create an instance of this class set to the ``sso_remove_login_url`` tag - with value ``val``. + Check if the union tag is ``file_get_copy_reference``. - :param SsoRemoveLoginUrlType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_remove_login_url', val) + return self._tag == 'file_get_copy_reference' - @classmethod - def sso_remove_logout_url(cls, val): + def is_file_locking_lock_status_changed(self): """ - Create an instance of this class set to the ``sso_remove_logout_url`` - tag with value ``val``. + Check if the union tag is ``file_locking_lock_status_changed``. - :param SsoRemoveLogoutUrlType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_remove_logout_url', val) + return self._tag == 'file_locking_lock_status_changed' - @classmethod - def team_folder_change_status(cls, val): + def is_file_move(self): """ - Create an instance of this class set to the - ``team_folder_change_status`` tag with value ``val``. + Check if the union tag is ``file_move``. - :param TeamFolderChangeStatusType val: - :rtype: EventType + :rtype: bool """ - return cls('team_folder_change_status', val) + return self._tag == 'file_move' - @classmethod - def team_folder_create(cls, val): + def is_file_permanently_delete(self): """ - Create an instance of this class set to the ``team_folder_create`` tag - with value ``val``. + Check if the union tag is ``file_permanently_delete``. - :param TeamFolderCreateType val: - :rtype: EventType + :rtype: bool """ - return cls('team_folder_create', val) + return self._tag == 'file_permanently_delete' - @classmethod - def team_folder_downgrade(cls, val): + def is_file_preview(self): """ - Create an instance of this class set to the ``team_folder_downgrade`` - tag with value ``val``. + Check if the union tag is ``file_preview``. - :param TeamFolderDowngradeType val: - :rtype: EventType + :rtype: bool """ - return cls('team_folder_downgrade', val) + return self._tag == 'file_preview' - @classmethod - def team_folder_permanently_delete(cls, val): + def is_file_rename(self): """ - Create an instance of this class set to the - ``team_folder_permanently_delete`` tag with value ``val``. + Check if the union tag is ``file_rename``. - :param TeamFolderPermanentlyDeleteType val: - :rtype: EventType + :rtype: bool """ - return cls('team_folder_permanently_delete', val) + return self._tag == 'file_rename' - @classmethod - def team_folder_rename(cls, val): + def is_file_restore(self): """ - Create an instance of this class set to the ``team_folder_rename`` tag - with value ``val``. + Check if the union tag is ``file_restore``. - :param TeamFolderRenameType val: - :rtype: EventType + :rtype: bool """ - return cls('team_folder_rename', val) + return self._tag == 'file_restore' - @classmethod - def team_selective_sync_settings_changed(cls, val): + def is_file_revert(self): """ - Create an instance of this class set to the - ``team_selective_sync_settings_changed`` tag with value ``val``. + Check if the union tag is ``file_revert``. - :param TeamSelectiveSyncSettingsChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('team_selective_sync_settings_changed', val) + return self._tag == 'file_revert' - @classmethod - def account_capture_change_policy(cls, val): + def is_file_rollback_changes(self): """ - Create an instance of this class set to the - ``account_capture_change_policy`` tag with value ``val``. + Check if the union tag is ``file_rollback_changes``. - :param AccountCaptureChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('account_capture_change_policy', val) + return self._tag == 'file_rollback_changes' - @classmethod - def allow_download_disabled(cls, val): + def is_file_save_copy_reference(self): """ - Create an instance of this class set to the ``allow_download_disabled`` - tag with value ``val``. + Check if the union tag is ``file_save_copy_reference``. - :param AllowDownloadDisabledType val: - :rtype: EventType + :rtype: bool """ - return cls('allow_download_disabled', val) + return self._tag == 'file_save_copy_reference' - @classmethod - def allow_download_enabled(cls, val): + def is_folder_overview_description_changed(self): """ - Create an instance of this class set to the ``allow_download_enabled`` - tag with value ``val``. + Check if the union tag is ``folder_overview_description_changed``. - :param AllowDownloadEnabledType val: - :rtype: EventType + :rtype: bool """ - return cls('allow_download_enabled', val) + return self._tag == 'folder_overview_description_changed' - @classmethod - def camera_uploads_policy_changed(cls, val): + def is_folder_overview_item_pinned(self): """ - Create an instance of this class set to the - ``camera_uploads_policy_changed`` tag with value ``val``. + Check if the union tag is ``folder_overview_item_pinned``. - :param CameraUploadsPolicyChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('camera_uploads_policy_changed', val) + return self._tag == 'folder_overview_item_pinned' - @classmethod - def data_placement_restriction_change_policy(cls, val): + def is_folder_overview_item_unpinned(self): """ - Create an instance of this class set to the - ``data_placement_restriction_change_policy`` tag with value ``val``. + Check if the union tag is ``folder_overview_item_unpinned``. - :param DataPlacementRestrictionChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('data_placement_restriction_change_policy', val) + return self._tag == 'folder_overview_item_unpinned' - @classmethod - def data_placement_restriction_satisfy_policy(cls, val): + def is_rewind_folder(self): """ - Create an instance of this class set to the - ``data_placement_restriction_satisfy_policy`` tag with value ``val``. + Check if the union tag is ``rewind_folder``. - :param DataPlacementRestrictionSatisfyPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('data_placement_restriction_satisfy_policy', val) + return self._tag == 'rewind_folder' - @classmethod - def device_approvals_change_desktop_policy(cls, val): + def is_file_request_change(self): """ - Create an instance of this class set to the - ``device_approvals_change_desktop_policy`` tag with value ``val``. + Check if the union tag is ``file_request_change``. - :param DeviceApprovalsChangeDesktopPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('device_approvals_change_desktop_policy', val) + return self._tag == 'file_request_change' - @classmethod - def device_approvals_change_mobile_policy(cls, val): + def is_file_request_close(self): """ - Create an instance of this class set to the - ``device_approvals_change_mobile_policy`` tag with value ``val``. + Check if the union tag is ``file_request_close``. - :param DeviceApprovalsChangeMobilePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('device_approvals_change_mobile_policy', val) + return self._tag == 'file_request_close' - @classmethod - def device_approvals_change_overage_action(cls, val): + def is_file_request_create(self): """ - Create an instance of this class set to the - ``device_approvals_change_overage_action`` tag with value ``val``. + Check if the union tag is ``file_request_create``. - :param DeviceApprovalsChangeOverageActionType val: - :rtype: EventType + :rtype: bool """ - return cls('device_approvals_change_overage_action', val) + return self._tag == 'file_request_create' - @classmethod - def device_approvals_change_unlink_action(cls, val): + def is_file_request_delete(self): """ - Create an instance of this class set to the - ``device_approvals_change_unlink_action`` tag with value ``val``. + Check if the union tag is ``file_request_delete``. - :param DeviceApprovalsChangeUnlinkActionType val: - :rtype: EventType + :rtype: bool """ - return cls('device_approvals_change_unlink_action', val) + return self._tag == 'file_request_delete' - @classmethod - def directory_restrictions_add_members(cls, val): + def is_file_request_receive_file(self): """ - Create an instance of this class set to the - ``directory_restrictions_add_members`` tag with value ``val``. + Check if the union tag is ``file_request_receive_file``. - :param DirectoryRestrictionsAddMembersType val: - :rtype: EventType + :rtype: bool """ - return cls('directory_restrictions_add_members', val) + return self._tag == 'file_request_receive_file' - @classmethod - def directory_restrictions_remove_members(cls, val): + def is_group_add_external_id(self): """ - Create an instance of this class set to the - ``directory_restrictions_remove_members`` tag with value ``val``. + Check if the union tag is ``group_add_external_id``. - :param DirectoryRestrictionsRemoveMembersType val: - :rtype: EventType + :rtype: bool """ - return cls('directory_restrictions_remove_members', val) + return self._tag == 'group_add_external_id' - @classmethod - def emm_add_exception(cls, val): + def is_group_add_member(self): """ - Create an instance of this class set to the ``emm_add_exception`` tag - with value ``val``. + Check if the union tag is ``group_add_member``. - :param EmmAddExceptionType val: - :rtype: EventType + :rtype: bool """ - return cls('emm_add_exception', val) + return self._tag == 'group_add_member' - @classmethod - def emm_change_policy(cls, val): + def is_group_change_external_id(self): """ - Create an instance of this class set to the ``emm_change_policy`` tag - with value ``val``. + Check if the union tag is ``group_change_external_id``. - :param EmmChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('emm_change_policy', val) + return self._tag == 'group_change_external_id' - @classmethod - def emm_remove_exception(cls, val): + def is_group_change_management_type(self): """ - Create an instance of this class set to the ``emm_remove_exception`` tag - with value ``val``. + Check if the union tag is ``group_change_management_type``. - :param EmmRemoveExceptionType val: - :rtype: EventType + :rtype: bool """ - return cls('emm_remove_exception', val) + return self._tag == 'group_change_management_type' - @classmethod - def extended_version_history_change_policy(cls, val): + def is_group_change_member_role(self): """ - Create an instance of this class set to the - ``extended_version_history_change_policy`` tag with value ``val``. + Check if the union tag is ``group_change_member_role``. - :param ExtendedVersionHistoryChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('extended_version_history_change_policy', val) + return self._tag == 'group_change_member_role' - @classmethod - def file_comments_change_policy(cls, val): + def is_group_create(self): """ - Create an instance of this class set to the - ``file_comments_change_policy`` tag with value ``val``. + Check if the union tag is ``group_create``. - :param FileCommentsChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('file_comments_change_policy', val) + return self._tag == 'group_create' - @classmethod - def file_requests_change_policy(cls, val): + def is_group_delete(self): """ - Create an instance of this class set to the - ``file_requests_change_policy`` tag with value ``val``. + Check if the union tag is ``group_delete``. - :param FileRequestsChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('file_requests_change_policy', val) + return self._tag == 'group_delete' - @classmethod - def file_requests_emails_enabled(cls, val): + def is_group_description_updated(self): """ - Create an instance of this class set to the - ``file_requests_emails_enabled`` tag with value ``val``. + Check if the union tag is ``group_description_updated``. - :param FileRequestsEmailsEnabledType val: - :rtype: EventType + :rtype: bool """ - return cls('file_requests_emails_enabled', val) + return self._tag == 'group_description_updated' - @classmethod - def file_requests_emails_restricted_to_team_only(cls, val): + def is_group_join_policy_updated(self): """ - Create an instance of this class set to the - ``file_requests_emails_restricted_to_team_only`` tag with value ``val``. + Check if the union tag is ``group_join_policy_updated``. - :param FileRequestsEmailsRestrictedToTeamOnlyType val: - :rtype: EventType + :rtype: bool """ - return cls('file_requests_emails_restricted_to_team_only', val) + return self._tag == 'group_join_policy_updated' - @classmethod - def google_sso_change_policy(cls, val): + def is_group_moved(self): """ - Create an instance of this class set to the ``google_sso_change_policy`` - tag with value ``val``. + Check if the union tag is ``group_moved``. - :param GoogleSsoChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('google_sso_change_policy', val) + return self._tag == 'group_moved' - @classmethod - def group_user_management_change_policy(cls, val): + def is_group_remove_external_id(self): """ - Create an instance of this class set to the - ``group_user_management_change_policy`` tag with value ``val``. + Check if the union tag is ``group_remove_external_id``. - :param GroupUserManagementChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('group_user_management_change_policy', val) + return self._tag == 'group_remove_external_id' - @classmethod - def integration_policy_changed(cls, val): + def is_group_remove_member(self): """ - Create an instance of this class set to the - ``integration_policy_changed`` tag with value ``val``. + Check if the union tag is ``group_remove_member``. - :param IntegrationPolicyChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('integration_policy_changed', val) + return self._tag == 'group_remove_member' - @classmethod - def member_requests_change_policy(cls, val): + def is_group_rename(self): """ - Create an instance of this class set to the - ``member_requests_change_policy`` tag with value ``val``. + Check if the union tag is ``group_rename``. - :param MemberRequestsChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('member_requests_change_policy', val) + return self._tag == 'group_rename' - @classmethod - def member_space_limits_add_exception(cls, val): + def is_legal_holds_activate_a_hold(self): """ - Create an instance of this class set to the - ``member_space_limits_add_exception`` tag with value ``val``. + Check if the union tag is ``legal_holds_activate_a_hold``. - :param MemberSpaceLimitsAddExceptionType val: - :rtype: EventType + :rtype: bool """ - return cls('member_space_limits_add_exception', val) + return self._tag == 'legal_holds_activate_a_hold' - @classmethod - def member_space_limits_change_caps_type_policy(cls, val): + def is_legal_holds_add_members(self): """ - Create an instance of this class set to the - ``member_space_limits_change_caps_type_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_add_members``. - :param MemberSpaceLimitsChangeCapsTypePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('member_space_limits_change_caps_type_policy', val) + return self._tag == 'legal_holds_add_members' - @classmethod - def member_space_limits_change_policy(cls, val): + def is_legal_holds_change_hold_details(self): """ - Create an instance of this class set to the - ``member_space_limits_change_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_change_hold_details``. - :param MemberSpaceLimitsChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('member_space_limits_change_policy', val) + return self._tag == 'legal_holds_change_hold_details' - @classmethod - def member_space_limits_remove_exception(cls, val): + def is_legal_holds_change_hold_name(self): """ - Create an instance of this class set to the - ``member_space_limits_remove_exception`` tag with value ``val``. + Check if the union tag is ``legal_holds_change_hold_name``. - :param MemberSpaceLimitsRemoveExceptionType val: - :rtype: EventType + :rtype: bool """ - return cls('member_space_limits_remove_exception', val) + return self._tag == 'legal_holds_change_hold_name' - @classmethod - def member_suggestions_change_policy(cls, val): + def is_legal_holds_export_a_hold(self): """ - Create an instance of this class set to the - ``member_suggestions_change_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_export_a_hold``. - :param MemberSuggestionsChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('member_suggestions_change_policy', val) + return self._tag == 'legal_holds_export_a_hold' - @classmethod - def microsoft_office_addin_change_policy(cls, val): + def is_legal_holds_export_cancelled(self): """ - Create an instance of this class set to the - ``microsoft_office_addin_change_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_export_cancelled``. - :param MicrosoftOfficeAddinChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('microsoft_office_addin_change_policy', val) + return self._tag == 'legal_holds_export_cancelled' - @classmethod - def network_control_change_policy(cls, val): + def is_legal_holds_export_downloaded(self): """ - Create an instance of this class set to the - ``network_control_change_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_export_downloaded``. - :param NetworkControlChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('network_control_change_policy', val) + return self._tag == 'legal_holds_export_downloaded' - @classmethod - def paper_change_deployment_policy(cls, val): + def is_legal_holds_export_removed(self): """ - Create an instance of this class set to the - ``paper_change_deployment_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_export_removed``. - :param PaperChangeDeploymentPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_change_deployment_policy', val) + return self._tag == 'legal_holds_export_removed' - @classmethod - def paper_change_member_link_policy(cls, val): + def is_legal_holds_release_a_hold(self): """ - Create an instance of this class set to the - ``paper_change_member_link_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_release_a_hold``. - :param PaperChangeMemberLinkPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_change_member_link_policy', val) + return self._tag == 'legal_holds_release_a_hold' - @classmethod - def paper_change_member_policy(cls, val): + def is_legal_holds_remove_members(self): """ - Create an instance of this class set to the - ``paper_change_member_policy`` tag with value ``val``. + Check if the union tag is ``legal_holds_remove_members``. - :param PaperChangeMemberPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_change_member_policy', val) + return self._tag == 'legal_holds_remove_members' - @classmethod - def paper_change_policy(cls, val): + def is_legal_holds_report_a_hold(self): """ - Create an instance of this class set to the ``paper_change_policy`` tag - with value ``val``. + Check if the union tag is ``legal_holds_report_a_hold``. - :param PaperChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_change_policy', val) + return self._tag == 'legal_holds_report_a_hold' - @classmethod - def paper_default_folder_policy_changed(cls, val): + def is_account_lock_or_unlocked(self): """ - Create an instance of this class set to the - ``paper_default_folder_policy_changed`` tag with value ``val``. + Check if the union tag is ``account_lock_or_unlocked``. - :param PaperDefaultFolderPolicyChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_default_folder_policy_changed', val) + return self._tag == 'account_lock_or_unlocked' - @classmethod - def paper_desktop_policy_changed(cls, val): + def is_emm_error(self): """ - Create an instance of this class set to the - ``paper_desktop_policy_changed`` tag with value ``val``. + Check if the union tag is ``emm_error``. - :param PaperDesktopPolicyChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_desktop_policy_changed', val) + return self._tag == 'emm_error' - @classmethod - def paper_enabled_users_group_addition(cls, val): + def is_guest_admin_signed_in_via_trusted_teams(self): """ - Create an instance of this class set to the - ``paper_enabled_users_group_addition`` tag with value ``val``. + Check if the union tag is ``guest_admin_signed_in_via_trusted_teams``. - :param PaperEnabledUsersGroupAdditionType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_enabled_users_group_addition', val) + return self._tag == 'guest_admin_signed_in_via_trusted_teams' - @classmethod - def paper_enabled_users_group_removal(cls, val): + def is_guest_admin_signed_out_via_trusted_teams(self): """ - Create an instance of this class set to the - ``paper_enabled_users_group_removal`` tag with value ``val``. + Check if the union tag is ``guest_admin_signed_out_via_trusted_teams``. - :param PaperEnabledUsersGroupRemovalType val: - :rtype: EventType + :rtype: bool """ - return cls('paper_enabled_users_group_removal', val) + return self._tag == 'guest_admin_signed_out_via_trusted_teams' - @classmethod - def permanent_delete_change_policy(cls, val): + def is_login_fail(self): """ - Create an instance of this class set to the - ``permanent_delete_change_policy`` tag with value ``val``. + Check if the union tag is ``login_fail``. - :param PermanentDeleteChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('permanent_delete_change_policy', val) + return self._tag == 'login_fail' - @classmethod - def reseller_support_change_policy(cls, val): + def is_login_success(self): """ - Create an instance of this class set to the - ``reseller_support_change_policy`` tag with value ``val``. + Check if the union tag is ``login_success``. - :param ResellerSupportChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('reseller_support_change_policy', val) + return self._tag == 'login_success' - @classmethod - def sharing_change_folder_join_policy(cls, val): + def is_logout(self): """ - Create an instance of this class set to the - ``sharing_change_folder_join_policy`` tag with value ``val``. + Check if the union tag is ``logout``. - :param SharingChangeFolderJoinPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('sharing_change_folder_join_policy', val) + return self._tag == 'logout' - @classmethod - def sharing_change_link_policy(cls, val): + def is_reseller_support_session_end(self): """ - Create an instance of this class set to the - ``sharing_change_link_policy`` tag with value ``val``. + Check if the union tag is ``reseller_support_session_end``. - :param SharingChangeLinkPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('sharing_change_link_policy', val) + return self._tag == 'reseller_support_session_end' - @classmethod - def sharing_change_member_policy(cls, val): + def is_reseller_support_session_start(self): """ - Create an instance of this class set to the - ``sharing_change_member_policy`` tag with value ``val``. + Check if the union tag is ``reseller_support_session_start``. - :param SharingChangeMemberPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('sharing_change_member_policy', val) + return self._tag == 'reseller_support_session_start' - @classmethod - def showcase_change_download_policy(cls, val): + def is_sign_in_as_session_end(self): """ - Create an instance of this class set to the - ``showcase_change_download_policy`` tag with value ``val``. + Check if the union tag is ``sign_in_as_session_end``. - :param ShowcaseChangeDownloadPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_change_download_policy', val) + return self._tag == 'sign_in_as_session_end' - @classmethod - def showcase_change_enabled_policy(cls, val): + def is_sign_in_as_session_start(self): """ - Create an instance of this class set to the - ``showcase_change_enabled_policy`` tag with value ``val``. + Check if the union tag is ``sign_in_as_session_start``. - :param ShowcaseChangeEnabledPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_change_enabled_policy', val) + return self._tag == 'sign_in_as_session_start' - @classmethod - def showcase_change_external_sharing_policy(cls, val): + def is_sso_error(self): """ - Create an instance of this class set to the - ``showcase_change_external_sharing_policy`` tag with value ``val``. + Check if the union tag is ``sso_error``. - :param ShowcaseChangeExternalSharingPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('showcase_change_external_sharing_policy', val) + return self._tag == 'sso_error' - @classmethod - def smart_sync_change_policy(cls, val): + def is_create_team_invite_link(self): """ - Create an instance of this class set to the ``smart_sync_change_policy`` - tag with value ``val``. + Check if the union tag is ``create_team_invite_link``. - :param SmartSyncChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('smart_sync_change_policy', val) + return self._tag == 'create_team_invite_link' - @classmethod - def smart_sync_not_opt_out(cls, val): + def is_delete_team_invite_link(self): """ - Create an instance of this class set to the ``smart_sync_not_opt_out`` - tag with value ``val``. + Check if the union tag is ``delete_team_invite_link``. - :param SmartSyncNotOptOutType val: - :rtype: EventType + :rtype: bool """ - return cls('smart_sync_not_opt_out', val) + return self._tag == 'delete_team_invite_link' - @classmethod - def smart_sync_opt_out(cls, val): + def is_member_add_external_id(self): """ - Create an instance of this class set to the ``smart_sync_opt_out`` tag - with value ``val``. + Check if the union tag is ``member_add_external_id``. - :param SmartSyncOptOutType val: - :rtype: EventType + :rtype: bool """ - return cls('smart_sync_opt_out', val) + return self._tag == 'member_add_external_id' - @classmethod - def sso_change_policy(cls, val): + def is_member_add_name(self): """ - Create an instance of this class set to the ``sso_change_policy`` tag - with value ``val``. + Check if the union tag is ``member_add_name``. - :param SsoChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('sso_change_policy', val) + return self._tag == 'member_add_name' - @classmethod - def team_extensions_policy_changed(cls, val): + def is_member_change_admin_role(self): """ - Create an instance of this class set to the - ``team_extensions_policy_changed`` tag with value ``val``. + Check if the union tag is ``member_change_admin_role``. - :param TeamExtensionsPolicyChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('team_extensions_policy_changed', val) + return self._tag == 'member_change_admin_role' - @classmethod - def team_selective_sync_policy_changed(cls, val): + def is_member_change_email(self): """ - Create an instance of this class set to the - ``team_selective_sync_policy_changed`` tag with value ``val``. + Check if the union tag is ``member_change_email``. - :param TeamSelectiveSyncPolicyChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('team_selective_sync_policy_changed', val) + return self._tag == 'member_change_email' - @classmethod - def tfa_change_policy(cls, val): + def is_member_change_external_id(self): """ - Create an instance of this class set to the ``tfa_change_policy`` tag - with value ``val``. + Check if the union tag is ``member_change_external_id``. - :param TfaChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_change_policy', val) + return self._tag == 'member_change_external_id' - @classmethod - def two_account_change_policy(cls, val): + def is_member_change_membership_type(self): """ - Create an instance of this class set to the - ``two_account_change_policy`` tag with value ``val``. + Check if the union tag is ``member_change_membership_type``. - :param TwoAccountChangePolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('two_account_change_policy', val) + return self._tag == 'member_change_membership_type' - @classmethod - def viewer_info_policy_changed(cls, val): + def is_member_change_name(self): """ - Create an instance of this class set to the - ``viewer_info_policy_changed`` tag with value ``val``. + Check if the union tag is ``member_change_name``. - :param ViewerInfoPolicyChangedType val: - :rtype: EventType + :rtype: bool """ - return cls('viewer_info_policy_changed', val) + return self._tag == 'member_change_name' - @classmethod - def web_sessions_change_fixed_length_policy(cls, val): + def is_member_change_status(self): """ - Create an instance of this class set to the - ``web_sessions_change_fixed_length_policy`` tag with value ``val``. + Check if the union tag is ``member_change_status``. - :param WebSessionsChangeFixedLengthPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('web_sessions_change_fixed_length_policy', val) + return self._tag == 'member_change_status' - @classmethod - def web_sessions_change_idle_length_policy(cls, val): + def is_member_delete_manual_contacts(self): """ - Create an instance of this class set to the - ``web_sessions_change_idle_length_policy`` tag with value ``val``. + Check if the union tag is ``member_delete_manual_contacts``. - :param WebSessionsChangeIdleLengthPolicyType val: - :rtype: EventType + :rtype: bool """ - return cls('web_sessions_change_idle_length_policy', val) + return self._tag == 'member_delete_manual_contacts' - @classmethod - def team_merge_from(cls, val): + def is_member_delete_profile_photo(self): """ - Create an instance of this class set to the ``team_merge_from`` tag with - value ``val``. + Check if the union tag is ``member_delete_profile_photo``. - :param TeamMergeFromType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_from', val) + return self._tag == 'member_delete_profile_photo' - @classmethod - def team_merge_to(cls, val): + def is_member_permanently_delete_account_contents(self): """ - Create an instance of this class set to the ``team_merge_to`` tag with - value ``val``. + Check if the union tag is ``member_permanently_delete_account_contents``. - :param TeamMergeToType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_to', val) + return self._tag == 'member_permanently_delete_account_contents' - @classmethod - def team_profile_add_logo(cls, val): + def is_member_remove_external_id(self): """ - Create an instance of this class set to the ``team_profile_add_logo`` - tag with value ``val``. + Check if the union tag is ``member_remove_external_id``. - :param TeamProfileAddLogoType val: - :rtype: EventType + :rtype: bool """ - return cls('team_profile_add_logo', val) + return self._tag == 'member_remove_external_id' - @classmethod - def team_profile_change_default_language(cls, val): + def is_member_set_profile_photo(self): """ - Create an instance of this class set to the - ``team_profile_change_default_language`` tag with value ``val``. + Check if the union tag is ``member_set_profile_photo``. - :param TeamProfileChangeDefaultLanguageType val: - :rtype: EventType + :rtype: bool """ - return cls('team_profile_change_default_language', val) + return self._tag == 'member_set_profile_photo' - @classmethod - def team_profile_change_logo(cls, val): + def is_member_space_limits_add_custom_quota(self): """ - Create an instance of this class set to the ``team_profile_change_logo`` - tag with value ``val``. + Check if the union tag is ``member_space_limits_add_custom_quota``. - :param TeamProfileChangeLogoType val: - :rtype: EventType + :rtype: bool """ - return cls('team_profile_change_logo', val) + return self._tag == 'member_space_limits_add_custom_quota' - @classmethod - def team_profile_change_name(cls, val): + def is_member_space_limits_change_custom_quota(self): """ - Create an instance of this class set to the ``team_profile_change_name`` - tag with value ``val``. + Check if the union tag is ``member_space_limits_change_custom_quota``. - :param TeamProfileChangeNameType val: - :rtype: EventType + :rtype: bool """ - return cls('team_profile_change_name', val) + return self._tag == 'member_space_limits_change_custom_quota' - @classmethod - def team_profile_remove_logo(cls, val): + def is_member_space_limits_change_status(self): """ - Create an instance of this class set to the ``team_profile_remove_logo`` - tag with value ``val``. + Check if the union tag is ``member_space_limits_change_status``. - :param TeamProfileRemoveLogoType val: - :rtype: EventType + :rtype: bool """ - return cls('team_profile_remove_logo', val) + return self._tag == 'member_space_limits_change_status' - @classmethod - def tfa_add_backup_phone(cls, val): + def is_member_space_limits_remove_custom_quota(self): """ - Create an instance of this class set to the ``tfa_add_backup_phone`` tag - with value ``val``. + Check if the union tag is ``member_space_limits_remove_custom_quota``. - :param TfaAddBackupPhoneType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_add_backup_phone', val) + return self._tag == 'member_space_limits_remove_custom_quota' - @classmethod - def tfa_add_security_key(cls, val): + def is_member_suggest(self): """ - Create an instance of this class set to the ``tfa_add_security_key`` tag - with value ``val``. + Check if the union tag is ``member_suggest``. - :param TfaAddSecurityKeyType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_add_security_key', val) + return self._tag == 'member_suggest' - @classmethod - def tfa_change_backup_phone(cls, val): + def is_member_transfer_account_contents(self): """ - Create an instance of this class set to the ``tfa_change_backup_phone`` - tag with value ``val``. + Check if the union tag is ``member_transfer_account_contents``. - :param TfaChangeBackupPhoneType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_change_backup_phone', val) + return self._tag == 'member_transfer_account_contents' - @classmethod - def tfa_change_status(cls, val): + def is_pending_secondary_email_added(self): """ - Create an instance of this class set to the ``tfa_change_status`` tag - with value ``val``. + Check if the union tag is ``pending_secondary_email_added``. - :param TfaChangeStatusType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_change_status', val) + return self._tag == 'pending_secondary_email_added' - @classmethod - def tfa_remove_backup_phone(cls, val): + def is_secondary_email_deleted(self): """ - Create an instance of this class set to the ``tfa_remove_backup_phone`` - tag with value ``val``. + Check if the union tag is ``secondary_email_deleted``. - :param TfaRemoveBackupPhoneType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_remove_backup_phone', val) + return self._tag == 'secondary_email_deleted' - @classmethod - def tfa_remove_security_key(cls, val): + def is_secondary_email_verified(self): """ - Create an instance of this class set to the ``tfa_remove_security_key`` - tag with value ``val``. + Check if the union tag is ``secondary_email_verified``. - :param TfaRemoveSecurityKeyType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_remove_security_key', val) + return self._tag == 'secondary_email_verified' - @classmethod - def tfa_reset(cls, val): + def is_secondary_mails_policy_changed(self): """ - Create an instance of this class set to the ``tfa_reset`` tag with value - ``val``. + Check if the union tag is ``secondary_mails_policy_changed``. - :param TfaResetType val: - :rtype: EventType + :rtype: bool """ - return cls('tfa_reset', val) + return self._tag == 'secondary_mails_policy_changed' - @classmethod - def guest_admin_change_status(cls, val): + def is_binder_add_page(self): """ - Create an instance of this class set to the - ``guest_admin_change_status`` tag with value ``val``. + Check if the union tag is ``binder_add_page``. - :param GuestAdminChangeStatusType val: - :rtype: EventType + :rtype: bool """ - return cls('guest_admin_change_status', val) + return self._tag == 'binder_add_page' - @classmethod - def team_merge_request_accepted(cls, val): + def is_binder_add_section(self): """ - Create an instance of this class set to the - ``team_merge_request_accepted`` tag with value ``val``. + Check if the union tag is ``binder_add_section``. - :param TeamMergeRequestAcceptedType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_accepted', val) + return self._tag == 'binder_add_section' - @classmethod - def team_merge_request_accepted_shown_to_primary_team(cls, val): + def is_binder_remove_page(self): """ - Create an instance of this class set to the - ``team_merge_request_accepted_shown_to_primary_team`` tag with value - ``val``. + Check if the union tag is ``binder_remove_page``. - :param TeamMergeRequestAcceptedShownToPrimaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_accepted_shown_to_primary_team', val) + return self._tag == 'binder_remove_page' - @classmethod - def team_merge_request_accepted_shown_to_secondary_team(cls, val): + def is_binder_remove_section(self): """ - Create an instance of this class set to the - ``team_merge_request_accepted_shown_to_secondary_team`` tag with value - ``val``. + Check if the union tag is ``binder_remove_section``. - :param TeamMergeRequestAcceptedShownToSecondaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_accepted_shown_to_secondary_team', val) + return self._tag == 'binder_remove_section' - @classmethod - def team_merge_request_auto_canceled(cls, val): + def is_binder_rename_page(self): """ - Create an instance of this class set to the - ``team_merge_request_auto_canceled`` tag with value ``val``. + Check if the union tag is ``binder_rename_page``. - :param TeamMergeRequestAutoCanceledType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_auto_canceled', val) + return self._tag == 'binder_rename_page' - @classmethod - def team_merge_request_canceled(cls, val): + def is_binder_rename_section(self): """ - Create an instance of this class set to the - ``team_merge_request_canceled`` tag with value ``val``. + Check if the union tag is ``binder_rename_section``. - :param TeamMergeRequestCanceledType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_canceled', val) + return self._tag == 'binder_rename_section' - @classmethod - def team_merge_request_canceled_shown_to_primary_team(cls, val): + def is_binder_reorder_page(self): """ - Create an instance of this class set to the - ``team_merge_request_canceled_shown_to_primary_team`` tag with value - ``val``. + Check if the union tag is ``binder_reorder_page``. - :param TeamMergeRequestCanceledShownToPrimaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_canceled_shown_to_primary_team', val) + return self._tag == 'binder_reorder_page' - @classmethod - def team_merge_request_canceled_shown_to_secondary_team(cls, val): + def is_binder_reorder_section(self): """ - Create an instance of this class set to the - ``team_merge_request_canceled_shown_to_secondary_team`` tag with value - ``val``. + Check if the union tag is ``binder_reorder_section``. - :param TeamMergeRequestCanceledShownToSecondaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_canceled_shown_to_secondary_team', val) + return self._tag == 'binder_reorder_section' - @classmethod - def team_merge_request_expired(cls, val): + def is_paper_content_add_member(self): """ - Create an instance of this class set to the - ``team_merge_request_expired`` tag with value ``val``. + Check if the union tag is ``paper_content_add_member``. - :param TeamMergeRequestExpiredType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_expired', val) + return self._tag == 'paper_content_add_member' - @classmethod - def team_merge_request_expired_shown_to_primary_team(cls, val): + def is_paper_content_add_to_folder(self): """ - Create an instance of this class set to the - ``team_merge_request_expired_shown_to_primary_team`` tag with value - ``val``. + Check if the union tag is ``paper_content_add_to_folder``. - :param TeamMergeRequestExpiredShownToPrimaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_expired_shown_to_primary_team', val) + return self._tag == 'paper_content_add_to_folder' - @classmethod - def team_merge_request_expired_shown_to_secondary_team(cls, val): + def is_paper_content_archive(self): """ - Create an instance of this class set to the - ``team_merge_request_expired_shown_to_secondary_team`` tag with value - ``val``. + Check if the union tag is ``paper_content_archive``. - :param TeamMergeRequestExpiredShownToSecondaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_expired_shown_to_secondary_team', val) + return self._tag == 'paper_content_archive' - @classmethod - def team_merge_request_rejected_shown_to_primary_team(cls, val): + def is_paper_content_create(self): """ - Create an instance of this class set to the - ``team_merge_request_rejected_shown_to_primary_team`` tag with value - ``val``. + Check if the union tag is ``paper_content_create``. - :param TeamMergeRequestRejectedShownToPrimaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_rejected_shown_to_primary_team', val) + return self._tag == 'paper_content_create' - @classmethod - def team_merge_request_rejected_shown_to_secondary_team(cls, val): + def is_paper_content_permanently_delete(self): """ - Create an instance of this class set to the - ``team_merge_request_rejected_shown_to_secondary_team`` tag with value - ``val``. + Check if the union tag is ``paper_content_permanently_delete``. - :param TeamMergeRequestRejectedShownToSecondaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_rejected_shown_to_secondary_team', val) + return self._tag == 'paper_content_permanently_delete' - @classmethod - def team_merge_request_reminder(cls, val): + def is_paper_content_remove_from_folder(self): """ - Create an instance of this class set to the - ``team_merge_request_reminder`` tag with value ``val``. + Check if the union tag is ``paper_content_remove_from_folder``. - :param TeamMergeRequestReminderType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_reminder', val) + return self._tag == 'paper_content_remove_from_folder' - @classmethod - def team_merge_request_reminder_shown_to_primary_team(cls, val): + def is_paper_content_remove_member(self): """ - Create an instance of this class set to the - ``team_merge_request_reminder_shown_to_primary_team`` tag with value - ``val``. + Check if the union tag is ``paper_content_remove_member``. - :param TeamMergeRequestReminderShownToPrimaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_reminder_shown_to_primary_team', val) + return self._tag == 'paper_content_remove_member' - @classmethod - def team_merge_request_reminder_shown_to_secondary_team(cls, val): + def is_paper_content_rename(self): """ - Create an instance of this class set to the - ``team_merge_request_reminder_shown_to_secondary_team`` tag with value - ``val``. + Check if the union tag is ``paper_content_rename``. - :param TeamMergeRequestReminderShownToSecondaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_reminder_shown_to_secondary_team', val) + return self._tag == 'paper_content_rename' - @classmethod - def team_merge_request_revoked(cls, val): + def is_paper_content_restore(self): """ - Create an instance of this class set to the - ``team_merge_request_revoked`` tag with value ``val``. + Check if the union tag is ``paper_content_restore``. - :param TeamMergeRequestRevokedType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_revoked', val) + return self._tag == 'paper_content_restore' - @classmethod - def team_merge_request_sent_shown_to_primary_team(cls, val): + def is_paper_doc_add_comment(self): """ - Create an instance of this class set to the - ``team_merge_request_sent_shown_to_primary_team`` tag with value - ``val``. + Check if the union tag is ``paper_doc_add_comment``. - :param TeamMergeRequestSentShownToPrimaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_sent_shown_to_primary_team', val) + return self._tag == 'paper_doc_add_comment' - @classmethod - def team_merge_request_sent_shown_to_secondary_team(cls, val): + def is_paper_doc_change_member_role(self): """ - Create an instance of this class set to the - ``team_merge_request_sent_shown_to_secondary_team`` tag with value - ``val``. + Check if the union tag is ``paper_doc_change_member_role``. - :param TeamMergeRequestSentShownToSecondaryTeamType val: - :rtype: EventType + :rtype: bool """ - return cls('team_merge_request_sent_shown_to_secondary_team', val) + return self._tag == 'paper_doc_change_member_role' - def is_app_link_team(self): + def is_paper_doc_change_sharing_policy(self): """ - Check if the union tag is ``app_link_team``. + Check if the union tag is ``paper_doc_change_sharing_policy``. :rtype: bool """ - return self._tag == 'app_link_team' + return self._tag == 'paper_doc_change_sharing_policy' - def is_app_link_user(self): + def is_paper_doc_change_subscription(self): """ - Check if the union tag is ``app_link_user``. + Check if the union tag is ``paper_doc_change_subscription``. :rtype: bool """ - return self._tag == 'app_link_user' + return self._tag == 'paper_doc_change_subscription' - def is_app_unlink_team(self): + def is_paper_doc_deleted(self): """ - Check if the union tag is ``app_unlink_team``. + Check if the union tag is ``paper_doc_deleted``. :rtype: bool """ - return self._tag == 'app_unlink_team' + return self._tag == 'paper_doc_deleted' - def is_app_unlink_user(self): + def is_paper_doc_delete_comment(self): """ - Check if the union tag is ``app_unlink_user``. + Check if the union tag is ``paper_doc_delete_comment``. :rtype: bool """ - return self._tag == 'app_unlink_user' + return self._tag == 'paper_doc_delete_comment' - def is_integration_connected(self): + def is_paper_doc_download(self): """ - Check if the union tag is ``integration_connected``. + Check if the union tag is ``paper_doc_download``. :rtype: bool """ - return self._tag == 'integration_connected' + return self._tag == 'paper_doc_download' - def is_integration_disconnected(self): + def is_paper_doc_edit(self): """ - Check if the union tag is ``integration_disconnected``. + Check if the union tag is ``paper_doc_edit``. :rtype: bool """ - return self._tag == 'integration_disconnected' + return self._tag == 'paper_doc_edit' - def is_file_add_comment(self): + def is_paper_doc_edit_comment(self): """ - Check if the union tag is ``file_add_comment``. + Check if the union tag is ``paper_doc_edit_comment``. :rtype: bool """ - return self._tag == 'file_add_comment' + return self._tag == 'paper_doc_edit_comment' - def is_file_change_comment_subscription(self): + def is_paper_doc_followed(self): """ - Check if the union tag is ``file_change_comment_subscription``. + Check if the union tag is ``paper_doc_followed``. :rtype: bool """ - return self._tag == 'file_change_comment_subscription' + return self._tag == 'paper_doc_followed' - def is_file_delete_comment(self): + def is_paper_doc_mention(self): """ - Check if the union tag is ``file_delete_comment``. + Check if the union tag is ``paper_doc_mention``. :rtype: bool """ - return self._tag == 'file_delete_comment' + return self._tag == 'paper_doc_mention' - def is_file_edit_comment(self): + def is_paper_doc_ownership_changed(self): """ - Check if the union tag is ``file_edit_comment``. + Check if the union tag is ``paper_doc_ownership_changed``. :rtype: bool """ - return self._tag == 'file_edit_comment' + return self._tag == 'paper_doc_ownership_changed' - def is_file_like_comment(self): + def is_paper_doc_request_access(self): """ - Check if the union tag is ``file_like_comment``. + Check if the union tag is ``paper_doc_request_access``. :rtype: bool """ - return self._tag == 'file_like_comment' + return self._tag == 'paper_doc_request_access' - def is_file_resolve_comment(self): + def is_paper_doc_resolve_comment(self): """ - Check if the union tag is ``file_resolve_comment``. + Check if the union tag is ``paper_doc_resolve_comment``. :rtype: bool """ - return self._tag == 'file_resolve_comment' + return self._tag == 'paper_doc_resolve_comment' - def is_file_unlike_comment(self): + def is_paper_doc_revert(self): """ - Check if the union tag is ``file_unlike_comment``. + Check if the union tag is ``paper_doc_revert``. :rtype: bool """ - return self._tag == 'file_unlike_comment' + return self._tag == 'paper_doc_revert' - def is_file_unresolve_comment(self): + def is_paper_doc_slack_share(self): """ - Check if the union tag is ``file_unresolve_comment``. + Check if the union tag is ``paper_doc_slack_share``. :rtype: bool """ - return self._tag == 'file_unresolve_comment' + return self._tag == 'paper_doc_slack_share' - def is_device_change_ip_desktop(self): + def is_paper_doc_team_invite(self): """ - Check if the union tag is ``device_change_ip_desktop``. + Check if the union tag is ``paper_doc_team_invite``. :rtype: bool """ - return self._tag == 'device_change_ip_desktop' + return self._tag == 'paper_doc_team_invite' - def is_device_change_ip_mobile(self): + def is_paper_doc_trashed(self): """ - Check if the union tag is ``device_change_ip_mobile``. + Check if the union tag is ``paper_doc_trashed``. :rtype: bool """ - return self._tag == 'device_change_ip_mobile' + return self._tag == 'paper_doc_trashed' - def is_device_change_ip_web(self): + def is_paper_doc_unresolve_comment(self): """ - Check if the union tag is ``device_change_ip_web``. + Check if the union tag is ``paper_doc_unresolve_comment``. :rtype: bool """ - return self._tag == 'device_change_ip_web' + return self._tag == 'paper_doc_unresolve_comment' - def is_device_delete_on_unlink_fail(self): + def is_paper_doc_untrashed(self): """ - Check if the union tag is ``device_delete_on_unlink_fail``. + Check if the union tag is ``paper_doc_untrashed``. :rtype: bool """ - return self._tag == 'device_delete_on_unlink_fail' + return self._tag == 'paper_doc_untrashed' - def is_device_delete_on_unlink_success(self): + def is_paper_doc_view(self): """ - Check if the union tag is ``device_delete_on_unlink_success``. + Check if the union tag is ``paper_doc_view``. :rtype: bool """ - return self._tag == 'device_delete_on_unlink_success' + return self._tag == 'paper_doc_view' - def is_device_link_fail(self): + def is_paper_external_view_allow(self): """ - Check if the union tag is ``device_link_fail``. + Check if the union tag is ``paper_external_view_allow``. :rtype: bool """ - return self._tag == 'device_link_fail' + return self._tag == 'paper_external_view_allow' - def is_device_link_success(self): + def is_paper_external_view_default_team(self): """ - Check if the union tag is ``device_link_success``. + Check if the union tag is ``paper_external_view_default_team``. :rtype: bool """ - return self._tag == 'device_link_success' + return self._tag == 'paper_external_view_default_team' - def is_device_management_disabled(self): + def is_paper_external_view_forbid(self): """ - Check if the union tag is ``device_management_disabled``. + Check if the union tag is ``paper_external_view_forbid``. :rtype: bool """ - return self._tag == 'device_management_disabled' + return self._tag == 'paper_external_view_forbid' - def is_device_management_enabled(self): + def is_paper_folder_change_subscription(self): """ - Check if the union tag is ``device_management_enabled``. + Check if the union tag is ``paper_folder_change_subscription``. :rtype: bool """ - return self._tag == 'device_management_enabled' + return self._tag == 'paper_folder_change_subscription' - def is_device_unlink(self): + def is_paper_folder_deleted(self): """ - Check if the union tag is ``device_unlink``. + Check if the union tag is ``paper_folder_deleted``. :rtype: bool """ - return self._tag == 'device_unlink' + return self._tag == 'paper_folder_deleted' - def is_emm_refresh_auth_token(self): + def is_paper_folder_followed(self): """ - Check if the union tag is ``emm_refresh_auth_token``. + Check if the union tag is ``paper_folder_followed``. :rtype: bool """ - return self._tag == 'emm_refresh_auth_token' + return self._tag == 'paper_folder_followed' - def is_account_capture_change_availability(self): + def is_paper_folder_team_invite(self): """ - Check if the union tag is ``account_capture_change_availability``. + Check if the union tag is ``paper_folder_team_invite``. :rtype: bool """ - return self._tag == 'account_capture_change_availability' + return self._tag == 'paper_folder_team_invite' - def is_account_capture_migrate_account(self): + def is_paper_published_link_change_permission(self): """ - Check if the union tag is ``account_capture_migrate_account``. + Check if the union tag is ``paper_published_link_change_permission``. :rtype: bool """ - return self._tag == 'account_capture_migrate_account' + return self._tag == 'paper_published_link_change_permission' - def is_account_capture_notification_emails_sent(self): + def is_paper_published_link_create(self): """ - Check if the union tag is ``account_capture_notification_emails_sent``. + Check if the union tag is ``paper_published_link_create``. :rtype: bool """ - return self._tag == 'account_capture_notification_emails_sent' + return self._tag == 'paper_published_link_create' - def is_account_capture_relinquish_account(self): + def is_paper_published_link_disabled(self): """ - Check if the union tag is ``account_capture_relinquish_account``. + Check if the union tag is ``paper_published_link_disabled``. :rtype: bool """ - return self._tag == 'account_capture_relinquish_account' + return self._tag == 'paper_published_link_disabled' - def is_disabled_domain_invites(self): + def is_paper_published_link_view(self): """ - Check if the union tag is ``disabled_domain_invites``. + Check if the union tag is ``paper_published_link_view``. :rtype: bool """ - return self._tag == 'disabled_domain_invites' + return self._tag == 'paper_published_link_view' - def is_domain_invites_approve_request_to_join_team(self): + def is_password_change(self): """ - Check if the union tag is ``domain_invites_approve_request_to_join_team``. + Check if the union tag is ``password_change``. :rtype: bool """ - return self._tag == 'domain_invites_approve_request_to_join_team' + return self._tag == 'password_change' - def is_domain_invites_decline_request_to_join_team(self): + def is_password_reset(self): """ - Check if the union tag is ``domain_invites_decline_request_to_join_team``. + Check if the union tag is ``password_reset``. :rtype: bool """ - return self._tag == 'domain_invites_decline_request_to_join_team' + return self._tag == 'password_reset' - def is_domain_invites_email_existing_users(self): + def is_password_reset_all(self): """ - Check if the union tag is ``domain_invites_email_existing_users``. + Check if the union tag is ``password_reset_all``. :rtype: bool """ - return self._tag == 'domain_invites_email_existing_users' + return self._tag == 'password_reset_all' - def is_domain_invites_request_to_join_team(self): + def is_emm_create_exceptions_report(self): """ - Check if the union tag is ``domain_invites_request_to_join_team``. + Check if the union tag is ``emm_create_exceptions_report``. :rtype: bool """ - return self._tag == 'domain_invites_request_to_join_team' + return self._tag == 'emm_create_exceptions_report' - def is_domain_invites_set_invite_new_user_pref_to_no(self): + def is_emm_create_usage_report(self): """ - Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_no``. + Check if the union tag is ``emm_create_usage_report``. :rtype: bool """ - return self._tag == 'domain_invites_set_invite_new_user_pref_to_no' + return self._tag == 'emm_create_usage_report' - def is_domain_invites_set_invite_new_user_pref_to_yes(self): + def is_export_members_report(self): """ - Check if the union tag is ``domain_invites_set_invite_new_user_pref_to_yes``. + Check if the union tag is ``export_members_report``. :rtype: bool """ - return self._tag == 'domain_invites_set_invite_new_user_pref_to_yes' + return self._tag == 'export_members_report' - def is_domain_verification_add_domain_fail(self): + def is_export_members_report_fail(self): """ - Check if the union tag is ``domain_verification_add_domain_fail``. + Check if the union tag is ``export_members_report_fail``. :rtype: bool """ - return self._tag == 'domain_verification_add_domain_fail' + return self._tag == 'export_members_report_fail' - def is_domain_verification_add_domain_success(self): + def is_no_expiration_link_gen_create_report(self): """ - Check if the union tag is ``domain_verification_add_domain_success``. + Check if the union tag is ``no_expiration_link_gen_create_report``. :rtype: bool """ - return self._tag == 'domain_verification_add_domain_success' + return self._tag == 'no_expiration_link_gen_create_report' - def is_domain_verification_remove_domain(self): + def is_no_expiration_link_gen_report_failed(self): """ - Check if the union tag is ``domain_verification_remove_domain``. + Check if the union tag is ``no_expiration_link_gen_report_failed``. :rtype: bool """ - return self._tag == 'domain_verification_remove_domain' + return self._tag == 'no_expiration_link_gen_report_failed' - def is_enabled_domain_invites(self): + def is_no_password_link_gen_create_report(self): """ - Check if the union tag is ``enabled_domain_invites``. + Check if the union tag is ``no_password_link_gen_create_report``. :rtype: bool """ - return self._tag == 'enabled_domain_invites' + return self._tag == 'no_password_link_gen_create_report' - def is_create_folder(self): + def is_no_password_link_gen_report_failed(self): """ - Check if the union tag is ``create_folder``. + Check if the union tag is ``no_password_link_gen_report_failed``. :rtype: bool """ - return self._tag == 'create_folder' + return self._tag == 'no_password_link_gen_report_failed' - def is_file_add(self): + def is_no_password_link_view_create_report(self): """ - Check if the union tag is ``file_add``. + Check if the union tag is ``no_password_link_view_create_report``. :rtype: bool """ - return self._tag == 'file_add' + return self._tag == 'no_password_link_view_create_report' - def is_file_copy(self): + def is_no_password_link_view_report_failed(self): """ - Check if the union tag is ``file_copy``. + Check if the union tag is ``no_password_link_view_report_failed``. :rtype: bool """ - return self._tag == 'file_copy' + return self._tag == 'no_password_link_view_report_failed' - def is_file_delete(self): + def is_outdated_link_view_create_report(self): """ - Check if the union tag is ``file_delete``. + Check if the union tag is ``outdated_link_view_create_report``. :rtype: bool """ - return self._tag == 'file_delete' + return self._tag == 'outdated_link_view_create_report' - def is_file_download(self): + def is_outdated_link_view_report_failed(self): """ - Check if the union tag is ``file_download``. + Check if the union tag is ``outdated_link_view_report_failed``. :rtype: bool """ - return self._tag == 'file_download' + return self._tag == 'outdated_link_view_report_failed' - def is_file_edit(self): + def is_paper_admin_export_start(self): """ - Check if the union tag is ``file_edit``. + Check if the union tag is ``paper_admin_export_start``. :rtype: bool """ - return self._tag == 'file_edit' + return self._tag == 'paper_admin_export_start' - def is_file_get_copy_reference(self): + def is_smart_sync_create_admin_privilege_report(self): """ - Check if the union tag is ``file_get_copy_reference``. + Check if the union tag is ``smart_sync_create_admin_privilege_report``. :rtype: bool """ - return self._tag == 'file_get_copy_reference' + return self._tag == 'smart_sync_create_admin_privilege_report' - def is_file_move(self): + def is_team_activity_create_report(self): """ - Check if the union tag is ``file_move``. + Check if the union tag is ``team_activity_create_report``. :rtype: bool """ - return self._tag == 'file_move' + return self._tag == 'team_activity_create_report' - def is_file_permanently_delete(self): + def is_team_activity_create_report_fail(self): """ - Check if the union tag is ``file_permanently_delete``. + Check if the union tag is ``team_activity_create_report_fail``. :rtype: bool """ - return self._tag == 'file_permanently_delete' + return self._tag == 'team_activity_create_report_fail' - def is_file_preview(self): + def is_collection_share(self): """ - Check if the union tag is ``file_preview``. + Check if the union tag is ``collection_share``. :rtype: bool """ - return self._tag == 'file_preview' + return self._tag == 'collection_share' - def is_file_rename(self): + def is_file_transfers_file_add(self): """ - Check if the union tag is ``file_rename``. + Check if the union tag is ``file_transfers_file_add``. :rtype: bool """ - return self._tag == 'file_rename' + return self._tag == 'file_transfers_file_add' - def is_file_restore(self): + def is_file_transfers_transfer_delete(self): """ - Check if the union tag is ``file_restore``. + Check if the union tag is ``file_transfers_transfer_delete``. :rtype: bool """ - return self._tag == 'file_restore' + return self._tag == 'file_transfers_transfer_delete' - def is_file_revert(self): + def is_file_transfers_transfer_download(self): """ - Check if the union tag is ``file_revert``. + Check if the union tag is ``file_transfers_transfer_download``. :rtype: bool """ - return self._tag == 'file_revert' + return self._tag == 'file_transfers_transfer_download' - def is_file_rollback_changes(self): + def is_file_transfers_transfer_send(self): """ - Check if the union tag is ``file_rollback_changes``. + Check if the union tag is ``file_transfers_transfer_send``. :rtype: bool """ - return self._tag == 'file_rollback_changes' + return self._tag == 'file_transfers_transfer_send' - def is_file_save_copy_reference(self): + def is_file_transfers_transfer_view(self): """ - Check if the union tag is ``file_save_copy_reference``. + Check if the union tag is ``file_transfers_transfer_view``. :rtype: bool """ - return self._tag == 'file_save_copy_reference' + return self._tag == 'file_transfers_transfer_view' - def is_file_request_change(self): + def is_note_acl_invite_only(self): """ - Check if the union tag is ``file_request_change``. + Check if the union tag is ``note_acl_invite_only``. :rtype: bool """ - return self._tag == 'file_request_change' + return self._tag == 'note_acl_invite_only' - def is_file_request_close(self): + def is_note_acl_link(self): """ - Check if the union tag is ``file_request_close``. + Check if the union tag is ``note_acl_link``. :rtype: bool """ - return self._tag == 'file_request_close' + return self._tag == 'note_acl_link' - def is_file_request_create(self): + def is_note_acl_team_link(self): """ - Check if the union tag is ``file_request_create``. + Check if the union tag is ``note_acl_team_link``. :rtype: bool """ - return self._tag == 'file_request_create' + return self._tag == 'note_acl_team_link' - def is_file_request_delete(self): + def is_note_shared(self): """ - Check if the union tag is ``file_request_delete``. + Check if the union tag is ``note_shared``. :rtype: bool """ - return self._tag == 'file_request_delete' + return self._tag == 'note_shared' - def is_file_request_receive_file(self): + def is_note_share_receive(self): """ - Check if the union tag is ``file_request_receive_file``. + Check if the union tag is ``note_share_receive``. :rtype: bool """ - return self._tag == 'file_request_receive_file' + return self._tag == 'note_share_receive' - def is_group_add_external_id(self): + def is_open_note_shared(self): """ - Check if the union tag is ``group_add_external_id``. + Check if the union tag is ``open_note_shared``. :rtype: bool """ - return self._tag == 'group_add_external_id' + return self._tag == 'open_note_shared' - def is_group_add_member(self): + def is_sf_add_group(self): """ - Check if the union tag is ``group_add_member``. + Check if the union tag is ``sf_add_group``. :rtype: bool """ - return self._tag == 'group_add_member' + return self._tag == 'sf_add_group' - def is_group_change_external_id(self): + def is_sf_allow_non_members_to_view_shared_links(self): """ - Check if the union tag is ``group_change_external_id``. + Check if the union tag is ``sf_allow_non_members_to_view_shared_links``. :rtype: bool """ - return self._tag == 'group_change_external_id' + return self._tag == 'sf_allow_non_members_to_view_shared_links' - def is_group_change_management_type(self): + def is_sf_external_invite_warn(self): """ - Check if the union tag is ``group_change_management_type``. + Check if the union tag is ``sf_external_invite_warn``. :rtype: bool """ - return self._tag == 'group_change_management_type' + return self._tag == 'sf_external_invite_warn' - def is_group_change_member_role(self): + def is_sf_fb_invite(self): """ - Check if the union tag is ``group_change_member_role``. + Check if the union tag is ``sf_fb_invite``. :rtype: bool """ - return self._tag == 'group_change_member_role' + return self._tag == 'sf_fb_invite' - def is_group_create(self): + def is_sf_fb_invite_change_role(self): """ - Check if the union tag is ``group_create``. + Check if the union tag is ``sf_fb_invite_change_role``. :rtype: bool """ - return self._tag == 'group_create' + return self._tag == 'sf_fb_invite_change_role' - def is_group_delete(self): + def is_sf_fb_uninvite(self): """ - Check if the union tag is ``group_delete``. + Check if the union tag is ``sf_fb_uninvite``. :rtype: bool """ - return self._tag == 'group_delete' + return self._tag == 'sf_fb_uninvite' - def is_group_description_updated(self): + def is_sf_invite_group(self): """ - Check if the union tag is ``group_description_updated``. + Check if the union tag is ``sf_invite_group``. :rtype: bool """ - return self._tag == 'group_description_updated' + return self._tag == 'sf_invite_group' - def is_group_join_policy_updated(self): + def is_sf_team_grant_access(self): """ - Check if the union tag is ``group_join_policy_updated``. + Check if the union tag is ``sf_team_grant_access``. :rtype: bool """ - return self._tag == 'group_join_policy_updated' + return self._tag == 'sf_team_grant_access' - def is_group_moved(self): + def is_sf_team_invite(self): """ - Check if the union tag is ``group_moved``. + Check if the union tag is ``sf_team_invite``. :rtype: bool """ - return self._tag == 'group_moved' + return self._tag == 'sf_team_invite' - def is_group_remove_external_id(self): + def is_sf_team_invite_change_role(self): """ - Check if the union tag is ``group_remove_external_id``. + Check if the union tag is ``sf_team_invite_change_role``. :rtype: bool """ - return self._tag == 'group_remove_external_id' + return self._tag == 'sf_team_invite_change_role' - def is_group_remove_member(self): + def is_sf_team_join(self): """ - Check if the union tag is ``group_remove_member``. + Check if the union tag is ``sf_team_join``. :rtype: bool """ - return self._tag == 'group_remove_member' + return self._tag == 'sf_team_join' - def is_group_rename(self): + def is_sf_team_join_from_oob_link(self): """ - Check if the union tag is ``group_rename``. + Check if the union tag is ``sf_team_join_from_oob_link``. :rtype: bool """ - return self._tag == 'group_rename' + return self._tag == 'sf_team_join_from_oob_link' - def is_emm_error(self): + def is_sf_team_uninvite(self): """ - Check if the union tag is ``emm_error``. + Check if the union tag is ``sf_team_uninvite``. :rtype: bool """ - return self._tag == 'emm_error' + return self._tag == 'sf_team_uninvite' - def is_guest_admin_signed_in_via_trusted_teams(self): + def is_shared_content_add_invitees(self): """ - Check if the union tag is ``guest_admin_signed_in_via_trusted_teams``. + Check if the union tag is ``shared_content_add_invitees``. :rtype: bool """ - return self._tag == 'guest_admin_signed_in_via_trusted_teams' + return self._tag == 'shared_content_add_invitees' - def is_guest_admin_signed_out_via_trusted_teams(self): + def is_shared_content_add_link_expiry(self): """ - Check if the union tag is ``guest_admin_signed_out_via_trusted_teams``. + Check if the union tag is ``shared_content_add_link_expiry``. :rtype: bool """ - return self._tag == 'guest_admin_signed_out_via_trusted_teams' + return self._tag == 'shared_content_add_link_expiry' - def is_login_fail(self): + def is_shared_content_add_link_password(self): """ - Check if the union tag is ``login_fail``. + Check if the union tag is ``shared_content_add_link_password``. :rtype: bool """ - return self._tag == 'login_fail' + return self._tag == 'shared_content_add_link_password' - def is_login_success(self): + def is_shared_content_add_member(self): """ - Check if the union tag is ``login_success``. + Check if the union tag is ``shared_content_add_member``. :rtype: bool """ - return self._tag == 'login_success' + return self._tag == 'shared_content_add_member' - def is_logout(self): + def is_shared_content_change_downloads_policy(self): """ - Check if the union tag is ``logout``. + Check if the union tag is ``shared_content_change_downloads_policy``. :rtype: bool """ - return self._tag == 'logout' + return self._tag == 'shared_content_change_downloads_policy' - def is_reseller_support_session_end(self): + def is_shared_content_change_invitee_role(self): """ - Check if the union tag is ``reseller_support_session_end``. + Check if the union tag is ``shared_content_change_invitee_role``. :rtype: bool """ - return self._tag == 'reseller_support_session_end' + return self._tag == 'shared_content_change_invitee_role' - def is_reseller_support_session_start(self): + def is_shared_content_change_link_audience(self): """ - Check if the union tag is ``reseller_support_session_start``. + Check if the union tag is ``shared_content_change_link_audience``. :rtype: bool """ - return self._tag == 'reseller_support_session_start' + return self._tag == 'shared_content_change_link_audience' - def is_sign_in_as_session_end(self): + def is_shared_content_change_link_expiry(self): """ - Check if the union tag is ``sign_in_as_session_end``. + Check if the union tag is ``shared_content_change_link_expiry``. :rtype: bool """ - return self._tag == 'sign_in_as_session_end' + return self._tag == 'shared_content_change_link_expiry' - def is_sign_in_as_session_start(self): + def is_shared_content_change_link_password(self): """ - Check if the union tag is ``sign_in_as_session_start``. + Check if the union tag is ``shared_content_change_link_password``. :rtype: bool """ - return self._tag == 'sign_in_as_session_start' + return self._tag == 'shared_content_change_link_password' - def is_sso_error(self): + def is_shared_content_change_member_role(self): """ - Check if the union tag is ``sso_error``. + Check if the union tag is ``shared_content_change_member_role``. :rtype: bool """ - return self._tag == 'sso_error' + return self._tag == 'shared_content_change_member_role' - def is_member_add_external_id(self): + def is_shared_content_change_viewer_info_policy(self): """ - Check if the union tag is ``member_add_external_id``. + Check if the union tag is ``shared_content_change_viewer_info_policy``. :rtype: bool """ - return self._tag == 'member_add_external_id' + return self._tag == 'shared_content_change_viewer_info_policy' - def is_member_add_name(self): + def is_shared_content_claim_invitation(self): """ - Check if the union tag is ``member_add_name``. + Check if the union tag is ``shared_content_claim_invitation``. :rtype: bool """ - return self._tag == 'member_add_name' + return self._tag == 'shared_content_claim_invitation' - def is_member_change_admin_role(self): + def is_shared_content_copy(self): """ - Check if the union tag is ``member_change_admin_role``. + Check if the union tag is ``shared_content_copy``. :rtype: bool """ - return self._tag == 'member_change_admin_role' + return self._tag == 'shared_content_copy' - def is_member_change_email(self): + def is_shared_content_download(self): """ - Check if the union tag is ``member_change_email``. + Check if the union tag is ``shared_content_download``. :rtype: bool """ - return self._tag == 'member_change_email' + return self._tag == 'shared_content_download' - def is_member_change_external_id(self): + def is_shared_content_relinquish_membership(self): """ - Check if the union tag is ``member_change_external_id``. + Check if the union tag is ``shared_content_relinquish_membership``. :rtype: bool """ - return self._tag == 'member_change_external_id' + return self._tag == 'shared_content_relinquish_membership' - def is_member_change_membership_type(self): + def is_shared_content_remove_invitees(self): """ - Check if the union tag is ``member_change_membership_type``. + Check if the union tag is ``shared_content_remove_invitees``. :rtype: bool """ - return self._tag == 'member_change_membership_type' + return self._tag == 'shared_content_remove_invitees' - def is_member_change_name(self): + def is_shared_content_remove_link_expiry(self): """ - Check if the union tag is ``member_change_name``. + Check if the union tag is ``shared_content_remove_link_expiry``. :rtype: bool """ - return self._tag == 'member_change_name' + return self._tag == 'shared_content_remove_link_expiry' - def is_member_change_status(self): + def is_shared_content_remove_link_password(self): """ - Check if the union tag is ``member_change_status``. + Check if the union tag is ``shared_content_remove_link_password``. :rtype: bool """ - return self._tag == 'member_change_status' + return self._tag == 'shared_content_remove_link_password' - def is_member_delete_manual_contacts(self): + def is_shared_content_remove_member(self): """ - Check if the union tag is ``member_delete_manual_contacts``. + Check if the union tag is ``shared_content_remove_member``. :rtype: bool """ - return self._tag == 'member_delete_manual_contacts' + return self._tag == 'shared_content_remove_member' - def is_member_permanently_delete_account_contents(self): + def is_shared_content_request_access(self): """ - Check if the union tag is ``member_permanently_delete_account_contents``. + Check if the union tag is ``shared_content_request_access``. :rtype: bool """ - return self._tag == 'member_permanently_delete_account_contents' + return self._tag == 'shared_content_request_access' - def is_member_remove_external_id(self): + def is_shared_content_restore_invitees(self): """ - Check if the union tag is ``member_remove_external_id``. + Check if the union tag is ``shared_content_restore_invitees``. :rtype: bool """ - return self._tag == 'member_remove_external_id' + return self._tag == 'shared_content_restore_invitees' - def is_member_space_limits_add_custom_quota(self): + def is_shared_content_restore_member(self): """ - Check if the union tag is ``member_space_limits_add_custom_quota``. + Check if the union tag is ``shared_content_restore_member``. :rtype: bool """ - return self._tag == 'member_space_limits_add_custom_quota' + return self._tag == 'shared_content_restore_member' - def is_member_space_limits_change_custom_quota(self): + def is_shared_content_unshare(self): """ - Check if the union tag is ``member_space_limits_change_custom_quota``. + Check if the union tag is ``shared_content_unshare``. :rtype: bool """ - return self._tag == 'member_space_limits_change_custom_quota' + return self._tag == 'shared_content_unshare' - def is_member_space_limits_change_status(self): + def is_shared_content_view(self): """ - Check if the union tag is ``member_space_limits_change_status``. + Check if the union tag is ``shared_content_view``. :rtype: bool """ - return self._tag == 'member_space_limits_change_status' + return self._tag == 'shared_content_view' - def is_member_space_limits_remove_custom_quota(self): + def is_shared_folder_change_link_policy(self): """ - Check if the union tag is ``member_space_limits_remove_custom_quota``. + Check if the union tag is ``shared_folder_change_link_policy``. :rtype: bool """ - return self._tag == 'member_space_limits_remove_custom_quota' + return self._tag == 'shared_folder_change_link_policy' - def is_member_suggest(self): + def is_shared_folder_change_members_inheritance_policy(self): """ - Check if the union tag is ``member_suggest``. + Check if the union tag is ``shared_folder_change_members_inheritance_policy``. :rtype: bool """ - return self._tag == 'member_suggest' + return self._tag == 'shared_folder_change_members_inheritance_policy' - def is_member_transfer_account_contents(self): + def is_shared_folder_change_members_management_policy(self): """ - Check if the union tag is ``member_transfer_account_contents``. + Check if the union tag is ``shared_folder_change_members_management_policy``. :rtype: bool """ - return self._tag == 'member_transfer_account_contents' + return self._tag == 'shared_folder_change_members_management_policy' - def is_secondary_mails_policy_changed(self): + def is_shared_folder_change_members_policy(self): """ - Check if the union tag is ``secondary_mails_policy_changed``. + Check if the union tag is ``shared_folder_change_members_policy``. :rtype: bool """ - return self._tag == 'secondary_mails_policy_changed' + return self._tag == 'shared_folder_change_members_policy' - def is_paper_content_add_member(self): + def is_shared_folder_create(self): """ - Check if the union tag is ``paper_content_add_member``. + Check if the union tag is ``shared_folder_create``. :rtype: bool """ - return self._tag == 'paper_content_add_member' + return self._tag == 'shared_folder_create' - def is_paper_content_add_to_folder(self): + def is_shared_folder_decline_invitation(self): """ - Check if the union tag is ``paper_content_add_to_folder``. + Check if the union tag is ``shared_folder_decline_invitation``. :rtype: bool """ - return self._tag == 'paper_content_add_to_folder' + return self._tag == 'shared_folder_decline_invitation' - def is_paper_content_archive(self): + def is_shared_folder_mount(self): """ - Check if the union tag is ``paper_content_archive``. + Check if the union tag is ``shared_folder_mount``. :rtype: bool """ - return self._tag == 'paper_content_archive' + return self._tag == 'shared_folder_mount' - def is_paper_content_create(self): + def is_shared_folder_nest(self): """ - Check if the union tag is ``paper_content_create``. + Check if the union tag is ``shared_folder_nest``. :rtype: bool """ - return self._tag == 'paper_content_create' + return self._tag == 'shared_folder_nest' - def is_paper_content_permanently_delete(self): + def is_shared_folder_transfer_ownership(self): """ - Check if the union tag is ``paper_content_permanently_delete``. + Check if the union tag is ``shared_folder_transfer_ownership``. :rtype: bool """ - return self._tag == 'paper_content_permanently_delete' + return self._tag == 'shared_folder_transfer_ownership' - def is_paper_content_remove_from_folder(self): + def is_shared_folder_unmount(self): """ - Check if the union tag is ``paper_content_remove_from_folder``. + Check if the union tag is ``shared_folder_unmount``. :rtype: bool """ - return self._tag == 'paper_content_remove_from_folder' + return self._tag == 'shared_folder_unmount' - def is_paper_content_remove_member(self): + def is_shared_link_add_expiry(self): """ - Check if the union tag is ``paper_content_remove_member``. + Check if the union tag is ``shared_link_add_expiry``. :rtype: bool """ - return self._tag == 'paper_content_remove_member' + return self._tag == 'shared_link_add_expiry' - def is_paper_content_rename(self): + def is_shared_link_change_expiry(self): """ - Check if the union tag is ``paper_content_rename``. + Check if the union tag is ``shared_link_change_expiry``. :rtype: bool """ - return self._tag == 'paper_content_rename' + return self._tag == 'shared_link_change_expiry' - def is_paper_content_restore(self): + def is_shared_link_change_visibility(self): """ - Check if the union tag is ``paper_content_restore``. + Check if the union tag is ``shared_link_change_visibility``. :rtype: bool """ - return self._tag == 'paper_content_restore' + return self._tag == 'shared_link_change_visibility' - def is_paper_doc_add_comment(self): + def is_shared_link_copy(self): """ - Check if the union tag is ``paper_doc_add_comment``. + Check if the union tag is ``shared_link_copy``. :rtype: bool """ - return self._tag == 'paper_doc_add_comment' + return self._tag == 'shared_link_copy' - def is_paper_doc_change_member_role(self): + def is_shared_link_create(self): """ - Check if the union tag is ``paper_doc_change_member_role``. + Check if the union tag is ``shared_link_create``. :rtype: bool """ - return self._tag == 'paper_doc_change_member_role' + return self._tag == 'shared_link_create' - def is_paper_doc_change_sharing_policy(self): + def is_shared_link_disable(self): """ - Check if the union tag is ``paper_doc_change_sharing_policy``. + Check if the union tag is ``shared_link_disable``. :rtype: bool """ - return self._tag == 'paper_doc_change_sharing_policy' + return self._tag == 'shared_link_disable' - def is_paper_doc_change_subscription(self): + def is_shared_link_download(self): """ - Check if the union tag is ``paper_doc_change_subscription``. + Check if the union tag is ``shared_link_download``. :rtype: bool """ - return self._tag == 'paper_doc_change_subscription' + return self._tag == 'shared_link_download' - def is_paper_doc_deleted(self): + def is_shared_link_remove_expiry(self): """ - Check if the union tag is ``paper_doc_deleted``. + Check if the union tag is ``shared_link_remove_expiry``. :rtype: bool """ - return self._tag == 'paper_doc_deleted' + return self._tag == 'shared_link_remove_expiry' - def is_paper_doc_delete_comment(self): + def is_shared_link_settings_add_expiration(self): """ - Check if the union tag is ``paper_doc_delete_comment``. + Check if the union tag is ``shared_link_settings_add_expiration``. :rtype: bool """ - return self._tag == 'paper_doc_delete_comment' + return self._tag == 'shared_link_settings_add_expiration' - def is_paper_doc_download(self): + def is_shared_link_settings_add_password(self): """ - Check if the union tag is ``paper_doc_download``. + Check if the union tag is ``shared_link_settings_add_password``. :rtype: bool """ - return self._tag == 'paper_doc_download' + return self._tag == 'shared_link_settings_add_password' - def is_paper_doc_edit(self): + def is_shared_link_settings_allow_download_disabled(self): """ - Check if the union tag is ``paper_doc_edit``. + Check if the union tag is ``shared_link_settings_allow_download_disabled``. :rtype: bool """ - return self._tag == 'paper_doc_edit' + return self._tag == 'shared_link_settings_allow_download_disabled' - def is_paper_doc_edit_comment(self): + def is_shared_link_settings_allow_download_enabled(self): """ - Check if the union tag is ``paper_doc_edit_comment``. + Check if the union tag is ``shared_link_settings_allow_download_enabled``. :rtype: bool """ - return self._tag == 'paper_doc_edit_comment' + return self._tag == 'shared_link_settings_allow_download_enabled' - def is_paper_doc_followed(self): + def is_shared_link_settings_change_audience(self): """ - Check if the union tag is ``paper_doc_followed``. + Check if the union tag is ``shared_link_settings_change_audience``. :rtype: bool """ - return self._tag == 'paper_doc_followed' + return self._tag == 'shared_link_settings_change_audience' - def is_paper_doc_mention(self): + def is_shared_link_settings_change_expiration(self): """ - Check if the union tag is ``paper_doc_mention``. + Check if the union tag is ``shared_link_settings_change_expiration``. :rtype: bool """ - return self._tag == 'paper_doc_mention' + return self._tag == 'shared_link_settings_change_expiration' - def is_paper_doc_ownership_changed(self): + def is_shared_link_settings_change_password(self): """ - Check if the union tag is ``paper_doc_ownership_changed``. + Check if the union tag is ``shared_link_settings_change_password``. :rtype: bool """ - return self._tag == 'paper_doc_ownership_changed' + return self._tag == 'shared_link_settings_change_password' - def is_paper_doc_request_access(self): + def is_shared_link_settings_remove_expiration(self): """ - Check if the union tag is ``paper_doc_request_access``. + Check if the union tag is ``shared_link_settings_remove_expiration``. :rtype: bool """ - return self._tag == 'paper_doc_request_access' + return self._tag == 'shared_link_settings_remove_expiration' - def is_paper_doc_resolve_comment(self): + def is_shared_link_settings_remove_password(self): """ - Check if the union tag is ``paper_doc_resolve_comment``. + Check if the union tag is ``shared_link_settings_remove_password``. :rtype: bool """ - return self._tag == 'paper_doc_resolve_comment' + return self._tag == 'shared_link_settings_remove_password' - def is_paper_doc_revert(self): + def is_shared_link_share(self): """ - Check if the union tag is ``paper_doc_revert``. + Check if the union tag is ``shared_link_share``. :rtype: bool """ - return self._tag == 'paper_doc_revert' + return self._tag == 'shared_link_share' - def is_paper_doc_slack_share(self): + def is_shared_link_view(self): """ - Check if the union tag is ``paper_doc_slack_share``. + Check if the union tag is ``shared_link_view``. :rtype: bool """ - return self._tag == 'paper_doc_slack_share' + return self._tag == 'shared_link_view' - def is_paper_doc_team_invite(self): + def is_shared_note_opened(self): """ - Check if the union tag is ``paper_doc_team_invite``. + Check if the union tag is ``shared_note_opened``. :rtype: bool """ - return self._tag == 'paper_doc_team_invite' + return self._tag == 'shared_note_opened' - def is_paper_doc_trashed(self): + def is_shmodel_group_share(self): """ - Check if the union tag is ``paper_doc_trashed``. + Check if the union tag is ``shmodel_group_share``. :rtype: bool """ - return self._tag == 'paper_doc_trashed' + return self._tag == 'shmodel_group_share' - def is_paper_doc_unresolve_comment(self): + def is_showcase_access_granted(self): """ - Check if the union tag is ``paper_doc_unresolve_comment``. + Check if the union tag is ``showcase_access_granted``. :rtype: bool """ - return self._tag == 'paper_doc_unresolve_comment' + return self._tag == 'showcase_access_granted' - def is_paper_doc_untrashed(self): + def is_showcase_add_member(self): """ - Check if the union tag is ``paper_doc_untrashed``. + Check if the union tag is ``showcase_add_member``. :rtype: bool """ - return self._tag == 'paper_doc_untrashed' + return self._tag == 'showcase_add_member' - def is_paper_doc_view(self): + def is_showcase_archived(self): """ - Check if the union tag is ``paper_doc_view``. + Check if the union tag is ``showcase_archived``. :rtype: bool """ - return self._tag == 'paper_doc_view' + return self._tag == 'showcase_archived' - def is_paper_external_view_allow(self): + def is_showcase_created(self): """ - Check if the union tag is ``paper_external_view_allow``. + Check if the union tag is ``showcase_created``. :rtype: bool """ - return self._tag == 'paper_external_view_allow' + return self._tag == 'showcase_created' - def is_paper_external_view_default_team(self): + def is_showcase_delete_comment(self): """ - Check if the union tag is ``paper_external_view_default_team``. + Check if the union tag is ``showcase_delete_comment``. :rtype: bool """ - return self._tag == 'paper_external_view_default_team' + return self._tag == 'showcase_delete_comment' - def is_paper_external_view_forbid(self): + def is_showcase_edited(self): """ - Check if the union tag is ``paper_external_view_forbid``. + Check if the union tag is ``showcase_edited``. :rtype: bool """ - return self._tag == 'paper_external_view_forbid' + return self._tag == 'showcase_edited' - def is_paper_folder_change_subscription(self): + def is_showcase_edit_comment(self): """ - Check if the union tag is ``paper_folder_change_subscription``. + Check if the union tag is ``showcase_edit_comment``. :rtype: bool """ - return self._tag == 'paper_folder_change_subscription' + return self._tag == 'showcase_edit_comment' - def is_paper_folder_deleted(self): + def is_showcase_file_added(self): """ - Check if the union tag is ``paper_folder_deleted``. + Check if the union tag is ``showcase_file_added``. :rtype: bool """ - return self._tag == 'paper_folder_deleted' + return self._tag == 'showcase_file_added' - def is_paper_folder_followed(self): + def is_showcase_file_download(self): """ - Check if the union tag is ``paper_folder_followed``. + Check if the union tag is ``showcase_file_download``. :rtype: bool """ - return self._tag == 'paper_folder_followed' + return self._tag == 'showcase_file_download' - def is_paper_folder_team_invite(self): + def is_showcase_file_removed(self): """ - Check if the union tag is ``paper_folder_team_invite``. + Check if the union tag is ``showcase_file_removed``. :rtype: bool """ - return self._tag == 'paper_folder_team_invite' + return self._tag == 'showcase_file_removed' - def is_paper_published_link_create(self): + def is_showcase_file_view(self): """ - Check if the union tag is ``paper_published_link_create``. + Check if the union tag is ``showcase_file_view``. :rtype: bool """ - return self._tag == 'paper_published_link_create' + return self._tag == 'showcase_file_view' - def is_paper_published_link_disabled(self): + def is_showcase_permanently_deleted(self): """ - Check if the union tag is ``paper_published_link_disabled``. + Check if the union tag is ``showcase_permanently_deleted``. :rtype: bool """ - return self._tag == 'paper_published_link_disabled' + return self._tag == 'showcase_permanently_deleted' - def is_paper_published_link_view(self): + def is_showcase_post_comment(self): """ - Check if the union tag is ``paper_published_link_view``. + Check if the union tag is ``showcase_post_comment``. :rtype: bool """ - return self._tag == 'paper_published_link_view' + return self._tag == 'showcase_post_comment' - def is_password_change(self): + def is_showcase_remove_member(self): """ - Check if the union tag is ``password_change``. + Check if the union tag is ``showcase_remove_member``. :rtype: bool """ - return self._tag == 'password_change' + return self._tag == 'showcase_remove_member' - def is_password_reset(self): + def is_showcase_renamed(self): """ - Check if the union tag is ``password_reset``. + Check if the union tag is ``showcase_renamed``. :rtype: bool """ - return self._tag == 'password_reset' + return self._tag == 'showcase_renamed' - def is_password_reset_all(self): + def is_showcase_request_access(self): """ - Check if the union tag is ``password_reset_all``. + Check if the union tag is ``showcase_request_access``. :rtype: bool """ - return self._tag == 'password_reset_all' + return self._tag == 'showcase_request_access' - def is_emm_create_exceptions_report(self): + def is_showcase_resolve_comment(self): """ - Check if the union tag is ``emm_create_exceptions_report``. + Check if the union tag is ``showcase_resolve_comment``. :rtype: bool """ - return self._tag == 'emm_create_exceptions_report' + return self._tag == 'showcase_resolve_comment' - def is_emm_create_usage_report(self): + def is_showcase_restored(self): """ - Check if the union tag is ``emm_create_usage_report``. + Check if the union tag is ``showcase_restored``. :rtype: bool """ - return self._tag == 'emm_create_usage_report' + return self._tag == 'showcase_restored' - def is_export_members_report(self): + def is_showcase_trashed(self): """ - Check if the union tag is ``export_members_report``. + Check if the union tag is ``showcase_trashed``. :rtype: bool """ - return self._tag == 'export_members_report' + return self._tag == 'showcase_trashed' - def is_paper_admin_export_start(self): + def is_showcase_trashed_deprecated(self): """ - Check if the union tag is ``paper_admin_export_start``. + Check if the union tag is ``showcase_trashed_deprecated``. :rtype: bool """ - return self._tag == 'paper_admin_export_start' + return self._tag == 'showcase_trashed_deprecated' - def is_smart_sync_create_admin_privilege_report(self): + def is_showcase_unresolve_comment(self): """ - Check if the union tag is ``smart_sync_create_admin_privilege_report``. + Check if the union tag is ``showcase_unresolve_comment``. :rtype: bool """ - return self._tag == 'smart_sync_create_admin_privilege_report' + return self._tag == 'showcase_unresolve_comment' - def is_team_activity_create_report(self): + def is_showcase_untrashed(self): """ - Check if the union tag is ``team_activity_create_report``. + Check if the union tag is ``showcase_untrashed``. :rtype: bool """ - return self._tag == 'team_activity_create_report' + return self._tag == 'showcase_untrashed' - def is_team_activity_create_report_fail(self): + def is_showcase_untrashed_deprecated(self): """ - Check if the union tag is ``team_activity_create_report_fail``. + Check if the union tag is ``showcase_untrashed_deprecated``. :rtype: bool """ - return self._tag == 'team_activity_create_report_fail' + return self._tag == 'showcase_untrashed_deprecated' - def is_collection_share(self): + def is_showcase_view(self): """ - Check if the union tag is ``collection_share``. + Check if the union tag is ``showcase_view``. :rtype: bool """ - return self._tag == 'collection_share' + return self._tag == 'showcase_view' - def is_note_acl_invite_only(self): + def is_sso_add_cert(self): """ - Check if the union tag is ``note_acl_invite_only``. + Check if the union tag is ``sso_add_cert``. :rtype: bool """ - return self._tag == 'note_acl_invite_only' + return self._tag == 'sso_add_cert' - def is_note_acl_link(self): + def is_sso_add_login_url(self): """ - Check if the union tag is ``note_acl_link``. + Check if the union tag is ``sso_add_login_url``. :rtype: bool """ - return self._tag == 'note_acl_link' + return self._tag == 'sso_add_login_url' - def is_note_acl_team_link(self): + def is_sso_add_logout_url(self): """ - Check if the union tag is ``note_acl_team_link``. + Check if the union tag is ``sso_add_logout_url``. :rtype: bool """ - return self._tag == 'note_acl_team_link' + return self._tag == 'sso_add_logout_url' - def is_note_shared(self): + def is_sso_change_cert(self): """ - Check if the union tag is ``note_shared``. + Check if the union tag is ``sso_change_cert``. :rtype: bool """ - return self._tag == 'note_shared' + return self._tag == 'sso_change_cert' - def is_note_share_receive(self): + def is_sso_change_login_url(self): """ - Check if the union tag is ``note_share_receive``. + Check if the union tag is ``sso_change_login_url``. :rtype: bool """ - return self._tag == 'note_share_receive' + return self._tag == 'sso_change_login_url' - def is_open_note_shared(self): + def is_sso_change_logout_url(self): """ - Check if the union tag is ``open_note_shared``. + Check if the union tag is ``sso_change_logout_url``. :rtype: bool """ - return self._tag == 'open_note_shared' + return self._tag == 'sso_change_logout_url' - def is_sf_add_group(self): + def is_sso_change_saml_identity_mode(self): """ - Check if the union tag is ``sf_add_group``. + Check if the union tag is ``sso_change_saml_identity_mode``. :rtype: bool """ - return self._tag == 'sf_add_group' + return self._tag == 'sso_change_saml_identity_mode' - def is_sf_allow_non_members_to_view_shared_links(self): + def is_sso_remove_cert(self): """ - Check if the union tag is ``sf_allow_non_members_to_view_shared_links``. + Check if the union tag is ``sso_remove_cert``. :rtype: bool """ - return self._tag == 'sf_allow_non_members_to_view_shared_links' + return self._tag == 'sso_remove_cert' - def is_sf_external_invite_warn(self): + def is_sso_remove_login_url(self): """ - Check if the union tag is ``sf_external_invite_warn``. + Check if the union tag is ``sso_remove_login_url``. :rtype: bool """ - return self._tag == 'sf_external_invite_warn' + return self._tag == 'sso_remove_login_url' - def is_sf_fb_invite(self): + def is_sso_remove_logout_url(self): """ - Check if the union tag is ``sf_fb_invite``. + Check if the union tag is ``sso_remove_logout_url``. :rtype: bool """ - return self._tag == 'sf_fb_invite' + return self._tag == 'sso_remove_logout_url' - def is_sf_fb_invite_change_role(self): + def is_team_folder_change_status(self): """ - Check if the union tag is ``sf_fb_invite_change_role``. + Check if the union tag is ``team_folder_change_status``. :rtype: bool """ - return self._tag == 'sf_fb_invite_change_role' + return self._tag == 'team_folder_change_status' - def is_sf_fb_uninvite(self): + def is_team_folder_create(self): """ - Check if the union tag is ``sf_fb_uninvite``. + Check if the union tag is ``team_folder_create``. :rtype: bool """ - return self._tag == 'sf_fb_uninvite' + return self._tag == 'team_folder_create' - def is_sf_invite_group(self): + def is_team_folder_downgrade(self): """ - Check if the union tag is ``sf_invite_group``. + Check if the union tag is ``team_folder_downgrade``. :rtype: bool """ - return self._tag == 'sf_invite_group' + return self._tag == 'team_folder_downgrade' - def is_sf_team_grant_access(self): + def is_team_folder_permanently_delete(self): """ - Check if the union tag is ``sf_team_grant_access``. + Check if the union tag is ``team_folder_permanently_delete``. :rtype: bool """ - return self._tag == 'sf_team_grant_access' + return self._tag == 'team_folder_permanently_delete' - def is_sf_team_invite(self): + def is_team_folder_rename(self): """ - Check if the union tag is ``sf_team_invite``. + Check if the union tag is ``team_folder_rename``. :rtype: bool """ - return self._tag == 'sf_team_invite' + return self._tag == 'team_folder_rename' - def is_sf_team_invite_change_role(self): + def is_team_selective_sync_settings_changed(self): """ - Check if the union tag is ``sf_team_invite_change_role``. + Check if the union tag is ``team_selective_sync_settings_changed``. :rtype: bool """ - return self._tag == 'sf_team_invite_change_role' + return self._tag == 'team_selective_sync_settings_changed' - def is_sf_team_join(self): + def is_account_capture_change_policy(self): """ - Check if the union tag is ``sf_team_join``. + Check if the union tag is ``account_capture_change_policy``. :rtype: bool """ - return self._tag == 'sf_team_join' + return self._tag == 'account_capture_change_policy' - def is_sf_team_join_from_oob_link(self): + def is_allow_download_disabled(self): """ - Check if the union tag is ``sf_team_join_from_oob_link``. + Check if the union tag is ``allow_download_disabled``. :rtype: bool """ - return self._tag == 'sf_team_join_from_oob_link' + return self._tag == 'allow_download_disabled' - def is_sf_team_uninvite(self): + def is_allow_download_enabled(self): """ - Check if the union tag is ``sf_team_uninvite``. + Check if the union tag is ``allow_download_enabled``. :rtype: bool """ - return self._tag == 'sf_team_uninvite' + return self._tag == 'allow_download_enabled' - def is_shared_content_add_invitees(self): + def is_camera_uploads_policy_changed(self): """ - Check if the union tag is ``shared_content_add_invitees``. + Check if the union tag is ``camera_uploads_policy_changed``. :rtype: bool """ - return self._tag == 'shared_content_add_invitees' + return self._tag == 'camera_uploads_policy_changed' - def is_shared_content_add_link_expiry(self): + def is_data_placement_restriction_change_policy(self): """ - Check if the union tag is ``shared_content_add_link_expiry``. + Check if the union tag is ``data_placement_restriction_change_policy``. :rtype: bool """ - return self._tag == 'shared_content_add_link_expiry' + return self._tag == 'data_placement_restriction_change_policy' - def is_shared_content_add_link_password(self): + def is_data_placement_restriction_satisfy_policy(self): """ - Check if the union tag is ``shared_content_add_link_password``. + Check if the union tag is ``data_placement_restriction_satisfy_policy``. :rtype: bool """ - return self._tag == 'shared_content_add_link_password' + return self._tag == 'data_placement_restriction_satisfy_policy' - def is_shared_content_add_member(self): + def is_device_approvals_add_exception(self): """ - Check if the union tag is ``shared_content_add_member``. + Check if the union tag is ``device_approvals_add_exception``. :rtype: bool """ - return self._tag == 'shared_content_add_member' + return self._tag == 'device_approvals_add_exception' - def is_shared_content_change_downloads_policy(self): + def is_device_approvals_change_desktop_policy(self): """ - Check if the union tag is ``shared_content_change_downloads_policy``. + Check if the union tag is ``device_approvals_change_desktop_policy``. :rtype: bool """ - return self._tag == 'shared_content_change_downloads_policy' + return self._tag == 'device_approvals_change_desktop_policy' - def is_shared_content_change_invitee_role(self): + def is_device_approvals_change_mobile_policy(self): """ - Check if the union tag is ``shared_content_change_invitee_role``. + Check if the union tag is ``device_approvals_change_mobile_policy``. :rtype: bool """ - return self._tag == 'shared_content_change_invitee_role' + return self._tag == 'device_approvals_change_mobile_policy' - def is_shared_content_change_link_audience(self): + def is_device_approvals_change_overage_action(self): """ - Check if the union tag is ``shared_content_change_link_audience``. + Check if the union tag is ``device_approvals_change_overage_action``. :rtype: bool """ - return self._tag == 'shared_content_change_link_audience' + return self._tag == 'device_approvals_change_overage_action' - def is_shared_content_change_link_expiry(self): + def is_device_approvals_change_unlink_action(self): """ - Check if the union tag is ``shared_content_change_link_expiry``. + Check if the union tag is ``device_approvals_change_unlink_action``. :rtype: bool """ - return self._tag == 'shared_content_change_link_expiry' + return self._tag == 'device_approvals_change_unlink_action' - def is_shared_content_change_link_password(self): + def is_device_approvals_remove_exception(self): """ - Check if the union tag is ``shared_content_change_link_password``. + Check if the union tag is ``device_approvals_remove_exception``. :rtype: bool """ - return self._tag == 'shared_content_change_link_password' + return self._tag == 'device_approvals_remove_exception' - def is_shared_content_change_member_role(self): + def is_directory_restrictions_add_members(self): """ - Check if the union tag is ``shared_content_change_member_role``. + Check if the union tag is ``directory_restrictions_add_members``. :rtype: bool """ - return self._tag == 'shared_content_change_member_role' + return self._tag == 'directory_restrictions_add_members' - def is_shared_content_change_viewer_info_policy(self): + def is_directory_restrictions_remove_members(self): """ - Check if the union tag is ``shared_content_change_viewer_info_policy``. + Check if the union tag is ``directory_restrictions_remove_members``. :rtype: bool """ - return self._tag == 'shared_content_change_viewer_info_policy' + return self._tag == 'directory_restrictions_remove_members' - def is_shared_content_claim_invitation(self): + def is_emm_add_exception(self): """ - Check if the union tag is ``shared_content_claim_invitation``. + Check if the union tag is ``emm_add_exception``. :rtype: bool """ - return self._tag == 'shared_content_claim_invitation' + return self._tag == 'emm_add_exception' - def is_shared_content_copy(self): + def is_emm_change_policy(self): """ - Check if the union tag is ``shared_content_copy``. + Check if the union tag is ``emm_change_policy``. :rtype: bool """ - return self._tag == 'shared_content_copy' + return self._tag == 'emm_change_policy' - def is_shared_content_download(self): + def is_emm_remove_exception(self): """ - Check if the union tag is ``shared_content_download``. + Check if the union tag is ``emm_remove_exception``. :rtype: bool """ - return self._tag == 'shared_content_download' + return self._tag == 'emm_remove_exception' - def is_shared_content_relinquish_membership(self): + def is_extended_version_history_change_policy(self): """ - Check if the union tag is ``shared_content_relinquish_membership``. + Check if the union tag is ``extended_version_history_change_policy``. :rtype: bool """ - return self._tag == 'shared_content_relinquish_membership' + return self._tag == 'extended_version_history_change_policy' - def is_shared_content_remove_invitees(self): + def is_file_comments_change_policy(self): """ - Check if the union tag is ``shared_content_remove_invitees``. + Check if the union tag is ``file_comments_change_policy``. :rtype: bool """ - return self._tag == 'shared_content_remove_invitees' + return self._tag == 'file_comments_change_policy' - def is_shared_content_remove_link_expiry(self): + def is_file_locking_policy_changed(self): """ - Check if the union tag is ``shared_content_remove_link_expiry``. + Check if the union tag is ``file_locking_policy_changed``. :rtype: bool """ - return self._tag == 'shared_content_remove_link_expiry' + return self._tag == 'file_locking_policy_changed' - def is_shared_content_remove_link_password(self): + def is_file_requests_change_policy(self): """ - Check if the union tag is ``shared_content_remove_link_password``. + Check if the union tag is ``file_requests_change_policy``. :rtype: bool """ - return self._tag == 'shared_content_remove_link_password' + return self._tag == 'file_requests_change_policy' - def is_shared_content_remove_member(self): + def is_file_requests_emails_enabled(self): """ - Check if the union tag is ``shared_content_remove_member``. + Check if the union tag is ``file_requests_emails_enabled``. :rtype: bool """ - return self._tag == 'shared_content_remove_member' + return self._tag == 'file_requests_emails_enabled' - def is_shared_content_request_access(self): + def is_file_requests_emails_restricted_to_team_only(self): """ - Check if the union tag is ``shared_content_request_access``. + Check if the union tag is ``file_requests_emails_restricted_to_team_only``. :rtype: bool """ - return self._tag == 'shared_content_request_access' + return self._tag == 'file_requests_emails_restricted_to_team_only' - def is_shared_content_unshare(self): + def is_file_transfers_policy_changed(self): """ - Check if the union tag is ``shared_content_unshare``. + Check if the union tag is ``file_transfers_policy_changed``. :rtype: bool """ - return self._tag == 'shared_content_unshare' + return self._tag == 'file_transfers_policy_changed' - def is_shared_content_view(self): + def is_google_sso_change_policy(self): """ - Check if the union tag is ``shared_content_view``. + Check if the union tag is ``google_sso_change_policy``. :rtype: bool """ - return self._tag == 'shared_content_view' + return self._tag == 'google_sso_change_policy' - def is_shared_folder_change_link_policy(self): + def is_group_user_management_change_policy(self): """ - Check if the union tag is ``shared_folder_change_link_policy``. + Check if the union tag is ``group_user_management_change_policy``. :rtype: bool """ - return self._tag == 'shared_folder_change_link_policy' + return self._tag == 'group_user_management_change_policy' - def is_shared_folder_change_members_inheritance_policy(self): + def is_integration_policy_changed(self): """ - Check if the union tag is ``shared_folder_change_members_inheritance_policy``. + Check if the union tag is ``integration_policy_changed``. :rtype: bool """ - return self._tag == 'shared_folder_change_members_inheritance_policy' + return self._tag == 'integration_policy_changed' - def is_shared_folder_change_members_management_policy(self): + def is_member_requests_change_policy(self): """ - Check if the union tag is ``shared_folder_change_members_management_policy``. + Check if the union tag is ``member_requests_change_policy``. :rtype: bool """ - return self._tag == 'shared_folder_change_members_management_policy' + return self._tag == 'member_requests_change_policy' - def is_shared_folder_change_members_policy(self): + def is_member_send_invite_policy_changed(self): """ - Check if the union tag is ``shared_folder_change_members_policy``. + Check if the union tag is ``member_send_invite_policy_changed``. :rtype: bool """ - return self._tag == 'shared_folder_change_members_policy' + return self._tag == 'member_send_invite_policy_changed' - def is_shared_folder_create(self): + def is_member_space_limits_add_exception(self): """ - Check if the union tag is ``shared_folder_create``. + Check if the union tag is ``member_space_limits_add_exception``. :rtype: bool """ - return self._tag == 'shared_folder_create' + return self._tag == 'member_space_limits_add_exception' - def is_shared_folder_decline_invitation(self): + def is_member_space_limits_change_caps_type_policy(self): """ - Check if the union tag is ``shared_folder_decline_invitation``. + Check if the union tag is ``member_space_limits_change_caps_type_policy``. :rtype: bool """ - return self._tag == 'shared_folder_decline_invitation' + return self._tag == 'member_space_limits_change_caps_type_policy' - def is_shared_folder_mount(self): + def is_member_space_limits_change_policy(self): """ - Check if the union tag is ``shared_folder_mount``. + Check if the union tag is ``member_space_limits_change_policy``. :rtype: bool """ - return self._tag == 'shared_folder_mount' + return self._tag == 'member_space_limits_change_policy' - def is_shared_folder_nest(self): + def is_member_space_limits_remove_exception(self): """ - Check if the union tag is ``shared_folder_nest``. + Check if the union tag is ``member_space_limits_remove_exception``. :rtype: bool """ - return self._tag == 'shared_folder_nest' + return self._tag == 'member_space_limits_remove_exception' - def is_shared_folder_transfer_ownership(self): + def is_member_suggestions_change_policy(self): """ - Check if the union tag is ``shared_folder_transfer_ownership``. + Check if the union tag is ``member_suggestions_change_policy``. :rtype: bool """ - return self._tag == 'shared_folder_transfer_ownership' + return self._tag == 'member_suggestions_change_policy' - def is_shared_folder_unmount(self): + def is_microsoft_office_addin_change_policy(self): """ - Check if the union tag is ``shared_folder_unmount``. + Check if the union tag is ``microsoft_office_addin_change_policy``. :rtype: bool """ - return self._tag == 'shared_folder_unmount' + return self._tag == 'microsoft_office_addin_change_policy' - def is_shared_link_add_expiry(self): + def is_network_control_change_policy(self): """ - Check if the union tag is ``shared_link_add_expiry``. + Check if the union tag is ``network_control_change_policy``. :rtype: bool """ - return self._tag == 'shared_link_add_expiry' + return self._tag == 'network_control_change_policy' - def is_shared_link_change_expiry(self): + def is_paper_change_deployment_policy(self): """ - Check if the union tag is ``shared_link_change_expiry``. + Check if the union tag is ``paper_change_deployment_policy``. :rtype: bool """ - return self._tag == 'shared_link_change_expiry' + return self._tag == 'paper_change_deployment_policy' - def is_shared_link_change_visibility(self): + def is_paper_change_member_link_policy(self): """ - Check if the union tag is ``shared_link_change_visibility``. + Check if the union tag is ``paper_change_member_link_policy``. :rtype: bool """ - return self._tag == 'shared_link_change_visibility' + return self._tag == 'paper_change_member_link_policy' - def is_shared_link_copy(self): + def is_paper_change_member_policy(self): """ - Check if the union tag is ``shared_link_copy``. + Check if the union tag is ``paper_change_member_policy``. :rtype: bool """ - return self._tag == 'shared_link_copy' + return self._tag == 'paper_change_member_policy' - def is_shared_link_create(self): + def is_paper_change_policy(self): """ - Check if the union tag is ``shared_link_create``. + Check if the union tag is ``paper_change_policy``. :rtype: bool """ - return self._tag == 'shared_link_create' + return self._tag == 'paper_change_policy' - def is_shared_link_disable(self): + def is_paper_default_folder_policy_changed(self): """ - Check if the union tag is ``shared_link_disable``. + Check if the union tag is ``paper_default_folder_policy_changed``. :rtype: bool """ - return self._tag == 'shared_link_disable' + return self._tag == 'paper_default_folder_policy_changed' - def is_shared_link_download(self): + def is_paper_desktop_policy_changed(self): """ - Check if the union tag is ``shared_link_download``. + Check if the union tag is ``paper_desktop_policy_changed``. :rtype: bool """ - return self._tag == 'shared_link_download' + return self._tag == 'paper_desktop_policy_changed' - def is_shared_link_remove_expiry(self): + def is_paper_enabled_users_group_addition(self): """ - Check if the union tag is ``shared_link_remove_expiry``. + Check if the union tag is ``paper_enabled_users_group_addition``. :rtype: bool """ - return self._tag == 'shared_link_remove_expiry' + return self._tag == 'paper_enabled_users_group_addition' - def is_shared_link_share(self): + def is_paper_enabled_users_group_removal(self): """ - Check if the union tag is ``shared_link_share``. + Check if the union tag is ``paper_enabled_users_group_removal``. :rtype: bool """ - return self._tag == 'shared_link_share' + return self._tag == 'paper_enabled_users_group_removal' - def is_shared_link_view(self): + def is_password_strength_requirements_change_policy(self): """ - Check if the union tag is ``shared_link_view``. + Check if the union tag is ``password_strength_requirements_change_policy``. :rtype: bool """ - return self._tag == 'shared_link_view' + return self._tag == 'password_strength_requirements_change_policy' - def is_shared_note_opened(self): + def is_permanent_delete_change_policy(self): """ - Check if the union tag is ``shared_note_opened``. + Check if the union tag is ``permanent_delete_change_policy``. :rtype: bool """ - return self._tag == 'shared_note_opened' + return self._tag == 'permanent_delete_change_policy' - def is_shmodel_group_share(self): + def is_reseller_support_change_policy(self): """ - Check if the union tag is ``shmodel_group_share``. + Check if the union tag is ``reseller_support_change_policy``. :rtype: bool """ - return self._tag == 'shmodel_group_share' + return self._tag == 'reseller_support_change_policy' - def is_showcase_access_granted(self): + def is_rewind_policy_changed(self): """ - Check if the union tag is ``showcase_access_granted``. + Check if the union tag is ``rewind_policy_changed``. :rtype: bool """ - return self._tag == 'showcase_access_granted' + return self._tag == 'rewind_policy_changed' - def is_showcase_add_member(self): + def is_sharing_change_folder_join_policy(self): """ - Check if the union tag is ``showcase_add_member``. + Check if the union tag is ``sharing_change_folder_join_policy``. :rtype: bool """ - return self._tag == 'showcase_add_member' + return self._tag == 'sharing_change_folder_join_policy' - def is_showcase_archived(self): + def is_sharing_change_link_policy(self): """ - Check if the union tag is ``showcase_archived``. + Check if the union tag is ``sharing_change_link_policy``. :rtype: bool """ - return self._tag == 'showcase_archived' + return self._tag == 'sharing_change_link_policy' - def is_showcase_created(self): + def is_sharing_change_member_policy(self): """ - Check if the union tag is ``showcase_created``. + Check if the union tag is ``sharing_change_member_policy``. :rtype: bool """ - return self._tag == 'showcase_created' + return self._tag == 'sharing_change_member_policy' - def is_showcase_delete_comment(self): + def is_showcase_change_download_policy(self): """ - Check if the union tag is ``showcase_delete_comment``. + Check if the union tag is ``showcase_change_download_policy``. :rtype: bool """ - return self._tag == 'showcase_delete_comment' + return self._tag == 'showcase_change_download_policy' - def is_showcase_edited(self): + def is_showcase_change_enabled_policy(self): """ - Check if the union tag is ``showcase_edited``. + Check if the union tag is ``showcase_change_enabled_policy``. :rtype: bool """ - return self._tag == 'showcase_edited' + return self._tag == 'showcase_change_enabled_policy' - def is_showcase_edit_comment(self): + def is_showcase_change_external_sharing_policy(self): """ - Check if the union tag is ``showcase_edit_comment``. + Check if the union tag is ``showcase_change_external_sharing_policy``. :rtype: bool """ - return self._tag == 'showcase_edit_comment' + return self._tag == 'showcase_change_external_sharing_policy' - def is_showcase_file_added(self): + def is_smarter_smart_sync_policy_changed(self): """ - Check if the union tag is ``showcase_file_added``. + Check if the union tag is ``smarter_smart_sync_policy_changed``. :rtype: bool """ - return self._tag == 'showcase_file_added' + return self._tag == 'smarter_smart_sync_policy_changed' - def is_showcase_file_download(self): + def is_smart_sync_change_policy(self): """ - Check if the union tag is ``showcase_file_download``. + Check if the union tag is ``smart_sync_change_policy``. :rtype: bool """ - return self._tag == 'showcase_file_download' + return self._tag == 'smart_sync_change_policy' - def is_showcase_file_removed(self): + def is_smart_sync_not_opt_out(self): """ - Check if the union tag is ``showcase_file_removed``. + Check if the union tag is ``smart_sync_not_opt_out``. :rtype: bool """ - return self._tag == 'showcase_file_removed' + return self._tag == 'smart_sync_not_opt_out' - def is_showcase_file_view(self): + def is_smart_sync_opt_out(self): """ - Check if the union tag is ``showcase_file_view``. + Check if the union tag is ``smart_sync_opt_out``. :rtype: bool """ - return self._tag == 'showcase_file_view' + return self._tag == 'smart_sync_opt_out' - def is_showcase_permanently_deleted(self): + def is_sso_change_policy(self): """ - Check if the union tag is ``showcase_permanently_deleted``. + Check if the union tag is ``sso_change_policy``. :rtype: bool """ - return self._tag == 'showcase_permanently_deleted' + return self._tag == 'sso_change_policy' - def is_showcase_post_comment(self): + def is_team_extensions_policy_changed(self): """ - Check if the union tag is ``showcase_post_comment``. + Check if the union tag is ``team_extensions_policy_changed``. :rtype: bool """ - return self._tag == 'showcase_post_comment' + return self._tag == 'team_extensions_policy_changed' - def is_showcase_remove_member(self): + def is_team_selective_sync_policy_changed(self): """ - Check if the union tag is ``showcase_remove_member``. + Check if the union tag is ``team_selective_sync_policy_changed``. :rtype: bool """ - return self._tag == 'showcase_remove_member' + return self._tag == 'team_selective_sync_policy_changed' - def is_showcase_renamed(self): + def is_team_sharing_whitelist_subjects_changed(self): """ - Check if the union tag is ``showcase_renamed``. + Check if the union tag is ``team_sharing_whitelist_subjects_changed``. :rtype: bool """ - return self._tag == 'showcase_renamed' + return self._tag == 'team_sharing_whitelist_subjects_changed' - def is_showcase_request_access(self): + def is_tfa_add_exception(self): """ - Check if the union tag is ``showcase_request_access``. + Check if the union tag is ``tfa_add_exception``. :rtype: bool """ - return self._tag == 'showcase_request_access' + return self._tag == 'tfa_add_exception' - def is_showcase_resolve_comment(self): + def is_tfa_change_policy(self): """ - Check if the union tag is ``showcase_resolve_comment``. + Check if the union tag is ``tfa_change_policy``. :rtype: bool """ - return self._tag == 'showcase_resolve_comment' + return self._tag == 'tfa_change_policy' - def is_showcase_restored(self): + def is_tfa_remove_exception(self): """ - Check if the union tag is ``showcase_restored``. + Check if the union tag is ``tfa_remove_exception``. :rtype: bool """ - return self._tag == 'showcase_restored' + return self._tag == 'tfa_remove_exception' - def is_showcase_trashed(self): + def is_two_account_change_policy(self): """ - Check if the union tag is ``showcase_trashed``. + Check if the union tag is ``two_account_change_policy``. :rtype: bool """ - return self._tag == 'showcase_trashed' + return self._tag == 'two_account_change_policy' - def is_showcase_trashed_deprecated(self): + def is_viewer_info_policy_changed(self): """ - Check if the union tag is ``showcase_trashed_deprecated``. + Check if the union tag is ``viewer_info_policy_changed``. :rtype: bool """ - return self._tag == 'showcase_trashed_deprecated' + return self._tag == 'viewer_info_policy_changed' - def is_showcase_unresolve_comment(self): + def is_watermarking_policy_changed(self): """ - Check if the union tag is ``showcase_unresolve_comment``. + Check if the union tag is ``watermarking_policy_changed``. :rtype: bool """ - return self._tag == 'showcase_unresolve_comment' + return self._tag == 'watermarking_policy_changed' - def is_showcase_untrashed(self): + def is_web_sessions_change_active_session_limit(self): """ - Check if the union tag is ``showcase_untrashed``. + Check if the union tag is ``web_sessions_change_active_session_limit``. :rtype: bool """ - return self._tag == 'showcase_untrashed' + return self._tag == 'web_sessions_change_active_session_limit' - def is_showcase_untrashed_deprecated(self): + def is_web_sessions_change_fixed_length_policy(self): """ - Check if the union tag is ``showcase_untrashed_deprecated``. + Check if the union tag is ``web_sessions_change_fixed_length_policy``. :rtype: bool """ - return self._tag == 'showcase_untrashed_deprecated' + return self._tag == 'web_sessions_change_fixed_length_policy' - def is_showcase_view(self): + def is_web_sessions_change_idle_length_policy(self): """ - Check if the union tag is ``showcase_view``. + Check if the union tag is ``web_sessions_change_idle_length_policy``. :rtype: bool """ - return self._tag == 'showcase_view' + return self._tag == 'web_sessions_change_idle_length_policy' - def is_sso_add_cert(self): + def is_team_merge_from(self): """ - Check if the union tag is ``sso_add_cert``. + Check if the union tag is ``team_merge_from``. :rtype: bool """ - return self._tag == 'sso_add_cert' + return self._tag == 'team_merge_from' - def is_sso_add_login_url(self): + def is_team_merge_to(self): """ - Check if the union tag is ``sso_add_login_url``. + Check if the union tag is ``team_merge_to``. :rtype: bool """ - return self._tag == 'sso_add_login_url' + return self._tag == 'team_merge_to' - def is_sso_add_logout_url(self): + def is_team_profile_add_logo(self): """ - Check if the union tag is ``sso_add_logout_url``. + Check if the union tag is ``team_profile_add_logo``. :rtype: bool """ - return self._tag == 'sso_add_logout_url' + return self._tag == 'team_profile_add_logo' - def is_sso_change_cert(self): + def is_team_profile_change_default_language(self): """ - Check if the union tag is ``sso_change_cert``. + Check if the union tag is ``team_profile_change_default_language``. :rtype: bool """ - return self._tag == 'sso_change_cert' + return self._tag == 'team_profile_change_default_language' - def is_sso_change_login_url(self): + def is_team_profile_change_logo(self): """ - Check if the union tag is ``sso_change_login_url``. + Check if the union tag is ``team_profile_change_logo``. :rtype: bool """ - return self._tag == 'sso_change_login_url' + return self._tag == 'team_profile_change_logo' - def is_sso_change_logout_url(self): + def is_team_profile_change_name(self): """ - Check if the union tag is ``sso_change_logout_url``. + Check if the union tag is ``team_profile_change_name``. :rtype: bool """ - return self._tag == 'sso_change_logout_url' + return self._tag == 'team_profile_change_name' - def is_sso_change_saml_identity_mode(self): + def is_team_profile_remove_logo(self): """ - Check if the union tag is ``sso_change_saml_identity_mode``. + Check if the union tag is ``team_profile_remove_logo``. :rtype: bool """ - return self._tag == 'sso_change_saml_identity_mode' + return self._tag == 'team_profile_remove_logo' - def is_sso_remove_cert(self): + def is_tfa_add_backup_phone(self): """ - Check if the union tag is ``sso_remove_cert``. + Check if the union tag is ``tfa_add_backup_phone``. :rtype: bool """ - return self._tag == 'sso_remove_cert' + return self._tag == 'tfa_add_backup_phone' - def is_sso_remove_login_url(self): + def is_tfa_add_security_key(self): """ - Check if the union tag is ``sso_remove_login_url``. + Check if the union tag is ``tfa_add_security_key``. :rtype: bool """ - return self._tag == 'sso_remove_login_url' + return self._tag == 'tfa_add_security_key' - def is_sso_remove_logout_url(self): + def is_tfa_change_backup_phone(self): """ - Check if the union tag is ``sso_remove_logout_url``. + Check if the union tag is ``tfa_change_backup_phone``. :rtype: bool """ - return self._tag == 'sso_remove_logout_url' + return self._tag == 'tfa_change_backup_phone' - def is_team_folder_change_status(self): + def is_tfa_change_status(self): """ - Check if the union tag is ``team_folder_change_status``. + Check if the union tag is ``tfa_change_status``. :rtype: bool """ - return self._tag == 'team_folder_change_status' + return self._tag == 'tfa_change_status' - def is_team_folder_create(self): + def is_tfa_remove_backup_phone(self): """ - Check if the union tag is ``team_folder_create``. + Check if the union tag is ``tfa_remove_backup_phone``. :rtype: bool """ - return self._tag == 'team_folder_create' + return self._tag == 'tfa_remove_backup_phone' - def is_team_folder_downgrade(self): + def is_tfa_remove_security_key(self): """ - Check if the union tag is ``team_folder_downgrade``. + Check if the union tag is ``tfa_remove_security_key``. :rtype: bool """ - return self._tag == 'team_folder_downgrade' + return self._tag == 'tfa_remove_security_key' - def is_team_folder_permanently_delete(self): + def is_tfa_reset(self): """ - Check if the union tag is ``team_folder_permanently_delete``. + Check if the union tag is ``tfa_reset``. :rtype: bool """ - return self._tag == 'team_folder_permanently_delete' + return self._tag == 'tfa_reset' - def is_team_folder_rename(self): + def is_changed_enterprise_admin_role(self): """ - Check if the union tag is ``team_folder_rename``. + Check if the union tag is ``changed_enterprise_admin_role``. :rtype: bool """ - return self._tag == 'team_folder_rename' + return self._tag == 'changed_enterprise_admin_role' - def is_team_selective_sync_settings_changed(self): + def is_changed_enterprise_connected_team_status(self): """ - Check if the union tag is ``team_selective_sync_settings_changed``. + Check if the union tag is ``changed_enterprise_connected_team_status``. :rtype: bool """ - return self._tag == 'team_selective_sync_settings_changed' + return self._tag == 'changed_enterprise_connected_team_status' - def is_account_capture_change_policy(self): + def is_ended_enterprise_admin_session(self): """ - Check if the union tag is ``account_capture_change_policy``. + Check if the union tag is ``ended_enterprise_admin_session``. :rtype: bool """ - return self._tag == 'account_capture_change_policy' + return self._tag == 'ended_enterprise_admin_session' - def is_allow_download_disabled(self): + def is_ended_enterprise_admin_session_deprecated(self): """ - Check if the union tag is ``allow_download_disabled``. + Check if the union tag is ``ended_enterprise_admin_session_deprecated``. :rtype: bool """ - return self._tag == 'allow_download_disabled' + return self._tag == 'ended_enterprise_admin_session_deprecated' - def is_allow_download_enabled(self): + def is_enterprise_settings_locking(self): """ - Check if the union tag is ``allow_download_enabled``. + Check if the union tag is ``enterprise_settings_locking``. :rtype: bool """ - return self._tag == 'allow_download_enabled' + return self._tag == 'enterprise_settings_locking' - def is_camera_uploads_policy_changed(self): + def is_guest_admin_change_status(self): """ - Check if the union tag is ``camera_uploads_policy_changed``. + Check if the union tag is ``guest_admin_change_status``. :rtype: bool """ - return self._tag == 'camera_uploads_policy_changed' + return self._tag == 'guest_admin_change_status' - def is_data_placement_restriction_change_policy(self): + def is_started_enterprise_admin_session(self): """ - Check if the union tag is ``data_placement_restriction_change_policy``. + Check if the union tag is ``started_enterprise_admin_session``. :rtype: bool """ - return self._tag == 'data_placement_restriction_change_policy' + return self._tag == 'started_enterprise_admin_session' - def is_data_placement_restriction_satisfy_policy(self): + def is_team_merge_request_accepted(self): """ - Check if the union tag is ``data_placement_restriction_satisfy_policy``. + Check if the union tag is ``team_merge_request_accepted``. :rtype: bool """ - return self._tag == 'data_placement_restriction_satisfy_policy' + return self._tag == 'team_merge_request_accepted' - def is_device_approvals_change_desktop_policy(self): + def is_team_merge_request_accepted_shown_to_primary_team(self): """ - Check if the union tag is ``device_approvals_change_desktop_policy``. + Check if the union tag is ``team_merge_request_accepted_shown_to_primary_team``. :rtype: bool """ - return self._tag == 'device_approvals_change_desktop_policy' + return self._tag == 'team_merge_request_accepted_shown_to_primary_team' - def is_device_approvals_change_mobile_policy(self): + def is_team_merge_request_accepted_shown_to_secondary_team(self): """ - Check if the union tag is ``device_approvals_change_mobile_policy``. + Check if the union tag is ``team_merge_request_accepted_shown_to_secondary_team``. :rtype: bool """ - return self._tag == 'device_approvals_change_mobile_policy' + return self._tag == 'team_merge_request_accepted_shown_to_secondary_team' - def is_device_approvals_change_overage_action(self): + def is_team_merge_request_auto_canceled(self): """ - Check if the union tag is ``device_approvals_change_overage_action``. + Check if the union tag is ``team_merge_request_auto_canceled``. :rtype: bool """ - return self._tag == 'device_approvals_change_overage_action' + return self._tag == 'team_merge_request_auto_canceled' - def is_device_approvals_change_unlink_action(self): + def is_team_merge_request_canceled(self): """ - Check if the union tag is ``device_approvals_change_unlink_action``. + Check if the union tag is ``team_merge_request_canceled``. :rtype: bool """ - return self._tag == 'device_approvals_change_unlink_action' + return self._tag == 'team_merge_request_canceled' - def is_directory_restrictions_add_members(self): + def is_team_merge_request_canceled_shown_to_primary_team(self): """ - Check if the union tag is ``directory_restrictions_add_members``. + Check if the union tag is ``team_merge_request_canceled_shown_to_primary_team``. :rtype: bool """ - return self._tag == 'directory_restrictions_add_members' + return self._tag == 'team_merge_request_canceled_shown_to_primary_team' - def is_directory_restrictions_remove_members(self): + def is_team_merge_request_canceled_shown_to_secondary_team(self): """ - Check if the union tag is ``directory_restrictions_remove_members``. + Check if the union tag is ``team_merge_request_canceled_shown_to_secondary_team``. :rtype: bool """ - return self._tag == 'directory_restrictions_remove_members' + return self._tag == 'team_merge_request_canceled_shown_to_secondary_team' - def is_emm_add_exception(self): + def is_team_merge_request_expired(self): """ - Check if the union tag is ``emm_add_exception``. + Check if the union tag is ``team_merge_request_expired``. :rtype: bool """ - return self._tag == 'emm_add_exception' + return self._tag == 'team_merge_request_expired' - def is_emm_change_policy(self): + def is_team_merge_request_expired_shown_to_primary_team(self): """ - Check if the union tag is ``emm_change_policy``. + Check if the union tag is ``team_merge_request_expired_shown_to_primary_team``. :rtype: bool """ - return self._tag == 'emm_change_policy' + return self._tag == 'team_merge_request_expired_shown_to_primary_team' - def is_emm_remove_exception(self): + def is_team_merge_request_expired_shown_to_secondary_team(self): """ - Check if the union tag is ``emm_remove_exception``. + Check if the union tag is ``team_merge_request_expired_shown_to_secondary_team``. :rtype: bool """ - return self._tag == 'emm_remove_exception' + return self._tag == 'team_merge_request_expired_shown_to_secondary_team' - def is_extended_version_history_change_policy(self): + def is_team_merge_request_rejected_shown_to_primary_team(self): """ - Check if the union tag is ``extended_version_history_change_policy``. + Check if the union tag is ``team_merge_request_rejected_shown_to_primary_team``. :rtype: bool """ - return self._tag == 'extended_version_history_change_policy' + return self._tag == 'team_merge_request_rejected_shown_to_primary_team' - def is_file_comments_change_policy(self): + def is_team_merge_request_rejected_shown_to_secondary_team(self): """ - Check if the union tag is ``file_comments_change_policy``. + Check if the union tag is ``team_merge_request_rejected_shown_to_secondary_team``. :rtype: bool """ - return self._tag == 'file_comments_change_policy' + return self._tag == 'team_merge_request_rejected_shown_to_secondary_team' - def is_file_requests_change_policy(self): + def is_team_merge_request_reminder(self): """ - Check if the union tag is ``file_requests_change_policy``. + Check if the union tag is ``team_merge_request_reminder``. :rtype: bool """ - return self._tag == 'file_requests_change_policy' + return self._tag == 'team_merge_request_reminder' - def is_file_requests_emails_enabled(self): + def is_team_merge_request_reminder_shown_to_primary_team(self): """ - Check if the union tag is ``file_requests_emails_enabled``. + Check if the union tag is ``team_merge_request_reminder_shown_to_primary_team``. :rtype: bool """ - return self._tag == 'file_requests_emails_enabled' + return self._tag == 'team_merge_request_reminder_shown_to_primary_team' - def is_file_requests_emails_restricted_to_team_only(self): + def is_team_merge_request_reminder_shown_to_secondary_team(self): """ - Check if the union tag is ``file_requests_emails_restricted_to_team_only``. + Check if the union tag is ``team_merge_request_reminder_shown_to_secondary_team``. :rtype: bool """ - return self._tag == 'file_requests_emails_restricted_to_team_only' + return self._tag == 'team_merge_request_reminder_shown_to_secondary_team' - def is_google_sso_change_policy(self): + def is_team_merge_request_revoked(self): """ - Check if the union tag is ``google_sso_change_policy``. + Check if the union tag is ``team_merge_request_revoked``. :rtype: bool """ - return self._tag == 'google_sso_change_policy' + return self._tag == 'team_merge_request_revoked' - def is_group_user_management_change_policy(self): + def is_team_merge_request_sent_shown_to_primary_team(self): """ - Check if the union tag is ``group_user_management_change_policy``. + Check if the union tag is ``team_merge_request_sent_shown_to_primary_team``. :rtype: bool """ - return self._tag == 'group_user_management_change_policy' + return self._tag == 'team_merge_request_sent_shown_to_primary_team' - def is_integration_policy_changed(self): + def is_team_merge_request_sent_shown_to_secondary_team(self): """ - Check if the union tag is ``integration_policy_changed``. + Check if the union tag is ``team_merge_request_sent_shown_to_secondary_team``. :rtype: bool """ - return self._tag == 'integration_policy_changed' + return self._tag == 'team_merge_request_sent_shown_to_secondary_team' - def is_member_requests_change_policy(self): + def is_other(self): """ - Check if the union tag is ``member_requests_change_policy``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'member_requests_change_policy' + return self._tag == 'other' - def is_member_space_limits_add_exception(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(EventTypeArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'EventTypeArg(%r, %r)' % (self._tag, self._value) + +EventTypeArg_validator = bv.Union(EventTypeArg) + +class ExportMembersReportDetails(bb.Struct): + """ + Created member data report. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExportMembersReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExportMembersReportDetails()' + +ExportMembersReportDetails_validator = bv.Struct(ExportMembersReportDetails) + +class ExportMembersReportFailDetails(bb.Struct): + """ + Failed to create members data report. + + :ivar team_log.ExportMembersReportFailDetails.failure_reason: Failure + reason. + """ + + __slots__ = [ + '_failure_reason_value', + '_failure_reason_present', + ] + + _has_required_fields = True + + def __init__(self, + failure_reason=None): + self._failure_reason_value = None + self._failure_reason_present = False + if failure_reason is not None: + self.failure_reason = failure_reason + + @property + def failure_reason(self): """ - Check if the union tag is ``member_space_limits_add_exception``. + Failure reason. - :rtype: bool + :rtype: team.TeamReportFailureReason """ - return self._tag == 'member_space_limits_add_exception' + if self._failure_reason_present: + return self._failure_reason_value + else: + raise AttributeError("missing required field 'failure_reason'") - def is_member_space_limits_change_caps_type_policy(self): + @failure_reason.setter + def failure_reason(self, val): + self._failure_reason_validator.validate_type_only(val) + self._failure_reason_value = val + self._failure_reason_present = True + + @failure_reason.deleter + def failure_reason(self): + self._failure_reason_value = None + self._failure_reason_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExportMembersReportFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExportMembersReportFailDetails(failure_reason={!r})'.format( + self._failure_reason_value, + ) + +ExportMembersReportFailDetails_validator = bv.Struct(ExportMembersReportFailDetails) + +class ExportMembersReportFailType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - Check if the union tag is ``member_space_limits_change_caps_type_policy``. + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :rtype: bool + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExportMembersReportFailType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExportMembersReportFailType(description={!r})'.format( + self._description_value, + ) + +ExportMembersReportFailType_validator = bv.Struct(ExportMembersReportFailType) + +class ExportMembersReportType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - return self._tag == 'member_space_limits_change_caps_type_policy' + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - def is_member_space_limits_change_policy(self): + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExportMembersReportType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ExportMembersReportType(description={!r})'.format( + self._description_value, + ) + +ExportMembersReportType_validator = bv.Struct(ExportMembersReportType) + +class ExtendedVersionHistoryChangePolicyDetails(bb.Struct): + """ + Accepted/opted out of extended version history. + + :ivar team_log.ExtendedVersionHistoryChangePolicyDetails.new_value: New + extended version history policy. + :ivar team_log.ExtendedVersionHistoryChangePolicyDetails.previous_value: + Previous extended version history policy. Might be missing due to + historical data gap. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): """ - Check if the union tag is ``member_space_limits_change_policy``. + New extended version history policy. - :rtype: bool + :rtype: ExtendedVersionHistoryPolicy """ - return self._tag == 'member_space_limits_change_policy' + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - def is_member_space_limits_remove_exception(self): + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): """ - Check if the union tag is ``member_space_limits_remove_exception``. + Previous extended version history policy. Might be missing due to + historical data gap. - :rtype: bool + :rtype: ExtendedVersionHistoryPolicy """ - return self._tag == 'member_space_limits_remove_exception' + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - def is_member_suggestions_change_policy(self): - """ - Check if the union tag is ``member_suggestions_change_policy``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExtendedVersionHistoryChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'member_suggestions_change_policy' + def __repr__(self): + return 'ExtendedVersionHistoryChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) - def is_microsoft_office_addin_change_policy(self): - """ - Check if the union tag is ``microsoft_office_addin_change_policy``. +ExtendedVersionHistoryChangePolicyDetails_validator = bv.Struct(ExtendedVersionHistoryChangePolicyDetails) - :rtype: bool - """ - return self._tag == 'microsoft_office_addin_change_policy' +class ExtendedVersionHistoryChangePolicyType(bb.Struct): - def is_network_control_change_policy(self): - """ - Check if the union tag is ``network_control_change_policy``. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: bool - """ - return self._tag == 'network_control_change_policy' + _has_required_fields = True - def is_paper_change_deployment_policy(self): - """ - Check if the union tag is ``paper_change_deployment_policy``. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: bool + @property + def description(self): """ - return self._tag == 'paper_change_deployment_policy' - - def is_paper_change_member_link_policy(self): + :rtype: str """ - Check if the union tag is ``paper_change_member_link_policy``. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - :rtype: bool - """ - return self._tag == 'paper_change_member_link_policy' + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - def is_paper_change_member_policy(self): - """ - Check if the union tag is ``paper_change_member_policy``. + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - :rtype: bool - """ - return self._tag == 'paper_change_member_policy' + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExtendedVersionHistoryChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) - def is_paper_change_policy(self): - """ - Check if the union tag is ``paper_change_policy``. + def __repr__(self): + return 'ExtendedVersionHistoryChangePolicyType(description={!r})'.format( + self._description_value, + ) - :rtype: bool - """ - return self._tag == 'paper_change_policy' +ExtendedVersionHistoryChangePolicyType_validator = bv.Struct(ExtendedVersionHistoryChangePolicyType) - def is_paper_default_folder_policy_changed(self): - """ - Check if the union tag is ``paper_default_folder_policy_changed``. +class ExtendedVersionHistoryPolicy(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - :rtype: bool - """ - return self._tag == 'paper_default_folder_policy_changed' + _catch_all = 'other' + # Attribute is overwritten below the class definition + explicitly_limited = None + # Attribute is overwritten below the class definition + explicitly_unlimited = None + # Attribute is overwritten below the class definition + implicitly_limited = None + # Attribute is overwritten below the class definition + implicitly_unlimited = None + # Attribute is overwritten below the class definition + other = None - def is_paper_desktop_policy_changed(self): + def is_explicitly_limited(self): """ - Check if the union tag is ``paper_desktop_policy_changed``. + Check if the union tag is ``explicitly_limited``. :rtype: bool """ - return self._tag == 'paper_desktop_policy_changed' + return self._tag == 'explicitly_limited' - def is_paper_enabled_users_group_addition(self): + def is_explicitly_unlimited(self): """ - Check if the union tag is ``paper_enabled_users_group_addition``. + Check if the union tag is ``explicitly_unlimited``. :rtype: bool """ - return self._tag == 'paper_enabled_users_group_addition' + return self._tag == 'explicitly_unlimited' - def is_paper_enabled_users_group_removal(self): + def is_implicitly_limited(self): """ - Check if the union tag is ``paper_enabled_users_group_removal``. + Check if the union tag is ``implicitly_limited``. :rtype: bool """ - return self._tag == 'paper_enabled_users_group_removal' + return self._tag == 'implicitly_limited' - def is_permanent_delete_change_policy(self): + def is_implicitly_unlimited(self): """ - Check if the union tag is ``permanent_delete_change_policy``. + Check if the union tag is ``implicitly_unlimited``. :rtype: bool """ - return self._tag == 'permanent_delete_change_policy' + return self._tag == 'implicitly_unlimited' - def is_reseller_support_change_policy(self): + def is_other(self): """ - Check if the union tag is ``reseller_support_change_policy``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'reseller_support_change_policy' + return self._tag == 'other' - def is_sharing_change_folder_join_policy(self): - """ - Check if the union tag is ``sharing_change_folder_join_policy``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExtendedVersionHistoryPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'sharing_change_folder_join_policy' + def __repr__(self): + return 'ExtendedVersionHistoryPolicy(%r, %r)' % (self._tag, self._value) - def is_sharing_change_link_policy(self): - """ - Check if the union tag is ``sharing_change_link_policy``. +ExtendedVersionHistoryPolicy_validator = bv.Union(ExtendedVersionHistoryPolicy) - :rtype: bool - """ - return self._tag == 'sharing_change_link_policy' +class ExternalUserLogInfo(bb.Struct): + """ + A user without a Dropbox account. - def is_sharing_change_member_policy(self): - """ - Check if the union tag is ``sharing_change_member_policy``. + :ivar team_log.ExternalUserLogInfo.user_identifier: An external user + identifier. + :ivar team_log.ExternalUserLogInfo.identifier_type: Identifier type. + """ - :rtype: bool - """ - return self._tag == 'sharing_change_member_policy' + __slots__ = [ + '_user_identifier_value', + '_user_identifier_present', + '_identifier_type_value', + '_identifier_type_present', + ] - def is_showcase_change_download_policy(self): - """ - Check if the union tag is ``showcase_change_download_policy``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'showcase_change_download_policy' + def __init__(self, + user_identifier=None, + identifier_type=None): + self._user_identifier_value = None + self._user_identifier_present = False + self._identifier_type_value = None + self._identifier_type_present = False + if user_identifier is not None: + self.user_identifier = user_identifier + if identifier_type is not None: + self.identifier_type = identifier_type - def is_showcase_change_enabled_policy(self): + @property + def user_identifier(self): """ - Check if the union tag is ``showcase_change_enabled_policy``. + An external user identifier. - :rtype: bool + :rtype: str """ - return self._tag == 'showcase_change_enabled_policy' + if self._user_identifier_present: + return self._user_identifier_value + else: + raise AttributeError("missing required field 'user_identifier'") - def is_showcase_change_external_sharing_policy(self): - """ - Check if the union tag is ``showcase_change_external_sharing_policy``. + @user_identifier.setter + def user_identifier(self, val): + val = self._user_identifier_validator.validate(val) + self._user_identifier_value = val + self._user_identifier_present = True - :rtype: bool - """ - return self._tag == 'showcase_change_external_sharing_policy' + @user_identifier.deleter + def user_identifier(self): + self._user_identifier_value = None + self._user_identifier_present = False - def is_smart_sync_change_policy(self): + @property + def identifier_type(self): """ - Check if the union tag is ``smart_sync_change_policy``. + Identifier type. - :rtype: bool + :rtype: IdentifierType """ - return self._tag == 'smart_sync_change_policy' + if self._identifier_type_present: + return self._identifier_type_value + else: + raise AttributeError("missing required field 'identifier_type'") - def is_smart_sync_not_opt_out(self): - """ - Check if the union tag is ``smart_sync_not_opt_out``. + @identifier_type.setter + def identifier_type(self, val): + self._identifier_type_validator.validate_type_only(val) + self._identifier_type_value = val + self._identifier_type_present = True - :rtype: bool - """ - return self._tag == 'smart_sync_not_opt_out' + @identifier_type.deleter + def identifier_type(self): + self._identifier_type_value = None + self._identifier_type_present = False - def is_smart_sync_opt_out(self): - """ - Check if the union tag is ``smart_sync_opt_out``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(ExternalUserLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'smart_sync_opt_out' + def __repr__(self): + return 'ExternalUserLogInfo(user_identifier={!r}, identifier_type={!r})'.format( + self._user_identifier_value, + self._identifier_type_value, + ) - def is_sso_change_policy(self): - """ - Check if the union tag is ``sso_change_policy``. +ExternalUserLogInfo_validator = bv.Struct(ExternalUserLogInfo) - :rtype: bool - """ - return self._tag == 'sso_change_policy' +class FailureDetailsLogInfo(bb.Struct): + """ + Provides details about a failure - def is_team_extensions_policy_changed(self): - """ - Check if the union tag is ``team_extensions_policy_changed``. + :ivar team_log.FailureDetailsLogInfo.user_friendly_message: A user friendly + explanation of the error. Might be missing due to historical data gap. + :ivar team_log.FailureDetailsLogInfo.technical_error_message: A technical + explanation of the error. This is relevant for some errors. + """ - :rtype: bool - """ - return self._tag == 'team_extensions_policy_changed' + __slots__ = [ + '_user_friendly_message_value', + '_user_friendly_message_present', + '_technical_error_message_value', + '_technical_error_message_present', + ] - def is_team_selective_sync_policy_changed(self): - """ - Check if the union tag is ``team_selective_sync_policy_changed``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'team_selective_sync_policy_changed' + def __init__(self, + user_friendly_message=None, + technical_error_message=None): + self._user_friendly_message_value = None + self._user_friendly_message_present = False + self._technical_error_message_value = None + self._technical_error_message_present = False + if user_friendly_message is not None: + self.user_friendly_message = user_friendly_message + if technical_error_message is not None: + self.technical_error_message = technical_error_message - def is_tfa_change_policy(self): + @property + def user_friendly_message(self): """ - Check if the union tag is ``tfa_change_policy``. + A user friendly explanation of the error. Might be missing due to + historical data gap. - :rtype: bool + :rtype: str """ - return self._tag == 'tfa_change_policy' + if self._user_friendly_message_present: + return self._user_friendly_message_value + else: + return None - def is_two_account_change_policy(self): - """ - Check if the union tag is ``two_account_change_policy``. + @user_friendly_message.setter + def user_friendly_message(self, val): + if val is None: + del self.user_friendly_message + return + val = self._user_friendly_message_validator.validate(val) + self._user_friendly_message_value = val + self._user_friendly_message_present = True - :rtype: bool - """ - return self._tag == 'two_account_change_policy' + @user_friendly_message.deleter + def user_friendly_message(self): + self._user_friendly_message_value = None + self._user_friendly_message_present = False - def is_viewer_info_policy_changed(self): + @property + def technical_error_message(self): """ - Check if the union tag is ``viewer_info_policy_changed``. + A technical explanation of the error. This is relevant for some errors. - :rtype: bool + :rtype: str """ - return self._tag == 'viewer_info_policy_changed' + if self._technical_error_message_present: + return self._technical_error_message_value + else: + return None - def is_web_sessions_change_fixed_length_policy(self): - """ - Check if the union tag is ``web_sessions_change_fixed_length_policy``. + @technical_error_message.setter + def technical_error_message(self, val): + if val is None: + del self.technical_error_message + return + val = self._technical_error_message_validator.validate(val) + self._technical_error_message_value = val + self._technical_error_message_present = True - :rtype: bool - """ - return self._tag == 'web_sessions_change_fixed_length_policy' + @technical_error_message.deleter + def technical_error_message(self): + self._technical_error_message_value = None + self._technical_error_message_present = False - def is_web_sessions_change_idle_length_policy(self): - """ - Check if the union tag is ``web_sessions_change_idle_length_policy``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FailureDetailsLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'web_sessions_change_idle_length_policy' + def __repr__(self): + return 'FailureDetailsLogInfo(user_friendly_message={!r}, technical_error_message={!r})'.format( + self._user_friendly_message_value, + self._technical_error_message_value, + ) - def is_team_merge_from(self): - """ - Check if the union tag is ``team_merge_from``. +FailureDetailsLogInfo_validator = bv.Struct(FailureDetailsLogInfo) - :rtype: bool - """ - return self._tag == 'team_merge_from' +class FedAdminRole(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - def is_team_merge_to(self): + _catch_all = 'other' + # Attribute is overwritten below the class definition + not_enterprise_admin = None + # Attribute is overwritten below the class definition + enterprise_admin = None + # Attribute is overwritten below the class definition + other = None + + def is_not_enterprise_admin(self): """ - Check if the union tag is ``team_merge_to``. + Check if the union tag is ``not_enterprise_admin``. :rtype: bool """ - return self._tag == 'team_merge_to' + return self._tag == 'not_enterprise_admin' - def is_team_profile_add_logo(self): + def is_enterprise_admin(self): """ - Check if the union tag is ``team_profile_add_logo``. + Check if the union tag is ``enterprise_admin``. :rtype: bool """ - return self._tag == 'team_profile_add_logo' + return self._tag == 'enterprise_admin' - def is_team_profile_change_default_language(self): + def is_other(self): """ - Check if the union tag is ``team_profile_change_default_language``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'team_profile_change_default_language' + return self._tag == 'other' - def is_team_profile_change_logo(self): - """ - Check if the union tag is ``team_profile_change_logo``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FedAdminRole, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'team_profile_change_logo' + def __repr__(self): + return 'FedAdminRole(%r, %r)' % (self._tag, self._value) - def is_team_profile_change_name(self): - """ - Check if the union tag is ``team_profile_change_name``. +FedAdminRole_validator = bv.Union(FedAdminRole) - :rtype: bool - """ - return self._tag == 'team_profile_change_name' +class FedExtraDetails(bb.Union): + """ + More details about the organization or team. - def is_team_profile_remove_logo(self): - """ - Check if the union tag is ``team_profile_remove_logo``. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - :rtype: bool - """ - return self._tag == 'team_profile_remove_logo' + :ivar TeamDetails FedExtraDetails.team: More details about the team. + :ivar OrganizationDetails FedExtraDetails.organization: More details about + the organization. + """ - def is_tfa_add_backup_phone(self): + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def team(cls, val): """ - Check if the union tag is ``tfa_add_backup_phone``. + Create an instance of this class set to the ``team`` tag with value + ``val``. - :rtype: bool + :param TeamDetails val: + :rtype: FedExtraDetails """ - return self._tag == 'tfa_add_backup_phone' + return cls('team', val) - def is_tfa_add_security_key(self): + @classmethod + def organization(cls, val): """ - Check if the union tag is ``tfa_add_security_key``. + Create an instance of this class set to the ``organization`` tag with + value ``val``. - :rtype: bool + :param OrganizationDetails val: + :rtype: FedExtraDetails """ - return self._tag == 'tfa_add_security_key' + return cls('organization', val) - def is_tfa_change_backup_phone(self): + def is_team(self): """ - Check if the union tag is ``tfa_change_backup_phone``. + Check if the union tag is ``team``. :rtype: bool """ - return self._tag == 'tfa_change_backup_phone' + return self._tag == 'team' - def is_tfa_change_status(self): + def is_organization(self): """ - Check if the union tag is ``tfa_change_status``. + Check if the union tag is ``organization``. :rtype: bool """ - return self._tag == 'tfa_change_status' + return self._tag == 'organization' - def is_tfa_remove_backup_phone(self): + def is_other(self): """ - Check if the union tag is ``tfa_remove_backup_phone``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'tfa_remove_backup_phone' + return self._tag == 'other' - def is_tfa_remove_security_key(self): + def get_team(self): """ - Check if the union tag is ``tfa_remove_security_key``. + More details about the team. - :rtype: bool - """ - return self._tag == 'tfa_remove_security_key' + Only call this if :meth:`is_team` is true. - def is_tfa_reset(self): + :rtype: TeamDetails """ - Check if the union tag is ``tfa_reset``. + if not self.is_team(): + raise AttributeError("tag 'team' not set") + return self._value - :rtype: bool + def get_organization(self): """ - return self._tag == 'tfa_reset' + More details about the organization. - def is_guest_admin_change_status(self): - """ - Check if the union tag is ``guest_admin_change_status``. + Only call this if :meth:`is_organization` is true. - :rtype: bool + :rtype: OrganizationDetails """ - return self._tag == 'guest_admin_change_status' + if not self.is_organization(): + raise AttributeError("tag 'organization' not set") + return self._value - def is_team_merge_request_accepted(self): - """ - Check if the union tag is ``team_merge_request_accepted``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FedExtraDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'team_merge_request_accepted' + def __repr__(self): + return 'FedExtraDetails(%r, %r)' % (self._tag, self._value) - def is_team_merge_request_accepted_shown_to_primary_team(self): - """ - Check if the union tag is ``team_merge_request_accepted_shown_to_primary_team``. +FedExtraDetails_validator = bv.Union(FedExtraDetails) - :rtype: bool - """ - return self._tag == 'team_merge_request_accepted_shown_to_primary_team' +class FedHandshakeAction(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - def is_team_merge_request_accepted_shown_to_secondary_team(self): + _catch_all = 'other' + # Attribute is overwritten below the class definition + invited = None + # Attribute is overwritten below the class definition + accepted_invite = None + # Attribute is overwritten below the class definition + rejected_invite = None + # Attribute is overwritten below the class definition + canceled_invite = None + # Attribute is overwritten below the class definition + removed_team = None + # Attribute is overwritten below the class definition + invite_expired = None + # Attribute is overwritten below the class definition + other = None + + def is_invited(self): """ - Check if the union tag is ``team_merge_request_accepted_shown_to_secondary_team``. + Check if the union tag is ``invited``. :rtype: bool """ - return self._tag == 'team_merge_request_accepted_shown_to_secondary_team' + return self._tag == 'invited' - def is_team_merge_request_auto_canceled(self): + def is_accepted_invite(self): """ - Check if the union tag is ``team_merge_request_auto_canceled``. + Check if the union tag is ``accepted_invite``. :rtype: bool """ - return self._tag == 'team_merge_request_auto_canceled' + return self._tag == 'accepted_invite' - def is_team_merge_request_canceled(self): + def is_rejected_invite(self): """ - Check if the union tag is ``team_merge_request_canceled``. + Check if the union tag is ``rejected_invite``. :rtype: bool """ - return self._tag == 'team_merge_request_canceled' + return self._tag == 'rejected_invite' - def is_team_merge_request_canceled_shown_to_primary_team(self): + def is_canceled_invite(self): """ - Check if the union tag is ``team_merge_request_canceled_shown_to_primary_team``. + Check if the union tag is ``canceled_invite``. :rtype: bool """ - return self._tag == 'team_merge_request_canceled_shown_to_primary_team' + return self._tag == 'canceled_invite' - def is_team_merge_request_canceled_shown_to_secondary_team(self): + def is_removed_team(self): """ - Check if the union tag is ``team_merge_request_canceled_shown_to_secondary_team``. + Check if the union tag is ``removed_team``. :rtype: bool """ - return self._tag == 'team_merge_request_canceled_shown_to_secondary_team' + return self._tag == 'removed_team' - def is_team_merge_request_expired(self): + def is_invite_expired(self): """ - Check if the union tag is ``team_merge_request_expired``. + Check if the union tag is ``invite_expired``. :rtype: bool """ - return self._tag == 'team_merge_request_expired' + return self._tag == 'invite_expired' - def is_team_merge_request_expired_shown_to_primary_team(self): + def is_other(self): """ - Check if the union tag is ``team_merge_request_expired_shown_to_primary_team``. + Check if the union tag is ``other``. :rtype: bool """ - return self._tag == 'team_merge_request_expired_shown_to_primary_team' + return self._tag == 'other' - def is_team_merge_request_expired_shown_to_secondary_team(self): - """ - Check if the union tag is ``team_merge_request_expired_shown_to_secondary_team``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FedHandshakeAction, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'team_merge_request_expired_shown_to_secondary_team' + def __repr__(self): + return 'FedHandshakeAction(%r, %r)' % (self._tag, self._value) - def is_team_merge_request_rejected_shown_to_primary_team(self): - """ - Check if the union tag is ``team_merge_request_rejected_shown_to_primary_team``. +FedHandshakeAction_validator = bv.Union(FedHandshakeAction) - :rtype: bool - """ - return self._tag == 'team_merge_request_rejected_shown_to_primary_team' +class FederationStatusChangeAdditionalInfo(bb.Union): + """ + Additional information about the organization or connected team - def is_team_merge_request_rejected_shown_to_secondary_team(self): - """ - Check if the union tag is ``team_merge_request_rejected_shown_to_secondary_team``. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - :rtype: bool - """ - return self._tag == 'team_merge_request_rejected_shown_to_secondary_team' + :ivar ConnectedTeamName + FederationStatusChangeAdditionalInfo.connected_team_name: The name of + the team. + :ivar NonTrustedTeamDetails + FederationStatusChangeAdditionalInfo.non_trusted_team_details: The email + to which the request was sent. + :ivar OrganizationName + FederationStatusChangeAdditionalInfo.organization_name: The name of the + organization. + """ - def is_team_merge_request_reminder(self): + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def connected_team_name(cls, val): """ - Check if the union tag is ``team_merge_request_reminder``. + Create an instance of this class set to the ``connected_team_name`` tag + with value ``val``. - :rtype: bool + :param ConnectedTeamName val: + :rtype: FederationStatusChangeAdditionalInfo """ - return self._tag == 'team_merge_request_reminder' + return cls('connected_team_name', val) - def is_team_merge_request_reminder_shown_to_primary_team(self): + @classmethod + def non_trusted_team_details(cls, val): """ - Check if the union tag is ``team_merge_request_reminder_shown_to_primary_team``. + Create an instance of this class set to the ``non_trusted_team_details`` + tag with value ``val``. - :rtype: bool + :param NonTrustedTeamDetails val: + :rtype: FederationStatusChangeAdditionalInfo """ - return self._tag == 'team_merge_request_reminder_shown_to_primary_team' + return cls('non_trusted_team_details', val) - def is_team_merge_request_reminder_shown_to_secondary_team(self): + @classmethod + def organization_name(cls, val): """ - Check if the union tag is ``team_merge_request_reminder_shown_to_secondary_team``. + Create an instance of this class set to the ``organization_name`` tag + with value ``val``. - :rtype: bool + :param OrganizationName val: + :rtype: FederationStatusChangeAdditionalInfo """ - return self._tag == 'team_merge_request_reminder_shown_to_secondary_team' + return cls('organization_name', val) - def is_team_merge_request_revoked(self): + def is_connected_team_name(self): """ - Check if the union tag is ``team_merge_request_revoked``. + Check if the union tag is ``connected_team_name``. :rtype: bool """ - return self._tag == 'team_merge_request_revoked' + return self._tag == 'connected_team_name' - def is_team_merge_request_sent_shown_to_primary_team(self): + def is_non_trusted_team_details(self): """ - Check if the union tag is ``team_merge_request_sent_shown_to_primary_team``. + Check if the union tag is ``non_trusted_team_details``. :rtype: bool """ - return self._tag == 'team_merge_request_sent_shown_to_primary_team' + return self._tag == 'non_trusted_team_details' - def is_team_merge_request_sent_shown_to_secondary_team(self): + def is_organization_name(self): """ - Check if the union tag is ``team_merge_request_sent_shown_to_secondary_team``. + Check if the union tag is ``organization_name``. :rtype: bool """ - return self._tag == 'team_merge_request_sent_shown_to_secondary_team' + return self._tag == 'organization_name' def is_other(self): """ @@ -25273,4266 +43328,5062 @@ def is_other(self): """ return self._tag == 'other' - def get_app_link_team(self): + def get_connected_team_name(self): """ - (apps) Linked app for team + The name of the team. - Only call this if :meth:`is_app_link_team` is true. + Only call this if :meth:`is_connected_team_name` is true. - :rtype: AppLinkTeamType + :rtype: ConnectedTeamName """ - if not self.is_app_link_team(): - raise AttributeError("tag 'app_link_team' not set") + if not self.is_connected_team_name(): + raise AttributeError("tag 'connected_team_name' not set") return self._value - def get_app_link_user(self): + def get_non_trusted_team_details(self): """ - (apps) Linked app for member + The email to which the request was sent. - Only call this if :meth:`is_app_link_user` is true. + Only call this if :meth:`is_non_trusted_team_details` is true. - :rtype: AppLinkUserType + :rtype: NonTrustedTeamDetails """ - if not self.is_app_link_user(): - raise AttributeError("tag 'app_link_user' not set") + if not self.is_non_trusted_team_details(): + raise AttributeError("tag 'non_trusted_team_details' not set") return self._value - def get_app_unlink_team(self): + def get_organization_name(self): """ - (apps) Unlinked app for team + The name of the organization. - Only call this if :meth:`is_app_unlink_team` is true. + Only call this if :meth:`is_organization_name` is true. - :rtype: AppUnlinkTeamType + :rtype: OrganizationName """ - if not self.is_app_unlink_team(): - raise AttributeError("tag 'app_unlink_team' not set") + if not self.is_organization_name(): + raise AttributeError("tag 'organization_name' not set") return self._value - def get_app_unlink_user(self): - """ - (apps) Unlinked app for member + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FederationStatusChangeAdditionalInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_app_unlink_user` is true. + def __repr__(self): + return 'FederationStatusChangeAdditionalInfo(%r, %r)' % (self._tag, self._value) - :rtype: AppUnlinkUserType - """ - if not self.is_app_unlink_user(): - raise AttributeError("tag 'app_unlink_user' not set") - return self._value +FederationStatusChangeAdditionalInfo_validator = bv.Union(FederationStatusChangeAdditionalInfo) - def get_integration_connected(self): - """ - (apps) Connected integration for member +class FileAddCommentDetails(bb.Struct): + """ + Added file comment. - Only call this if :meth:`is_integration_connected` is true. + :ivar team_log.FileAddCommentDetails.comment_text: Comment text. Might be + missing due to historical data gap. + """ - :rtype: IntegrationConnectedType - """ - if not self.is_integration_connected(): - raise AttributeError("tag 'integration_connected' not set") - return self._value + __slots__ = [ + '_comment_text_value', + '_comment_text_present', + ] - def get_integration_disconnected(self): - """ - (apps) Disconnected integration for member + _has_required_fields = False - Only call this if :meth:`is_integration_disconnected` is true. + def __init__(self, + comment_text=None): + self._comment_text_value = None + self._comment_text_present = False + if comment_text is not None: + self.comment_text = comment_text - :rtype: IntegrationDisconnectedType + @property + def comment_text(self): """ - if not self.is_integration_disconnected(): - raise AttributeError("tag 'integration_disconnected' not set") - return self._value + Comment text. Might be missing due to historical data gap. - def get_file_add_comment(self): + :rtype: str """ - (comments) Added file comment + if self._comment_text_present: + return self._comment_text_value + else: + return None - Only call this if :meth:`is_file_add_comment` is true. + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - :rtype: FileAddCommentType - """ - if not self.is_file_add_comment(): - raise AttributeError("tag 'file_add_comment' not set") - return self._value + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False - def get_file_change_comment_subscription(self): - """ - (comments) Subscribed to or unsubscribed from comment notifications for - file + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileAddCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_file_change_comment_subscription` is true. + def __repr__(self): + return 'FileAddCommentDetails(comment_text={!r})'.format( + self._comment_text_value, + ) - :rtype: FileChangeCommentSubscriptionType - """ - if not self.is_file_change_comment_subscription(): - raise AttributeError("tag 'file_change_comment_subscription' not set") - return self._value +FileAddCommentDetails_validator = bv.Struct(FileAddCommentDetails) - def get_file_delete_comment(self): - """ - (comments) Deleted file comment +class FileAddCommentType(bb.Struct): - Only call this if :meth:`is_file_delete_comment` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: FileDeleteCommentType - """ - if not self.is_file_delete_comment(): - raise AttributeError("tag 'file_delete_comment' not set") - return self._value + _has_required_fields = True - def get_file_edit_comment(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (comments) Edited file comment + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_file_edit_comment` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: FileEditCommentType - """ - if not self.is_file_edit_comment(): - raise AttributeError("tag 'file_edit_comment' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_file_like_comment(self): - """ - (comments) Liked file comment (deprecated, no longer logged) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileAddCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_file_like_comment` is true. + def __repr__(self): + return 'FileAddCommentType(description={!r})'.format( + self._description_value, + ) - :rtype: FileLikeCommentType - """ - if not self.is_file_like_comment(): - raise AttributeError("tag 'file_like_comment' not set") - return self._value +FileAddCommentType_validator = bv.Struct(FileAddCommentType) - def get_file_resolve_comment(self): - """ - (comments) Resolved file comment +class FileAddDetails(bb.Struct): + """ + Added files and/or folders. + """ - Only call this if :meth:`is_file_resolve_comment` is true. + __slots__ = [ + ] - :rtype: FileResolveCommentType - """ - if not self.is_file_resolve_comment(): - raise AttributeError("tag 'file_resolve_comment' not set") - return self._value + _has_required_fields = False - def get_file_unlike_comment(self): - """ - (comments) Unliked file comment (deprecated, no longer logged) + def __init__(self): + pass - Only call this if :meth:`is_file_unlike_comment` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileAddDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: FileUnlikeCommentType - """ - if not self.is_file_unlike_comment(): - raise AttributeError("tag 'file_unlike_comment' not set") - return self._value + def __repr__(self): + return 'FileAddDetails()' - def get_file_unresolve_comment(self): - """ - (comments) Unresolved file comment +FileAddDetails_validator = bv.Struct(FileAddDetails) - Only call this if :meth:`is_file_unresolve_comment` is true. +class FileAddType(bb.Struct): - :rtype: FileUnresolveCommentType - """ - if not self.is_file_unresolve_comment(): - raise AttributeError("tag 'file_unresolve_comment' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_device_change_ip_desktop(self): - """ - (devices) Changed IP address associated with active desktop session + _has_required_fields = True - Only call this if :meth:`is_device_change_ip_desktop` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: DeviceChangeIpDesktopType + @property + def description(self): """ - if not self.is_device_change_ip_desktop(): - raise AttributeError("tag 'device_change_ip_desktop' not set") - return self._value - - def get_device_change_ip_mobile(self): + :rtype: str """ - (devices) Changed IP address associated with active mobile session + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_device_change_ip_mobile` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: DeviceChangeIpMobileType - """ - if not self.is_device_change_ip_mobile(): - raise AttributeError("tag 'device_change_ip_mobile' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_device_change_ip_web(self): - """ - (devices) Changed IP address associated with active web session + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileAddType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_device_change_ip_web` is true. + def __repr__(self): + return 'FileAddType(description={!r})'.format( + self._description_value, + ) - :rtype: DeviceChangeIpWebType +FileAddType_validator = bv.Struct(FileAddType) + +class FileChangeCommentSubscriptionDetails(bb.Struct): + """ + Subscribed to or unsubscribed from comment notifications for file. + + :ivar team_log.FileChangeCommentSubscriptionDetails.new_value: New file + comment subscription. + :ivar team_log.FileChangeCommentSubscriptionDetails.previous_value: Previous + file comment subscription. Might be missing due to historical data gap. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): """ - if not self.is_device_change_ip_web(): - raise AttributeError("tag 'device_change_ip_web' not set") - return self._value + New file comment subscription. - def get_device_delete_on_unlink_fail(self): + :rtype: FileCommentNotificationPolicy """ - (devices) Failed to delete all files from unlinked device + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - Only call this if :meth:`is_device_delete_on_unlink_fail` is true. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - :rtype: DeviceDeleteOnUnlinkFailType + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): """ - if not self.is_device_delete_on_unlink_fail(): - raise AttributeError("tag 'device_delete_on_unlink_fail' not set") - return self._value + Previous file comment subscription. Might be missing due to historical + data gap. - def get_device_delete_on_unlink_success(self): + :rtype: FileCommentNotificationPolicy """ - (devices) Deleted all files from unlinked device + if self._previous_value_present: + return self._previous_value_value + else: + return None - Only call this if :meth:`is_device_delete_on_unlink_success` is true. + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - :rtype: DeviceDeleteOnUnlinkSuccessType - """ - if not self.is_device_delete_on_unlink_success(): - raise AttributeError("tag 'device_delete_on_unlink_success' not set") - return self._value + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - def get_device_link_fail(self): + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileChangeCommentSubscriptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileChangeCommentSubscriptionDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) + +FileChangeCommentSubscriptionDetails_validator = bv.Struct(FileChangeCommentSubscriptionDetails) + +class FileChangeCommentSubscriptionType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (devices) Failed to link device + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_device_link_fail` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileChangeCommentSubscriptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileChangeCommentSubscriptionType(description={!r})'.format( + self._description_value, + ) + +FileChangeCommentSubscriptionType_validator = bv.Struct(FileChangeCommentSubscriptionType) + +class FileCommentNotificationPolicy(bb.Union): + """ + Enable or disable file comments notifications + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - :rtype: DeviceLinkFailType + def is_disabled(self): """ - if not self.is_device_link_fail(): - raise AttributeError("tag 'device_link_fail' not set") - return self._value + Check if the union tag is ``disabled``. - def get_device_link_success(self): + :rtype: bool """ - (devices) Linked device - - Only call this if :meth:`is_device_link_success` is true. + return self._tag == 'disabled' - :rtype: DeviceLinkSuccessType + def is_enabled(self): """ - if not self.is_device_link_success(): - raise AttributeError("tag 'device_link_success' not set") - return self._value + Check if the union tag is ``enabled``. - def get_device_management_disabled(self): + :rtype: bool """ - (devices) Disabled device management (deprecated, no longer logged) - - Only call this if :meth:`is_device_management_disabled` is true. + return self._tag == 'enabled' - :rtype: DeviceManagementDisabledType + def is_other(self): """ - if not self.is_device_management_disabled(): - raise AttributeError("tag 'device_management_disabled' not set") - return self._value + Check if the union tag is ``other``. - def get_device_management_enabled(self): + :rtype: bool """ - (devices) Enabled device management (deprecated, no longer logged) + return self._tag == 'other' - Only call this if :meth:`is_device_management_enabled` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileCommentNotificationPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: DeviceManagementEnabledType - """ - if not self.is_device_management_enabled(): - raise AttributeError("tag 'device_management_enabled' not set") - return self._value + def __repr__(self): + return 'FileCommentNotificationPolicy(%r, %r)' % (self._tag, self._value) - def get_device_unlink(self): - """ - (devices) Disconnected device +FileCommentNotificationPolicy_validator = bv.Union(FileCommentNotificationPolicy) - Only call this if :meth:`is_device_unlink` is true. +class FileCommentsChangePolicyDetails(bb.Struct): + """ + Enabled/disabled commenting on team files. - :rtype: DeviceUnlinkType - """ - if not self.is_device_unlink(): - raise AttributeError("tag 'device_unlink' not set") - return self._value + :ivar team_log.FileCommentsChangePolicyDetails.new_value: New commenting on + team files policy. + :ivar team_log.FileCommentsChangePolicyDetails.previous_value: Previous + commenting on team files policy. Might be missing due to historical data + gap. + """ - def get_emm_refresh_auth_token(self): - """ - (devices) Refreshed auth token used for setting up EMM + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] - Only call this if :meth:`is_emm_refresh_auth_token` is true. + _has_required_fields = True - :rtype: EmmRefreshAuthTokenType - """ - if not self.is_emm_refresh_auth_token(): - raise AttributeError("tag 'emm_refresh_auth_token' not set") - return self._value + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value - def get_account_capture_change_availability(self): + @property + def new_value(self): """ - (domains) Granted/revoked option to enable account capture on team - domains - - Only call this if :meth:`is_account_capture_change_availability` is true. + New commenting on team files policy. - :rtype: AccountCaptureChangeAvailabilityType + :rtype: FileCommentsPolicy """ - if not self.is_account_capture_change_availability(): - raise AttributeError("tag 'account_capture_change_availability' not set") - return self._value + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - def get_account_capture_migrate_account(self): - """ - (domains) Account-captured user migrated account to team + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - Only call this if :meth:`is_account_capture_migrate_account` is true. + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - :rtype: AccountCaptureMigrateAccountType + @property + def previous_value(self): """ - if not self.is_account_capture_migrate_account(): - raise AttributeError("tag 'account_capture_migrate_account' not set") - return self._value + Previous commenting on team files policy. Might be missing due to + historical data gap. - def get_account_capture_notification_emails_sent(self): + :rtype: FileCommentsPolicy """ - (domains) Sent proactive account capture email to all unmanaged members - - Only call this if :meth:`is_account_capture_notification_emails_sent` is true. + if self._previous_value_present: + return self._previous_value_value + else: + return None - :rtype: AccountCaptureNotificationEmailsSentType - """ - if not self.is_account_capture_notification_emails_sent(): - raise AttributeError("tag 'account_capture_notification_emails_sent' not set") - return self._value + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - def get_account_capture_relinquish_account(self): - """ - (domains) Account-captured user changed account email to personal email + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - Only call this if :meth:`is_account_capture_relinquish_account` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileCommentsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: AccountCaptureRelinquishAccountType - """ - if not self.is_account_capture_relinquish_account(): - raise AttributeError("tag 'account_capture_relinquish_account' not set") - return self._value + def __repr__(self): + return 'FileCommentsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) - def get_disabled_domain_invites(self): - """ - (domains) Disabled domain invites (deprecated, no longer logged) +FileCommentsChangePolicyDetails_validator = bv.Struct(FileCommentsChangePolicyDetails) - Only call this if :meth:`is_disabled_domain_invites` is true. +class FileCommentsChangePolicyType(bb.Struct): - :rtype: DisabledDomainInvitesType - """ - if not self.is_disabled_domain_invites(): - raise AttributeError("tag 'disabled_domain_invites' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_domain_invites_approve_request_to_join_team(self): - """ - (domains) Approved user's request to join team + _has_required_fields = True - Only call this if :meth:`is_domain_invites_approve_request_to_join_team` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: DomainInvitesApproveRequestToJoinTeamType + @property + def description(self): """ - if not self.is_domain_invites_approve_request_to_join_team(): - raise AttributeError("tag 'domain_invites_approve_request_to_join_team' not set") - return self._value - - def get_domain_invites_decline_request_to_join_team(self): + :rtype: str """ - (domains) Declined user's request to join team + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_domain_invites_decline_request_to_join_team` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: DomainInvitesDeclineRequestToJoinTeamType - """ - if not self.is_domain_invites_decline_request_to_join_team(): - raise AttributeError("tag 'domain_invites_decline_request_to_join_team' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_domain_invites_email_existing_users(self): - """ - (domains) Sent domain invites to existing domain accounts (deprecated, - no longer logged) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileCommentsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_domain_invites_email_existing_users` is true. + def __repr__(self): + return 'FileCommentsChangePolicyType(description={!r})'.format( + self._description_value, + ) - :rtype: DomainInvitesEmailExistingUsersType - """ - if not self.is_domain_invites_email_existing_users(): - raise AttributeError("tag 'domain_invites_email_existing_users' not set") - return self._value +FileCommentsChangePolicyType_validator = bv.Struct(FileCommentsChangePolicyType) - def get_domain_invites_request_to_join_team(self): - """ - (domains) Requested to join team +class FileCommentsPolicy(bb.Union): + """ + File comments policy - Only call this if :meth:`is_domain_invites_request_to_join_team` is true. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - :rtype: DomainInvitesRequestToJoinTeamType - """ - if not self.is_domain_invites_request_to_join_team(): - raise AttributeError("tag 'domain_invites_request_to_join_team' not set") - return self._value + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - def get_domain_invites_set_invite_new_user_pref_to_no(self): + def is_disabled(self): """ - (domains) Disabled "Automatically invite new users" (deprecated, no - longer logged) - - Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_no` is true. + Check if the union tag is ``disabled``. - :rtype: DomainInvitesSetInviteNewUserPrefToNoType + :rtype: bool """ - if not self.is_domain_invites_set_invite_new_user_pref_to_no(): - raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_no' not set") - return self._value + return self._tag == 'disabled' - def get_domain_invites_set_invite_new_user_pref_to_yes(self): + def is_enabled(self): """ - (domains) Enabled "Automatically invite new users" (deprecated, no - longer logged) - - Only call this if :meth:`is_domain_invites_set_invite_new_user_pref_to_yes` is true. + Check if the union tag is ``enabled``. - :rtype: DomainInvitesSetInviteNewUserPrefToYesType + :rtype: bool """ - if not self.is_domain_invites_set_invite_new_user_pref_to_yes(): - raise AttributeError("tag 'domain_invites_set_invite_new_user_pref_to_yes' not set") - return self._value + return self._tag == 'enabled' - def get_domain_verification_add_domain_fail(self): + def is_other(self): """ - (domains) Failed to verify team domain - - Only call this if :meth:`is_domain_verification_add_domain_fail` is true. + Check if the union tag is ``other``. - :rtype: DomainVerificationAddDomainFailType + :rtype: bool """ - if not self.is_domain_verification_add_domain_fail(): - raise AttributeError("tag 'domain_verification_add_domain_fail' not set") - return self._value + return self._tag == 'other' - def get_domain_verification_add_domain_success(self): - """ - (domains) Verified team domain + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileCommentsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_domain_verification_add_domain_success` is true. + def __repr__(self): + return 'FileCommentsPolicy(%r, %r)' % (self._tag, self._value) - :rtype: DomainVerificationAddDomainSuccessType - """ - if not self.is_domain_verification_add_domain_success(): - raise AttributeError("tag 'domain_verification_add_domain_success' not set") - return self._value +FileCommentsPolicy_validator = bv.Union(FileCommentsPolicy) - def get_domain_verification_remove_domain(self): - """ - (domains) Removed domain from list of verified team domains +class FileCopyDetails(bb.Struct): + """ + Copied files and/or folders. - Only call this if :meth:`is_domain_verification_remove_domain` is true. + :ivar team_log.FileCopyDetails.relocate_action_details: Relocate action + details. + """ - :rtype: DomainVerificationRemoveDomainType - """ - if not self.is_domain_verification_remove_domain(): - raise AttributeError("tag 'domain_verification_remove_domain' not set") - return self._value + __slots__ = [ + '_relocate_action_details_value', + '_relocate_action_details_present', + ] - def get_enabled_domain_invites(self): - """ - (domains) Enabled domain invites (deprecated, no longer logged) + _has_required_fields = True - Only call this if :meth:`is_enabled_domain_invites` is true. + def __init__(self, + relocate_action_details=None): + self._relocate_action_details_value = None + self._relocate_action_details_present = False + if relocate_action_details is not None: + self.relocate_action_details = relocate_action_details - :rtype: EnabledDomainInvitesType + @property + def relocate_action_details(self): """ - if not self.is_enabled_domain_invites(): - raise AttributeError("tag 'enabled_domain_invites' not set") - return self._value + Relocate action details. - def get_create_folder(self): + :rtype: list of [RelocateAssetReferencesLogInfo] """ - (file_operations) Created folders (deprecated, no longer logged) + if self._relocate_action_details_present: + return self._relocate_action_details_value + else: + raise AttributeError("missing required field 'relocate_action_details'") - Only call this if :meth:`is_create_folder` is true. + @relocate_action_details.setter + def relocate_action_details(self, val): + val = self._relocate_action_details_validator.validate(val) + self._relocate_action_details_value = val + self._relocate_action_details_present = True - :rtype: CreateFolderType - """ - if not self.is_create_folder(): - raise AttributeError("tag 'create_folder' not set") - return self._value + @relocate_action_details.deleter + def relocate_action_details(self): + self._relocate_action_details_value = None + self._relocate_action_details_present = False - def get_file_add(self): - """ - (file_operations) Added files and/or folders + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileCopyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_file_add` is true. + def __repr__(self): + return 'FileCopyDetails(relocate_action_details={!r})'.format( + self._relocate_action_details_value, + ) - :rtype: FileAddType - """ - if not self.is_file_add(): - raise AttributeError("tag 'file_add' not set") - return self._value +FileCopyDetails_validator = bv.Struct(FileCopyDetails) - def get_file_copy(self): - """ - (file_operations) Copied files and/or folders +class FileCopyType(bb.Struct): - Only call this if :meth:`is_file_copy` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: FileCopyType - """ - if not self.is_file_copy(): - raise AttributeError("tag 'file_copy' not set") - return self._value + _has_required_fields = True - def get_file_delete(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (file_operations) Deleted files and/or folders + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_file_delete` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: FileDeleteType - """ - if not self.is_file_delete(): - raise AttributeError("tag 'file_delete' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_file_download(self): - """ - (file_operations) Downloaded files and/or folders + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileCopyType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_file_download` is true. + def __repr__(self): + return 'FileCopyType(description={!r})'.format( + self._description_value, + ) - :rtype: FileDownloadType - """ - if not self.is_file_download(): - raise AttributeError("tag 'file_download' not set") - return self._value +FileCopyType_validator = bv.Struct(FileCopyType) - def get_file_edit(self): - """ - (file_operations) Edited files +class FileDeleteCommentDetails(bb.Struct): + """ + Deleted file comment. - Only call this if :meth:`is_file_edit` is true. + :ivar team_log.FileDeleteCommentDetails.comment_text: Comment text. Might be + missing due to historical data gap. + """ - :rtype: FileEditType - """ - if not self.is_file_edit(): - raise AttributeError("tag 'file_edit' not set") - return self._value + __slots__ = [ + '_comment_text_value', + '_comment_text_present', + ] - def get_file_get_copy_reference(self): - """ - (file_operations) Created copy reference to file/folder + _has_required_fields = False - Only call this if :meth:`is_file_get_copy_reference` is true. + def __init__(self, + comment_text=None): + self._comment_text_value = None + self._comment_text_present = False + if comment_text is not None: + self.comment_text = comment_text - :rtype: FileGetCopyReferenceType + @property + def comment_text(self): """ - if not self.is_file_get_copy_reference(): - raise AttributeError("tag 'file_get_copy_reference' not set") - return self._value + Comment text. Might be missing due to historical data gap. - def get_file_move(self): + :rtype: str """ - (file_operations) Moved files and/or folders + if self._comment_text_present: + return self._comment_text_value + else: + return None + + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True + + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False - Only call this if :meth:`is_file_move` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileDeleteCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: FileMoveType - """ - if not self.is_file_move(): - raise AttributeError("tag 'file_move' not set") - return self._value + def __repr__(self): + return 'FileDeleteCommentDetails(comment_text={!r})'.format( + self._comment_text_value, + ) - def get_file_permanently_delete(self): - """ - (file_operations) Permanently deleted files and/or folders +FileDeleteCommentDetails_validator = bv.Struct(FileDeleteCommentDetails) - Only call this if :meth:`is_file_permanently_delete` is true. +class FileDeleteCommentType(bb.Struct): - :rtype: FilePermanentlyDeleteType - """ - if not self.is_file_permanently_delete(): - raise AttributeError("tag 'file_permanently_delete' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_file_preview(self): - """ - (file_operations) Previewed files and/or folders + _has_required_fields = True - Only call this if :meth:`is_file_preview` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: FilePreviewType + @property + def description(self): """ - if not self.is_file_preview(): - raise AttributeError("tag 'file_preview' not set") - return self._value - - def get_file_rename(self): + :rtype: str """ - (file_operations) Renamed files and/or folders + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_file_rename` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: FileRenameType - """ - if not self.is_file_rename(): - raise AttributeError("tag 'file_rename' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_file_restore(self): - """ - (file_operations) Restored deleted files and/or folders + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileDeleteCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_file_restore` is true. + def __repr__(self): + return 'FileDeleteCommentType(description={!r})'.format( + self._description_value, + ) - :rtype: FileRestoreType - """ - if not self.is_file_restore(): - raise AttributeError("tag 'file_restore' not set") - return self._value +FileDeleteCommentType_validator = bv.Struct(FileDeleteCommentType) - def get_file_revert(self): - """ - (file_operations) Reverted files to previous version +class FileDeleteDetails(bb.Struct): + """ + Deleted files and/or folders. + """ - Only call this if :meth:`is_file_revert` is true. + __slots__ = [ + ] - :rtype: FileRevertType - """ - if not self.is_file_revert(): - raise AttributeError("tag 'file_revert' not set") - return self._value + _has_required_fields = False - def get_file_rollback_changes(self): - """ - (file_operations) Rolled back file actions + def __init__(self): + pass - Only call this if :meth:`is_file_rollback_changes` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: FileRollbackChangesType - """ - if not self.is_file_rollback_changes(): - raise AttributeError("tag 'file_rollback_changes' not set") - return self._value + def __repr__(self): + return 'FileDeleteDetails()' - def get_file_save_copy_reference(self): - """ - (file_operations) Saved file/folder using copy reference +FileDeleteDetails_validator = bv.Struct(FileDeleteDetails) - Only call this if :meth:`is_file_save_copy_reference` is true. +class FileDeleteType(bb.Struct): - :rtype: FileSaveCopyReferenceType - """ - if not self.is_file_save_copy_reference(): - raise AttributeError("tag 'file_save_copy_reference' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_file_request_change(self): - """ - (file_requests) Changed file request + _has_required_fields = True - Only call this if :meth:`is_file_request_change` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: FileRequestChangeType + @property + def description(self): """ - if not self.is_file_request_change(): - raise AttributeError("tag 'file_request_change' not set") - return self._value - - def get_file_request_close(self): + :rtype: str """ - (file_requests) Closed file request + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_file_request_close` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: FileRequestCloseType - """ - if not self.is_file_request_close(): - raise AttributeError("tag 'file_request_close' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_file_request_create(self): - """ - (file_requests) Created file request + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_file_request_create` is true. + def __repr__(self): + return 'FileDeleteType(description={!r})'.format( + self._description_value, + ) - :rtype: FileRequestCreateType - """ - if not self.is_file_request_create(): - raise AttributeError("tag 'file_request_create' not set") - return self._value +FileDeleteType_validator = bv.Struct(FileDeleteType) - def get_file_request_delete(self): - """ - (file_requests) Delete file request +class FileDownloadDetails(bb.Struct): + """ + Downloaded files and/or folders. + """ - Only call this if :meth:`is_file_request_delete` is true. + __slots__ = [ + ] - :rtype: FileRequestDeleteType - """ - if not self.is_file_request_delete(): - raise AttributeError("tag 'file_request_delete' not set") - return self._value + _has_required_fields = False - def get_file_request_receive_file(self): - """ - (file_requests) Received files for file request + def __init__(self): + pass - Only call this if :meth:`is_file_request_receive_file` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: FileRequestReceiveFileType - """ - if not self.is_file_request_receive_file(): - raise AttributeError("tag 'file_request_receive_file' not set") - return self._value + def __repr__(self): + return 'FileDownloadDetails()' - def get_group_add_external_id(self): - """ - (groups) Added external ID for group +FileDownloadDetails_validator = bv.Struct(FileDownloadDetails) - Only call this if :meth:`is_group_add_external_id` is true. +class FileDownloadType(bb.Struct): - :rtype: GroupAddExternalIdType - """ - if not self.is_group_add_external_id(): - raise AttributeError("tag 'group_add_external_id' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_group_add_member(self): - """ - (groups) Added team members to group + _has_required_fields = True - Only call this if :meth:`is_group_add_member` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: GroupAddMemberType + @property + def description(self): """ - if not self.is_group_add_member(): - raise AttributeError("tag 'group_add_member' not set") - return self._value - - def get_group_change_external_id(self): + :rtype: str """ - (groups) Changed external ID for group + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_group_change_external_id` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: GroupChangeExternalIdType - """ - if not self.is_group_change_external_id(): - raise AttributeError("tag 'group_change_external_id' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_group_change_management_type(self): - """ - (groups) Changed group management type + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_group_change_management_type` is true. + def __repr__(self): + return 'FileDownloadType(description={!r})'.format( + self._description_value, + ) - :rtype: GroupChangeManagementTypeType - """ - if not self.is_group_change_management_type(): - raise AttributeError("tag 'group_change_management_type' not set") - return self._value +FileDownloadType_validator = bv.Struct(FileDownloadType) - def get_group_change_member_role(self): - """ - (groups) Changed manager permissions of group member +class FileEditCommentDetails(bb.Struct): + """ + Edited file comment. - Only call this if :meth:`is_group_change_member_role` is true. + :ivar team_log.FileEditCommentDetails.comment_text: Comment text. Might be + missing due to historical data gap. + :ivar team_log.FileEditCommentDetails.previous_comment_text: Previous + comment text. + """ - :rtype: GroupChangeMemberRoleType - """ - if not self.is_group_change_member_role(): - raise AttributeError("tag 'group_change_member_role' not set") - return self._value + __slots__ = [ + '_comment_text_value', + '_comment_text_present', + '_previous_comment_text_value', + '_previous_comment_text_present', + ] - def get_group_create(self): - """ - (groups) Created group + _has_required_fields = True - Only call this if :meth:`is_group_create` is true. + def __init__(self, + previous_comment_text=None, + comment_text=None): + self._comment_text_value = None + self._comment_text_present = False + self._previous_comment_text_value = None + self._previous_comment_text_present = False + if comment_text is not None: + self.comment_text = comment_text + if previous_comment_text is not None: + self.previous_comment_text = previous_comment_text - :rtype: GroupCreateType + @property + def comment_text(self): """ - if not self.is_group_create(): - raise AttributeError("tag 'group_create' not set") - return self._value + Comment text. Might be missing due to historical data gap. - def get_group_delete(self): + :rtype: str """ - (groups) Deleted group + if self._comment_text_present: + return self._comment_text_value + else: + return None - Only call this if :meth:`is_group_delete` is true. + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - :rtype: GroupDeleteType + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False + + @property + def previous_comment_text(self): """ - if not self.is_group_delete(): - raise AttributeError("tag 'group_delete' not set") - return self._value + Previous comment text. - def get_group_description_updated(self): + :rtype: str """ - (groups) Updated group (deprecated, no longer logged) + if self._previous_comment_text_present: + return self._previous_comment_text_value + else: + raise AttributeError("missing required field 'previous_comment_text'") - Only call this if :meth:`is_group_description_updated` is true. + @previous_comment_text.setter + def previous_comment_text(self, val): + val = self._previous_comment_text_validator.validate(val) + self._previous_comment_text_value = val + self._previous_comment_text_present = True - :rtype: GroupDescriptionUpdatedType - """ - if not self.is_group_description_updated(): - raise AttributeError("tag 'group_description_updated' not set") - return self._value + @previous_comment_text.deleter + def previous_comment_text(self): + self._previous_comment_text_value = None + self._previous_comment_text_present = False - def get_group_join_policy_updated(self): - """ - (groups) Updated group join policy (deprecated, no longer logged) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileEditCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_group_join_policy_updated` is true. + def __repr__(self): + return 'FileEditCommentDetails(previous_comment_text={!r}, comment_text={!r})'.format( + self._previous_comment_text_value, + self._comment_text_value, + ) - :rtype: GroupJoinPolicyUpdatedType - """ - if not self.is_group_join_policy_updated(): - raise AttributeError("tag 'group_join_policy_updated' not set") - return self._value +FileEditCommentDetails_validator = bv.Struct(FileEditCommentDetails) - def get_group_moved(self): - """ - (groups) Moved group (deprecated, no longer logged) +class FileEditCommentType(bb.Struct): - Only call this if :meth:`is_group_moved` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: GroupMovedType - """ - if not self.is_group_moved(): - raise AttributeError("tag 'group_moved' not set") - return self._value + _has_required_fields = True - def get_group_remove_external_id(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (groups) Removed external ID for group + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_group_remove_external_id` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: GroupRemoveExternalIdType - """ - if not self.is_group_remove_external_id(): - raise AttributeError("tag 'group_remove_external_id' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_group_remove_member(self): - """ - (groups) Removed team members from group + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileEditCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_group_remove_member` is true. + def __repr__(self): + return 'FileEditCommentType(description={!r})'.format( + self._description_value, + ) - :rtype: GroupRemoveMemberType - """ - if not self.is_group_remove_member(): - raise AttributeError("tag 'group_remove_member' not set") - return self._value +FileEditCommentType_validator = bv.Struct(FileEditCommentType) - def get_group_rename(self): - """ - (groups) Renamed group +class FileEditDetails(bb.Struct): + """ + Edited files. + """ - Only call this if :meth:`is_group_rename` is true. + __slots__ = [ + ] - :rtype: GroupRenameType - """ - if not self.is_group_rename(): - raise AttributeError("tag 'group_rename' not set") - return self._value + _has_required_fields = False - def get_emm_error(self): - """ - (logins) Failed to sign in via EMM (deprecated, replaced by 'Failed to - sign in') + def __init__(self): + pass - Only call this if :meth:`is_emm_error` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileEditDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: EmmErrorType - """ - if not self.is_emm_error(): - raise AttributeError("tag 'emm_error' not set") - return self._value + def __repr__(self): + return 'FileEditDetails()' - def get_guest_admin_signed_in_via_trusted_teams(self): - """ - (logins) Started trusted team admin session +FileEditDetails_validator = bv.Struct(FileEditDetails) - Only call this if :meth:`is_guest_admin_signed_in_via_trusted_teams` is true. +class FileEditType(bb.Struct): - :rtype: GuestAdminSignedInViaTrustedTeamsType - """ - if not self.is_guest_admin_signed_in_via_trusted_teams(): - raise AttributeError("tag 'guest_admin_signed_in_via_trusted_teams' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_guest_admin_signed_out_via_trusted_teams(self): - """ - (logins) Ended trusted team admin session + _has_required_fields = True - Only call this if :meth:`is_guest_admin_signed_out_via_trusted_teams` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: GuestAdminSignedOutViaTrustedTeamsType + @property + def description(self): """ - if not self.is_guest_admin_signed_out_via_trusted_teams(): - raise AttributeError("tag 'guest_admin_signed_out_via_trusted_teams' not set") - return self._value - - def get_login_fail(self): + :rtype: str """ - (logins) Failed to sign in + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_login_fail` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: LoginFailType - """ - if not self.is_login_fail(): - raise AttributeError("tag 'login_fail' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_login_success(self): - """ - (logins) Signed in + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileEditType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_login_success` is true. + def __repr__(self): + return 'FileEditType(description={!r})'.format( + self._description_value, + ) - :rtype: LoginSuccessType - """ - if not self.is_login_success(): - raise AttributeError("tag 'login_success' not set") - return self._value +FileEditType_validator = bv.Struct(FileEditType) - def get_logout(self): - """ - (logins) Signed out +class FileGetCopyReferenceDetails(bb.Struct): + """ + Created copy reference to file/folder. + """ - Only call this if :meth:`is_logout` is true. + __slots__ = [ + ] - :rtype: LogoutType - """ - if not self.is_logout(): - raise AttributeError("tag 'logout' not set") - return self._value + _has_required_fields = False - def get_reseller_support_session_end(self): - """ - (logins) Ended reseller support session + def __init__(self): + pass - Only call this if :meth:`is_reseller_support_session_end` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileGetCopyReferenceDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: ResellerSupportSessionEndType - """ - if not self.is_reseller_support_session_end(): - raise AttributeError("tag 'reseller_support_session_end' not set") - return self._value + def __repr__(self): + return 'FileGetCopyReferenceDetails()' - def get_reseller_support_session_start(self): - """ - (logins) Started reseller support session +FileGetCopyReferenceDetails_validator = bv.Struct(FileGetCopyReferenceDetails) - Only call this if :meth:`is_reseller_support_session_start` is true. +class FileGetCopyReferenceType(bb.Struct): - :rtype: ResellerSupportSessionStartType - """ - if not self.is_reseller_support_session_start(): - raise AttributeError("tag 'reseller_support_session_start' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_sign_in_as_session_end(self): - """ - (logins) Ended admin sign-in-as session + _has_required_fields = True - Only call this if :meth:`is_sign_in_as_session_end` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: SignInAsSessionEndType + @property + def description(self): """ - if not self.is_sign_in_as_session_end(): - raise AttributeError("tag 'sign_in_as_session_end' not set") - return self._value - - def get_sign_in_as_session_start(self): + :rtype: str """ - (logins) Started admin sign-in-as session + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_sign_in_as_session_start` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SignInAsSessionStartType - """ - if not self.is_sign_in_as_session_start(): - raise AttributeError("tag 'sign_in_as_session_start' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_sso_error(self): - """ - (logins) Failed to sign in via SSO (deprecated, replaced by 'Failed to - sign in') + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileGetCopyReferenceType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_sso_error` is true. + def __repr__(self): + return 'FileGetCopyReferenceType(description={!r})'.format( + self._description_value, + ) - :rtype: SsoErrorType - """ - if not self.is_sso_error(): - raise AttributeError("tag 'sso_error' not set") - return self._value +FileGetCopyReferenceType_validator = bv.Struct(FileGetCopyReferenceType) - def get_member_add_external_id(self): - """ - (members) Added an external ID for team member +class FileLikeCommentDetails(bb.Struct): + """ + Liked file comment. - Only call this if :meth:`is_member_add_external_id` is true. + :ivar team_log.FileLikeCommentDetails.comment_text: Comment text. Might be + missing due to historical data gap. + """ - :rtype: MemberAddExternalIdType - """ - if not self.is_member_add_external_id(): - raise AttributeError("tag 'member_add_external_id' not set") - return self._value + __slots__ = [ + '_comment_text_value', + '_comment_text_present', + ] - def get_member_add_name(self): - """ - (members) Added team member name + _has_required_fields = False - Only call this if :meth:`is_member_add_name` is true. + def __init__(self, + comment_text=None): + self._comment_text_value = None + self._comment_text_present = False + if comment_text is not None: + self.comment_text = comment_text - :rtype: MemberAddNameType + @property + def comment_text(self): """ - if not self.is_member_add_name(): - raise AttributeError("tag 'member_add_name' not set") - return self._value + Comment text. Might be missing due to historical data gap. - def get_member_change_admin_role(self): + :rtype: str """ - (members) Changed team member admin role + if self._comment_text_present: + return self._comment_text_value + else: + return None - Only call this if :meth:`is_member_change_admin_role` is true. + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - :rtype: MemberChangeAdminRoleType - """ - if not self.is_member_change_admin_role(): - raise AttributeError("tag 'member_change_admin_role' not set") - return self._value + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False - def get_member_change_email(self): - """ - (members) Changed team member email + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLikeCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_member_change_email` is true. + def __repr__(self): + return 'FileLikeCommentDetails(comment_text={!r})'.format( + self._comment_text_value, + ) - :rtype: MemberChangeEmailType - """ - if not self.is_member_change_email(): - raise AttributeError("tag 'member_change_email' not set") - return self._value +FileLikeCommentDetails_validator = bv.Struct(FileLikeCommentDetails) - def get_member_change_external_id(self): - """ - (members) Changed the external ID for team member +class FileLikeCommentType(bb.Struct): - Only call this if :meth:`is_member_change_external_id` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: MemberChangeExternalIdType - """ - if not self.is_member_change_external_id(): - raise AttributeError("tag 'member_change_external_id' not set") - return self._value + _has_required_fields = True - def get_member_change_membership_type(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (members) Changed membership type (limited/full) of member (deprecated, - no longer logged) + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_member_change_membership_type` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: MemberChangeMembershipTypeType - """ - if not self.is_member_change_membership_type(): - raise AttributeError("tag 'member_change_membership_type' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_member_change_name(self): - """ - (members) Changed team member name + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLikeCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_member_change_name` is true. + def __repr__(self): + return 'FileLikeCommentType(description={!r})'.format( + self._description_value, + ) - :rtype: MemberChangeNameType - """ - if not self.is_member_change_name(): - raise AttributeError("tag 'member_change_name' not set") - return self._value +FileLikeCommentType_validator = bv.Struct(FileLikeCommentType) - def get_member_change_status(self): - """ - (members) Changed member status (invited, joined, suspended, etc.) +class FileLockingLockStatusChangedDetails(bb.Struct): + """ + Locked/unlocked editing for a file. - Only call this if :meth:`is_member_change_status` is true. + :ivar team_log.FileLockingLockStatusChangedDetails.previous_value: Previous + lock status of the file. + :ivar team_log.FileLockingLockStatusChangedDetails.new_value: New lock + status of the file. + """ - :rtype: MemberChangeStatusType - """ - if not self.is_member_change_status(): - raise AttributeError("tag 'member_change_status' not set") - return self._value + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] - def get_member_delete_manual_contacts(self): - """ - (members) Cleared manually added contacts + _has_required_fields = True - Only call this if :meth:`is_member_delete_manual_contacts` is true. + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value - :rtype: MemberDeleteManualContactsType + @property + def previous_value(self): """ - if not self.is_member_delete_manual_contacts(): - raise AttributeError("tag 'member_delete_manual_contacts' not set") - return self._value + Previous lock status of the file. - def get_member_permanently_delete_account_contents(self): + :rtype: LockStatus """ - (members) Permanently deleted contents of deleted team member account + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") - Only call this if :meth:`is_member_permanently_delete_account_contents` is true. + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - :rtype: MemberPermanentlyDeleteAccountContentsType + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + @property + def new_value(self): """ - if not self.is_member_permanently_delete_account_contents(): - raise AttributeError("tag 'member_permanently_delete_account_contents' not set") - return self._value + New lock status of the file. - def get_member_remove_external_id(self): + :rtype: LockStatus """ - (members) Removed the external ID for team member + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - Only call this if :meth:`is_member_remove_external_id` is true. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - :rtype: MemberRemoveExternalIdType - """ - if not self.is_member_remove_external_id(): - raise AttributeError("tag 'member_remove_external_id' not set") - return self._value + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - def get_member_space_limits_add_custom_quota(self): - """ - (members) Set custom member space limit + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockingLockStatusChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_member_space_limits_add_custom_quota` is true. + def __repr__(self): + return 'FileLockingLockStatusChangedDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, + ) - :rtype: MemberSpaceLimitsAddCustomQuotaType - """ - if not self.is_member_space_limits_add_custom_quota(): - raise AttributeError("tag 'member_space_limits_add_custom_quota' not set") - return self._value +FileLockingLockStatusChangedDetails_validator = bv.Struct(FileLockingLockStatusChangedDetails) - def get_member_space_limits_change_custom_quota(self): - """ - (members) Changed custom member space limit +class FileLockingLockStatusChangedType(bb.Struct): - Only call this if :meth:`is_member_space_limits_change_custom_quota` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: MemberSpaceLimitsChangeCustomQuotaType - """ - if not self.is_member_space_limits_change_custom_quota(): - raise AttributeError("tag 'member_space_limits_change_custom_quota' not set") - return self._value + _has_required_fields = True - def get_member_space_limits_change_status(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (members) Changed space limit status + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_member_space_limits_change_status` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: MemberSpaceLimitsChangeStatusType - """ - if not self.is_member_space_limits_change_status(): - raise AttributeError("tag 'member_space_limits_change_status' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_member_space_limits_remove_custom_quota(self): - """ - (members) Removed custom member space limit + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockingLockStatusChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_member_space_limits_remove_custom_quota` is true. + def __repr__(self): + return 'FileLockingLockStatusChangedType(description={!r})'.format( + self._description_value, + ) - :rtype: MemberSpaceLimitsRemoveCustomQuotaType - """ - if not self.is_member_space_limits_remove_custom_quota(): - raise AttributeError("tag 'member_space_limits_remove_custom_quota' not set") - return self._value +FileLockingLockStatusChangedType_validator = bv.Struct(FileLockingLockStatusChangedType) - def get_member_suggest(self): - """ - (members) Suggested person to add to team +class FileLockingPolicyChangedDetails(bb.Struct): + """ + Changed file locking policy for team. - Only call this if :meth:`is_member_suggest` is true. + :ivar team_log.FileLockingPolicyChangedDetails.new_value: New file locking + policy. + :ivar team_log.FileLockingPolicyChangedDetails.previous_value: Previous file + locking policy. + """ - :rtype: MemberSuggestType - """ - if not self.is_member_suggest(): - raise AttributeError("tag 'member_suggest' not set") - return self._value + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] - def get_member_transfer_account_contents(self): - """ - (members) Transferred contents of deleted member account to another - member + _has_required_fields = True - Only call this if :meth:`is_member_transfer_account_contents` is true. + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value - :rtype: MemberTransferAccountContentsType + @property + def new_value(self): """ - if not self.is_member_transfer_account_contents(): - raise AttributeError("tag 'member_transfer_account_contents' not set") - return self._value + New file locking policy. - def get_secondary_mails_policy_changed(self): + :rtype: team_policies.FileLockingPolicyState """ - (members) Secondary mails policy changed + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - Only call this if :meth:`is_secondary_mails_policy_changed` is true. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - :rtype: SecondaryMailsPolicyChangedType + @property + def previous_value(self): """ - if not self.is_secondary_mails_policy_changed(): - raise AttributeError("tag 'secondary_mails_policy_changed' not set") - return self._value + Previous file locking policy. - def get_paper_content_add_member(self): + :rtype: team_policies.FileLockingPolicyState """ - (paper) Added team member to Paper doc/folder - - Only call this if :meth:`is_paper_content_add_member` is true. + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") - :rtype: PaperContentAddMemberType - """ - if not self.is_paper_content_add_member(): - raise AttributeError("tag 'paper_content_add_member' not set") - return self._value + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - def get_paper_content_add_to_folder(self): - """ - (paper) Added Paper doc/folder to folder + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - Only call this if :meth:`is_paper_content_add_to_folder` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockingPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: PaperContentAddToFolderType - """ - if not self.is_paper_content_add_to_folder(): - raise AttributeError("tag 'paper_content_add_to_folder' not set") - return self._value + def __repr__(self): + return 'FileLockingPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) - def get_paper_content_archive(self): - """ - (paper) Archived Paper doc/folder +FileLockingPolicyChangedDetails_validator = bv.Struct(FileLockingPolicyChangedDetails) - Only call this if :meth:`is_paper_content_archive` is true. +class FileLockingPolicyChangedType(bb.Struct): - :rtype: PaperContentArchiveType - """ - if not self.is_paper_content_archive(): - raise AttributeError("tag 'paper_content_archive' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_paper_content_create(self): - """ - (paper) Created Paper doc/folder + _has_required_fields = True - Only call this if :meth:`is_paper_content_create` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: PaperContentCreateType + @property + def description(self): """ - if not self.is_paper_content_create(): - raise AttributeError("tag 'paper_content_create' not set") - return self._value - - def get_paper_content_permanently_delete(self): + :rtype: str """ - (paper) Permanently deleted Paper doc/folder + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_paper_content_permanently_delete` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: PaperContentPermanentlyDeleteType - """ - if not self.is_paper_content_permanently_delete(): - raise AttributeError("tag 'paper_content_permanently_delete' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_paper_content_remove_from_folder(self): - """ - (paper) Removed Paper doc/folder from folder + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockingPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_paper_content_remove_from_folder` is true. + def __repr__(self): + return 'FileLockingPolicyChangedType(description={!r})'.format( + self._description_value, + ) - :rtype: PaperContentRemoveFromFolderType - """ - if not self.is_paper_content_remove_from_folder(): - raise AttributeError("tag 'paper_content_remove_from_folder' not set") - return self._value +FileLockingPolicyChangedType_validator = bv.Struct(FileLockingPolicyChangedType) - def get_paper_content_remove_member(self): - """ - (paper) Removed team member from Paper doc/folder +class FileOrFolderLogInfo(bb.Struct): + """ + Generic information relevant both for files and folders - Only call this if :meth:`is_paper_content_remove_member` is true. + :ivar team_log.FileOrFolderLogInfo.path: Path relative to event context. + :ivar team_log.FileOrFolderLogInfo.display_name: Display name. Might be + missing due to historical data gap. + :ivar team_log.FileOrFolderLogInfo.file_id: Unique ID. Might be missing due + to historical data gap. + :ivar team_log.FileOrFolderLogInfo.file_size: File or folder size in bytes. + """ - :rtype: PaperContentRemoveMemberType - """ - if not self.is_paper_content_remove_member(): - raise AttributeError("tag 'paper_content_remove_member' not set") - return self._value + __slots__ = [ + '_path_value', + '_path_present', + '_display_name_value', + '_display_name_present', + '_file_id_value', + '_file_id_present', + '_file_size_value', + '_file_size_present', + ] - def get_paper_content_rename(self): - """ - (paper) Renamed Paper doc/folder + _has_required_fields = True - Only call this if :meth:`is_paper_content_rename` is true. + def __init__(self, + path=None, + display_name=None, + file_id=None, + file_size=None): + self._path_value = None + self._path_present = False + self._display_name_value = None + self._display_name_present = False + self._file_id_value = None + self._file_id_present = False + self._file_size_value = None + self._file_size_present = False + if path is not None: + self.path = path + if display_name is not None: + self.display_name = display_name + if file_id is not None: + self.file_id = file_id + if file_size is not None: + self.file_size = file_size - :rtype: PaperContentRenameType + @property + def path(self): """ - if not self.is_paper_content_rename(): - raise AttributeError("tag 'paper_content_rename' not set") - return self._value + Path relative to event context. - def get_paper_content_restore(self): + :rtype: PathLogInfo """ - (paper) Restored archived Paper doc/folder + if self._path_present: + return self._path_value + else: + raise AttributeError("missing required field 'path'") - Only call this if :meth:`is_paper_content_restore` is true. + @path.setter + def path(self, val): + self._path_validator.validate_type_only(val) + self._path_value = val + self._path_present = True - :rtype: PaperContentRestoreType - """ - if not self.is_paper_content_restore(): - raise AttributeError("tag 'paper_content_restore' not set") - return self._value + @path.deleter + def path(self): + self._path_value = None + self._path_present = False - def get_paper_doc_add_comment(self): + @property + def display_name(self): """ - (paper) Added Paper doc comment - - Only call this if :meth:`is_paper_doc_add_comment` is true. + Display name. Might be missing due to historical data gap. - :rtype: PaperDocAddCommentType + :rtype: str """ - if not self.is_paper_doc_add_comment(): - raise AttributeError("tag 'paper_doc_add_comment' not set") - return self._value + if self._display_name_present: + return self._display_name_value + else: + return None - def get_paper_doc_change_member_role(self): - """ - (paper) Changed team member permissions for Paper doc + @display_name.setter + def display_name(self, val): + if val is None: + del self.display_name + return + val = self._display_name_validator.validate(val) + self._display_name_value = val + self._display_name_present = True - Only call this if :meth:`is_paper_doc_change_member_role` is true. + @display_name.deleter + def display_name(self): + self._display_name_value = None + self._display_name_present = False - :rtype: PaperDocChangeMemberRoleType + @property + def file_id(self): """ - if not self.is_paper_doc_change_member_role(): - raise AttributeError("tag 'paper_doc_change_member_role' not set") - return self._value + Unique ID. Might be missing due to historical data gap. - def get_paper_doc_change_sharing_policy(self): + :rtype: str """ - (paper) Changed sharing setting for Paper doc + if self._file_id_present: + return self._file_id_value + else: + return None - Only call this if :meth:`is_paper_doc_change_sharing_policy` is true. + @file_id.setter + def file_id(self, val): + if val is None: + del self.file_id + return + val = self._file_id_validator.validate(val) + self._file_id_value = val + self._file_id_present = True - :rtype: PaperDocChangeSharingPolicyType - """ - if not self.is_paper_doc_change_sharing_policy(): - raise AttributeError("tag 'paper_doc_change_sharing_policy' not set") - return self._value + @file_id.deleter + def file_id(self): + self._file_id_value = None + self._file_id_present = False - def get_paper_doc_change_subscription(self): + @property + def file_size(self): """ - (paper) Followed/unfollowed Paper doc - - Only call this if :meth:`is_paper_doc_change_subscription` is true. + File or folder size in bytes. - :rtype: PaperDocChangeSubscriptionType + :rtype: int """ - if not self.is_paper_doc_change_subscription(): - raise AttributeError("tag 'paper_doc_change_subscription' not set") - return self._value + if self._file_size_present: + return self._file_size_value + else: + return None - def get_paper_doc_deleted(self): - """ - (paper) Archived Paper doc (deprecated, no longer logged) + @file_size.setter + def file_size(self, val): + if val is None: + del self.file_size + return + val = self._file_size_validator.validate(val) + self._file_size_value = val + self._file_size_present = True - Only call this if :meth:`is_paper_doc_deleted` is true. + @file_size.deleter + def file_size(self): + self._file_size_value = None + self._file_size_present = False - :rtype: PaperDocDeletedType - """ - if not self.is_paper_doc_deleted(): - raise AttributeError("tag 'paper_doc_deleted' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileOrFolderLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_paper_doc_delete_comment(self): - """ - (paper) Deleted Paper doc comment + def __repr__(self): + return 'FileOrFolderLogInfo(path={!r}, display_name={!r}, file_id={!r}, file_size={!r})'.format( + self._path_value, + self._display_name_value, + self._file_id_value, + self._file_size_value, + ) - Only call this if :meth:`is_paper_doc_delete_comment` is true. +FileOrFolderLogInfo_validator = bv.Struct(FileOrFolderLogInfo) - :rtype: PaperDocDeleteCommentType - """ - if not self.is_paper_doc_delete_comment(): - raise AttributeError("tag 'paper_doc_delete_comment' not set") - return self._value +class FileLogInfo(FileOrFolderLogInfo): + """ + File's logged information. + """ - def get_paper_doc_download(self): - """ - (paper) Downloaded Paper doc in specific format + __slots__ = [ + ] - Only call this if :meth:`is_paper_doc_download` is true. + _has_required_fields = True - :rtype: PaperDocDownloadType - """ - if not self.is_paper_doc_download(): - raise AttributeError("tag 'paper_doc_download' not set") - return self._value + def __init__(self, + path=None, + display_name=None, + file_id=None, + file_size=None): + super(FileLogInfo, self).__init__(path, + display_name, + file_id, + file_size) - def get_paper_doc_edit(self): - """ - (paper) Edited Paper doc + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_paper_doc_edit` is true. + def __repr__(self): + return 'FileLogInfo(path={!r}, display_name={!r}, file_id={!r}, file_size={!r})'.format( + self._path_value, + self._display_name_value, + self._file_id_value, + self._file_size_value, + ) - :rtype: PaperDocEditType - """ - if not self.is_paper_doc_edit(): - raise AttributeError("tag 'paper_doc_edit' not set") - return self._value +FileLogInfo_validator = bv.Struct(FileLogInfo) - def get_paper_doc_edit_comment(self): - """ - (paper) Edited Paper doc comment +class FileMoveDetails(bb.Struct): + """ + Moved files and/or folders. - Only call this if :meth:`is_paper_doc_edit_comment` is true. + :ivar team_log.FileMoveDetails.relocate_action_details: Relocate action + details. + """ - :rtype: PaperDocEditCommentType - """ - if not self.is_paper_doc_edit_comment(): - raise AttributeError("tag 'paper_doc_edit_comment' not set") - return self._value + __slots__ = [ + '_relocate_action_details_value', + '_relocate_action_details_present', + ] - def get_paper_doc_followed(self): - """ - (paper) Followed Paper doc (deprecated, replaced by 'Followed/unfollowed - Paper doc') + _has_required_fields = True - Only call this if :meth:`is_paper_doc_followed` is true. + def __init__(self, + relocate_action_details=None): + self._relocate_action_details_value = None + self._relocate_action_details_present = False + if relocate_action_details is not None: + self.relocate_action_details = relocate_action_details - :rtype: PaperDocFollowedType + @property + def relocate_action_details(self): """ - if not self.is_paper_doc_followed(): - raise AttributeError("tag 'paper_doc_followed' not set") - return self._value + Relocate action details. - def get_paper_doc_mention(self): + :rtype: list of [RelocateAssetReferencesLogInfo] """ - (paper) Mentioned team member in Paper doc + if self._relocate_action_details_present: + return self._relocate_action_details_value + else: + raise AttributeError("missing required field 'relocate_action_details'") - Only call this if :meth:`is_paper_doc_mention` is true. + @relocate_action_details.setter + def relocate_action_details(self, val): + val = self._relocate_action_details_validator.validate(val) + self._relocate_action_details_value = val + self._relocate_action_details_present = True - :rtype: PaperDocMentionType - """ - if not self.is_paper_doc_mention(): - raise AttributeError("tag 'paper_doc_mention' not set") - return self._value + @relocate_action_details.deleter + def relocate_action_details(self): + self._relocate_action_details_value = None + self._relocate_action_details_present = False - def get_paper_doc_ownership_changed(self): - """ - (paper) Transferred ownership of Paper doc + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileMoveDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_paper_doc_ownership_changed` is true. + def __repr__(self): + return 'FileMoveDetails(relocate_action_details={!r})'.format( + self._relocate_action_details_value, + ) - :rtype: PaperDocOwnershipChangedType - """ - if not self.is_paper_doc_ownership_changed(): - raise AttributeError("tag 'paper_doc_ownership_changed' not set") - return self._value +FileMoveDetails_validator = bv.Struct(FileMoveDetails) - def get_paper_doc_request_access(self): - """ - (paper) Requested access to Paper doc +class FileMoveType(bb.Struct): - Only call this if :meth:`is_paper_doc_request_access` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: PaperDocRequestAccessType - """ - if not self.is_paper_doc_request_access(): - raise AttributeError("tag 'paper_doc_request_access' not set") - return self._value + _has_required_fields = True - def get_paper_doc_resolve_comment(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (paper) Resolved Paper doc comment + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_paper_doc_resolve_comment` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: PaperDocResolveCommentType - """ - if not self.is_paper_doc_resolve_comment(): - raise AttributeError("tag 'paper_doc_resolve_comment' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_paper_doc_revert(self): - """ - (paper) Restored Paper doc to previous version + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileMoveType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_paper_doc_revert` is true. + def __repr__(self): + return 'FileMoveType(description={!r})'.format( + self._description_value, + ) - :rtype: PaperDocRevertType - """ - if not self.is_paper_doc_revert(): - raise AttributeError("tag 'paper_doc_revert' not set") - return self._value +FileMoveType_validator = bv.Struct(FileMoveType) - def get_paper_doc_slack_share(self): - """ - (paper) Shared Paper doc via Slack +class FilePermanentlyDeleteDetails(bb.Struct): + """ + Permanently deleted files and/or folders. + """ - Only call this if :meth:`is_paper_doc_slack_share` is true. + __slots__ = [ + ] - :rtype: PaperDocSlackShareType - """ - if not self.is_paper_doc_slack_share(): - raise AttributeError("tag 'paper_doc_slack_share' not set") - return self._value + _has_required_fields = False - def get_paper_doc_team_invite(self): - """ - (paper) Shared Paper doc with team member (deprecated, no longer logged) + def __init__(self): + pass - Only call this if :meth:`is_paper_doc_team_invite` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FilePermanentlyDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: PaperDocTeamInviteType - """ - if not self.is_paper_doc_team_invite(): - raise AttributeError("tag 'paper_doc_team_invite' not set") - return self._value + def __repr__(self): + return 'FilePermanentlyDeleteDetails()' - def get_paper_doc_trashed(self): - """ - (paper) Deleted Paper doc +FilePermanentlyDeleteDetails_validator = bv.Struct(FilePermanentlyDeleteDetails) - Only call this if :meth:`is_paper_doc_trashed` is true. +class FilePermanentlyDeleteType(bb.Struct): - :rtype: PaperDocTrashedType - """ - if not self.is_paper_doc_trashed(): - raise AttributeError("tag 'paper_doc_trashed' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_paper_doc_unresolve_comment(self): - """ - (paper) Unresolved Paper doc comment + _has_required_fields = True - Only call this if :meth:`is_paper_doc_unresolve_comment` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: PaperDocUnresolveCommentType + @property + def description(self): """ - if not self.is_paper_doc_unresolve_comment(): - raise AttributeError("tag 'paper_doc_unresolve_comment' not set") - return self._value - - def get_paper_doc_untrashed(self): + :rtype: str """ - (paper) Restored Paper doc + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_paper_doc_untrashed` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: PaperDocUntrashedType - """ - if not self.is_paper_doc_untrashed(): - raise AttributeError("tag 'paper_doc_untrashed' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_paper_doc_view(self): - """ - (paper) Viewed Paper doc + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FilePermanentlyDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_paper_doc_view` is true. + def __repr__(self): + return 'FilePermanentlyDeleteType(description={!r})'.format( + self._description_value, + ) - :rtype: PaperDocViewType - """ - if not self.is_paper_doc_view(): - raise AttributeError("tag 'paper_doc_view' not set") - return self._value +FilePermanentlyDeleteType_validator = bv.Struct(FilePermanentlyDeleteType) - def get_paper_external_view_allow(self): - """ - (paper) Changed Paper external sharing setting to anyone (deprecated, no - longer logged) +class FilePreviewDetails(bb.Struct): + """ + Previewed files and/or folders. + """ - Only call this if :meth:`is_paper_external_view_allow` is true. + __slots__ = [ + ] - :rtype: PaperExternalViewAllowType - """ - if not self.is_paper_external_view_allow(): - raise AttributeError("tag 'paper_external_view_allow' not set") - return self._value + _has_required_fields = False - def get_paper_external_view_default_team(self): - """ - (paper) Changed Paper external sharing setting to default team - (deprecated, no longer logged) + def __init__(self): + pass - Only call this if :meth:`is_paper_external_view_default_team` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FilePreviewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: PaperExternalViewDefaultTeamType - """ - if not self.is_paper_external_view_default_team(): - raise AttributeError("tag 'paper_external_view_default_team' not set") - return self._value + def __repr__(self): + return 'FilePreviewDetails()' - def get_paper_external_view_forbid(self): - """ - (paper) Changed Paper external sharing setting to team-only (deprecated, - no longer logged) +FilePreviewDetails_validator = bv.Struct(FilePreviewDetails) - Only call this if :meth:`is_paper_external_view_forbid` is true. +class FilePreviewType(bb.Struct): - :rtype: PaperExternalViewForbidType - """ - if not self.is_paper_external_view_forbid(): - raise AttributeError("tag 'paper_external_view_forbid' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_paper_folder_change_subscription(self): - """ - (paper) Followed/unfollowed Paper folder + _has_required_fields = True - Only call this if :meth:`is_paper_folder_change_subscription` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: PaperFolderChangeSubscriptionType + @property + def description(self): """ - if not self.is_paper_folder_change_subscription(): - raise AttributeError("tag 'paper_folder_change_subscription' not set") - return self._value - - def get_paper_folder_deleted(self): + :rtype: str """ - (paper) Archived Paper folder (deprecated, no longer logged) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_paper_folder_deleted` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: PaperFolderDeletedType - """ - if not self.is_paper_folder_deleted(): - raise AttributeError("tag 'paper_folder_deleted' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_paper_folder_followed(self): - """ - (paper) Followed Paper folder (deprecated, replaced by - 'Followed/unfollowed Paper folder') + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FilePreviewType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_paper_folder_followed` is true. + def __repr__(self): + return 'FilePreviewType(description={!r})'.format( + self._description_value, + ) - :rtype: PaperFolderFollowedType - """ - if not self.is_paper_folder_followed(): - raise AttributeError("tag 'paper_folder_followed' not set") - return self._value +FilePreviewType_validator = bv.Struct(FilePreviewType) - def get_paper_folder_team_invite(self): - """ - (paper) Shared Paper folder with member (deprecated, no longer logged) +class FileRenameDetails(bb.Struct): + """ + Renamed files and/or folders. - Only call this if :meth:`is_paper_folder_team_invite` is true. + :ivar team_log.FileRenameDetails.relocate_action_details: Relocate action + details. + """ - :rtype: PaperFolderTeamInviteType - """ - if not self.is_paper_folder_team_invite(): - raise AttributeError("tag 'paper_folder_team_invite' not set") - return self._value + __slots__ = [ + '_relocate_action_details_value', + '_relocate_action_details_present', + ] - def get_paper_published_link_create(self): - """ - (paper) Published doc + _has_required_fields = True - Only call this if :meth:`is_paper_published_link_create` is true. + def __init__(self, + relocate_action_details=None): + self._relocate_action_details_value = None + self._relocate_action_details_present = False + if relocate_action_details is not None: + self.relocate_action_details = relocate_action_details - :rtype: PaperPublishedLinkCreateType + @property + def relocate_action_details(self): """ - if not self.is_paper_published_link_create(): - raise AttributeError("tag 'paper_published_link_create' not set") - return self._value + Relocate action details. - def get_paper_published_link_disabled(self): + :rtype: list of [RelocateAssetReferencesLogInfo] """ - (paper) Unpublished doc - - Only call this if :meth:`is_paper_published_link_disabled` is true. + if self._relocate_action_details_present: + return self._relocate_action_details_value + else: + raise AttributeError("missing required field 'relocate_action_details'") - :rtype: PaperPublishedLinkDisabledType - """ - if not self.is_paper_published_link_disabled(): - raise AttributeError("tag 'paper_published_link_disabled' not set") - return self._value + @relocate_action_details.setter + def relocate_action_details(self, val): + val = self._relocate_action_details_validator.validate(val) + self._relocate_action_details_value = val + self._relocate_action_details_present = True - def get_paper_published_link_view(self): - """ - (paper) Viewed published doc + @relocate_action_details.deleter + def relocate_action_details(self): + self._relocate_action_details_value = None + self._relocate_action_details_present = False - Only call this if :meth:`is_paper_published_link_view` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRenameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: PaperPublishedLinkViewType - """ - if not self.is_paper_published_link_view(): - raise AttributeError("tag 'paper_published_link_view' not set") - return self._value + def __repr__(self): + return 'FileRenameDetails(relocate_action_details={!r})'.format( + self._relocate_action_details_value, + ) - def get_password_change(self): - """ - (passwords) Changed password +FileRenameDetails_validator = bv.Struct(FileRenameDetails) - Only call this if :meth:`is_password_change` is true. +class FileRenameType(bb.Struct): - :rtype: PasswordChangeType - """ - if not self.is_password_change(): - raise AttributeError("tag 'password_change' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_password_reset(self): - """ - (passwords) Reset password + _has_required_fields = True - Only call this if :meth:`is_password_reset` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: PasswordResetType + @property + def description(self): """ - if not self.is_password_reset(): - raise AttributeError("tag 'password_reset' not set") - return self._value - - def get_password_reset_all(self): + :rtype: str """ - (passwords) Reset all team member passwords + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_password_reset_all` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: PasswordResetAllType - """ - if not self.is_password_reset_all(): - raise AttributeError("tag 'password_reset_all' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_emm_create_exceptions_report(self): - """ - (reports) Created EMM-excluded users report + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRenameType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_emm_create_exceptions_report` is true. + def __repr__(self): + return 'FileRenameType(description={!r})'.format( + self._description_value, + ) - :rtype: EmmCreateExceptionsReportType - """ - if not self.is_emm_create_exceptions_report(): - raise AttributeError("tag 'emm_create_exceptions_report' not set") - return self._value +FileRenameType_validator = bv.Struct(FileRenameType) - def get_emm_create_usage_report(self): - """ - (reports) Created EMM mobile app usage report +class FileRequestChangeDetails(bb.Struct): + """ + Changed file request. - Only call this if :meth:`is_emm_create_usage_report` is true. + :ivar team_log.FileRequestChangeDetails.file_request_id: File request id. + Might be missing due to historical data gap. + :ivar team_log.FileRequestChangeDetails.previous_details: Previous file + request details. Might be missing due to historical data gap. + :ivar team_log.FileRequestChangeDetails.new_details: New file request + details. + """ - :rtype: EmmCreateUsageReportType - """ - if not self.is_emm_create_usage_report(): - raise AttributeError("tag 'emm_create_usage_report' not set") - return self._value + __slots__ = [ + '_file_request_id_value', + '_file_request_id_present', + '_previous_details_value', + '_previous_details_present', + '_new_details_value', + '_new_details_present', + ] - def get_export_members_report(self): - """ - (reports) Created member data report + _has_required_fields = True - Only call this if :meth:`is_export_members_report` is true. + def __init__(self, + new_details=None, + file_request_id=None, + previous_details=None): + self._file_request_id_value = None + self._file_request_id_present = False + self._previous_details_value = None + self._previous_details_present = False + self._new_details_value = None + self._new_details_present = False + if file_request_id is not None: + self.file_request_id = file_request_id + if previous_details is not None: + self.previous_details = previous_details + if new_details is not None: + self.new_details = new_details - :rtype: ExportMembersReportType + @property + def file_request_id(self): """ - if not self.is_export_members_report(): - raise AttributeError("tag 'export_members_report' not set") - return self._value + File request id. Might be missing due to historical data gap. - def get_paper_admin_export_start(self): + :rtype: str """ - (reports) Exported all team Paper docs + if self._file_request_id_present: + return self._file_request_id_value + else: + return None - Only call this if :meth:`is_paper_admin_export_start` is true. + @file_request_id.setter + def file_request_id(self, val): + if val is None: + del self.file_request_id + return + val = self._file_request_id_validator.validate(val) + self._file_request_id_value = val + self._file_request_id_present = True - :rtype: PaperAdminExportStartType - """ - if not self.is_paper_admin_export_start(): - raise AttributeError("tag 'paper_admin_export_start' not set") - return self._value + @file_request_id.deleter + def file_request_id(self): + self._file_request_id_value = None + self._file_request_id_present = False - def get_smart_sync_create_admin_privilege_report(self): + @property + def previous_details(self): """ - (reports) Created Smart Sync non-admin devices report - - Only call this if :meth:`is_smart_sync_create_admin_privilege_report` is true. + Previous file request details. Might be missing due to historical data + gap. - :rtype: SmartSyncCreateAdminPrivilegeReportType + :rtype: FileRequestDetails """ - if not self.is_smart_sync_create_admin_privilege_report(): - raise AttributeError("tag 'smart_sync_create_admin_privilege_report' not set") - return self._value + if self._previous_details_present: + return self._previous_details_value + else: + return None - def get_team_activity_create_report(self): - """ - (reports) Created team activity report + @previous_details.setter + def previous_details(self, val): + if val is None: + del self.previous_details + return + self._previous_details_validator.validate_type_only(val) + self._previous_details_value = val + self._previous_details_present = True - Only call this if :meth:`is_team_activity_create_report` is true. + @previous_details.deleter + def previous_details(self): + self._previous_details_value = None + self._previous_details_present = False - :rtype: TeamActivityCreateReportType + @property + def new_details(self): """ - if not self.is_team_activity_create_report(): - raise AttributeError("tag 'team_activity_create_report' not set") - return self._value + New file request details. - def get_team_activity_create_report_fail(self): + :rtype: FileRequestDetails """ - (reports) Couldn't generate team activity report - - Only call this if :meth:`is_team_activity_create_report_fail` is true. + if self._new_details_present: + return self._new_details_value + else: + raise AttributeError("missing required field 'new_details'") - :rtype: TeamActivityCreateReportFailType - """ - if not self.is_team_activity_create_report_fail(): - raise AttributeError("tag 'team_activity_create_report_fail' not set") - return self._value + @new_details.setter + def new_details(self, val): + self._new_details_validator.validate_type_only(val) + self._new_details_value = val + self._new_details_present = True - def get_collection_share(self): - """ - (sharing) Shared album + @new_details.deleter + def new_details(self): + self._new_details_value = None + self._new_details_present = False - Only call this if :meth:`is_collection_share` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestChangeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: CollectionShareType - """ - if not self.is_collection_share(): - raise AttributeError("tag 'collection_share' not set") - return self._value + def __repr__(self): + return 'FileRequestChangeDetails(new_details={!r}, file_request_id={!r}, previous_details={!r})'.format( + self._new_details_value, + self._file_request_id_value, + self._previous_details_value, + ) - def get_note_acl_invite_only(self): - """ - (sharing) Changed Paper doc to invite-only (deprecated, no longer - logged) +FileRequestChangeDetails_validator = bv.Struct(FileRequestChangeDetails) - Only call this if :meth:`is_note_acl_invite_only` is true. +class FileRequestChangeType(bb.Struct): - :rtype: NoteAclInviteOnlyType - """ - if not self.is_note_acl_invite_only(): - raise AttributeError("tag 'note_acl_invite_only' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_note_acl_link(self): - """ - (sharing) Changed Paper doc to link-accessible (deprecated, no longer - logged) + _has_required_fields = True - Only call this if :meth:`is_note_acl_link` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: NoteAclLinkType + @property + def description(self): """ - if not self.is_note_acl_link(): - raise AttributeError("tag 'note_acl_link' not set") - return self._value - - def get_note_acl_team_link(self): + :rtype: str """ - (sharing) Changed Paper doc to link-accessible for team (deprecated, no - longer logged) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_note_acl_team_link` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: NoteAclTeamLinkType - """ - if not self.is_note_acl_team_link(): - raise AttributeError("tag 'note_acl_team_link' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_note_shared(self): - """ - (sharing) Shared Paper doc (deprecated, no longer logged) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestChangeType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_note_shared` is true. + def __repr__(self): + return 'FileRequestChangeType(description={!r})'.format( + self._description_value, + ) - :rtype: NoteSharedType - """ - if not self.is_note_shared(): - raise AttributeError("tag 'note_shared' not set") - return self._value +FileRequestChangeType_validator = bv.Struct(FileRequestChangeType) - def get_note_share_receive(self): - """ - (sharing) Shared received Paper doc (deprecated, no longer logged) +class FileRequestCloseDetails(bb.Struct): + """ + Closed file request. - Only call this if :meth:`is_note_share_receive` is true. + :ivar team_log.FileRequestCloseDetails.file_request_id: File request id. + Might be missing due to historical data gap. + :ivar team_log.FileRequestCloseDetails.previous_details: Previous file + request details. Might be missing due to historical data gap. + """ - :rtype: NoteShareReceiveType - """ - if not self.is_note_share_receive(): - raise AttributeError("tag 'note_share_receive' not set") - return self._value + __slots__ = [ + '_file_request_id_value', + '_file_request_id_present', + '_previous_details_value', + '_previous_details_present', + ] - def get_open_note_shared(self): - """ - (sharing) Opened shared Paper doc (deprecated, no longer logged) + _has_required_fields = False - Only call this if :meth:`is_open_note_shared` is true. + def __init__(self, + file_request_id=None, + previous_details=None): + self._file_request_id_value = None + self._file_request_id_present = False + self._previous_details_value = None + self._previous_details_present = False + if file_request_id is not None: + self.file_request_id = file_request_id + if previous_details is not None: + self.previous_details = previous_details - :rtype: OpenNoteSharedType + @property + def file_request_id(self): """ - if not self.is_open_note_shared(): - raise AttributeError("tag 'open_note_shared' not set") - return self._value + File request id. Might be missing due to historical data gap. - def get_sf_add_group(self): + :rtype: str """ - (sharing) Added team to shared folder (deprecated, no longer logged) + if self._file_request_id_present: + return self._file_request_id_value + else: + return None - Only call this if :meth:`is_sf_add_group` is true. + @file_request_id.setter + def file_request_id(self, val): + if val is None: + del self.file_request_id + return + val = self._file_request_id_validator.validate(val) + self._file_request_id_value = val + self._file_request_id_present = True - :rtype: SfAddGroupType - """ - if not self.is_sf_add_group(): - raise AttributeError("tag 'sf_add_group' not set") - return self._value + @file_request_id.deleter + def file_request_id(self): + self._file_request_id_value = None + self._file_request_id_present = False - def get_sf_allow_non_members_to_view_shared_links(self): + @property + def previous_details(self): """ - (sharing) Allowed non-collaborators to view links to files in shared - folder (deprecated, no longer logged) - - Only call this if :meth:`is_sf_allow_non_members_to_view_shared_links` is true. + Previous file request details. Might be missing due to historical data + gap. - :rtype: SfAllowNonMembersToViewSharedLinksType + :rtype: FileRequestDetails """ - if not self.is_sf_allow_non_members_to_view_shared_links(): - raise AttributeError("tag 'sf_allow_non_members_to_view_shared_links' not set") - return self._value + if self._previous_details_present: + return self._previous_details_value + else: + return None - def get_sf_external_invite_warn(self): - """ - (sharing) Set team members to see warning before sharing folders outside - team (deprecated, no longer logged) + @previous_details.setter + def previous_details(self, val): + if val is None: + del self.previous_details + return + self._previous_details_validator.validate_type_only(val) + self._previous_details_value = val + self._previous_details_present = True - Only call this if :meth:`is_sf_external_invite_warn` is true. + @previous_details.deleter + def previous_details(self): + self._previous_details_value = None + self._previous_details_present = False - :rtype: SfExternalInviteWarnType - """ - if not self.is_sf_external_invite_warn(): - raise AttributeError("tag 'sf_external_invite_warn' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestCloseDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_sf_fb_invite(self): - """ - (sharing) Invited Facebook users to shared folder (deprecated, no longer - logged) + def __repr__(self): + return 'FileRequestCloseDetails(file_request_id={!r}, previous_details={!r})'.format( + self._file_request_id_value, + self._previous_details_value, + ) - Only call this if :meth:`is_sf_fb_invite` is true. +FileRequestCloseDetails_validator = bv.Struct(FileRequestCloseDetails) - :rtype: SfFbInviteType - """ - if not self.is_sf_fb_invite(): - raise AttributeError("tag 'sf_fb_invite' not set") - return self._value +class FileRequestCloseType(bb.Struct): - def get_sf_fb_invite_change_role(self): - """ - (sharing) Changed Facebook user's role in shared folder (deprecated, no - longer logged) + __slots__ = [ + '_description_value', + '_description_present', + ] - Only call this if :meth:`is_sf_fb_invite_change_role` is true. + _has_required_fields = True - :rtype: SfFbInviteChangeRoleType - """ - if not self.is_sf_fb_invite_change_role(): - raise AttributeError("tag 'sf_fb_invite_change_role' not set") - return self._value + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def get_sf_fb_uninvite(self): + @property + def description(self): """ - (sharing) Uninvited Facebook user from shared folder (deprecated, no - longer logged) + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_sf_fb_uninvite` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SfFbUninviteType - """ - if not self.is_sf_fb_uninvite(): - raise AttributeError("tag 'sf_fb_uninvite' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_sf_invite_group(self): - """ - (sharing) Invited group to shared folder (deprecated, no longer logged) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestCloseType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_sf_invite_group` is true. + def __repr__(self): + return 'FileRequestCloseType(description={!r})'.format( + self._description_value, + ) - :rtype: SfInviteGroupType - """ - if not self.is_sf_invite_group(): - raise AttributeError("tag 'sf_invite_group' not set") - return self._value +FileRequestCloseType_validator = bv.Struct(FileRequestCloseType) - def get_sf_team_grant_access(self): - """ - (sharing) Granted access to shared folder (deprecated, no longer logged) +class FileRequestCreateDetails(bb.Struct): + """ + Created file request. - Only call this if :meth:`is_sf_team_grant_access` is true. + :ivar team_log.FileRequestCreateDetails.file_request_id: File request id. + Might be missing due to historical data gap. + :ivar team_log.FileRequestCreateDetails.request_details: File request + details. Might be missing due to historical data gap. + """ - :rtype: SfTeamGrantAccessType - """ - if not self.is_sf_team_grant_access(): - raise AttributeError("tag 'sf_team_grant_access' not set") - return self._value + __slots__ = [ + '_file_request_id_value', + '_file_request_id_present', + '_request_details_value', + '_request_details_present', + ] - def get_sf_team_invite(self): - """ - (sharing) Invited team members to shared folder (deprecated, replaced by - 'Invited user to Dropbox and added them to shared file/folder') + _has_required_fields = False - Only call this if :meth:`is_sf_team_invite` is true. + def __init__(self, + file_request_id=None, + request_details=None): + self._file_request_id_value = None + self._file_request_id_present = False + self._request_details_value = None + self._request_details_present = False + if file_request_id is not None: + self.file_request_id = file_request_id + if request_details is not None: + self.request_details = request_details - :rtype: SfTeamInviteType + @property + def file_request_id(self): """ - if not self.is_sf_team_invite(): - raise AttributeError("tag 'sf_team_invite' not set") - return self._value + File request id. Might be missing due to historical data gap. - def get_sf_team_invite_change_role(self): + :rtype: str """ - (sharing) Changed team member's role in shared folder (deprecated, no - longer logged) + if self._file_request_id_present: + return self._file_request_id_value + else: + return None - Only call this if :meth:`is_sf_team_invite_change_role` is true. + @file_request_id.setter + def file_request_id(self, val): + if val is None: + del self.file_request_id + return + val = self._file_request_id_validator.validate(val) + self._file_request_id_value = val + self._file_request_id_present = True - :rtype: SfTeamInviteChangeRoleType - """ - if not self.is_sf_team_invite_change_role(): - raise AttributeError("tag 'sf_team_invite_change_role' not set") - return self._value + @file_request_id.deleter + def file_request_id(self): + self._file_request_id_value = None + self._file_request_id_present = False - def get_sf_team_join(self): + @property + def request_details(self): """ - (sharing) Joined team member's shared folder (deprecated, no longer - logged) - - Only call this if :meth:`is_sf_team_join` is true. + File request details. Might be missing due to historical data gap. - :rtype: SfTeamJoinType + :rtype: FileRequestDetails """ - if not self.is_sf_team_join(): - raise AttributeError("tag 'sf_team_join' not set") - return self._value + if self._request_details_present: + return self._request_details_value + else: + return None - def get_sf_team_join_from_oob_link(self): - """ - (sharing) Joined team member's shared folder from link (deprecated, no - longer logged) + @request_details.setter + def request_details(self, val): + if val is None: + del self.request_details + return + self._request_details_validator.validate_type_only(val) + self._request_details_value = val + self._request_details_present = True - Only call this if :meth:`is_sf_team_join_from_oob_link` is true. + @request_details.deleter + def request_details(self): + self._request_details_value = None + self._request_details_present = False - :rtype: SfTeamJoinFromOobLinkType - """ - if not self.is_sf_team_join_from_oob_link(): - raise AttributeError("tag 'sf_team_join_from_oob_link' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_sf_team_uninvite(self): - """ - (sharing) Unshared folder with team member (deprecated, replaced by - 'Removed invitee from shared file/folder before invite was accepted') + def __repr__(self): + return 'FileRequestCreateDetails(file_request_id={!r}, request_details={!r})'.format( + self._file_request_id_value, + self._request_details_value, + ) - Only call this if :meth:`is_sf_team_uninvite` is true. +FileRequestCreateDetails_validator = bv.Struct(FileRequestCreateDetails) - :rtype: SfTeamUninviteType - """ - if not self.is_sf_team_uninvite(): - raise AttributeError("tag 'sf_team_uninvite' not set") - return self._value +class FileRequestCreateType(bb.Struct): - def get_shared_content_add_invitees(self): - """ - (sharing) Invited user to Dropbox and added them to shared file/folder + __slots__ = [ + '_description_value', + '_description_present', + ] - Only call this if :meth:`is_shared_content_add_invitees` is true. + _has_required_fields = True - :rtype: SharedContentAddInviteesType - """ - if not self.is_shared_content_add_invitees(): - raise AttributeError("tag 'shared_content_add_invitees' not set") - return self._value + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def get_shared_content_add_link_expiry(self): + @property + def description(self): """ - (sharing) Added expiration date to link for shared file/folder + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_shared_content_add_link_expiry` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SharedContentAddLinkExpiryType - """ - if not self.is_shared_content_add_link_expiry(): - raise AttributeError("tag 'shared_content_add_link_expiry' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_shared_content_add_link_password(self): - """ - (sharing) Added password to link for shared file/folder + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_shared_content_add_link_password` is true. + def __repr__(self): + return 'FileRequestCreateType(description={!r})'.format( + self._description_value, + ) - :rtype: SharedContentAddLinkPasswordType - """ - if not self.is_shared_content_add_link_password(): - raise AttributeError("tag 'shared_content_add_link_password' not set") - return self._value +FileRequestCreateType_validator = bv.Struct(FileRequestCreateType) - def get_shared_content_add_member(self): - """ - (sharing) Added users and/or groups to shared file/folder +class FileRequestDeadline(bb.Struct): + """ + File request deadline - Only call this if :meth:`is_shared_content_add_member` is true. + :ivar team_log.FileRequestDeadline.deadline: The deadline for this file + request. Might be missing due to historical data gap. + :ivar team_log.FileRequestDeadline.allow_late_uploads: If set, allow uploads + after the deadline has passed. Might be missing due to historical data + gap. + """ - :rtype: SharedContentAddMemberType - """ - if not self.is_shared_content_add_member(): - raise AttributeError("tag 'shared_content_add_member' not set") - return self._value + __slots__ = [ + '_deadline_value', + '_deadline_present', + '_allow_late_uploads_value', + '_allow_late_uploads_present', + ] - def get_shared_content_change_downloads_policy(self): - """ - (sharing) Changed whether members can download shared file/folder + _has_required_fields = False - Only call this if :meth:`is_shared_content_change_downloads_policy` is true. + def __init__(self, + deadline=None, + allow_late_uploads=None): + self._deadline_value = None + self._deadline_present = False + self._allow_late_uploads_value = None + self._allow_late_uploads_present = False + if deadline is not None: + self.deadline = deadline + if allow_late_uploads is not None: + self.allow_late_uploads = allow_late_uploads - :rtype: SharedContentChangeDownloadsPolicyType + @property + def deadline(self): """ - if not self.is_shared_content_change_downloads_policy(): - raise AttributeError("tag 'shared_content_change_downloads_policy' not set") - return self._value + The deadline for this file request. Might be missing due to historical + data gap. - def get_shared_content_change_invitee_role(self): + :rtype: datetime.datetime """ - (sharing) Changed access type of invitee to shared file/folder before - invite was accepted + if self._deadline_present: + return self._deadline_value + else: + return None - Only call this if :meth:`is_shared_content_change_invitee_role` is true. + @deadline.setter + def deadline(self, val): + if val is None: + del self.deadline + return + val = self._deadline_validator.validate(val) + self._deadline_value = val + self._deadline_present = True - :rtype: SharedContentChangeInviteeRoleType - """ - if not self.is_shared_content_change_invitee_role(): - raise AttributeError("tag 'shared_content_change_invitee_role' not set") - return self._value + @deadline.deleter + def deadline(self): + self._deadline_value = None + self._deadline_present = False - def get_shared_content_change_link_audience(self): + @property + def allow_late_uploads(self): """ - (sharing) Changed link audience of shared file/folder - - Only call this if :meth:`is_shared_content_change_link_audience` is true. + If set, allow uploads after the deadline has passed. Might be missing + due to historical data gap. - :rtype: SharedContentChangeLinkAudienceType + :rtype: str """ - if not self.is_shared_content_change_link_audience(): - raise AttributeError("tag 'shared_content_change_link_audience' not set") - return self._value + if self._allow_late_uploads_present: + return self._allow_late_uploads_value + else: + return None - def get_shared_content_change_link_expiry(self): - """ - (sharing) Changed link expiration of shared file/folder + @allow_late_uploads.setter + def allow_late_uploads(self, val): + if val is None: + del self.allow_late_uploads + return + val = self._allow_late_uploads_validator.validate(val) + self._allow_late_uploads_value = val + self._allow_late_uploads_present = True + + @allow_late_uploads.deleter + def allow_late_uploads(self): + self._allow_late_uploads_value = None + self._allow_late_uploads_present = False - Only call this if :meth:`is_shared_content_change_link_expiry` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestDeadline, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: SharedContentChangeLinkExpiryType - """ - if not self.is_shared_content_change_link_expiry(): - raise AttributeError("tag 'shared_content_change_link_expiry' not set") - return self._value + def __repr__(self): + return 'FileRequestDeadline(deadline={!r}, allow_late_uploads={!r})'.format( + self._deadline_value, + self._allow_late_uploads_value, + ) - def get_shared_content_change_link_password(self): - """ - (sharing) Changed link password of shared file/folder +FileRequestDeadline_validator = bv.Struct(FileRequestDeadline) - Only call this if :meth:`is_shared_content_change_link_password` is true. +class FileRequestDeleteDetails(bb.Struct): + """ + Delete file request. - :rtype: SharedContentChangeLinkPasswordType - """ - if not self.is_shared_content_change_link_password(): - raise AttributeError("tag 'shared_content_change_link_password' not set") - return self._value + :ivar team_log.FileRequestDeleteDetails.file_request_id: File request id. + Might be missing due to historical data gap. + :ivar team_log.FileRequestDeleteDetails.previous_details: Previous file + request details. Might be missing due to historical data gap. + """ - def get_shared_content_change_member_role(self): - """ - (sharing) Changed access type of shared file/folder member + __slots__ = [ + '_file_request_id_value', + '_file_request_id_present', + '_previous_details_value', + '_previous_details_present', + ] - Only call this if :meth:`is_shared_content_change_member_role` is true. + _has_required_fields = False - :rtype: SharedContentChangeMemberRoleType - """ - if not self.is_shared_content_change_member_role(): - raise AttributeError("tag 'shared_content_change_member_role' not set") - return self._value + def __init__(self, + file_request_id=None, + previous_details=None): + self._file_request_id_value = None + self._file_request_id_present = False + self._previous_details_value = None + self._previous_details_present = False + if file_request_id is not None: + self.file_request_id = file_request_id + if previous_details is not None: + self.previous_details = previous_details - def get_shared_content_change_viewer_info_policy(self): + @property + def file_request_id(self): """ - (sharing) Changed whether members can see who viewed shared file/folder - - Only call this if :meth:`is_shared_content_change_viewer_info_policy` is true. + File request id. Might be missing due to historical data gap. - :rtype: SharedContentChangeViewerInfoPolicyType + :rtype: str """ - if not self.is_shared_content_change_viewer_info_policy(): - raise AttributeError("tag 'shared_content_change_viewer_info_policy' not set") - return self._value + if self._file_request_id_present: + return self._file_request_id_value + else: + return None - def get_shared_content_claim_invitation(self): - """ - (sharing) Acquired membership of shared file/folder by accepting invite + @file_request_id.setter + def file_request_id(self, val): + if val is None: + del self.file_request_id + return + val = self._file_request_id_validator.validate(val) + self._file_request_id_value = val + self._file_request_id_present = True - Only call this if :meth:`is_shared_content_claim_invitation` is true. + @file_request_id.deleter + def file_request_id(self): + self._file_request_id_value = None + self._file_request_id_present = False - :rtype: SharedContentClaimInvitationType + @property + def previous_details(self): """ - if not self.is_shared_content_claim_invitation(): - raise AttributeError("tag 'shared_content_claim_invitation' not set") - return self._value + Previous file request details. Might be missing due to historical data + gap. - def get_shared_content_copy(self): + :rtype: FileRequestDetails """ - (sharing) Copied shared file/folder to own Dropbox - - Only call this if :meth:`is_shared_content_copy` is true. + if self._previous_details_present: + return self._previous_details_value + else: + return None - :rtype: SharedContentCopyType - """ - if not self.is_shared_content_copy(): - raise AttributeError("tag 'shared_content_copy' not set") - return self._value + @previous_details.setter + def previous_details(self, val): + if val is None: + del self.previous_details + return + self._previous_details_validator.validate_type_only(val) + self._previous_details_value = val + self._previous_details_present = True - def get_shared_content_download(self): - """ - (sharing) Downloaded shared file/folder + @previous_details.deleter + def previous_details(self): + self._previous_details_value = None + self._previous_details_present = False - Only call this if :meth:`is_shared_content_download` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: SharedContentDownloadType - """ - if not self.is_shared_content_download(): - raise AttributeError("tag 'shared_content_download' not set") - return self._value + def __repr__(self): + return 'FileRequestDeleteDetails(file_request_id={!r}, previous_details={!r})'.format( + self._file_request_id_value, + self._previous_details_value, + ) - def get_shared_content_relinquish_membership(self): - """ - (sharing) Left shared file/folder +FileRequestDeleteDetails_validator = bv.Struct(FileRequestDeleteDetails) - Only call this if :meth:`is_shared_content_relinquish_membership` is true. +class FileRequestDeleteType(bb.Struct): - :rtype: SharedContentRelinquishMembershipType - """ - if not self.is_shared_content_relinquish_membership(): - raise AttributeError("tag 'shared_content_relinquish_membership' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_shared_content_remove_invitees(self): - """ - (sharing) Removed invitee from shared file/folder before invite was - accepted + _has_required_fields = True - Only call this if :meth:`is_shared_content_remove_invitees` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: SharedContentRemoveInviteesType + @property + def description(self): """ - if not self.is_shared_content_remove_invitees(): - raise AttributeError("tag 'shared_content_remove_invitees' not set") - return self._value - - def get_shared_content_remove_link_expiry(self): + :rtype: str """ - (sharing) Removed link expiration date of shared file/folder + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_shared_content_remove_link_expiry` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SharedContentRemoveLinkExpiryType - """ - if not self.is_shared_content_remove_link_expiry(): - raise AttributeError("tag 'shared_content_remove_link_expiry' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_shared_content_remove_link_password(self): - """ - (sharing) Removed link password of shared file/folder + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_shared_content_remove_link_password` is true. + def __repr__(self): + return 'FileRequestDeleteType(description={!r})'.format( + self._description_value, + ) - :rtype: SharedContentRemoveLinkPasswordType - """ - if not self.is_shared_content_remove_link_password(): - raise AttributeError("tag 'shared_content_remove_link_password' not set") - return self._value +FileRequestDeleteType_validator = bv.Struct(FileRequestDeleteType) - def get_shared_content_remove_member(self): - """ - (sharing) Removed user/group from shared file/folder +class FileRequestDetails(bb.Struct): + """ + File request details - Only call this if :meth:`is_shared_content_remove_member` is true. + :ivar team_log.FileRequestDetails.asset_index: Asset position in the Assets + list. + :ivar team_log.FileRequestDetails.deadline: File request deadline. Might be + missing due to historical data gap. + """ - :rtype: SharedContentRemoveMemberType - """ - if not self.is_shared_content_remove_member(): - raise AttributeError("tag 'shared_content_remove_member' not set") - return self._value + __slots__ = [ + '_asset_index_value', + '_asset_index_present', + '_deadline_value', + '_deadline_present', + ] - def get_shared_content_request_access(self): - """ - (sharing) Requested access to shared file/folder + _has_required_fields = True - Only call this if :meth:`is_shared_content_request_access` is true. + def __init__(self, + asset_index=None, + deadline=None): + self._asset_index_value = None + self._asset_index_present = False + self._deadline_value = None + self._deadline_present = False + if asset_index is not None: + self.asset_index = asset_index + if deadline is not None: + self.deadline = deadline - :rtype: SharedContentRequestAccessType + @property + def asset_index(self): """ - if not self.is_shared_content_request_access(): - raise AttributeError("tag 'shared_content_request_access' not set") - return self._value + Asset position in the Assets list. - def get_shared_content_unshare(self): + :rtype: int """ - (sharing) Unshared file/folder by clearing membership and turning off - link + if self._asset_index_present: + return self._asset_index_value + else: + raise AttributeError("missing required field 'asset_index'") - Only call this if :meth:`is_shared_content_unshare` is true. + @asset_index.setter + def asset_index(self, val): + val = self._asset_index_validator.validate(val) + self._asset_index_value = val + self._asset_index_present = True - :rtype: SharedContentUnshareType + @asset_index.deleter + def asset_index(self): + self._asset_index_value = None + self._asset_index_present = False + + @property + def deadline(self): """ - if not self.is_shared_content_unshare(): - raise AttributeError("tag 'shared_content_unshare' not set") - return self._value + File request deadline. Might be missing due to historical data gap. - def get_shared_content_view(self): + :rtype: FileRequestDeadline """ - (sharing) Previewed shared file/folder + if self._deadline_present: + return self._deadline_value + else: + return None - Only call this if :meth:`is_shared_content_view` is true. + @deadline.setter + def deadline(self, val): + if val is None: + del self.deadline + return + self._deadline_validator.validate_type_only(val) + self._deadline_value = val + self._deadline_present = True - :rtype: SharedContentViewType - """ - if not self.is_shared_content_view(): - raise AttributeError("tag 'shared_content_view' not set") - return self._value + @deadline.deleter + def deadline(self): + self._deadline_value = None + self._deadline_present = False - def get_shared_folder_change_link_policy(self): - """ - (sharing) Changed who can access shared folder via link + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_shared_folder_change_link_policy` is true. + def __repr__(self): + return 'FileRequestDetails(asset_index={!r}, deadline={!r})'.format( + self._asset_index_value, + self._deadline_value, + ) - :rtype: SharedFolderChangeLinkPolicyType - """ - if not self.is_shared_folder_change_link_policy(): - raise AttributeError("tag 'shared_folder_change_link_policy' not set") - return self._value +FileRequestDetails_validator = bv.Struct(FileRequestDetails) - def get_shared_folder_change_members_inheritance_policy(self): - """ - (sharing) Changed whether shared folder inherits members from parent - folder +class FileRequestReceiveFileDetails(bb.Struct): + """ + Received files for file request. - Only call this if :meth:`is_shared_folder_change_members_inheritance_policy` is true. + :ivar team_log.FileRequestReceiveFileDetails.file_request_id: File request + id. Might be missing due to historical data gap. + :ivar team_log.FileRequestReceiveFileDetails.file_request_details: File + request details. Might be missing due to historical data gap. + :ivar team_log.FileRequestReceiveFileDetails.submitted_file_names: Submitted + file names. + :ivar team_log.FileRequestReceiveFileDetails.submitter_name: The name as + provided by the submitter. Might be missing due to historical data gap. + :ivar team_log.FileRequestReceiveFileDetails.submitter_email: The email as + provided by the submitter. Might be missing due to historical data gap. + """ - :rtype: SharedFolderChangeMembersInheritancePolicyType - """ - if not self.is_shared_folder_change_members_inheritance_policy(): - raise AttributeError("tag 'shared_folder_change_members_inheritance_policy' not set") - return self._value + __slots__ = [ + '_file_request_id_value', + '_file_request_id_present', + '_file_request_details_value', + '_file_request_details_present', + '_submitted_file_names_value', + '_submitted_file_names_present', + '_submitter_name_value', + '_submitter_name_present', + '_submitter_email_value', + '_submitter_email_present', + ] - def get_shared_folder_change_members_management_policy(self): - """ - (sharing) Changed who can add/remove members of shared folder + _has_required_fields = True - Only call this if :meth:`is_shared_folder_change_members_management_policy` is true. + def __init__(self, + submitted_file_names=None, + file_request_id=None, + file_request_details=None, + submitter_name=None, + submitter_email=None): + self._file_request_id_value = None + self._file_request_id_present = False + self._file_request_details_value = None + self._file_request_details_present = False + self._submitted_file_names_value = None + self._submitted_file_names_present = False + self._submitter_name_value = None + self._submitter_name_present = False + self._submitter_email_value = None + self._submitter_email_present = False + if file_request_id is not None: + self.file_request_id = file_request_id + if file_request_details is not None: + self.file_request_details = file_request_details + if submitted_file_names is not None: + self.submitted_file_names = submitted_file_names + if submitter_name is not None: + self.submitter_name = submitter_name + if submitter_email is not None: + self.submitter_email = submitter_email - :rtype: SharedFolderChangeMembersManagementPolicyType + @property + def file_request_id(self): """ - if not self.is_shared_folder_change_members_management_policy(): - raise AttributeError("tag 'shared_folder_change_members_management_policy' not set") - return self._value + File request id. Might be missing due to historical data gap. - def get_shared_folder_change_members_policy(self): + :rtype: str """ - (sharing) Changed who can become member of shared folder + if self._file_request_id_present: + return self._file_request_id_value + else: + return None - Only call this if :meth:`is_shared_folder_change_members_policy` is true. + @file_request_id.setter + def file_request_id(self, val): + if val is None: + del self.file_request_id + return + val = self._file_request_id_validator.validate(val) + self._file_request_id_value = val + self._file_request_id_present = True - :rtype: SharedFolderChangeMembersPolicyType - """ - if not self.is_shared_folder_change_members_policy(): - raise AttributeError("tag 'shared_folder_change_members_policy' not set") - return self._value + @file_request_id.deleter + def file_request_id(self): + self._file_request_id_value = None + self._file_request_id_present = False - def get_shared_folder_create(self): + @property + def file_request_details(self): """ - (sharing) Created shared folder - - Only call this if :meth:`is_shared_folder_create` is true. + File request details. Might be missing due to historical data gap. - :rtype: SharedFolderCreateType + :rtype: FileRequestDetails """ - if not self.is_shared_folder_create(): - raise AttributeError("tag 'shared_folder_create' not set") - return self._value + if self._file_request_details_present: + return self._file_request_details_value + else: + return None - def get_shared_folder_decline_invitation(self): - """ - (sharing) Declined team member's invite to shared folder + @file_request_details.setter + def file_request_details(self, val): + if val is None: + del self.file_request_details + return + self._file_request_details_validator.validate_type_only(val) + self._file_request_details_value = val + self._file_request_details_present = True - Only call this if :meth:`is_shared_folder_decline_invitation` is true. + @file_request_details.deleter + def file_request_details(self): + self._file_request_details_value = None + self._file_request_details_present = False - :rtype: SharedFolderDeclineInvitationType + @property + def submitted_file_names(self): """ - if not self.is_shared_folder_decline_invitation(): - raise AttributeError("tag 'shared_folder_decline_invitation' not set") - return self._value + Submitted file names. - def get_shared_folder_mount(self): + :rtype: list of [str] """ - (sharing) Added shared folder to own Dropbox + if self._submitted_file_names_present: + return self._submitted_file_names_value + else: + raise AttributeError("missing required field 'submitted_file_names'") - Only call this if :meth:`is_shared_folder_mount` is true. + @submitted_file_names.setter + def submitted_file_names(self, val): + val = self._submitted_file_names_validator.validate(val) + self._submitted_file_names_value = val + self._submitted_file_names_present = True - :rtype: SharedFolderMountType - """ - if not self.is_shared_folder_mount(): - raise AttributeError("tag 'shared_folder_mount' not set") - return self._value + @submitted_file_names.deleter + def submitted_file_names(self): + self._submitted_file_names_value = None + self._submitted_file_names_present = False - def get_shared_folder_nest(self): + @property + def submitter_name(self): """ - (sharing) Changed parent of shared folder - - Only call this if :meth:`is_shared_folder_nest` is true. + The name as provided by the submitter. Might be missing due to + historical data gap. - :rtype: SharedFolderNestType + :rtype: str """ - if not self.is_shared_folder_nest(): - raise AttributeError("tag 'shared_folder_nest' not set") - return self._value + if self._submitter_name_present: + return self._submitter_name_value + else: + return None - def get_shared_folder_transfer_ownership(self): - """ - (sharing) Transferred ownership of shared folder to another member + @submitter_name.setter + def submitter_name(self, val): + if val is None: + del self.submitter_name + return + val = self._submitter_name_validator.validate(val) + self._submitter_name_value = val + self._submitter_name_present = True - Only call this if :meth:`is_shared_folder_transfer_ownership` is true. + @submitter_name.deleter + def submitter_name(self): + self._submitter_name_value = None + self._submitter_name_present = False - :rtype: SharedFolderTransferOwnershipType + @property + def submitter_email(self): """ - if not self.is_shared_folder_transfer_ownership(): - raise AttributeError("tag 'shared_folder_transfer_ownership' not set") - return self._value + The email as provided by the submitter. Might be missing due to + historical data gap. - def get_shared_folder_unmount(self): + :rtype: str """ - (sharing) Deleted shared folder from Dropbox - - Only call this if :meth:`is_shared_folder_unmount` is true. + if self._submitter_email_present: + return self._submitter_email_value + else: + return None - :rtype: SharedFolderUnmountType - """ - if not self.is_shared_folder_unmount(): - raise AttributeError("tag 'shared_folder_unmount' not set") - return self._value + @submitter_email.setter + def submitter_email(self, val): + if val is None: + del self.submitter_email + return + val = self._submitter_email_validator.validate(val) + self._submitter_email_value = val + self._submitter_email_present = True - def get_shared_link_add_expiry(self): - """ - (sharing) Added shared link expiration date + @submitter_email.deleter + def submitter_email(self): + self._submitter_email_value = None + self._submitter_email_present = False - Only call this if :meth:`is_shared_link_add_expiry` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestReceiveFileDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: SharedLinkAddExpiryType - """ - if not self.is_shared_link_add_expiry(): - raise AttributeError("tag 'shared_link_add_expiry' not set") - return self._value + def __repr__(self): + return 'FileRequestReceiveFileDetails(submitted_file_names={!r}, file_request_id={!r}, file_request_details={!r}, submitter_name={!r}, submitter_email={!r})'.format( + self._submitted_file_names_value, + self._file_request_id_value, + self._file_request_details_value, + self._submitter_name_value, + self._submitter_email_value, + ) - def get_shared_link_change_expiry(self): - """ - (sharing) Changed shared link expiration date +FileRequestReceiveFileDetails_validator = bv.Struct(FileRequestReceiveFileDetails) - Only call this if :meth:`is_shared_link_change_expiry` is true. +class FileRequestReceiveFileType(bb.Struct): - :rtype: SharedLinkChangeExpiryType - """ - if not self.is_shared_link_change_expiry(): - raise AttributeError("tag 'shared_link_change_expiry' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_shared_link_change_visibility(self): - """ - (sharing) Changed visibility of shared link + _has_required_fields = True - Only call this if :meth:`is_shared_link_change_visibility` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: SharedLinkChangeVisibilityType + @property + def description(self): """ - if not self.is_shared_link_change_visibility(): - raise AttributeError("tag 'shared_link_change_visibility' not set") - return self._value - - def get_shared_link_copy(self): + :rtype: str """ - (sharing) Added file/folder to Dropbox from shared link + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_shared_link_copy` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SharedLinkCopyType - """ - if not self.is_shared_link_copy(): - raise AttributeError("tag 'shared_link_copy' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_shared_link_create(self): - """ - (sharing) Created shared link + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestReceiveFileType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_shared_link_create` is true. + def __repr__(self): + return 'FileRequestReceiveFileType(description={!r})'.format( + self._description_value, + ) - :rtype: SharedLinkCreateType - """ - if not self.is_shared_link_create(): - raise AttributeError("tag 'shared_link_create' not set") - return self._value +FileRequestReceiveFileType_validator = bv.Struct(FileRequestReceiveFileType) - def get_shared_link_disable(self): - """ - (sharing) Removed shared link +class FileRequestsChangePolicyDetails(bb.Struct): + """ + Enabled/disabled file requests. - Only call this if :meth:`is_shared_link_disable` is true. + :ivar team_log.FileRequestsChangePolicyDetails.new_value: New file requests + policy. + :ivar team_log.FileRequestsChangePolicyDetails.previous_value: Previous file + requests policy. Might be missing due to historical data gap. + """ - :rtype: SharedLinkDisableType - """ - if not self.is_shared_link_disable(): - raise AttributeError("tag 'shared_link_disable' not set") - return self._value + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] - def get_shared_link_download(self): - """ - (sharing) Downloaded file/folder from shared link + _has_required_fields = True - Only call this if :meth:`is_shared_link_download` is true. + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value - :rtype: SharedLinkDownloadType + @property + def new_value(self): """ - if not self.is_shared_link_download(): - raise AttributeError("tag 'shared_link_download' not set") - return self._value + New file requests policy. - def get_shared_link_remove_expiry(self): + :rtype: FileRequestsPolicy """ - (sharing) Removed shared link expiration date + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - Only call this if :meth:`is_shared_link_remove_expiry` is true. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - :rtype: SharedLinkRemoveExpiryType - """ - if not self.is_shared_link_remove_expiry(): - raise AttributeError("tag 'shared_link_remove_expiry' not set") - return self._value + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - def get_shared_link_share(self): + @property + def previous_value(self): """ - (sharing) Added members as audience of shared link - - Only call this if :meth:`is_shared_link_share` is true. + Previous file requests policy. Might be missing due to historical data + gap. - :rtype: SharedLinkShareType + :rtype: FileRequestsPolicy """ - if not self.is_shared_link_share(): - raise AttributeError("tag 'shared_link_share' not set") - return self._value + if self._previous_value_present: + return self._previous_value_value + else: + return None - def get_shared_link_view(self): - """ - (sharing) Opened shared link + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - Only call this if :meth:`is_shared_link_view` is true. + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - :rtype: SharedLinkViewType - """ - if not self.is_shared_link_view(): - raise AttributeError("tag 'shared_link_view' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_shared_note_opened(self): - """ - (sharing) Opened shared Paper doc (deprecated, no longer logged) + def __repr__(self): + return 'FileRequestsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) - Only call this if :meth:`is_shared_note_opened` is true. +FileRequestsChangePolicyDetails_validator = bv.Struct(FileRequestsChangePolicyDetails) - :rtype: SharedNoteOpenedType - """ - if not self.is_shared_note_opened(): - raise AttributeError("tag 'shared_note_opened' not set") - return self._value +class FileRequestsChangePolicyType(bb.Struct): - def get_shmodel_group_share(self): - """ - (sharing) Shared link with group (deprecated, no longer logged) + __slots__ = [ + '_description_value', + '_description_present', + ] - Only call this if :meth:`is_shmodel_group_share` is true. + _has_required_fields = True - :rtype: ShmodelGroupShareType - """ - if not self.is_shmodel_group_share(): - raise AttributeError("tag 'shmodel_group_share' not set") - return self._value + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def get_showcase_access_granted(self): + @property + def description(self): """ - (showcase) Granted access to showcase + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_showcase_access_granted` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: ShowcaseAccessGrantedType - """ - if not self.is_showcase_access_granted(): - raise AttributeError("tag 'showcase_access_granted' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_showcase_add_member(self): - """ - (showcase) Added member to showcase + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_showcase_add_member` is true. + def __repr__(self): + return 'FileRequestsChangePolicyType(description={!r})'.format( + self._description_value, + ) - :rtype: ShowcaseAddMemberType - """ - if not self.is_showcase_add_member(): - raise AttributeError("tag 'showcase_add_member' not set") - return self._value +FileRequestsChangePolicyType_validator = bv.Struct(FileRequestsChangePolicyType) - def get_showcase_archived(self): - """ - (showcase) Archived showcase +class FileRequestsEmailsEnabledDetails(bb.Struct): + """ + Enabled file request emails for everyone. + """ - Only call this if :meth:`is_showcase_archived` is true. + __slots__ = [ + ] - :rtype: ShowcaseArchivedType - """ - if not self.is_showcase_archived(): - raise AttributeError("tag 'showcase_archived' not set") - return self._value + _has_required_fields = False - def get_showcase_created(self): - """ - (showcase) Created showcase + def __init__(self): + pass - Only call this if :meth:`is_showcase_created` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestsEmailsEnabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: ShowcaseCreatedType - """ - if not self.is_showcase_created(): - raise AttributeError("tag 'showcase_created' not set") - return self._value + def __repr__(self): + return 'FileRequestsEmailsEnabledDetails()' - def get_showcase_delete_comment(self): - """ - (showcase) Deleted showcase comment +FileRequestsEmailsEnabledDetails_validator = bv.Struct(FileRequestsEmailsEnabledDetails) - Only call this if :meth:`is_showcase_delete_comment` is true. +class FileRequestsEmailsEnabledType(bb.Struct): - :rtype: ShowcaseDeleteCommentType - """ - if not self.is_showcase_delete_comment(): - raise AttributeError("tag 'showcase_delete_comment' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_showcase_edited(self): - """ - (showcase) Edited showcase + _has_required_fields = True - Only call this if :meth:`is_showcase_edited` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: ShowcaseEditedType + @property + def description(self): """ - if not self.is_showcase_edited(): - raise AttributeError("tag 'showcase_edited' not set") - return self._value - - def get_showcase_edit_comment(self): + :rtype: str """ - (showcase) Edited showcase comment + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_showcase_edit_comment` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: ShowcaseEditCommentType - """ - if not self.is_showcase_edit_comment(): - raise AttributeError("tag 'showcase_edit_comment' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_showcase_file_added(self): - """ - (showcase) Added file to showcase + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestsEmailsEnabledType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_showcase_file_added` is true. + def __repr__(self): + return 'FileRequestsEmailsEnabledType(description={!r})'.format( + self._description_value, + ) - :rtype: ShowcaseFileAddedType - """ - if not self.is_showcase_file_added(): - raise AttributeError("tag 'showcase_file_added' not set") - return self._value +FileRequestsEmailsEnabledType_validator = bv.Struct(FileRequestsEmailsEnabledType) - def get_showcase_file_download(self): - """ - (showcase) Downloaded file from showcase +class FileRequestsEmailsRestrictedToTeamOnlyDetails(bb.Struct): + """ + Enabled file request emails for team. + """ - Only call this if :meth:`is_showcase_file_download` is true. + __slots__ = [ + ] - :rtype: ShowcaseFileDownloadType - """ - if not self.is_showcase_file_download(): - raise AttributeError("tag 'showcase_file_download' not set") - return self._value + _has_required_fields = False - def get_showcase_file_removed(self): - """ - (showcase) Removed file from showcase + def __init__(self): + pass - Only call this if :meth:`is_showcase_file_removed` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestsEmailsRestrictedToTeamOnlyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: ShowcaseFileRemovedType - """ - if not self.is_showcase_file_removed(): - raise AttributeError("tag 'showcase_file_removed' not set") - return self._value + def __repr__(self): + return 'FileRequestsEmailsRestrictedToTeamOnlyDetails()' - def get_showcase_file_view(self): - """ - (showcase) Viewed file in showcase +FileRequestsEmailsRestrictedToTeamOnlyDetails_validator = bv.Struct(FileRequestsEmailsRestrictedToTeamOnlyDetails) - Only call this if :meth:`is_showcase_file_view` is true. +class FileRequestsEmailsRestrictedToTeamOnlyType(bb.Struct): - :rtype: ShowcaseFileViewType - """ - if not self.is_showcase_file_view(): - raise AttributeError("tag 'showcase_file_view' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_showcase_permanently_deleted(self): - """ - (showcase) Permanently deleted showcase + _has_required_fields = True - Only call this if :meth:`is_showcase_permanently_deleted` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: ShowcasePermanentlyDeletedType + @property + def description(self): """ - if not self.is_showcase_permanently_deleted(): - raise AttributeError("tag 'showcase_permanently_deleted' not set") - return self._value - - def get_showcase_post_comment(self): + :rtype: str """ - (showcase) Added showcase comment + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_showcase_post_comment` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: ShowcasePostCommentType - """ - if not self.is_showcase_post_comment(): - raise AttributeError("tag 'showcase_post_comment' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_showcase_remove_member(self): - """ - (showcase) Removed member from showcase + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestsEmailsRestrictedToTeamOnlyType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileRequestsEmailsRestrictedToTeamOnlyType(description={!r})'.format( + self._description_value, + ) - Only call this if :meth:`is_showcase_remove_member` is true. +FileRequestsEmailsRestrictedToTeamOnlyType_validator = bv.Struct(FileRequestsEmailsRestrictedToTeamOnlyType) - :rtype: ShowcaseRemoveMemberType - """ - if not self.is_showcase_remove_member(): - raise AttributeError("tag 'showcase_remove_member' not set") - return self._value +class FileRequestsPolicy(bb.Union): + """ + File requests policy - def get_showcase_renamed(self): - """ - (showcase) Renamed showcase + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - Only call this if :meth:`is_showcase_renamed` is true. + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - :rtype: ShowcaseRenamedType + def is_disabled(self): """ - if not self.is_showcase_renamed(): - raise AttributeError("tag 'showcase_renamed' not set") - return self._value + Check if the union tag is ``disabled``. - def get_showcase_request_access(self): + :rtype: bool """ - (showcase) Requested access to showcase - - Only call this if :meth:`is_showcase_request_access` is true. + return self._tag == 'disabled' - :rtype: ShowcaseRequestAccessType + def is_enabled(self): """ - if not self.is_showcase_request_access(): - raise AttributeError("tag 'showcase_request_access' not set") - return self._value + Check if the union tag is ``enabled``. - def get_showcase_resolve_comment(self): + :rtype: bool """ - (showcase) Resolved showcase comment - - Only call this if :meth:`is_showcase_resolve_comment` is true. + return self._tag == 'enabled' - :rtype: ShowcaseResolveCommentType + def is_other(self): """ - if not self.is_showcase_resolve_comment(): - raise AttributeError("tag 'showcase_resolve_comment' not set") - return self._value + Check if the union tag is ``other``. - def get_showcase_restored(self): + :rtype: bool """ - (showcase) Unarchived showcase + return self._tag == 'other' - Only call this if :meth:`is_showcase_restored` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRequestsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: ShowcaseRestoredType - """ - if not self.is_showcase_restored(): - raise AttributeError("tag 'showcase_restored' not set") - return self._value + def __repr__(self): + return 'FileRequestsPolicy(%r, %r)' % (self._tag, self._value) - def get_showcase_trashed(self): - """ - (showcase) Deleted showcase +FileRequestsPolicy_validator = bv.Union(FileRequestsPolicy) - Only call this if :meth:`is_showcase_trashed` is true. +class FileResolveCommentDetails(bb.Struct): + """ + Resolved file comment. - :rtype: ShowcaseTrashedType - """ - if not self.is_showcase_trashed(): - raise AttributeError("tag 'showcase_trashed' not set") - return self._value + :ivar team_log.FileResolveCommentDetails.comment_text: Comment text. Might + be missing due to historical data gap. + """ - def get_showcase_trashed_deprecated(self): - """ - (showcase) Deleted showcase (old version) (deprecated, replaced by - 'Deleted showcase') + __slots__ = [ + '_comment_text_value', + '_comment_text_present', + ] - Only call this if :meth:`is_showcase_trashed_deprecated` is true. + _has_required_fields = False - :rtype: ShowcaseTrashedDeprecatedType - """ - if not self.is_showcase_trashed_deprecated(): - raise AttributeError("tag 'showcase_trashed_deprecated' not set") - return self._value + def __init__(self, + comment_text=None): + self._comment_text_value = None + self._comment_text_present = False + if comment_text is not None: + self.comment_text = comment_text - def get_showcase_unresolve_comment(self): + @property + def comment_text(self): """ - (showcase) Unresolved showcase comment - - Only call this if :meth:`is_showcase_unresolve_comment` is true. + Comment text. Might be missing due to historical data gap. - :rtype: ShowcaseUnresolveCommentType + :rtype: str """ - if not self.is_showcase_unresolve_comment(): - raise AttributeError("tag 'showcase_unresolve_comment' not set") - return self._value + if self._comment_text_present: + return self._comment_text_value + else: + return None - def get_showcase_untrashed(self): - """ - (showcase) Restored showcase + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - Only call this if :meth:`is_showcase_untrashed` is true. + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False - :rtype: ShowcaseUntrashedType - """ - if not self.is_showcase_untrashed(): - raise AttributeError("tag 'showcase_untrashed' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileResolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_showcase_untrashed_deprecated(self): - """ - (showcase) Restored showcase (old version) (deprecated, replaced by - 'Restored showcase') + def __repr__(self): + return 'FileResolveCommentDetails(comment_text={!r})'.format( + self._comment_text_value, + ) - Only call this if :meth:`is_showcase_untrashed_deprecated` is true. +FileResolveCommentDetails_validator = bv.Struct(FileResolveCommentDetails) - :rtype: ShowcaseUntrashedDeprecatedType - """ - if not self.is_showcase_untrashed_deprecated(): - raise AttributeError("tag 'showcase_untrashed_deprecated' not set") - return self._value +class FileResolveCommentType(bb.Struct): - def get_showcase_view(self): - """ - (showcase) Viewed showcase + __slots__ = [ + '_description_value', + '_description_present', + ] - Only call this if :meth:`is_showcase_view` is true. + _has_required_fields = True - :rtype: ShowcaseViewType - """ - if not self.is_showcase_view(): - raise AttributeError("tag 'showcase_view' not set") - return self._value + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def get_sso_add_cert(self): + @property + def description(self): """ - (sso) Added X.509 certificate for SSO + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_sso_add_cert` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SsoAddCertType - """ - if not self.is_sso_add_cert(): - raise AttributeError("tag 'sso_add_cert' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_sso_add_login_url(self): - """ - (sso) Added sign-in URL for SSO + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileResolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_sso_add_login_url` is true. + def __repr__(self): + return 'FileResolveCommentType(description={!r})'.format( + self._description_value, + ) - :rtype: SsoAddLoginUrlType - """ - if not self.is_sso_add_login_url(): - raise AttributeError("tag 'sso_add_login_url' not set") - return self._value +FileResolveCommentType_validator = bv.Struct(FileResolveCommentType) - def get_sso_add_logout_url(self): - """ - (sso) Added sign-out URL for SSO +class FileRestoreDetails(bb.Struct): + """ + Restored deleted files and/or folders. + """ - Only call this if :meth:`is_sso_add_logout_url` is true. + __slots__ = [ + ] - :rtype: SsoAddLogoutUrlType - """ - if not self.is_sso_add_logout_url(): - raise AttributeError("tag 'sso_add_logout_url' not set") - return self._value + _has_required_fields = False - def get_sso_change_cert(self): - """ - (sso) Changed X.509 certificate for SSO + def __init__(self): + pass - Only call this if :meth:`is_sso_change_cert` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRestoreDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: SsoChangeCertType - """ - if not self.is_sso_change_cert(): - raise AttributeError("tag 'sso_change_cert' not set") - return self._value + def __repr__(self): + return 'FileRestoreDetails()' - def get_sso_change_login_url(self): - """ - (sso) Changed sign-in URL for SSO +FileRestoreDetails_validator = bv.Struct(FileRestoreDetails) - Only call this if :meth:`is_sso_change_login_url` is true. +class FileRestoreType(bb.Struct): - :rtype: SsoChangeLoginUrlType - """ - if not self.is_sso_change_login_url(): - raise AttributeError("tag 'sso_change_login_url' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_sso_change_logout_url(self): - """ - (sso) Changed sign-out URL for SSO + _has_required_fields = True - Only call this if :meth:`is_sso_change_logout_url` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: SsoChangeLogoutUrlType + @property + def description(self): """ - if not self.is_sso_change_logout_url(): - raise AttributeError("tag 'sso_change_logout_url' not set") - return self._value - - def get_sso_change_saml_identity_mode(self): + :rtype: str """ - (sso) Changed SAML identity mode for SSO + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_sso_change_saml_identity_mode` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SsoChangeSamlIdentityModeType - """ - if not self.is_sso_change_saml_identity_mode(): - raise AttributeError("tag 'sso_change_saml_identity_mode' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_sso_remove_cert(self): - """ - (sso) Removed X.509 certificate for SSO + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRestoreType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_sso_remove_cert` is true. + def __repr__(self): + return 'FileRestoreType(description={!r})'.format( + self._description_value, + ) - :rtype: SsoRemoveCertType - """ - if not self.is_sso_remove_cert(): - raise AttributeError("tag 'sso_remove_cert' not set") - return self._value +FileRestoreType_validator = bv.Struct(FileRestoreType) - def get_sso_remove_login_url(self): - """ - (sso) Removed sign-in URL for SSO +class FileRevertDetails(bb.Struct): + """ + Reverted files to previous version. + """ - Only call this if :meth:`is_sso_remove_login_url` is true. + __slots__ = [ + ] - :rtype: SsoRemoveLoginUrlType - """ - if not self.is_sso_remove_login_url(): - raise AttributeError("tag 'sso_remove_login_url' not set") - return self._value + _has_required_fields = False - def get_sso_remove_logout_url(self): - """ - (sso) Removed sign-out URL for SSO + def __init__(self): + pass - Only call this if :meth:`is_sso_remove_logout_url` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRevertDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: SsoRemoveLogoutUrlType - """ - if not self.is_sso_remove_logout_url(): - raise AttributeError("tag 'sso_remove_logout_url' not set") - return self._value + def __repr__(self): + return 'FileRevertDetails()' - def get_team_folder_change_status(self): - """ - (team_folders) Changed archival status of team folder +FileRevertDetails_validator = bv.Struct(FileRevertDetails) - Only call this if :meth:`is_team_folder_change_status` is true. +class FileRevertType(bb.Struct): - :rtype: TeamFolderChangeStatusType - """ - if not self.is_team_folder_change_status(): - raise AttributeError("tag 'team_folder_change_status' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_team_folder_create(self): - """ - (team_folders) Created team folder in active status + _has_required_fields = True - Only call this if :meth:`is_team_folder_create` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: TeamFolderCreateType + @property + def description(self): """ - if not self.is_team_folder_create(): - raise AttributeError("tag 'team_folder_create' not set") - return self._value - - def get_team_folder_downgrade(self): + :rtype: str """ - (team_folders) Downgraded team folder to regular shared folder + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_team_folder_downgrade` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: TeamFolderDowngradeType - """ - if not self.is_team_folder_downgrade(): - raise AttributeError("tag 'team_folder_downgrade' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_team_folder_permanently_delete(self): - """ - (team_folders) Permanently deleted archived team folder + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRevertType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_team_folder_permanently_delete` is true. + def __repr__(self): + return 'FileRevertType(description={!r})'.format( + self._description_value, + ) - :rtype: TeamFolderPermanentlyDeleteType - """ - if not self.is_team_folder_permanently_delete(): - raise AttributeError("tag 'team_folder_permanently_delete' not set") - return self._value +FileRevertType_validator = bv.Struct(FileRevertType) - def get_team_folder_rename(self): - """ - (team_folders) Renamed active/archived team folder +class FileRollbackChangesDetails(bb.Struct): + """ + Rolled back file actions. + """ - Only call this if :meth:`is_team_folder_rename` is true. + __slots__ = [ + ] - :rtype: TeamFolderRenameType - """ - if not self.is_team_folder_rename(): - raise AttributeError("tag 'team_folder_rename' not set") - return self._value + _has_required_fields = False - def get_team_selective_sync_settings_changed(self): - """ - (team_folders) Changed sync default + def __init__(self): + pass - Only call this if :meth:`is_team_selective_sync_settings_changed` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRollbackChangesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: TeamSelectiveSyncSettingsChangedType - """ - if not self.is_team_selective_sync_settings_changed(): - raise AttributeError("tag 'team_selective_sync_settings_changed' not set") - return self._value + def __repr__(self): + return 'FileRollbackChangesDetails()' - def get_account_capture_change_policy(self): - """ - (team_policies) Changed account capture setting on team domain +FileRollbackChangesDetails_validator = bv.Struct(FileRollbackChangesDetails) - Only call this if :meth:`is_account_capture_change_policy` is true. +class FileRollbackChangesType(bb.Struct): - :rtype: AccountCaptureChangePolicyType - """ - if not self.is_account_capture_change_policy(): - raise AttributeError("tag 'account_capture_change_policy' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_allow_download_disabled(self): - """ - (team_policies) Disabled downloads (deprecated, no longer logged) + _has_required_fields = True - Only call this if :meth:`is_allow_download_disabled` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: AllowDownloadDisabledType + @property + def description(self): """ - if not self.is_allow_download_disabled(): - raise AttributeError("tag 'allow_download_disabled' not set") - return self._value - - def get_allow_download_enabled(self): + :rtype: str """ - (team_policies) Enabled downloads (deprecated, no longer logged) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_allow_download_enabled` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: AllowDownloadEnabledType - """ - if not self.is_allow_download_enabled(): - raise AttributeError("tag 'allow_download_enabled' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_camera_uploads_policy_changed(self): - """ - (team_policies) Changed camera uploads setting for team + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileRollbackChangesType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_camera_uploads_policy_changed` is true. + def __repr__(self): + return 'FileRollbackChangesType(description={!r})'.format( + self._description_value, + ) - :rtype: CameraUploadsPolicyChangedType - """ - if not self.is_camera_uploads_policy_changed(): - raise AttributeError("tag 'camera_uploads_policy_changed' not set") - return self._value +FileRollbackChangesType_validator = bv.Struct(FileRollbackChangesType) - def get_data_placement_restriction_change_policy(self): - """ - (team_policies) Set restrictions on data center locations where team - data resides +class FileSaveCopyReferenceDetails(bb.Struct): + """ + Saved file/folder using copy reference. - Only call this if :meth:`is_data_placement_restriction_change_policy` is true. + :ivar team_log.FileSaveCopyReferenceDetails.relocate_action_details: + Relocate action details. + """ - :rtype: DataPlacementRestrictionChangePolicyType - """ - if not self.is_data_placement_restriction_change_policy(): - raise AttributeError("tag 'data_placement_restriction_change_policy' not set") - return self._value + __slots__ = [ + '_relocate_action_details_value', + '_relocate_action_details_present', + ] - def get_data_placement_restriction_satisfy_policy(self): - """ - (team_policies) Completed restrictions on data center locations where - team data resides + _has_required_fields = True - Only call this if :meth:`is_data_placement_restriction_satisfy_policy` is true. + def __init__(self, + relocate_action_details=None): + self._relocate_action_details_value = None + self._relocate_action_details_present = False + if relocate_action_details is not None: + self.relocate_action_details = relocate_action_details - :rtype: DataPlacementRestrictionSatisfyPolicyType + @property + def relocate_action_details(self): """ - if not self.is_data_placement_restriction_satisfy_policy(): - raise AttributeError("tag 'data_placement_restriction_satisfy_policy' not set") - return self._value + Relocate action details. - def get_device_approvals_change_desktop_policy(self): + :rtype: list of [RelocateAssetReferencesLogInfo] """ - (team_policies) Set/removed limit on number of computers member can link - to team Dropbox account - - Only call this if :meth:`is_device_approvals_change_desktop_policy` is true. + if self._relocate_action_details_present: + return self._relocate_action_details_value + else: + raise AttributeError("missing required field 'relocate_action_details'") - :rtype: DeviceApprovalsChangeDesktopPolicyType - """ - if not self.is_device_approvals_change_desktop_policy(): - raise AttributeError("tag 'device_approvals_change_desktop_policy' not set") - return self._value + @relocate_action_details.setter + def relocate_action_details(self, val): + val = self._relocate_action_details_validator.validate(val) + self._relocate_action_details_value = val + self._relocate_action_details_present = True - def get_device_approvals_change_mobile_policy(self): - """ - (team_policies) Set/removed limit on number of mobile devices member can - link to team Dropbox account + @relocate_action_details.deleter + def relocate_action_details(self): + self._relocate_action_details_value = None + self._relocate_action_details_present = False - Only call this if :meth:`is_device_approvals_change_mobile_policy` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileSaveCopyReferenceDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: DeviceApprovalsChangeMobilePolicyType - """ - if not self.is_device_approvals_change_mobile_policy(): - raise AttributeError("tag 'device_approvals_change_mobile_policy' not set") - return self._value + def __repr__(self): + return 'FileSaveCopyReferenceDetails(relocate_action_details={!r})'.format( + self._relocate_action_details_value, + ) - def get_device_approvals_change_overage_action(self): - """ - (team_policies) Changed device approvals setting when member is over - limit +FileSaveCopyReferenceDetails_validator = bv.Struct(FileSaveCopyReferenceDetails) - Only call this if :meth:`is_device_approvals_change_overage_action` is true. +class FileSaveCopyReferenceType(bb.Struct): - :rtype: DeviceApprovalsChangeOverageActionType - """ - if not self.is_device_approvals_change_overage_action(): - raise AttributeError("tag 'device_approvals_change_overage_action' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_device_approvals_change_unlink_action(self): - """ - (team_policies) Changed device approvals setting when member unlinks - approved device + _has_required_fields = True - Only call this if :meth:`is_device_approvals_change_unlink_action` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: DeviceApprovalsChangeUnlinkActionType + @property + def description(self): """ - if not self.is_device_approvals_change_unlink_action(): - raise AttributeError("tag 'device_approvals_change_unlink_action' not set") - return self._value - - def get_directory_restrictions_add_members(self): + :rtype: str """ - (team_policies) Added members to directory restrictions list + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_directory_restrictions_add_members` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: DirectoryRestrictionsAddMembersType - """ - if not self.is_directory_restrictions_add_members(): - raise AttributeError("tag 'directory_restrictions_add_members' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_directory_restrictions_remove_members(self): - """ - (team_policies) Removed members from directory restrictions list + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileSaveCopyReferenceType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_directory_restrictions_remove_members` is true. + def __repr__(self): + return 'FileSaveCopyReferenceType(description={!r})'.format( + self._description_value, + ) - :rtype: DirectoryRestrictionsRemoveMembersType - """ - if not self.is_directory_restrictions_remove_members(): - raise AttributeError("tag 'directory_restrictions_remove_members' not set") - return self._value +FileSaveCopyReferenceType_validator = bv.Struct(FileSaveCopyReferenceType) - def get_emm_add_exception(self): - """ - (team_policies) Added members to EMM exception list +class FileTransfersFileAddDetails(bb.Struct): + """ + Transfer files added. - Only call this if :meth:`is_emm_add_exception` is true. + :ivar team_log.FileTransfersFileAddDetails.file_transfer_id: Transfer id. + """ - :rtype: EmmAddExceptionType - """ - if not self.is_emm_add_exception(): - raise AttributeError("tag 'emm_add_exception' not set") - return self._value + __slots__ = [ + '_file_transfer_id_value', + '_file_transfer_id_present', + ] - def get_emm_change_policy(self): - """ - (team_policies) Enabled/disabled enterprise mobility management for - members + _has_required_fields = True - Only call this if :meth:`is_emm_change_policy` is true. + def __init__(self, + file_transfer_id=None): + self._file_transfer_id_value = None + self._file_transfer_id_present = False + if file_transfer_id is not None: + self.file_transfer_id = file_transfer_id - :rtype: EmmChangePolicyType + @property + def file_transfer_id(self): """ - if not self.is_emm_change_policy(): - raise AttributeError("tag 'emm_change_policy' not set") - return self._value + Transfer id. - def get_emm_remove_exception(self): + :rtype: str """ - (team_policies) Removed members from EMM exception list - - Only call this if :meth:`is_emm_remove_exception` is true. + if self._file_transfer_id_present: + return self._file_transfer_id_value + else: + raise AttributeError("missing required field 'file_transfer_id'") - :rtype: EmmRemoveExceptionType - """ - if not self.is_emm_remove_exception(): - raise AttributeError("tag 'emm_remove_exception' not set") - return self._value + @file_transfer_id.setter + def file_transfer_id(self, val): + val = self._file_transfer_id_validator.validate(val) + self._file_transfer_id_value = val + self._file_transfer_id_present = True - def get_extended_version_history_change_policy(self): - """ - (team_policies) Accepted/opted out of extended version history + @file_transfer_id.deleter + def file_transfer_id(self): + self._file_transfer_id_value = None + self._file_transfer_id_present = False - Only call this if :meth:`is_extended_version_history_change_policy` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersFileAddDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: ExtendedVersionHistoryChangePolicyType - """ - if not self.is_extended_version_history_change_policy(): - raise AttributeError("tag 'extended_version_history_change_policy' not set") - return self._value + def __repr__(self): + return 'FileTransfersFileAddDetails(file_transfer_id={!r})'.format( + self._file_transfer_id_value, + ) - def get_file_comments_change_policy(self): - """ - (team_policies) Enabled/disabled commenting on team files +FileTransfersFileAddDetails_validator = bv.Struct(FileTransfersFileAddDetails) - Only call this if :meth:`is_file_comments_change_policy` is true. +class FileTransfersFileAddType(bb.Struct): - :rtype: FileCommentsChangePolicyType - """ - if not self.is_file_comments_change_policy(): - raise AttributeError("tag 'file_comments_change_policy' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_file_requests_change_policy(self): - """ - (team_policies) Enabled/disabled file requests + _has_required_fields = True - Only call this if :meth:`is_file_requests_change_policy` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: FileRequestsChangePolicyType + @property + def description(self): """ - if not self.is_file_requests_change_policy(): - raise AttributeError("tag 'file_requests_change_policy' not set") - return self._value - - def get_file_requests_emails_enabled(self): + :rtype: str """ - (team_policies) Enabled file request emails for everyone (deprecated, no - longer logged) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_file_requests_emails_enabled` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: FileRequestsEmailsEnabledType - """ - if not self.is_file_requests_emails_enabled(): - raise AttributeError("tag 'file_requests_emails_enabled' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_file_requests_emails_restricted_to_team_only(self): - """ - (team_policies) Enabled file request emails for team (deprecated, no - longer logged) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersFileAddType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_file_requests_emails_restricted_to_team_only` is true. + def __repr__(self): + return 'FileTransfersFileAddType(description={!r})'.format( + self._description_value, + ) - :rtype: FileRequestsEmailsRestrictedToTeamOnlyType - """ - if not self.is_file_requests_emails_restricted_to_team_only(): - raise AttributeError("tag 'file_requests_emails_restricted_to_team_only' not set") - return self._value +FileTransfersFileAddType_validator = bv.Struct(FileTransfersFileAddType) - def get_google_sso_change_policy(self): - """ - (team_policies) Enabled/disabled Google single sign-on for team +class FileTransfersPolicy(bb.Union): + """ + File transfers policy - Only call this if :meth:`is_google_sso_change_policy` is true. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - :rtype: GoogleSsoChangePolicyType - """ - if not self.is_google_sso_change_policy(): - raise AttributeError("tag 'google_sso_change_policy' not set") - return self._value + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - def get_group_user_management_change_policy(self): + def is_disabled(self): """ - (team_policies) Changed who can create groups - - Only call this if :meth:`is_group_user_management_change_policy` is true. + Check if the union tag is ``disabled``. - :rtype: GroupUserManagementChangePolicyType + :rtype: bool """ - if not self.is_group_user_management_change_policy(): - raise AttributeError("tag 'group_user_management_change_policy' not set") - return self._value + return self._tag == 'disabled' - def get_integration_policy_changed(self): + def is_enabled(self): """ - (team_policies) Changed integration policy for team - - Only call this if :meth:`is_integration_policy_changed` is true. + Check if the union tag is ``enabled``. - :rtype: IntegrationPolicyChangedType + :rtype: bool """ - if not self.is_integration_policy_changed(): - raise AttributeError("tag 'integration_policy_changed' not set") - return self._value + return self._tag == 'enabled' - def get_member_requests_change_policy(self): + def is_other(self): """ - (team_policies) Changed whether users can find team when not invited - - Only call this if :meth:`is_member_requests_change_policy` is true. + Check if the union tag is ``other``. - :rtype: MemberRequestsChangePolicyType + :rtype: bool """ - if not self.is_member_requests_change_policy(): - raise AttributeError("tag 'member_requests_change_policy' not set") - return self._value + return self._tag == 'other' - def get_member_space_limits_add_exception(self): - """ - (team_policies) Added members to member space limit exception list + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_member_space_limits_add_exception` is true. + def __repr__(self): + return 'FileTransfersPolicy(%r, %r)' % (self._tag, self._value) - :rtype: MemberSpaceLimitsAddExceptionType - """ - if not self.is_member_space_limits_add_exception(): - raise AttributeError("tag 'member_space_limits_add_exception' not set") - return self._value +FileTransfersPolicy_validator = bv.Union(FileTransfersPolicy) - def get_member_space_limits_change_caps_type_policy(self): - """ - (team_policies) Changed member space limit type for team +class FileTransfersPolicyChangedDetails(bb.Struct): + """ + Changed file transfers policy for team. - Only call this if :meth:`is_member_space_limits_change_caps_type_policy` is true. + :ivar team_log.FileTransfersPolicyChangedDetails.new_value: New file + transfers policy. + :ivar team_log.FileTransfersPolicyChangedDetails.previous_value: Previous + file transfers policy. + """ - :rtype: MemberSpaceLimitsChangeCapsTypePolicyType - """ - if not self.is_member_space_limits_change_caps_type_policy(): - raise AttributeError("tag 'member_space_limits_change_caps_type_policy' not set") - return self._value + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] - def get_member_space_limits_change_policy(self): - """ - (team_policies) Changed team default member space limit + _has_required_fields = True - Only call this if :meth:`is_member_space_limits_change_policy` is true. + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value - :rtype: MemberSpaceLimitsChangePolicyType + @property + def new_value(self): """ - if not self.is_member_space_limits_change_policy(): - raise AttributeError("tag 'member_space_limits_change_policy' not set") - return self._value + New file transfers policy. - def get_member_space_limits_remove_exception(self): + :rtype: FileTransfersPolicy """ - (team_policies) Removed members from member space limit exception list + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - Only call this if :meth:`is_member_space_limits_remove_exception` is true. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - :rtype: MemberSpaceLimitsRemoveExceptionType - """ - if not self.is_member_space_limits_remove_exception(): - raise AttributeError("tag 'member_space_limits_remove_exception' not set") - return self._value + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - def get_member_suggestions_change_policy(self): + @property + def previous_value(self): """ - (team_policies) Enabled/disabled option for team members to suggest - people to add to team - - Only call this if :meth:`is_member_suggestions_change_policy` is true. + Previous file transfers policy. - :rtype: MemberSuggestionsChangePolicyType + :rtype: FileTransfersPolicy """ - if not self.is_member_suggestions_change_policy(): - raise AttributeError("tag 'member_suggestions_change_policy' not set") - return self._value + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") - def get_microsoft_office_addin_change_policy(self): - """ - (team_policies) Enabled/disabled Microsoft Office add-in + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - Only call this if :meth:`is_microsoft_office_addin_change_policy` is true. + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - :rtype: MicrosoftOfficeAddinChangePolicyType - """ - if not self.is_microsoft_office_addin_change_policy(): - raise AttributeError("tag 'microsoft_office_addin_change_policy' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_network_control_change_policy(self): - """ - (team_policies) Enabled/disabled network control + def __repr__(self): + return 'FileTransfersPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) - Only call this if :meth:`is_network_control_change_policy` is true. +FileTransfersPolicyChangedDetails_validator = bv.Struct(FileTransfersPolicyChangedDetails) - :rtype: NetworkControlChangePolicyType - """ - if not self.is_network_control_change_policy(): - raise AttributeError("tag 'network_control_change_policy' not set") - return self._value +class FileTransfersPolicyChangedType(bb.Struct): - def get_paper_change_deployment_policy(self): - """ - (team_policies) Changed whether Dropbox Paper, when enabled, is deployed - to all members or to specific members + __slots__ = [ + '_description_value', + '_description_present', + ] - Only call this if :meth:`is_paper_change_deployment_policy` is true. + _has_required_fields = True - :rtype: PaperChangeDeploymentPolicyType - """ - if not self.is_paper_change_deployment_policy(): - raise AttributeError("tag 'paper_change_deployment_policy' not set") - return self._value + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def get_paper_change_member_link_policy(self): + @property + def description(self): """ - (team_policies) Changed whether non-members can view Paper docs with - link (deprecated, no longer logged) - - Only call this if :meth:`is_paper_change_member_link_policy` is true. - - :rtype: PaperChangeMemberLinkPolicyType + :rtype: str """ - if not self.is_paper_change_member_link_policy(): - raise AttributeError("tag 'paper_change_member_link_policy' not set") - return self._value + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - def get_paper_change_member_policy(self): - """ - (team_policies) Changed whether members can share Paper docs outside - team, and if docs are accessible only by team members or anyone by - default + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - Only call this if :meth:`is_paper_change_member_policy` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: PaperChangeMemberPolicyType - """ - if not self.is_paper_change_member_policy(): - raise AttributeError("tag 'paper_change_member_policy' not set") - return self._value + def __repr__(self): + return 'FileTransfersPolicyChangedType(description={!r})'.format( + self._description_value, + ) - def get_paper_change_policy(self): - """ - (team_policies) Enabled/disabled Dropbox Paper for team +FileTransfersPolicyChangedType_validator = bv.Struct(FileTransfersPolicyChangedType) - Only call this if :meth:`is_paper_change_policy` is true. +class FileTransfersTransferDeleteDetails(bb.Struct): + """ + Deleted transfer. - :rtype: PaperChangePolicyType - """ - if not self.is_paper_change_policy(): - raise AttributeError("tag 'paper_change_policy' not set") - return self._value + :ivar team_log.FileTransfersTransferDeleteDetails.file_transfer_id: Transfer + id. + """ - def get_paper_default_folder_policy_changed(self): - """ - (team_policies) Changed Paper Default Folder Policy setting for team + __slots__ = [ + '_file_transfer_id_value', + '_file_transfer_id_present', + ] - Only call this if :meth:`is_paper_default_folder_policy_changed` is true. + _has_required_fields = True - :rtype: PaperDefaultFolderPolicyChangedType - """ - if not self.is_paper_default_folder_policy_changed(): - raise AttributeError("tag 'paper_default_folder_policy_changed' not set") - return self._value + def __init__(self, + file_transfer_id=None): + self._file_transfer_id_value = None + self._file_transfer_id_present = False + if file_transfer_id is not None: + self.file_transfer_id = file_transfer_id - def get_paper_desktop_policy_changed(self): + @property + def file_transfer_id(self): """ - (team_policies) Enabled/disabled Paper Desktop for team - - Only call this if :meth:`is_paper_desktop_policy_changed` is true. + Transfer id. - :rtype: PaperDesktopPolicyChangedType + :rtype: str """ - if not self.is_paper_desktop_policy_changed(): - raise AttributeError("tag 'paper_desktop_policy_changed' not set") - return self._value + if self._file_transfer_id_present: + return self._file_transfer_id_value + else: + raise AttributeError("missing required field 'file_transfer_id'") - def get_paper_enabled_users_group_addition(self): - """ - (team_policies) Added users to Paper-enabled users list + @file_transfer_id.setter + def file_transfer_id(self, val): + val = self._file_transfer_id_validator.validate(val) + self._file_transfer_id_value = val + self._file_transfer_id_present = True - Only call this if :meth:`is_paper_enabled_users_group_addition` is true. + @file_transfer_id.deleter + def file_transfer_id(self): + self._file_transfer_id_value = None + self._file_transfer_id_present = False - :rtype: PaperEnabledUsersGroupAdditionType - """ - if not self.is_paper_enabled_users_group_addition(): - raise AttributeError("tag 'paper_enabled_users_group_addition' not set") - return self._value + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - def get_paper_enabled_users_group_removal(self): - """ - (team_policies) Removed users from Paper-enabled users list + def __repr__(self): + return 'FileTransfersTransferDeleteDetails(file_transfer_id={!r})'.format( + self._file_transfer_id_value, + ) - Only call this if :meth:`is_paper_enabled_users_group_removal` is true. +FileTransfersTransferDeleteDetails_validator = bv.Struct(FileTransfersTransferDeleteDetails) - :rtype: PaperEnabledUsersGroupRemovalType - """ - if not self.is_paper_enabled_users_group_removal(): - raise AttributeError("tag 'paper_enabled_users_group_removal' not set") - return self._value +class FileTransfersTransferDeleteType(bb.Struct): - def get_permanent_delete_change_policy(self): - """ - (team_policies) Enabled/disabled ability of team members to permanently - delete content + __slots__ = [ + '_description_value', + '_description_present', + ] - Only call this if :meth:`is_permanent_delete_change_policy` is true. + _has_required_fields = True - :rtype: PermanentDeleteChangePolicyType - """ - if not self.is_permanent_delete_change_policy(): - raise AttributeError("tag 'permanent_delete_change_policy' not set") - return self._value + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def get_reseller_support_change_policy(self): + @property + def description(self): """ - (team_policies) Enabled/disabled reseller support + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_reseller_support_change_policy` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: ResellerSupportChangePolicyType - """ - if not self.is_reseller_support_change_policy(): - raise AttributeError("tag 'reseller_support_change_policy' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_sharing_change_folder_join_policy(self): - """ - (team_policies) Changed whether team members can join shared folders - owned outside team + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_sharing_change_folder_join_policy` is true. + def __repr__(self): + return 'FileTransfersTransferDeleteType(description={!r})'.format( + self._description_value, + ) - :rtype: SharingChangeFolderJoinPolicyType - """ - if not self.is_sharing_change_folder_join_policy(): - raise AttributeError("tag 'sharing_change_folder_join_policy' not set") - return self._value +FileTransfersTransferDeleteType_validator = bv.Struct(FileTransfersTransferDeleteType) - def get_sharing_change_link_policy(self): - """ - (team_policies) Changed whether members can share links outside team, - and if links are accessible only by team members or anyone by default +class FileTransfersTransferDownloadDetails(bb.Struct): + """ + Transfer downloaded. - Only call this if :meth:`is_sharing_change_link_policy` is true. + :ivar team_log.FileTransfersTransferDownloadDetails.file_transfer_id: + Transfer id. + """ - :rtype: SharingChangeLinkPolicyType - """ - if not self.is_sharing_change_link_policy(): - raise AttributeError("tag 'sharing_change_link_policy' not set") - return self._value + __slots__ = [ + '_file_transfer_id_value', + '_file_transfer_id_present', + ] - def get_sharing_change_member_policy(self): - """ - (team_policies) Changed whether members can share files/folders outside - team + _has_required_fields = True - Only call this if :meth:`is_sharing_change_member_policy` is true. + def __init__(self, + file_transfer_id=None): + self._file_transfer_id_value = None + self._file_transfer_id_present = False + if file_transfer_id is not None: + self.file_transfer_id = file_transfer_id - :rtype: SharingChangeMemberPolicyType + @property + def file_transfer_id(self): """ - if not self.is_sharing_change_member_policy(): - raise AttributeError("tag 'sharing_change_member_policy' not set") - return self._value + Transfer id. - def get_showcase_change_download_policy(self): + :rtype: str """ - (team_policies) Enabled/disabled downloading files from Dropbox Showcase - for team - - Only call this if :meth:`is_showcase_change_download_policy` is true. + if self._file_transfer_id_present: + return self._file_transfer_id_value + else: + raise AttributeError("missing required field 'file_transfer_id'") - :rtype: ShowcaseChangeDownloadPolicyType - """ - if not self.is_showcase_change_download_policy(): - raise AttributeError("tag 'showcase_change_download_policy' not set") - return self._value + @file_transfer_id.setter + def file_transfer_id(self, val): + val = self._file_transfer_id_validator.validate(val) + self._file_transfer_id_value = val + self._file_transfer_id_present = True - def get_showcase_change_enabled_policy(self): - """ - (team_policies) Enabled/disabled Dropbox Showcase for team + @file_transfer_id.deleter + def file_transfer_id(self): + self._file_transfer_id_value = None + self._file_transfer_id_present = False - Only call this if :meth:`is_showcase_change_enabled_policy` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: ShowcaseChangeEnabledPolicyType - """ - if not self.is_showcase_change_enabled_policy(): - raise AttributeError("tag 'showcase_change_enabled_policy' not set") - return self._value + def __repr__(self): + return 'FileTransfersTransferDownloadDetails(file_transfer_id={!r})'.format( + self._file_transfer_id_value, + ) - def get_showcase_change_external_sharing_policy(self): - """ - (team_policies) Enabled/disabled sharing Dropbox Showcase externally for - team +FileTransfersTransferDownloadDetails_validator = bv.Struct(FileTransfersTransferDownloadDetails) - Only call this if :meth:`is_showcase_change_external_sharing_policy` is true. +class FileTransfersTransferDownloadType(bb.Struct): - :rtype: ShowcaseChangeExternalSharingPolicyType - """ - if not self.is_showcase_change_external_sharing_policy(): - raise AttributeError("tag 'showcase_change_external_sharing_policy' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_smart_sync_change_policy(self): - """ - (team_policies) Changed default Smart Sync setting for team members + _has_required_fields = True - Only call this if :meth:`is_smart_sync_change_policy` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: SmartSyncChangePolicyType + @property + def description(self): """ - if not self.is_smart_sync_change_policy(): - raise AttributeError("tag 'smart_sync_change_policy' not set") - return self._value - - def get_smart_sync_not_opt_out(self): + :rtype: str """ - (team_policies) Opted team into Smart Sync + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_smart_sync_not_opt_out` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: SmartSyncNotOptOutType - """ - if not self.is_smart_sync_not_opt_out(): - raise AttributeError("tag 'smart_sync_not_opt_out' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_smart_sync_opt_out(self): - """ - (team_policies) Opted team out of Smart Sync + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_smart_sync_opt_out` is true. + def __repr__(self): + return 'FileTransfersTransferDownloadType(description={!r})'.format( + self._description_value, + ) - :rtype: SmartSyncOptOutType - """ - if not self.is_smart_sync_opt_out(): - raise AttributeError("tag 'smart_sync_opt_out' not set") - return self._value +FileTransfersTransferDownloadType_validator = bv.Struct(FileTransfersTransferDownloadType) - def get_sso_change_policy(self): - """ - (team_policies) Changed single sign-on setting for team +class FileTransfersTransferSendDetails(bb.Struct): + """ + Sent transfer. - Only call this if :meth:`is_sso_change_policy` is true. + :ivar team_log.FileTransfersTransferSendDetails.file_transfer_id: Transfer + id. + """ - :rtype: SsoChangePolicyType - """ - if not self.is_sso_change_policy(): - raise AttributeError("tag 'sso_change_policy' not set") - return self._value + __slots__ = [ + '_file_transfer_id_value', + '_file_transfer_id_present', + ] - def get_team_extensions_policy_changed(self): - """ - (team_policies) Changed App Integrations setting for team + _has_required_fields = True - Only call this if :meth:`is_team_extensions_policy_changed` is true. + def __init__(self, + file_transfer_id=None): + self._file_transfer_id_value = None + self._file_transfer_id_present = False + if file_transfer_id is not None: + self.file_transfer_id = file_transfer_id - :rtype: TeamExtensionsPolicyChangedType + @property + def file_transfer_id(self): """ - if not self.is_team_extensions_policy_changed(): - raise AttributeError("tag 'team_extensions_policy_changed' not set") - return self._value + Transfer id. - def get_team_selective_sync_policy_changed(self): + :rtype: str """ - (team_policies) Enabled/disabled Team Selective Sync for team + if self._file_transfer_id_present: + return self._file_transfer_id_value + else: + raise AttributeError("missing required field 'file_transfer_id'") - Only call this if :meth:`is_team_selective_sync_policy_changed` is true. + @file_transfer_id.setter + def file_transfer_id(self, val): + val = self._file_transfer_id_validator.validate(val) + self._file_transfer_id_value = val + self._file_transfer_id_present = True - :rtype: TeamSelectiveSyncPolicyChangedType - """ - if not self.is_team_selective_sync_policy_changed(): - raise AttributeError("tag 'team_selective_sync_policy_changed' not set") - return self._value + @file_transfer_id.deleter + def file_transfer_id(self): + self._file_transfer_id_value = None + self._file_transfer_id_present = False - def get_tfa_change_policy(self): - """ - (team_policies) Changed two-step verification setting for team + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferSendDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_tfa_change_policy` is true. + def __repr__(self): + return 'FileTransfersTransferSendDetails(file_transfer_id={!r})'.format( + self._file_transfer_id_value, + ) - :rtype: TfaChangePolicyType - """ - if not self.is_tfa_change_policy(): - raise AttributeError("tag 'tfa_change_policy' not set") - return self._value +FileTransfersTransferSendDetails_validator = bv.Struct(FileTransfersTransferSendDetails) - def get_two_account_change_policy(self): - """ - (team_policies) Enabled/disabled option for members to link personal - Dropbox account and team account to same computer +class FileTransfersTransferSendType(bb.Struct): - Only call this if :meth:`is_two_account_change_policy` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: TwoAccountChangePolicyType - """ - if not self.is_two_account_change_policy(): - raise AttributeError("tag 'two_account_change_policy' not set") - return self._value + _has_required_fields = True - def get_viewer_info_policy_changed(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (team_policies) Changed team policy for viewer info + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_viewer_info_policy_changed` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: ViewerInfoPolicyChangedType - """ - if not self.is_viewer_info_policy_changed(): - raise AttributeError("tag 'viewer_info_policy_changed' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_web_sessions_change_fixed_length_policy(self): - """ - (team_policies) Changed how long members can stay signed in to - Dropbox.com + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferSendType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_web_sessions_change_fixed_length_policy` is true. + def __repr__(self): + return 'FileTransfersTransferSendType(description={!r})'.format( + self._description_value, + ) - :rtype: WebSessionsChangeFixedLengthPolicyType - """ - if not self.is_web_sessions_change_fixed_length_policy(): - raise AttributeError("tag 'web_sessions_change_fixed_length_policy' not set") - return self._value +FileTransfersTransferSendType_validator = bv.Struct(FileTransfersTransferSendType) - def get_web_sessions_change_idle_length_policy(self): - """ - (team_policies) Changed how long team members can be idle while signed - in to Dropbox.com +class FileTransfersTransferViewDetails(bb.Struct): + """ + Viewed transfer. - Only call this if :meth:`is_web_sessions_change_idle_length_policy` is true. + :ivar team_log.FileTransfersTransferViewDetails.file_transfer_id: Transfer + id. + """ - :rtype: WebSessionsChangeIdleLengthPolicyType - """ - if not self.is_web_sessions_change_idle_length_policy(): - raise AttributeError("tag 'web_sessions_change_idle_length_policy' not set") - return self._value + __slots__ = [ + '_file_transfer_id_value', + '_file_transfer_id_present', + ] - def get_team_merge_from(self): - """ - (team_profile) Merged another team into this team + _has_required_fields = True - Only call this if :meth:`is_team_merge_from` is true. + def __init__(self, + file_transfer_id=None): + self._file_transfer_id_value = None + self._file_transfer_id_present = False + if file_transfer_id is not None: + self.file_transfer_id = file_transfer_id - :rtype: TeamMergeFromType + @property + def file_transfer_id(self): """ - if not self.is_team_merge_from(): - raise AttributeError("tag 'team_merge_from' not set") - return self._value + Transfer id. - def get_team_merge_to(self): + :rtype: str """ - (team_profile) Merged this team into another team + if self._file_transfer_id_present: + return self._file_transfer_id_value + else: + raise AttributeError("missing required field 'file_transfer_id'") - Only call this if :meth:`is_team_merge_to` is true. + @file_transfer_id.setter + def file_transfer_id(self, val): + val = self._file_transfer_id_validator.validate(val) + self._file_transfer_id_value = val + self._file_transfer_id_present = True - :rtype: TeamMergeToType - """ - if not self.is_team_merge_to(): - raise AttributeError("tag 'team_merge_to' not set") - return self._value + @file_transfer_id.deleter + def file_transfer_id(self): + self._file_transfer_id_value = None + self._file_transfer_id_present = False - def get_team_profile_add_logo(self): - """ - (team_profile) Added team logo to display on shared link headers + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferViewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_team_profile_add_logo` is true. + def __repr__(self): + return 'FileTransfersTransferViewDetails(file_transfer_id={!r})'.format( + self._file_transfer_id_value, + ) - :rtype: TeamProfileAddLogoType - """ - if not self.is_team_profile_add_logo(): - raise AttributeError("tag 'team_profile_add_logo' not set") - return self._value +FileTransfersTransferViewDetails_validator = bv.Struct(FileTransfersTransferViewDetails) - def get_team_profile_change_default_language(self): - """ - (team_profile) Changed default language for team +class FileTransfersTransferViewType(bb.Struct): - Only call this if :meth:`is_team_profile_change_default_language` is true. + __slots__ = [ + '_description_value', + '_description_present', + ] - :rtype: TeamProfileChangeDefaultLanguageType - """ - if not self.is_team_profile_change_default_language(): - raise AttributeError("tag 'team_profile_change_default_language' not set") - return self._value + _has_required_fields = True - def get_team_profile_change_logo(self): + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - (team_profile) Changed team logo displayed on shared link headers + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_team_profile_change_logo` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: TeamProfileChangeLogoType - """ - if not self.is_team_profile_change_logo(): - raise AttributeError("tag 'team_profile_change_logo' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_team_profile_change_name(self): - """ - (team_profile) Changed team name + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileTransfersTransferViewType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_team_profile_change_name` is true. + def __repr__(self): + return 'FileTransfersTransferViewType(description={!r})'.format( + self._description_value, + ) - :rtype: TeamProfileChangeNameType - """ - if not self.is_team_profile_change_name(): - raise AttributeError("tag 'team_profile_change_name' not set") - return self._value +FileTransfersTransferViewType_validator = bv.Struct(FileTransfersTransferViewType) - def get_team_profile_remove_logo(self): - """ - (team_profile) Removed team logo displayed on shared link headers +class FileUnlikeCommentDetails(bb.Struct): + """ + Unliked file comment. - Only call this if :meth:`is_team_profile_remove_logo` is true. + :ivar team_log.FileUnlikeCommentDetails.comment_text: Comment text. Might be + missing due to historical data gap. + """ - :rtype: TeamProfileRemoveLogoType - """ - if not self.is_team_profile_remove_logo(): - raise AttributeError("tag 'team_profile_remove_logo' not set") - return self._value + __slots__ = [ + '_comment_text_value', + '_comment_text_present', + ] - def get_tfa_add_backup_phone(self): - """ - (tfa) Added backup phone for two-step verification + _has_required_fields = False - Only call this if :meth:`is_tfa_add_backup_phone` is true. + def __init__(self, + comment_text=None): + self._comment_text_value = None + self._comment_text_present = False + if comment_text is not None: + self.comment_text = comment_text - :rtype: TfaAddBackupPhoneType + @property + def comment_text(self): """ - if not self.is_tfa_add_backup_phone(): - raise AttributeError("tag 'tfa_add_backup_phone' not set") - return self._value + Comment text. Might be missing due to historical data gap. - def get_tfa_add_security_key(self): + :rtype: str """ - (tfa) Added security key for two-step verification - - Only call this if :meth:`is_tfa_add_security_key` is true. + if self._comment_text_present: + return self._comment_text_value + else: + return None - :rtype: TfaAddSecurityKeyType - """ - if not self.is_tfa_add_security_key(): - raise AttributeError("tag 'tfa_add_security_key' not set") - return self._value + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - def get_tfa_change_backup_phone(self): - """ - (tfa) Changed backup phone for two-step verification + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False - Only call this if :meth:`is_tfa_change_backup_phone` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileUnlikeCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: TfaChangeBackupPhoneType - """ - if not self.is_tfa_change_backup_phone(): - raise AttributeError("tag 'tfa_change_backup_phone' not set") - return self._value + def __repr__(self): + return 'FileUnlikeCommentDetails(comment_text={!r})'.format( + self._comment_text_value, + ) - def get_tfa_change_status(self): - """ - (tfa) Enabled/disabled/changed two-step verification setting +FileUnlikeCommentDetails_validator = bv.Struct(FileUnlikeCommentDetails) - Only call this if :meth:`is_tfa_change_status` is true. +class FileUnlikeCommentType(bb.Struct): - :rtype: TfaChangeStatusType - """ - if not self.is_tfa_change_status(): - raise AttributeError("tag 'tfa_change_status' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_tfa_remove_backup_phone(self): - """ - (tfa) Removed backup phone for two-step verification + _has_required_fields = True - Only call this if :meth:`is_tfa_remove_backup_phone` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: TfaRemoveBackupPhoneType + @property + def description(self): """ - if not self.is_tfa_remove_backup_phone(): - raise AttributeError("tag 'tfa_remove_backup_phone' not set") - return self._value - - def get_tfa_remove_security_key(self): + :rtype: str """ - (tfa) Removed security key for two-step verification + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_tfa_remove_security_key` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: TfaRemoveSecurityKeyType - """ - if not self.is_tfa_remove_security_key(): - raise AttributeError("tag 'tfa_remove_security_key' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_tfa_reset(self): - """ - (tfa) Reset two-step verification for team member + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileUnlikeCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_tfa_reset` is true. + def __repr__(self): + return 'FileUnlikeCommentType(description={!r})'.format( + self._description_value, + ) - :rtype: TfaResetType - """ - if not self.is_tfa_reset(): - raise AttributeError("tag 'tfa_reset' not set") - return self._value +FileUnlikeCommentType_validator = bv.Struct(FileUnlikeCommentType) - def get_guest_admin_change_status(self): - """ - (trusted_teams) Changed guest team admin status +class FileUnresolveCommentDetails(bb.Struct): + """ + Unresolved file comment. - Only call this if :meth:`is_guest_admin_change_status` is true. + :ivar team_log.FileUnresolveCommentDetails.comment_text: Comment text. Might + be missing due to historical data gap. + """ - :rtype: GuestAdminChangeStatusType - """ - if not self.is_guest_admin_change_status(): - raise AttributeError("tag 'guest_admin_change_status' not set") - return self._value + __slots__ = [ + '_comment_text_value', + '_comment_text_present', + ] - def get_team_merge_request_accepted(self): - """ - (trusted_teams) Accepted a team merge request + _has_required_fields = False - Only call this if :meth:`is_team_merge_request_accepted` is true. + def __init__(self, + comment_text=None): + self._comment_text_value = None + self._comment_text_present = False + if comment_text is not None: + self.comment_text = comment_text - :rtype: TeamMergeRequestAcceptedType + @property + def comment_text(self): """ - if not self.is_team_merge_request_accepted(): - raise AttributeError("tag 'team_merge_request_accepted' not set") - return self._value + Comment text. Might be missing due to historical data gap. - def get_team_merge_request_accepted_shown_to_primary_team(self): + :rtype: str """ - (trusted_teams) Accepted a team merge request (deprecated, replaced by - 'Accepted a team merge request') - - Only call this if :meth:`is_team_merge_request_accepted_shown_to_primary_team` is true. + if self._comment_text_present: + return self._comment_text_value + else: + return None - :rtype: TeamMergeRequestAcceptedShownToPrimaryTeamType - """ - if not self.is_team_merge_request_accepted_shown_to_primary_team(): - raise AttributeError("tag 'team_merge_request_accepted_shown_to_primary_team' not set") - return self._value + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - def get_team_merge_request_accepted_shown_to_secondary_team(self): - """ - (trusted_teams) Accepted a team merge request (deprecated, replaced by - 'Accepted a team merge request') + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False - Only call this if :meth:`is_team_merge_request_accepted_shown_to_secondary_team` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileUnresolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: TeamMergeRequestAcceptedShownToSecondaryTeamType - """ - if not self.is_team_merge_request_accepted_shown_to_secondary_team(): - raise AttributeError("tag 'team_merge_request_accepted_shown_to_secondary_team' not set") - return self._value + def __repr__(self): + return 'FileUnresolveCommentDetails(comment_text={!r})'.format( + self._comment_text_value, + ) - def get_team_merge_request_auto_canceled(self): - """ - (trusted_teams) Automatically canceled team merge request +FileUnresolveCommentDetails_validator = bv.Struct(FileUnresolveCommentDetails) - Only call this if :meth:`is_team_merge_request_auto_canceled` is true. +class FileUnresolveCommentType(bb.Struct): - :rtype: TeamMergeRequestAutoCanceledType - """ - if not self.is_team_merge_request_auto_canceled(): - raise AttributeError("tag 'team_merge_request_auto_canceled' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_team_merge_request_canceled(self): - """ - (trusted_teams) Canceled a team merge request + _has_required_fields = True - Only call this if :meth:`is_team_merge_request_canceled` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: TeamMergeRequestCanceledType + @property + def description(self): """ - if not self.is_team_merge_request_canceled(): - raise AttributeError("tag 'team_merge_request_canceled' not set") - return self._value - - def get_team_merge_request_canceled_shown_to_primary_team(self): + :rtype: str """ - (trusted_teams) Canceled a team merge request (deprecated, replaced by - 'Canceled a team merge request') + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_team_merge_request_canceled_shown_to_primary_team` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: TeamMergeRequestCanceledShownToPrimaryTeamType - """ - if not self.is_team_merge_request_canceled_shown_to_primary_team(): - raise AttributeError("tag 'team_merge_request_canceled_shown_to_primary_team' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - def get_team_merge_request_canceled_shown_to_secondary_team(self): - """ - (trusted_teams) Canceled a team merge request (deprecated, replaced by - 'Canceled a team merge request') + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileUnresolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_team_merge_request_canceled_shown_to_secondary_team` is true. + def __repr__(self): + return 'FileUnresolveCommentType(description={!r})'.format( + self._description_value, + ) - :rtype: TeamMergeRequestCanceledShownToSecondaryTeamType - """ - if not self.is_team_merge_request_canceled_shown_to_secondary_team(): - raise AttributeError("tag 'team_merge_request_canceled_shown_to_secondary_team' not set") - return self._value +FileUnresolveCommentType_validator = bv.Struct(FileUnresolveCommentType) - def get_team_merge_request_expired(self): - """ - (trusted_teams) Team merge request expired +class FolderLogInfo(FileOrFolderLogInfo): + """ + Folder's logged information. - Only call this if :meth:`is_team_merge_request_expired` is true. + :ivar team_log.FolderLogInfo.file_count: Number of files within the folder. + """ - :rtype: TeamMergeRequestExpiredType - """ - if not self.is_team_merge_request_expired(): - raise AttributeError("tag 'team_merge_request_expired' not set") - return self._value + __slots__ = [ + '_file_count_value', + '_file_count_present', + ] - def get_team_merge_request_expired_shown_to_primary_team(self): - """ - (trusted_teams) Team merge request expired (deprecated, replaced by - 'Team merge request expired') + _has_required_fields = True - Only call this if :meth:`is_team_merge_request_expired_shown_to_primary_team` is true. + def __init__(self, + path=None, + display_name=None, + file_id=None, + file_size=None, + file_count=None): + super(FolderLogInfo, self).__init__(path, + display_name, + file_id, + file_size) + self._file_count_value = None + self._file_count_present = False + if file_count is not None: + self.file_count = file_count - :rtype: TeamMergeRequestExpiredShownToPrimaryTeamType + @property + def file_count(self): """ - if not self.is_team_merge_request_expired_shown_to_primary_team(): - raise AttributeError("tag 'team_merge_request_expired_shown_to_primary_team' not set") - return self._value + Number of files within the folder. - def get_team_merge_request_expired_shown_to_secondary_team(self): + :rtype: int """ - (trusted_teams) Team merge request expired (deprecated, replaced by - 'Team merge request expired') + if self._file_count_present: + return self._file_count_value + else: + return None - Only call this if :meth:`is_team_merge_request_expired_shown_to_secondary_team` is true. + @file_count.setter + def file_count(self, val): + if val is None: + del self.file_count + return + val = self._file_count_validator.validate(val) + self._file_count_value = val + self._file_count_present = True - :rtype: TeamMergeRequestExpiredShownToSecondaryTeamType - """ - if not self.is_team_merge_request_expired_shown_to_secondary_team(): - raise AttributeError("tag 'team_merge_request_expired_shown_to_secondary_team' not set") - return self._value + @file_count.deleter + def file_count(self): + self._file_count_value = None + self._file_count_present = False - def get_team_merge_request_rejected_shown_to_primary_team(self): - """ - (trusted_teams) Rejected a team merge request (deprecated, no longer - logged) + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FolderLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - Only call this if :meth:`is_team_merge_request_rejected_shown_to_primary_team` is true. + def __repr__(self): + return 'FolderLogInfo(path={!r}, display_name={!r}, file_id={!r}, file_size={!r}, file_count={!r})'.format( + self._path_value, + self._display_name_value, + self._file_id_value, + self._file_size_value, + self._file_count_value, + ) - :rtype: TeamMergeRequestRejectedShownToPrimaryTeamType - """ - if not self.is_team_merge_request_rejected_shown_to_primary_team(): - raise AttributeError("tag 'team_merge_request_rejected_shown_to_primary_team' not set") - return self._value +FolderLogInfo_validator = bv.Struct(FolderLogInfo) - def get_team_merge_request_rejected_shown_to_secondary_team(self): - """ - (trusted_teams) Rejected a team merge request (deprecated, no longer - logged) +class FolderOverviewDescriptionChangedDetails(bb.Struct): + """ + Updated folder overview. - Only call this if :meth:`is_team_merge_request_rejected_shown_to_secondary_team` is true. + :ivar + team_log.FolderOverviewDescriptionChangedDetails.folder_overview_location_asset: + Folder Overview location position in the Assets list. + """ - :rtype: TeamMergeRequestRejectedShownToSecondaryTeamType - """ - if not self.is_team_merge_request_rejected_shown_to_secondary_team(): - raise AttributeError("tag 'team_merge_request_rejected_shown_to_secondary_team' not set") - return self._value + __slots__ = [ + '_folder_overview_location_asset_value', + '_folder_overview_location_asset_present', + ] - def get_team_merge_request_reminder(self): - """ - (trusted_teams) Sent a team merge request reminder + _has_required_fields = True - Only call this if :meth:`is_team_merge_request_reminder` is true. + def __init__(self, + folder_overview_location_asset=None): + self._folder_overview_location_asset_value = None + self._folder_overview_location_asset_present = False + if folder_overview_location_asset is not None: + self.folder_overview_location_asset = folder_overview_location_asset - :rtype: TeamMergeRequestReminderType + @property + def folder_overview_location_asset(self): """ - if not self.is_team_merge_request_reminder(): - raise AttributeError("tag 'team_merge_request_reminder' not set") - return self._value + Folder Overview location position in the Assets list. - def get_team_merge_request_reminder_shown_to_primary_team(self): + :rtype: int """ - (trusted_teams) Sent a team merge request reminder (deprecated, replaced - by 'Sent a team merge request reminder') - - Only call this if :meth:`is_team_merge_request_reminder_shown_to_primary_team` is true. + if self._folder_overview_location_asset_present: + return self._folder_overview_location_asset_value + else: + raise AttributeError("missing required field 'folder_overview_location_asset'") - :rtype: TeamMergeRequestReminderShownToPrimaryTeamType - """ - if not self.is_team_merge_request_reminder_shown_to_primary_team(): - raise AttributeError("tag 'team_merge_request_reminder_shown_to_primary_team' not set") - return self._value + @folder_overview_location_asset.setter + def folder_overview_location_asset(self, val): + val = self._folder_overview_location_asset_validator.validate(val) + self._folder_overview_location_asset_value = val + self._folder_overview_location_asset_present = True - def get_team_merge_request_reminder_shown_to_secondary_team(self): - """ - (trusted_teams) Sent a team merge request reminder (deprecated, replaced - by 'Sent a team merge request reminder') + @folder_overview_location_asset.deleter + def folder_overview_location_asset(self): + self._folder_overview_location_asset_value = None + self._folder_overview_location_asset_present = False - Only call this if :meth:`is_team_merge_request_reminder_shown_to_secondary_team` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FolderOverviewDescriptionChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: TeamMergeRequestReminderShownToSecondaryTeamType - """ - if not self.is_team_merge_request_reminder_shown_to_secondary_team(): - raise AttributeError("tag 'team_merge_request_reminder_shown_to_secondary_team' not set") - return self._value + def __repr__(self): + return 'FolderOverviewDescriptionChangedDetails(folder_overview_location_asset={!r})'.format( + self._folder_overview_location_asset_value, + ) - def get_team_merge_request_revoked(self): - """ - (trusted_teams) Canceled the team merge +FolderOverviewDescriptionChangedDetails_validator = bv.Struct(FolderOverviewDescriptionChangedDetails) - Only call this if :meth:`is_team_merge_request_revoked` is true. +class FolderOverviewDescriptionChangedType(bb.Struct): - :rtype: TeamMergeRequestRevokedType - """ - if not self.is_team_merge_request_revoked(): - raise AttributeError("tag 'team_merge_request_revoked' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_team_merge_request_sent_shown_to_primary_team(self): - """ - (trusted_teams) Requested to merge their Dropbox team into yours + _has_required_fields = True - Only call this if :meth:`is_team_merge_request_sent_shown_to_primary_team` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: TeamMergeRequestSentShownToPrimaryTeamType + @property + def description(self): """ - if not self.is_team_merge_request_sent_shown_to_primary_team(): - raise AttributeError("tag 'team_merge_request_sent_shown_to_primary_team' not set") - return self._value - - def get_team_merge_request_sent_shown_to_secondary_team(self): + :rtype: str """ - (trusted_teams) Requested to merge your team into another Dropbox team + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_team_merge_request_sent_shown_to_secondary_team` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: TeamMergeRequestSentShownToSecondaryTeamType - """ - if not self.is_team_merge_request_sent_shown_to_secondary_team(): - raise AttributeError("tag 'team_merge_request_sent_shown_to_secondary_team' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(EventType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(FolderOverviewDescriptionChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'EventType(%r, %r)' % (self._tag, self._value) + return 'FolderOverviewDescriptionChangedType(description={!r})'.format( + self._description_value, + ) -EventType_validator = bv.Union(EventType) +FolderOverviewDescriptionChangedType_validator = bv.Struct(FolderOverviewDescriptionChangedType) -class ExportMembersReportDetails(bb.Struct): +class FolderOverviewItemPinnedDetails(bb.Struct): """ - Created member data report. + Pinned item to folder overview. + + :ivar + team_log.FolderOverviewItemPinnedDetails.folder_overview_location_asset: + Folder Overview location position in the Assets list. + :ivar team_log.FolderOverviewItemPinnedDetails.pinned_items_asset_indices: + Pinned items positions in the Assets list. """ __slots__ = [ + '_folder_overview_location_asset_value', + '_folder_overview_location_asset_present', + '_pinned_items_asset_indices_value', + '_pinned_items_asset_indices_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + folder_overview_location_asset=None, + pinned_items_asset_indices=None): + self._folder_overview_location_asset_value = None + self._folder_overview_location_asset_present = False + self._pinned_items_asset_indices_value = None + self._pinned_items_asset_indices_present = False + if folder_overview_location_asset is not None: + self.folder_overview_location_asset = folder_overview_location_asset + if pinned_items_asset_indices is not None: + self.pinned_items_asset_indices = pinned_items_asset_indices + + @property + def folder_overview_location_asset(self): + """ + Folder Overview location position in the Assets list. + + :rtype: int + """ + if self._folder_overview_location_asset_present: + return self._folder_overview_location_asset_value + else: + raise AttributeError("missing required field 'folder_overview_location_asset'") + + @folder_overview_location_asset.setter + def folder_overview_location_asset(self, val): + val = self._folder_overview_location_asset_validator.validate(val) + self._folder_overview_location_asset_value = val + self._folder_overview_location_asset_present = True + + @folder_overview_location_asset.deleter + def folder_overview_location_asset(self): + self._folder_overview_location_asset_value = None + self._folder_overview_location_asset_present = False + + @property + def pinned_items_asset_indices(self): + """ + Pinned items positions in the Assets list. + + :rtype: list of [int] + """ + if self._pinned_items_asset_indices_present: + return self._pinned_items_asset_indices_value + else: + raise AttributeError("missing required field 'pinned_items_asset_indices'") + + @pinned_items_asset_indices.setter + def pinned_items_asset_indices(self, val): + val = self._pinned_items_asset_indices_validator.validate(val) + self._pinned_items_asset_indices_value = val + self._pinned_items_asset_indices_present = True + + @pinned_items_asset_indices.deleter + def pinned_items_asset_indices(self): + self._pinned_items_asset_indices_value = None + self._pinned_items_asset_indices_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExportMembersReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(FolderOverviewItemPinnedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExportMembersReportDetails()' + return 'FolderOverviewItemPinnedDetails(folder_overview_location_asset={!r}, pinned_items_asset_indices={!r})'.format( + self._folder_overview_location_asset_value, + self._pinned_items_asset_indices_value, + ) -ExportMembersReportDetails_validator = bv.Struct(ExportMembersReportDetails) +FolderOverviewItemPinnedDetails_validator = bv.Struct(FolderOverviewItemPinnedDetails) -class ExportMembersReportType(bb.Struct): +class FolderOverviewItemPinnedType(bb.Struct): __slots__ = [ '_description_value', @@ -29570,109 +48421,105 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExportMembersReportType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(FolderOverviewItemPinnedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExportMembersReportType(description={!r})'.format( + return 'FolderOverviewItemPinnedType(description={!r})'.format( self._description_value, ) -ExportMembersReportType_validator = bv.Struct(ExportMembersReportType) +FolderOverviewItemPinnedType_validator = bv.Struct(FolderOverviewItemPinnedType) -class ExtendedVersionHistoryChangePolicyDetails(bb.Struct): +class FolderOverviewItemUnpinnedDetails(bb.Struct): """ - Accepted/opted out of extended version history. + Unpinned item from folder overview. - :ivar team_log.ExtendedVersionHistoryChangePolicyDetails.new_value: New - extended version history policy. - :ivar team_log.ExtendedVersionHistoryChangePolicyDetails.previous_value: - Previous extended version history policy. Might be missing due to - historical data gap. + :ivar + team_log.FolderOverviewItemUnpinnedDetails.folder_overview_location_asset: + Folder Overview location position in the Assets list. + :ivar team_log.FolderOverviewItemUnpinnedDetails.pinned_items_asset_indices: + Pinned items positions in the Assets list. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_folder_overview_location_asset_value', + '_folder_overview_location_asset_present', + '_pinned_items_asset_indices_value', + '_pinned_items_asset_indices_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + folder_overview_location_asset=None, + pinned_items_asset_indices=None): + self._folder_overview_location_asset_value = None + self._folder_overview_location_asset_present = False + self._pinned_items_asset_indices_value = None + self._pinned_items_asset_indices_present = False + if folder_overview_location_asset is not None: + self.folder_overview_location_asset = folder_overview_location_asset + if pinned_items_asset_indices is not None: + self.pinned_items_asset_indices = pinned_items_asset_indices @property - def new_value(self): + def folder_overview_location_asset(self): """ - New extended version history policy. + Folder Overview location position in the Assets list. - :rtype: ExtendedVersionHistoryPolicy + :rtype: int """ - if self._new_value_present: - return self._new_value_value + if self._folder_overview_location_asset_present: + return self._folder_overview_location_asset_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'folder_overview_location_asset'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @folder_overview_location_asset.setter + def folder_overview_location_asset(self, val): + val = self._folder_overview_location_asset_validator.validate(val) + self._folder_overview_location_asset_value = val + self._folder_overview_location_asset_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @folder_overview_location_asset.deleter + def folder_overview_location_asset(self): + self._folder_overview_location_asset_value = None + self._folder_overview_location_asset_present = False @property - def previous_value(self): - """ - Previous extended version history policy. Might be missing due to - historical data gap. - - :rtype: ExtendedVersionHistoryPolicy + def pinned_items_asset_indices(self): """ - if self._previous_value_present: - return self._previous_value_value - else: - return None + Pinned items positions in the Assets list. - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + :rtype: list of [int] + """ + if self._pinned_items_asset_indices_present: + return self._pinned_items_asset_indices_value + else: + raise AttributeError("missing required field 'pinned_items_asset_indices'") - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @pinned_items_asset_indices.setter + def pinned_items_asset_indices(self, val): + val = self._pinned_items_asset_indices_validator.validate(val) + self._pinned_items_asset_indices_value = val + self._pinned_items_asset_indices_present = True + + @pinned_items_asset_indices.deleter + def pinned_items_asset_indices(self): + self._pinned_items_asset_indices_value = None + self._pinned_items_asset_indices_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExtendedVersionHistoryChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(FolderOverviewItemUnpinnedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExtendedVersionHistoryChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'FolderOverviewItemUnpinnedDetails(folder_overview_location_asset={!r}, pinned_items_asset_indices={!r})'.format( + self._folder_overview_location_asset_value, + self._pinned_items_asset_indices_value, ) -ExtendedVersionHistoryChangePolicyDetails_validator = bv.Struct(ExtendedVersionHistoryChangePolicyDetails) +FolderOverviewItemUnpinnedDetails_validator = bv.Struct(FolderOverviewItemUnpinnedDetails) -class ExtendedVersionHistoryChangePolicyType(bb.Struct): +class FolderOverviewItemUnpinnedType(bb.Struct): __slots__ = [ '_description_value', @@ -29710,445 +48557,738 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExtendedVersionHistoryChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(FolderOverviewItemUnpinnedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExtendedVersionHistoryChangePolicyType(description={!r})'.format( + return 'FolderOverviewItemUnpinnedType(description={!r})'.format( self._description_value, ) -ExtendedVersionHistoryChangePolicyType_validator = bv.Struct(ExtendedVersionHistoryChangePolicyType) +FolderOverviewItemUnpinnedType_validator = bv.Struct(FolderOverviewItemUnpinnedType) -class ExtendedVersionHistoryPolicy(bb.Union): +class GeoLocationLogInfo(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Geographic location details. + + :ivar team_log.GeoLocationLogInfo.city: City name. + :ivar team_log.GeoLocationLogInfo.region: Region name. + :ivar team_log.GeoLocationLogInfo.country: Country code. + :ivar team_log.GeoLocationLogInfo.ip_address: IP address. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - explicitly_limited = None - # Attribute is overwritten below the class definition - explicitly_unlimited = None - # Attribute is overwritten below the class definition - implicitly_limited = None - # Attribute is overwritten below the class definition - implicitly_unlimited = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_city_value', + '_city_present', + '_region_value', + '_region_present', + '_country_value', + '_country_present', + '_ip_address_value', + '_ip_address_present', + ] - def is_explicitly_limited(self): - """ - Check if the union tag is ``explicitly_limited``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'explicitly_limited' + def __init__(self, + ip_address=None, + city=None, + region=None, + country=None): + self._city_value = None + self._city_present = False + self._region_value = None + self._region_present = False + self._country_value = None + self._country_present = False + self._ip_address_value = None + self._ip_address_present = False + if city is not None: + self.city = city + if region is not None: + self.region = region + if country is not None: + self.country = country + if ip_address is not None: + self.ip_address = ip_address - def is_explicitly_unlimited(self): + @property + def city(self): """ - Check if the union tag is ``explicitly_unlimited``. + City name. - :rtype: bool + :rtype: str """ - return self._tag == 'explicitly_unlimited' + if self._city_present: + return self._city_value + else: + return None - def is_implicitly_limited(self): + @city.setter + def city(self, val): + if val is None: + del self.city + return + val = self._city_validator.validate(val) + self._city_value = val + self._city_present = True + + @city.deleter + def city(self): + self._city_value = None + self._city_present = False + + @property + def region(self): """ - Check if the union tag is ``implicitly_limited``. + Region name. - :rtype: bool + :rtype: str """ - return self._tag == 'implicitly_limited' + if self._region_present: + return self._region_value + else: + return None - def is_implicitly_unlimited(self): + @region.setter + def region(self, val): + if val is None: + del self.region + return + val = self._region_validator.validate(val) + self._region_value = val + self._region_present = True + + @region.deleter + def region(self): + self._region_value = None + self._region_present = False + + @property + def country(self): """ - Check if the union tag is ``implicitly_unlimited``. + Country code. - :rtype: bool + :rtype: str """ - return self._tag == 'implicitly_unlimited' + if self._country_present: + return self._country_value + else: + return None - def is_other(self): + @country.setter + def country(self, val): + if val is None: + del self.country + return + val = self._country_validator.validate(val) + self._country_value = val + self._country_present = True + + @country.deleter + def country(self): + self._country_value = None + self._country_present = False + + @property + def ip_address(self): """ - Check if the union tag is ``other``. + IP address. - :rtype: bool + :rtype: str """ - return self._tag == 'other' + if self._ip_address_present: + return self._ip_address_value + else: + raise AttributeError("missing required field 'ip_address'") + + @ip_address.setter + def ip_address(self, val): + val = self._ip_address_validator.validate(val) + self._ip_address_value = val + self._ip_address_present = True + + @ip_address.deleter + def ip_address(self): + self._ip_address_value = None + self._ip_address_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExtendedVersionHistoryPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GeoLocationLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExtendedVersionHistoryPolicy(%r, %r)' % (self._tag, self._value) + return 'GeoLocationLogInfo(ip_address={!r}, city={!r}, region={!r}, country={!r})'.format( + self._ip_address_value, + self._city_value, + self._region_value, + self._country_value, + ) -ExtendedVersionHistoryPolicy_validator = bv.Union(ExtendedVersionHistoryPolicy) +GeoLocationLogInfo_validator = bv.Struct(GeoLocationLogInfo) -class ExternalUserLogInfo(bb.Struct): +class GetTeamEventsArg(bb.Struct): """ - A user without a Dropbox account. - - :ivar team_log.ExternalUserLogInfo.user_identifier: An external user - identifier. - :ivar team_log.ExternalUserLogInfo.identifier_type: Identifier type. + :ivar team_log.GetTeamEventsArg.limit: The maximal number of results to + return per call. Note that some calls may not return ``limit`` number of + events, and may even return no events, even with `has_more` set to true. + In this case, callers should fetch again using + :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`. + :ivar team_log.GetTeamEventsArg.account_id: Filter the events by account ID. + Return only events with this account_id as either Actor, Context, or + Participants. + :ivar team_log.GetTeamEventsArg.time: Filter by time range. + :ivar team_log.GetTeamEventsArg.category: Filter the returned events to a + single category. + :ivar team_log.GetTeamEventsArg.event_type: Filter the returned events to a + single event type. Note that event_type shouldn't be provided together + with category. """ __slots__ = [ - '_user_identifier_value', - '_user_identifier_present', - '_identifier_type_value', - '_identifier_type_present', + '_limit_value', + '_limit_present', + '_account_id_value', + '_account_id_present', + '_time_value', + '_time_present', + '_category_value', + '_category_present', + '_event_type_value', + '_event_type_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - user_identifier=None, - identifier_type=None): - self._user_identifier_value = None - self._user_identifier_present = False - self._identifier_type_value = None - self._identifier_type_present = False - if user_identifier is not None: - self.user_identifier = user_identifier - if identifier_type is not None: - self.identifier_type = identifier_type + limit=None, + account_id=None, + time=None, + category=None, + event_type=None): + self._limit_value = None + self._limit_present = False + self._account_id_value = None + self._account_id_present = False + self._time_value = None + self._time_present = False + self._category_value = None + self._category_present = False + self._event_type_value = None + self._event_type_present = False + if limit is not None: + self.limit = limit + if account_id is not None: + self.account_id = account_id + if time is not None: + self.time = time + if category is not None: + self.category = category + if event_type is not None: + self.event_type = event_type @property - def user_identifier(self): + def limit(self): """ - An external user identifier. + The maximal number of results to return per call. Note that some calls + may not return ``limit`` number of events, and may even return no + events, even with `has_more` set to true. In this case, callers should + fetch again using + :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`. + + :rtype: int + """ + if self._limit_present: + return self._limit_value + else: + return 1000 + + @limit.setter + def limit(self, val): + val = self._limit_validator.validate(val) + self._limit_value = val + self._limit_present = True + + @limit.deleter + def limit(self): + self._limit_value = None + self._limit_present = False + + @property + def account_id(self): + """ + Filter the events by account ID. Return only events with this account_id + as either Actor, Context, or Participants. :rtype: str """ - if self._user_identifier_present: - return self._user_identifier_value + if self._account_id_present: + return self._account_id_value else: - raise AttributeError("missing required field 'user_identifier'") + return None - @user_identifier.setter - def user_identifier(self, val): - val = self._user_identifier_validator.validate(val) - self._user_identifier_value = val - self._user_identifier_present = True + @account_id.setter + def account_id(self, val): + if val is None: + del self.account_id + return + val = self._account_id_validator.validate(val) + self._account_id_value = val + self._account_id_present = True - @user_identifier.deleter - def user_identifier(self): - self._user_identifier_value = None - self._user_identifier_present = False + @account_id.deleter + def account_id(self): + self._account_id_value = None + self._account_id_present = False @property - def identifier_type(self): + def time(self): """ - Identifier type. + Filter by time range. - :rtype: IdentifierType + :rtype: team_common.TimeRange """ - if self._identifier_type_present: - return self._identifier_type_value + if self._time_present: + return self._time_value else: - raise AttributeError("missing required field 'identifier_type'") + return None - @identifier_type.setter - def identifier_type(self, val): - self._identifier_type_validator.validate_type_only(val) - self._identifier_type_value = val - self._identifier_type_present = True + @time.setter + def time(self, val): + if val is None: + del self.time + return + self._time_validator.validate_type_only(val) + self._time_value = val + self._time_present = True - @identifier_type.deleter - def identifier_type(self): - self._identifier_type_value = None - self._identifier_type_present = False + @time.deleter + def time(self): + self._time_value = None + self._time_present = False + + @property + def category(self): + """ + Filter the returned events to a single category. + + :rtype: EventCategory + """ + if self._category_present: + return self._category_value + else: + return None + + @category.setter + def category(self, val): + if val is None: + del self.category + return + self._category_validator.validate_type_only(val) + self._category_value = val + self._category_present = True + + @category.deleter + def category(self): + self._category_value = None + self._category_present = False + + @property + def event_type(self): + """ + Filter the returned events to a single event type. Note that event_type + shouldn't be provided together with category. + + :rtype: EventTypeArg + """ + if self._event_type_present: + return self._event_type_value + else: + return None + + @event_type.setter + def event_type(self, val): + if val is None: + del self.event_type + return + self._event_type_validator.validate_type_only(val) + self._event_type_value = val + self._event_type_present = True + + @event_type.deleter + def event_type(self): + self._event_type_value = None + self._event_type_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ExternalUserLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GetTeamEventsArg, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ExternalUserLogInfo(user_identifier={!r}, identifier_type={!r})'.format( - self._user_identifier_value, - self._identifier_type_value, + return 'GetTeamEventsArg(limit={!r}, account_id={!r}, time={!r}, category={!r}, event_type={!r})'.format( + self._limit_value, + self._account_id_value, + self._time_value, + self._category_value, + self._event_type_value, ) -ExternalUserLogInfo_validator = bv.Struct(ExternalUserLogInfo) +GetTeamEventsArg_validator = bv.Struct(GetTeamEventsArg) -class FailureDetailsLogInfo(bb.Struct): +class GetTeamEventsContinueArg(bb.Struct): """ - Provides details about a failure - - :ivar team_log.FailureDetailsLogInfo.user_friendly_message: A user friendly - explanation of the error. Might be missing due to historical data gap. - :ivar team_log.FailureDetailsLogInfo.technical_error_message: A technical - explanation of the error. This is relevant for some errors. + :ivar team_log.GetTeamEventsContinueArg.cursor: Indicates from what point to + get the next set of events. """ __slots__ = [ - '_user_friendly_message_value', - '_user_friendly_message_present', - '_technical_error_message_value', - '_technical_error_message_present', + '_cursor_value', + '_cursor_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - user_friendly_message=None, - technical_error_message=None): - self._user_friendly_message_value = None - self._user_friendly_message_present = False - self._technical_error_message_value = None - self._technical_error_message_present = False - if user_friendly_message is not None: - self.user_friendly_message = user_friendly_message - if technical_error_message is not None: - self.technical_error_message = technical_error_message + cursor=None): + self._cursor_value = None + self._cursor_present = False + if cursor is not None: + self.cursor = cursor @property - def user_friendly_message(self): + def cursor(self): + """ + Indicates from what point to get the next set of events. + + :rtype: str + """ + if self._cursor_present: + return self._cursor_value + else: + raise AttributeError("missing required field 'cursor'") + + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True + + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GetTeamEventsContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GetTeamEventsContinueArg(cursor={!r})'.format( + self._cursor_value, + ) + +GetTeamEventsContinueArg_validator = bv.Struct(GetTeamEventsContinueArg) + +class GetTeamEventsContinueError(bb.Union): + """ + Errors that can be raised when calling + :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team_log.GetTeamEventsContinueError.bad_cursor: Bad cursor. + :ivar datetime.datetime team_log.GetTeamEventsContinueError.reset: Cursors + are intended to be used quickly. Individual cursor values are normally + valid for days, but in rare cases may be reset sooner. Cursor reset + errors should be handled by fetching a new cursor from + :route:`get_events`. The associated value is the approximate timestamp + of the most recent event returned by the cursor. This should be used as + a resumption point when calling :route:`get_events` to obtain a new + cursor. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + bad_cursor = None + # Attribute is overwritten below the class definition + other = None + + @classmethod + def reset(cls, val): + """ + Create an instance of this class set to the ``reset`` tag with value + ``val``. + + :param datetime.datetime val: + :rtype: GetTeamEventsContinueError + """ + return cls('reset', val) + + def is_bad_cursor(self): + """ + Check if the union tag is ``bad_cursor``. + + :rtype: bool """ - A user friendly explanation of the error. Might be missing due to - historical data gap. + return self._tag == 'bad_cursor' - :rtype: str + def is_reset(self): """ - if self._user_friendly_message_present: - return self._user_friendly_message_value - else: - return None + Check if the union tag is ``reset``. - @user_friendly_message.setter - def user_friendly_message(self, val): - if val is None: - del self.user_friendly_message - return - val = self._user_friendly_message_validator.validate(val) - self._user_friendly_message_value = val - self._user_friendly_message_present = True + :rtype: bool + """ + return self._tag == 'reset' - @user_friendly_message.deleter - def user_friendly_message(self): - self._user_friendly_message_value = None - self._user_friendly_message_present = False + def is_other(self): + """ + Check if the union tag is ``other``. - @property - def technical_error_message(self): + :rtype: bool """ - A technical explanation of the error. This is relevant for some errors. + return self._tag == 'other' - :rtype: str + def get_reset(self): """ - if self._technical_error_message_present: - return self._technical_error_message_value - else: - return None + Cursors are intended to be used quickly. Individual cursor values are + normally valid for days, but in rare cases may be reset sooner. Cursor + reset errors should be handled by fetching a new cursor from + :meth:`dropbox.dropbox.Dropbox.team_log_get_events`. The associated + value is the approximate timestamp of the most recent event returned by + the cursor. This should be used as a resumption point when calling + :meth:`dropbox.dropbox.Dropbox.team_log_get_events` to obtain a new + cursor. - @technical_error_message.setter - def technical_error_message(self, val): - if val is None: - del self.technical_error_message - return - val = self._technical_error_message_validator.validate(val) - self._technical_error_message_value = val - self._technical_error_message_present = True + Only call this if :meth:`is_reset` is true. - @technical_error_message.deleter - def technical_error_message(self): - self._technical_error_message_value = None - self._technical_error_message_present = False + :rtype: datetime.datetime + """ + if not self.is_reset(): + raise AttributeError("tag 'reset' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FailureDetailsLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GetTeamEventsContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FailureDetailsLogInfo(user_friendly_message={!r}, technical_error_message={!r})'.format( - self._user_friendly_message_value, - self._technical_error_message_value, - ) + return 'GetTeamEventsContinueError(%r, %r)' % (self._tag, self._value) -FailureDetailsLogInfo_validator = bv.Struct(FailureDetailsLogInfo) +GetTeamEventsContinueError_validator = bv.Union(GetTeamEventsContinueError) -class FileAddCommentDetails(bb.Struct): +class GetTeamEventsError(bb.Union): """ - Added file comment. + Errors that can be raised when calling + :meth:`dropbox.dropbox.Dropbox.team_log_get_events`. - :ivar team_log.FileAddCommentDetails.comment_text: Comment text. Might be - missing due to historical data gap. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team_log.GetTeamEventsError.account_id_not_found: No user found + matching the provided account_id. + :ivar team_log.GetTeamEventsError.invalid_time_range: Invalid time range. + :ivar team_log.GetTeamEventsError.invalid_filters: Invalid filters. + event_type and category should not be provided together. """ - __slots__ = [ - '_comment_text_value', - '_comment_text_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + account_id_not_found = None + # Attribute is overwritten below the class definition + invalid_time_range = None + # Attribute is overwritten below the class definition + invalid_filters = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = False + def is_account_id_not_found(self): + """ + Check if the union tag is ``account_id_not_found``. - def __init__(self, - comment_text=None): - self._comment_text_value = None - self._comment_text_present = False - if comment_text is not None: - self.comment_text = comment_text + :rtype: bool + """ + return self._tag == 'account_id_not_found' - @property - def comment_text(self): + def is_invalid_time_range(self): """ - Comment text. Might be missing due to historical data gap. + Check if the union tag is ``invalid_time_range``. - :rtype: str + :rtype: bool """ - if self._comment_text_present: - return self._comment_text_value - else: - return None + return self._tag == 'invalid_time_range' - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + def is_invalid_filters(self): + """ + Check if the union tag is ``invalid_filters``. - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + :rtype: bool + """ + return self._tag == 'invalid_filters' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileAddCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GetTeamEventsError, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileAddCommentDetails(comment_text={!r})'.format( - self._comment_text_value, - ) + return 'GetTeamEventsError(%r, %r)' % (self._tag, self._value) -FileAddCommentDetails_validator = bv.Struct(FileAddCommentDetails) +GetTeamEventsError_validator = bv.Union(GetTeamEventsError) -class FileAddCommentType(bb.Struct): +class GetTeamEventsResult(bb.Struct): + """ + :ivar team_log.GetTeamEventsResult.events: List of events. Note that events + are not guaranteed to be sorted by their timestamp value. + :ivar team_log.GetTeamEventsResult.cursor: Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` to obtain + additional events. The value of ``cursor`` may change for each response + from :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`, + regardless of the value of ``has_more``; older cursor strings may + expire. Thus, callers should ensure that they update their cursor based + on the latest value of ``cursor`` after each call, and poll regularly if + they wish to poll for new events. Callers should handle reset exceptions + for expired cursors. + :ivar team_log.GetTeamEventsResult.has_more: Is true if there may be + additional events that have not been returned yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` can + retrieve them. Note that ``has_more`` may be ``True``, even if + ``events`` is empty. + """ __slots__ = [ - '_description_value', - '_description_present', + '_events_value', + '_events_present', + '_cursor_value', + '_cursor_present', + '_has_more_value', + '_has_more_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + events=None, + cursor=None, + has_more=None): + self._events_value = None + self._events_present = False + self._cursor_value = None + self._cursor_present = False + self._has_more_value = None + self._has_more_present = False + if events is not None: + self.events = events + if cursor is not None: + self.cursor = cursor + if has_more is not None: + self.has_more = has_more @property - def description(self): + def events(self): """ - :rtype: str + List of events. Note that events are not guaranteed to be sorted by + their timestamp value. + + :rtype: list of [TeamEvent] """ - if self._description_present: - return self._description_value + if self._events_present: + return self._events_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileAddCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FileAddCommentType(description={!r})'.format( - self._description_value, - ) - -FileAddCommentType_validator = bv.Struct(FileAddCommentType) - -class FileAddDetails(bb.Struct): - """ - Added files and/or folders. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileAddDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + raise AttributeError("missing required field 'events'") - def __repr__(self): - return 'FileAddDetails()' + @events.setter + def events(self, val): + val = self._events_validator.validate(val) + self._events_value = val + self._events_present = True -FileAddDetails_validator = bv.Struct(FileAddDetails) + @events.deleter + def events(self): + self._events_value = None + self._events_present = False -class FileAddType(bb.Struct): + @property + def cursor(self): + """ + Pass the cursor into + :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` to obtain + additional events. The value of ``cursor`` may change for each response + from :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`, + regardless of the value of ``has_more``; older cursor strings may + expire. Thus, callers should ensure that they update their cursor based + on the latest value of ``cursor`` after each call, and poll regularly if + they wish to poll for new events. Callers should handle reset exceptions + for expired cursors. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: str + """ + if self._cursor_present: + return self._cursor_value + else: + raise AttributeError("missing required field 'cursor'") - _has_required_fields = True + @cursor.setter + def cursor(self, val): + val = self._cursor_validator.validate(val) + self._cursor_value = val + self._cursor_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @cursor.deleter + def cursor(self): + self._cursor_value = None + self._cursor_present = False @property - def description(self): + def has_more(self): """ - :rtype: str + Is true if there may be additional events that have not been returned + yet. An additional call to + :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` can + retrieve them. Note that ``has_more`` may be ``True``, even if + ``events`` is empty. + + :rtype: bool """ - if self._description_present: - return self._description_value + if self._has_more_present: + return self._has_more_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'has_more'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @has_more.setter + def has_more(self, val): + val = self._has_more_validator.validate(val) + self._has_more_value = val + self._has_more_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @has_more.deleter + def has_more(self): + self._has_more_value = None + self._has_more_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileAddType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GetTeamEventsResult, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileAddType(description={!r})'.format( - self._description_value, + return 'GetTeamEventsResult(events={!r}, cursor={!r}, has_more={!r})'.format( + self._events_value, + self._cursor_value, + self._has_more_value, ) -FileAddType_validator = bv.Struct(FileAddType) +GetTeamEventsResult_validator = bv.Struct(GetTeamEventsResult) -class FileChangeCommentSubscriptionDetails(bb.Struct): +class GoogleSsoChangePolicyDetails(bb.Struct): """ - Subscribed to or unsubscribed from comment notifications for file. + Enabled/disabled Google single sign-on for team. - :ivar team_log.FileChangeCommentSubscriptionDetails.new_value: New file - comment subscription. - :ivar team_log.FileChangeCommentSubscriptionDetails.previous_value: Previous - file comment subscription. Might be missing due to historical data gap. + :ivar team_log.GoogleSsoChangePolicyDetails.new_value: New Google single + sign-on policy. + :ivar team_log.GoogleSsoChangePolicyDetails.previous_value: Previous Google + single sign-on policy. Might be missing due to historical data gap. """ __slots__ = [ @@ -30175,9 +49315,9 @@ def __init__(self, @property def new_value(self): """ - New file comment subscription. + New Google single sign-on policy. - :rtype: FileCommentNotificationPolicy + :rtype: GoogleSsoPolicy """ if self._new_value_present: return self._new_value_value @@ -30198,10 +49338,10 @@ def new_value(self): @property def previous_value(self): """ - Previous file comment subscription. Might be missing due to historical - data gap. + Previous Google single sign-on policy. Might be missing due to + historical data gap. - :rtype: FileCommentNotificationPolicy + :rtype: GoogleSsoPolicy """ if self._previous_value_present: return self._previous_value_value @@ -30223,17 +49363,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileChangeCommentSubscriptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GoogleSsoChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileChangeCommentSubscriptionDetails(new_value={!r}, previous_value={!r})'.format( + return 'GoogleSsoChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -FileChangeCommentSubscriptionDetails_validator = bv.Struct(FileChangeCommentSubscriptionDetails) +GoogleSsoChangePolicyDetails_validator = bv.Struct(GoogleSsoChangePolicyDetails) -class FileChangeCommentSubscriptionType(bb.Struct): +class GoogleSsoChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -30271,18 +49411,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileChangeCommentSubscriptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GoogleSsoChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileChangeCommentSubscriptionType(description={!r})'.format( + return 'GoogleSsoChangePolicyType(description={!r})'.format( self._description_value, ) -FileChangeCommentSubscriptionType_validator = bv.Struct(FileChangeCommentSubscriptionType) +GoogleSsoChangePolicyType_validator = bv.Struct(GoogleSsoChangePolicyType) -class FileCommentNotificationPolicy(bb.Union): +class GoogleSsoPolicy(bb.Union): """ - Enable or disable file comments notifications + Google SSO policy This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the @@ -30322,51 +49462,40 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileCommentNotificationPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GoogleSsoPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileCommentNotificationPolicy(%r, %r)' % (self._tag, self._value) + return 'GoogleSsoPolicy(%r, %r)' % (self._tag, self._value) -FileCommentNotificationPolicy_validator = bv.Union(FileCommentNotificationPolicy) +GoogleSsoPolicy_validator = bv.Union(GoogleSsoPolicy) -class FileCommentsChangePolicyDetails(bb.Struct): +class GroupAddExternalIdDetails(bb.Struct): """ - Enabled/disabled commenting on team files. + Added external ID for group. - :ivar team_log.FileCommentsChangePolicyDetails.new_value: New commenting on - team files policy. - :ivar team_log.FileCommentsChangePolicyDetails.previous_value: Previous - commenting on team files policy. Might be missing due to historical data - gap. + :ivar team_log.GroupAddExternalIdDetails.new_value: Current external id. """ __slots__ = [ '_new_value_value', '_new_value_present', - '_previous_value_value', - '_previous_value_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): + new_value=None): self._new_value_value = None self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False if new_value is not None: self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value @property def new_value(self): """ - New commenting on team files policy. + Current external id. - :rtype: FileCommentsPolicy + :rtype: str """ if self._new_value_present: return self._new_value_value @@ -30375,7 +49504,7 @@ def new_value(self): @new_value.setter def new_value(self, val): - self._new_value_validator.validate_type_only(val) + val = self._new_value_validator.validate(val) self._new_value_value = val self._new_value_present = True @@ -30384,45 +49513,17 @@ def new_value(self): self._new_value_value = None self._new_value_present = False - @property - def previous_value(self): - """ - Previous commenting on team files policy. Might be missing due to - historical data gap. - - :rtype: FileCommentsPolicy - """ - if self._previous_value_present: - return self._previous_value_value - else: - return None - - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True - - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileCommentsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupAddExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileCommentsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'GroupAddExternalIdDetails(new_value={!r})'.format( self._new_value_value, - self._previous_value_value, ) -FileCommentsChangePolicyDetails_validator = bv.Struct(FileCommentsChangePolicyDetails) +GroupAddExternalIdDetails_validator = bv.Struct(GroupAddExternalIdDetails) -class FileCommentsChangePolicyType(bb.Struct): +class GroupAddExternalIdType(bb.Struct): __slots__ = [ '_description_value', @@ -30448,132 +49549,82 @@ def description(self): else: raise AttributeError("missing required field 'description'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileCommentsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FileCommentsChangePolicyType(description={!r})'.format( - self._description_value, - ) - -FileCommentsChangePolicyType_validator = bv.Struct(FileCommentsChangePolicyType) - -class FileCommentsPolicy(bb.Union): - """ - File comments policy - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None - - def is_disabled(self): - """ - Check if the union tag is ``disabled``. - - :rtype: bool - """ - return self._tag == 'disabled' - - def is_enabled(self): - """ - Check if the union tag is ``enabled``. - - :rtype: bool - """ - return self._tag == 'enabled' - - def is_other(self): - """ - Check if the union tag is ``other``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: bool - """ - return self._tag == 'other' + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileCommentsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupAddExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileCommentsPolicy(%r, %r)' % (self._tag, self._value) + return 'GroupAddExternalIdType(description={!r})'.format( + self._description_value, + ) -FileCommentsPolicy_validator = bv.Union(FileCommentsPolicy) +GroupAddExternalIdType_validator = bv.Struct(GroupAddExternalIdType) -class FileCopyDetails(bb.Struct): +class GroupAddMemberDetails(bb.Struct): """ - Copied files and/or folders. + Added team members to group. - :ivar team_log.FileCopyDetails.relocate_action_details: Relocate action - details. + :ivar team_log.GroupAddMemberDetails.is_group_owner: Is group owner. """ __slots__ = [ - '_relocate_action_details_value', - '_relocate_action_details_present', + '_is_group_owner_value', + '_is_group_owner_present', ] _has_required_fields = True def __init__(self, - relocate_action_details=None): - self._relocate_action_details_value = None - self._relocate_action_details_present = False - if relocate_action_details is not None: - self.relocate_action_details = relocate_action_details + is_group_owner=None): + self._is_group_owner_value = None + self._is_group_owner_present = False + if is_group_owner is not None: + self.is_group_owner = is_group_owner @property - def relocate_action_details(self): + def is_group_owner(self): """ - Relocate action details. + Is group owner. - :rtype: list of [RelocateAssetReferencesLogInfo] + :rtype: bool """ - if self._relocate_action_details_present: - return self._relocate_action_details_value + if self._is_group_owner_present: + return self._is_group_owner_value else: - raise AttributeError("missing required field 'relocate_action_details'") + raise AttributeError("missing required field 'is_group_owner'") - @relocate_action_details.setter - def relocate_action_details(self, val): - val = self._relocate_action_details_validator.validate(val) - self._relocate_action_details_value = val - self._relocate_action_details_present = True + @is_group_owner.setter + def is_group_owner(self, val): + val = self._is_group_owner_validator.validate(val) + self._is_group_owner_value = val + self._is_group_owner_present = True - @relocate_action_details.deleter - def relocate_action_details(self): - self._relocate_action_details_value = None - self._relocate_action_details_present = False + @is_group_owner.deleter + def is_group_owner(self): + self._is_group_owner_value = None + self._is_group_owner_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileCopyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupAddMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileCopyDetails(relocate_action_details={!r})'.format( - self._relocate_action_details_value, + return 'GroupAddMemberDetails(is_group_owner={!r})'.format( + self._is_group_owner_value, ) -FileCopyDetails_validator = bv.Struct(FileCopyDetails) +GroupAddMemberDetails_validator = bv.Struct(GroupAddMemberDetails) -class FileCopyType(bb.Struct): +class GroupAddMemberType(bb.Struct): __slots__ = [ '_description_value', @@ -30611,74 +49662,102 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileCopyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupAddMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileCopyType(description={!r})'.format( + return 'GroupAddMemberType(description={!r})'.format( self._description_value, ) -FileCopyType_validator = bv.Struct(FileCopyType) +GroupAddMemberType_validator = bv.Struct(GroupAddMemberType) -class FileDeleteCommentDetails(bb.Struct): +class GroupChangeExternalIdDetails(bb.Struct): """ - Deleted file comment. + Changed external ID for group. - :ivar team_log.FileDeleteCommentDetails.comment_text: Comment text. Might be - missing due to historical data gap. + :ivar team_log.GroupChangeExternalIdDetails.new_value: Current external id. + :ivar team_log.GroupChangeExternalIdDetails.previous_value: Old external id. """ __slots__ = [ - '_comment_text_value', - '_comment_text_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - comment_text=None): - self._comment_text_value = None - self._comment_text_present = False - if comment_text is not None: - self.comment_text = comment_text + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def comment_text(self): + def new_value(self): """ - Comment text. Might be missing due to historical data gap. + Current external id. :rtype: str """ - if self._comment_text_present: - return self._comment_text_value + if self._new_value_present: + return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Old external id. + + :rtype: str + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileDeleteCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupChangeExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileDeleteCommentDetails(comment_text={!r})'.format( - self._comment_text_value, + return 'GroupChangeExternalIdDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -FileDeleteCommentDetails_validator = bv.Struct(FileDeleteCommentDetails) +GroupChangeExternalIdDetails_validator = bv.Struct(GroupChangeExternalIdDetails) -class FileDeleteCommentType(bb.Struct): +class GroupChangeExternalIdType(bb.Struct): __slots__ = [ '_description_value', @@ -30716,37 +49795,108 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileDeleteCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupChangeExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileDeleteCommentType(description={!r})'.format( + return 'GroupChangeExternalIdType(description={!r})'.format( self._description_value, ) -FileDeleteCommentType_validator = bv.Struct(FileDeleteCommentType) +GroupChangeExternalIdType_validator = bv.Struct(GroupChangeExternalIdType) -class FileDeleteDetails(bb.Struct): +class GroupChangeManagementTypeDetails(bb.Struct): """ - Deleted files and/or folders. + Changed group management type. + + :ivar team_log.GroupChangeManagementTypeDetails.new_value: New group + management type. + :ivar team_log.GroupChangeManagementTypeDetails.previous_value: Previous + group management type. Might be missing due to historical data gap. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New group management type. + + :rtype: team_common.GroupManagementType + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous group management type. Might be missing due to historical data + gap. + + :rtype: team_common.GroupManagementType + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupChangeManagementTypeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileDeleteDetails()' + return 'GroupChangeManagementTypeDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -FileDeleteDetails_validator = bv.Struct(FileDeleteDetails) +GroupChangeManagementTypeDetails_validator = bv.Struct(GroupChangeManagementTypeDetails) -class FileDeleteType(bb.Struct): +class GroupChangeManagementTypeType(bb.Struct): __slots__ = [ '_description_value', @@ -30784,37 +49934,70 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupChangeManagementTypeType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileDeleteType(description={!r})'.format( + return 'GroupChangeManagementTypeType(description={!r})'.format( self._description_value, ) -FileDeleteType_validator = bv.Struct(FileDeleteType) +GroupChangeManagementTypeType_validator = bv.Struct(GroupChangeManagementTypeType) -class FileDownloadDetails(bb.Struct): +class GroupChangeMemberRoleDetails(bb.Struct): """ - Downloaded files and/or folders. + Changed manager permissions of group member. + + :ivar team_log.GroupChangeMemberRoleDetails.is_group_owner: Is group owner. """ __slots__ = [ + '_is_group_owner_value', + '_is_group_owner_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + is_group_owner=None): + self._is_group_owner_value = None + self._is_group_owner_present = False + if is_group_owner is not None: + self.is_group_owner = is_group_owner + + @property + def is_group_owner(self): + """ + Is group owner. + + :rtype: bool + """ + if self._is_group_owner_present: + return self._is_group_owner_value + else: + raise AttributeError("missing required field 'is_group_owner'") + + @is_group_owner.setter + def is_group_owner(self, val): + val = self._is_group_owner_validator.validate(val) + self._is_group_owner_value = val + self._is_group_owner_present = True + + @is_group_owner.deleter + def is_group_owner(self): + self._is_group_owner_value = None + self._is_group_owner_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupChangeMemberRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileDownloadDetails()' + return 'GroupChangeMemberRoleDetails(is_group_owner={!r})'.format( + self._is_group_owner_value, + ) -FileDownloadDetails_validator = bv.Struct(FileDownloadDetails) +GroupChangeMemberRoleDetails_validator = bv.Struct(GroupChangeMemberRoleDetails) -class FileDownloadType(bb.Struct): +class GroupChangeMemberRoleType(bb.Struct): __slots__ = [ '_description_value', @@ -30852,107 +50035,109 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupChangeMemberRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileDownloadType(description={!r})'.format( + return 'GroupChangeMemberRoleType(description={!r})'.format( self._description_value, ) -FileDownloadType_validator = bv.Struct(FileDownloadType) +GroupChangeMemberRoleType_validator = bv.Struct(GroupChangeMemberRoleType) -class FileEditCommentDetails(bb.Struct): +class GroupCreateDetails(bb.Struct): """ - Edited file comment. + Created group. - :ivar team_log.FileEditCommentDetails.comment_text: Comment text. Might be - missing due to historical data gap. - :ivar team_log.FileEditCommentDetails.previous_comment_text: Previous - comment text. + :ivar team_log.GroupCreateDetails.is_company_managed: Is company managed + group. Might be missing due to historical data gap. + :ivar team_log.GroupCreateDetails.join_policy: Group join policy. """ __slots__ = [ - '_comment_text_value', - '_comment_text_present', - '_previous_comment_text_value', - '_previous_comment_text_present', + '_is_company_managed_value', + '_is_company_managed_present', + '_join_policy_value', + '_join_policy_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - previous_comment_text=None, - comment_text=None): - self._comment_text_value = None - self._comment_text_present = False - self._previous_comment_text_value = None - self._previous_comment_text_present = False - if comment_text is not None: - self.comment_text = comment_text - if previous_comment_text is not None: - self.previous_comment_text = previous_comment_text + is_company_managed=None, + join_policy=None): + self._is_company_managed_value = None + self._is_company_managed_present = False + self._join_policy_value = None + self._join_policy_present = False + if is_company_managed is not None: + self.is_company_managed = is_company_managed + if join_policy is not None: + self.join_policy = join_policy @property - def comment_text(self): + def is_company_managed(self): """ - Comment text. Might be missing due to historical data gap. + Is company managed group. Might be missing due to historical data gap. - :rtype: str + :rtype: bool """ - if self._comment_text_present: - return self._comment_text_value + if self._is_company_managed_present: + return self._is_company_managed_value else: return None - @comment_text.setter - def comment_text(self, val): + @is_company_managed.setter + def is_company_managed(self, val): if val is None: - del self.comment_text + del self.is_company_managed return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + val = self._is_company_managed_validator.validate(val) + self._is_company_managed_value = val + self._is_company_managed_present = True - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + @is_company_managed.deleter + def is_company_managed(self): + self._is_company_managed_value = None + self._is_company_managed_present = False @property - def previous_comment_text(self): + def join_policy(self): """ - Previous comment text. + Group join policy. - :rtype: str + :rtype: GroupJoinPolicy """ - if self._previous_comment_text_present: - return self._previous_comment_text_value + if self._join_policy_present: + return self._join_policy_value else: - raise AttributeError("missing required field 'previous_comment_text'") + return None - @previous_comment_text.setter - def previous_comment_text(self, val): - val = self._previous_comment_text_validator.validate(val) - self._previous_comment_text_value = val - self._previous_comment_text_present = True + @join_policy.setter + def join_policy(self, val): + if val is None: + del self.join_policy + return + self._join_policy_validator.validate_type_only(val) + self._join_policy_value = val + self._join_policy_present = True - @previous_comment_text.deleter - def previous_comment_text(self): - self._previous_comment_text_value = None - self._previous_comment_text_present = False + @join_policy.deleter + def join_policy(self): + self._join_policy_value = None + self._join_policy_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileEditCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileEditCommentDetails(previous_comment_text={!r}, comment_text={!r})'.format( - self._previous_comment_text_value, - self._comment_text_value, + return 'GroupCreateDetails(is_company_managed={!r}, join_policy={!r})'.format( + self._is_company_managed_value, + self._join_policy_value, ) -FileEditCommentDetails_validator = bv.Struct(FileEditCommentDetails) +GroupCreateDetails_validator = bv.Struct(GroupCreateDetails) -class FileEditCommentType(bb.Struct): +class GroupCreateType(bb.Struct): __slots__ = [ '_description_value', @@ -30990,37 +50175,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileEditCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileEditCommentType(description={!r})'.format( + return 'GroupCreateType(description={!r})'.format( self._description_value, ) -FileEditCommentType_validator = bv.Struct(FileEditCommentType) +GroupCreateType_validator = bv.Struct(GroupCreateType) -class FileEditDetails(bb.Struct): +class GroupDeleteDetails(bb.Struct): """ - Edited files. + Deleted group. + + :ivar team_log.GroupDeleteDetails.is_company_managed: Is company managed + group. Might be missing due to historical data gap. """ __slots__ = [ + '_is_company_managed_value', + '_is_company_managed_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + is_company_managed=None): + self._is_company_managed_value = None + self._is_company_managed_present = False + if is_company_managed is not None: + self.is_company_managed = is_company_managed + + @property + def is_company_managed(self): + """ + Is company managed group. Might be missing due to historical data gap. + + :rtype: bool + """ + if self._is_company_managed_present: + return self._is_company_managed_value + else: + return None + + @is_company_managed.setter + def is_company_managed(self, val): + if val is None: + del self.is_company_managed + return + val = self._is_company_managed_validator.validate(val) + self._is_company_managed_value = val + self._is_company_managed_present = True + + @is_company_managed.deleter + def is_company_managed(self): + self._is_company_managed_value = None + self._is_company_managed_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileEditDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileEditDetails()' + return 'GroupDeleteDetails(is_company_managed={!r})'.format( + self._is_company_managed_value, + ) -FileEditDetails_validator = bv.Struct(FileEditDetails) +GroupDeleteDetails_validator = bv.Struct(GroupDeleteDetails) -class FileEditType(bb.Struct): +class GroupDeleteType(bb.Struct): __slots__ = [ '_description_value', @@ -31058,18 +50280,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileEditType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileEditType(description={!r})'.format( + return 'GroupDeleteType(description={!r})'.format( self._description_value, ) -FileEditType_validator = bv.Struct(FileEditType) +GroupDeleteType_validator = bv.Struct(GroupDeleteType) -class FileGetCopyReferenceDetails(bb.Struct): +class GroupDescriptionUpdatedDetails(bb.Struct): """ - Created copy reference to file/folder. + Updated group. """ __slots__ = [ @@ -31081,14 +50303,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileGetCopyReferenceDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupDescriptionUpdatedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileGetCopyReferenceDetails()' + return 'GroupDescriptionUpdatedDetails()' -FileGetCopyReferenceDetails_validator = bv.Struct(FileGetCopyReferenceDetails) +GroupDescriptionUpdatedDetails_validator = bv.Struct(GroupDescriptionUpdatedDetails) -class FileGetCopyReferenceType(bb.Struct): +class GroupDescriptionUpdatedType(bb.Struct): __slots__ = [ '_description_value', @@ -31126,74 +50348,156 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileGetCopyReferenceType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupDescriptionUpdatedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileGetCopyReferenceType(description={!r})'.format( + return 'GroupDescriptionUpdatedType(description={!r})'.format( self._description_value, ) -FileGetCopyReferenceType_validator = bv.Struct(FileGetCopyReferenceType) +GroupDescriptionUpdatedType_validator = bv.Struct(GroupDescriptionUpdatedType) -class FileLikeCommentDetails(bb.Struct): +class GroupJoinPolicy(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - Liked file comment. - :ivar team_log.FileLikeCommentDetails.comment_text: Comment text. Might be - missing due to historical data gap. + _catch_all = 'other' + # Attribute is overwritten below the class definition + open = None + # Attribute is overwritten below the class definition + request_to_join = None + # Attribute is overwritten below the class definition + other = None + + def is_open(self): + """ + Check if the union tag is ``open``. + + :rtype: bool + """ + return self._tag == 'open' + + def is_request_to_join(self): + """ + Check if the union tag is ``request_to_join``. + + :rtype: bool + """ + return self._tag == 'request_to_join' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GroupJoinPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GroupJoinPolicy(%r, %r)' % (self._tag, self._value) + +GroupJoinPolicy_validator = bv.Union(GroupJoinPolicy) + +class GroupJoinPolicyUpdatedDetails(bb.Struct): + """ + Updated group join policy. + + :ivar team_log.GroupJoinPolicyUpdatedDetails.is_company_managed: Is company + managed group. Might be missing due to historical data gap. + :ivar team_log.GroupJoinPolicyUpdatedDetails.join_policy: Group join policy. """ __slots__ = [ - '_comment_text_value', - '_comment_text_present', + '_is_company_managed_value', + '_is_company_managed_present', + '_join_policy_value', + '_join_policy_present', ] _has_required_fields = False def __init__(self, - comment_text=None): - self._comment_text_value = None - self._comment_text_present = False - if comment_text is not None: - self.comment_text = comment_text + is_company_managed=None, + join_policy=None): + self._is_company_managed_value = None + self._is_company_managed_present = False + self._join_policy_value = None + self._join_policy_present = False + if is_company_managed is not None: + self.is_company_managed = is_company_managed + if join_policy is not None: + self.join_policy = join_policy @property - def comment_text(self): + def is_company_managed(self): """ - Comment text. Might be missing due to historical data gap. + Is company managed group. Might be missing due to historical data gap. - :rtype: str + :rtype: bool """ - if self._comment_text_present: - return self._comment_text_value + if self._is_company_managed_present: + return self._is_company_managed_value else: return None - @comment_text.setter - def comment_text(self, val): + @is_company_managed.setter + def is_company_managed(self, val): if val is None: - del self.comment_text + del self.is_company_managed return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + val = self._is_company_managed_validator.validate(val) + self._is_company_managed_value = val + self._is_company_managed_present = True - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + @is_company_managed.deleter + def is_company_managed(self): + self._is_company_managed_value = None + self._is_company_managed_present = False + + @property + def join_policy(self): + """ + Group join policy. + + :rtype: GroupJoinPolicy + """ + if self._join_policy_present: + return self._join_policy_value + else: + return None + + @join_policy.setter + def join_policy(self, val): + if val is None: + del self.join_policy + return + self._join_policy_validator.validate_type_only(val) + self._join_policy_value = val + self._join_policy_present = True + + @join_policy.deleter + def join_policy(self): + self._join_policy_value = None + self._join_policy_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileLikeCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupJoinPolicyUpdatedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileLikeCommentDetails(comment_text={!r})'.format( - self._comment_text_value, + return 'GroupJoinPolicyUpdatedDetails(is_company_managed={!r}, join_policy={!r})'.format( + self._is_company_managed_value, + self._join_policy_value, ) -FileLikeCommentDetails_validator = bv.Struct(FileLikeCommentDetails) +GroupJoinPolicyUpdatedDetails_validator = bv.Struct(GroupJoinPolicyUpdatedDetails) -class FileLikeCommentType(bb.Struct): +class GroupJoinPolicyUpdatedType(bb.Struct): __slots__ = [ '_description_value', @@ -31231,94 +50535,95 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileLikeCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupJoinPolicyUpdatedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileLikeCommentType(description={!r})'.format( + return 'GroupJoinPolicyUpdatedType(description={!r})'.format( self._description_value, ) -FileLikeCommentType_validator = bv.Struct(FileLikeCommentType) +GroupJoinPolicyUpdatedType_validator = bv.Struct(GroupJoinPolicyUpdatedType) -class FileOrFolderLogInfo(bb.Struct): +class GroupLogInfo(bb.Struct): """ - Generic information relevant both for files and folders + Group's logged information. - :ivar team_log.FileOrFolderLogInfo.path: Path relative to event context. - :ivar team_log.FileOrFolderLogInfo.display_name: Display name. Might be + :ivar team_log.GroupLogInfo.group_id: The unique id of this group. Might be missing due to historical data gap. - :ivar team_log.FileOrFolderLogInfo.file_id: Unique ID. Might be missing due - to historical data gap. + :ivar team_log.GroupLogInfo.display_name: The name of this group. + :ivar team_log.GroupLogInfo.external_id: External group ID. Might be missing + due to historical data gap. """ __slots__ = [ - '_path_value', - '_path_present', + '_group_id_value', + '_group_id_present', '_display_name_value', '_display_name_present', - '_file_id_value', - '_file_id_present', + '_external_id_value', + '_external_id_present', ] _has_required_fields = True def __init__(self, - path=None, display_name=None, - file_id=None): - self._path_value = None - self._path_present = False + group_id=None, + external_id=None): + self._group_id_value = None + self._group_id_present = False self._display_name_value = None self._display_name_present = False - self._file_id_value = None - self._file_id_present = False - if path is not None: - self.path = path + self._external_id_value = None + self._external_id_present = False + if group_id is not None: + self.group_id = group_id if display_name is not None: self.display_name = display_name - if file_id is not None: - self.file_id = file_id + if external_id is not None: + self.external_id = external_id @property - def path(self): + def group_id(self): """ - Path relative to event context. + The unique id of this group. Might be missing due to historical data + gap. - :rtype: PathLogInfo + :rtype: str """ - if self._path_present: - return self._path_value + if self._group_id_present: + return self._group_id_value else: - raise AttributeError("missing required field 'path'") + return None - @path.setter - def path(self, val): - self._path_validator.validate_type_only(val) - self._path_value = val - self._path_present = True + @group_id.setter + def group_id(self, val): + if val is None: + del self.group_id + return + val = self._group_id_validator.validate(val) + self._group_id_value = val + self._group_id_present = True - @path.deleter - def path(self): - self._path_value = None - self._path_present = False + @group_id.deleter + def group_id(self): + self._group_id_value = None + self._group_id_present = False @property def display_name(self): """ - Display name. Might be missing due to historical data gap. + The name of this group. :rtype: str """ if self._display_name_present: return self._display_name_value else: - return None + raise AttributeError("missing required field 'display_name'") @display_name.setter def display_name(self, val): - if val is None: - del self.display_name - return val = self._display_name_validator.validate(val) self._display_name_value = val self._display_name_present = True @@ -31329,129 +50634,65 @@ def display_name(self): self._display_name_present = False @property - def file_id(self): + def external_id(self): """ - Unique ID. Might be missing due to historical data gap. + External group ID. Might be missing due to historical data gap. :rtype: str """ - if self._file_id_present: - return self._file_id_value + if self._external_id_present: + return self._external_id_value else: return None - @file_id.setter - def file_id(self, val): + @external_id.setter + def external_id(self, val): if val is None: - del self.file_id + del self.external_id return - val = self._file_id_validator.validate(val) - self._file_id_value = val - self._file_id_present = True - - @file_id.deleter - def file_id(self): - self._file_id_value = None - self._file_id_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileOrFolderLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FileOrFolderLogInfo(path={!r}, display_name={!r}, file_id={!r})'.format( - self._path_value, - self._display_name_value, - self._file_id_value, - ) - -FileOrFolderLogInfo_validator = bv.Struct(FileOrFolderLogInfo) - -class FileLogInfo(FileOrFolderLogInfo): - """ - File's logged information. - """ - - __slots__ = [ - ] - - _has_required_fields = True + val = self._external_id_validator.validate(val) + self._external_id_value = val + self._external_id_present = True - def __init__(self, - path=None, - display_name=None, - file_id=None): - super(FileLogInfo, self).__init__(path, - display_name, - file_id) + @external_id.deleter + def external_id(self): + self._external_id_value = None + self._external_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileLogInfo(path={!r}, display_name={!r}, file_id={!r})'.format( - self._path_value, + return 'GroupLogInfo(display_name={!r}, group_id={!r}, external_id={!r})'.format( self._display_name_value, - self._file_id_value, + self._group_id_value, + self._external_id_value, ) -FileLogInfo_validator = bv.Struct(FileLogInfo) +GroupLogInfo_validator = bv.Struct(GroupLogInfo) -class FileMoveDetails(bb.Struct): +class GroupMovedDetails(bb.Struct): """ - Moved files and/or folders. - - :ivar team_log.FileMoveDetails.relocate_action_details: Relocate action - details. + Moved group. """ __slots__ = [ - '_relocate_action_details_value', - '_relocate_action_details_present', ] - _has_required_fields = True - - def __init__(self, - relocate_action_details=None): - self._relocate_action_details_value = None - self._relocate_action_details_present = False - if relocate_action_details is not None: - self.relocate_action_details = relocate_action_details - - @property - def relocate_action_details(self): - """ - Relocate action details. - - :rtype: list of [RelocateAssetReferencesLogInfo] - """ - if self._relocate_action_details_present: - return self._relocate_action_details_value - else: - raise AttributeError("missing required field 'relocate_action_details'") - - @relocate_action_details.setter - def relocate_action_details(self, val): - val = self._relocate_action_details_validator.validate(val) - self._relocate_action_details_value = val - self._relocate_action_details_present = True + _has_required_fields = False - @relocate_action_details.deleter - def relocate_action_details(self): - self._relocate_action_details_value = None - self._relocate_action_details_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileMoveDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupMovedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileMoveDetails(relocate_action_details={!r})'.format( - self._relocate_action_details_value, - ) + return 'GroupMovedDetails()' -FileMoveDetails_validator = bv.Struct(FileMoveDetails) +GroupMovedDetails_validator = bv.Struct(GroupMovedDetails) -class FileMoveType(bb.Struct): +class GroupMovedType(bb.Struct): __slots__ = [ '_description_value', @@ -31489,105 +50730,70 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileMoveType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupMovedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileMoveType(description={!r})'.format( + return 'GroupMovedType(description={!r})'.format( self._description_value, ) -FileMoveType_validator = bv.Struct(FileMoveType) +GroupMovedType_validator = bv.Struct(GroupMovedType) -class FilePermanentlyDeleteDetails(bb.Struct): - """ - Permanently deleted files and/or folders. +class GroupRemoveExternalIdDetails(bb.Struct): """ + Removed external ID for group. - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FilePermanentlyDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FilePermanentlyDeleteDetails()' - -FilePermanentlyDeleteDetails_validator = bv.Struct(FilePermanentlyDeleteDetails) - -class FilePermanentlyDeleteType(bb.Struct): + :ivar team_log.GroupRemoveExternalIdDetails.previous_value: Old external id. + """ __slots__ = [ - '_description_value', - '_description_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + previous_value=None): + self._previous_value_value = None + self._previous_value_present = False + if previous_value is not None: + self.previous_value = previous_value @property - def description(self): + def previous_value(self): """ + Old external id. + :rtype: str """ - if self._description_present: - return self._description_value + if self._previous_value_present: + return self._previous_value_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'previous_value'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FilePermanentlyDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupRemoveExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FilePermanentlyDeleteType(description={!r})'.format( - self._description_value, + return 'GroupRemoveExternalIdDetails(previous_value={!r})'.format( + self._previous_value_value, ) -FilePermanentlyDeleteType_validator = bv.Struct(FilePermanentlyDeleteType) - -class FilePreviewDetails(bb.Struct): - """ - Previewed files and/or folders. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FilePreviewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FilePreviewDetails()' - -FilePreviewDetails_validator = bv.Struct(FilePreviewDetails) +GroupRemoveExternalIdDetails_validator = bv.Struct(GroupRemoveExternalIdDetails) -class FilePreviewType(bb.Struct): +class GroupRemoveExternalIdType(bb.Struct): __slots__ = [ '_description_value', @@ -31625,71 +50831,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FilePreviewType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupRemoveExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FilePreviewType(description={!r})'.format( + return 'GroupRemoveExternalIdType(description={!r})'.format( self._description_value, ) -FilePreviewType_validator = bv.Struct(FilePreviewType) +GroupRemoveExternalIdType_validator = bv.Struct(GroupRemoveExternalIdType) -class FileRenameDetails(bb.Struct): +class GroupRemoveMemberDetails(bb.Struct): """ - Renamed files and/or folders. - - :ivar team_log.FileRenameDetails.relocate_action_details: Relocate action - details. + Removed team members from group. """ - __slots__ = [ - '_relocate_action_details_value', - '_relocate_action_details_present', - ] - - _has_required_fields = True - - def __init__(self, - relocate_action_details=None): - self._relocate_action_details_value = None - self._relocate_action_details_present = False - if relocate_action_details is not None: - self.relocate_action_details = relocate_action_details - - @property - def relocate_action_details(self): - """ - Relocate action details. - - :rtype: list of [RelocateAssetReferencesLogInfo] - """ - if self._relocate_action_details_present: - return self._relocate_action_details_value - else: - raise AttributeError("missing required field 'relocate_action_details'") + __slots__ = [ + ] - @relocate_action_details.setter - def relocate_action_details(self, val): - val = self._relocate_action_details_validator.validate(val) - self._relocate_action_details_value = val - self._relocate_action_details_present = True + _has_required_fields = False - @relocate_action_details.deleter - def relocate_action_details(self): - self._relocate_action_details_value = None - self._relocate_action_details_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRenameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupRemoveMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRenameDetails(relocate_action_details={!r})'.format( - self._relocate_action_details_value, - ) + return 'GroupRemoveMemberDetails()' -FileRenameDetails_validator = bv.Struct(FileRenameDetails) +GroupRemoveMemberDetails_validator = bv.Struct(GroupRemoveMemberDetails) -class FileRenameType(bb.Struct): +class GroupRemoveMemberType(bb.Struct): __slots__ = [ '_description_value', @@ -31727,144 +50899,102 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRenameType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupRemoveMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRenameType(description={!r})'.format( + return 'GroupRemoveMemberType(description={!r})'.format( self._description_value, ) -FileRenameType_validator = bv.Struct(FileRenameType) +GroupRemoveMemberType_validator = bv.Struct(GroupRemoveMemberType) -class FileRequestChangeDetails(bb.Struct): +class GroupRenameDetails(bb.Struct): """ - Changed file request. + Renamed group. - :ivar team_log.FileRequestChangeDetails.file_request_id: File request id. - Might be missing due to historical data gap. - :ivar team_log.FileRequestChangeDetails.previous_details: Previous file - request details. Might be missing due to historical data gap. - :ivar team_log.FileRequestChangeDetails.new_details: New file request - details. + :ivar team_log.GroupRenameDetails.previous_value: Previous display name. + :ivar team_log.GroupRenameDetails.new_value: New display name. """ __slots__ = [ - '_file_request_id_value', - '_file_request_id_present', - '_previous_details_value', - '_previous_details_present', - '_new_details_value', - '_new_details_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', ] _has_required_fields = True def __init__(self, - new_details=None, - file_request_id=None, - previous_details=None): - self._file_request_id_value = None - self._file_request_id_present = False - self._previous_details_value = None - self._previous_details_present = False - self._new_details_value = None - self._new_details_present = False - if file_request_id is not None: - self.file_request_id = file_request_id - if previous_details is not None: - self.previous_details = previous_details - if new_details is not None: - self.new_details = new_details + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def file_request_id(self): + def previous_value(self): """ - File request id. Might be missing due to historical data gap. + Previous display name. :rtype: str """ - if self._file_request_id_present: - return self._file_request_id_value - else: - return None - - @file_request_id.setter - def file_request_id(self, val): - if val is None: - del self.file_request_id - return - val = self._file_request_id_validator.validate(val) - self._file_request_id_value = val - self._file_request_id_present = True - - @file_request_id.deleter - def file_request_id(self): - self._file_request_id_value = None - self._file_request_id_present = False - - @property - def previous_details(self): - """ - Previous file request details. Might be missing due to historical data - gap. - - :rtype: FileRequestDetails - """ - if self._previous_details_present: - return self._previous_details_value + if self._previous_value_present: + return self._previous_value_value else: - return None + raise AttributeError("missing required field 'previous_value'") - @previous_details.setter - def previous_details(self, val): - if val is None: - del self.previous_details - return - self._previous_details_validator.validate_type_only(val) - self._previous_details_value = val - self._previous_details_present = True + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - @previous_details.deleter - def previous_details(self): - self._previous_details_value = None - self._previous_details_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property - def new_details(self): + def new_value(self): """ - New file request details. + New display name. - :rtype: FileRequestDetails + :rtype: str """ - if self._new_details_present: - return self._new_details_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'new_details'") + raise AttributeError("missing required field 'new_value'") - @new_details.setter - def new_details(self, val): - self._new_details_validator.validate_type_only(val) - self._new_details_value = val - self._new_details_present = True + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @new_details.deleter - def new_details(self): - self._new_details_value = None - self._new_details_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestChangeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupRenameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestChangeDetails(new_details={!r}, file_request_id={!r}, previous_details={!r})'.format( - self._new_details_value, - self._file_request_id_value, - self._previous_details_value, + return 'GroupRenameDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, ) -FileRequestChangeDetails_validator = bv.Struct(FileRequestChangeDetails) +GroupRenameDetails_validator = bv.Struct(GroupRenameDetails) -class FileRequestChangeType(bb.Struct): +class GroupRenameType(bb.Struct): __slots__ = [ '_description_value', @@ -31902,111 +51032,109 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestChangeType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupRenameType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestChangeType(description={!r})'.format( + return 'GroupRenameType(description={!r})'.format( self._description_value, ) -FileRequestChangeType_validator = bv.Struct(FileRequestChangeType) +GroupRenameType_validator = bv.Struct(GroupRenameType) -class FileRequestCloseDetails(bb.Struct): +class GroupUserManagementChangePolicyDetails(bb.Struct): """ - Closed file request. + Changed who can create groups. - :ivar team_log.FileRequestCloseDetails.file_request_id: File request id. - Might be missing due to historical data gap. - :ivar team_log.FileRequestCloseDetails.previous_details: Previous file - request details. Might be missing due to historical data gap. + :ivar team_log.GroupUserManagementChangePolicyDetails.new_value: New group + users management policy. + :ivar team_log.GroupUserManagementChangePolicyDetails.previous_value: + Previous group users management policy. Might be missing due to + historical data gap. """ __slots__ = [ - '_file_request_id_value', - '_file_request_id_present', - '_previous_details_value', - '_previous_details_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - file_request_id=None, - previous_details=None): - self._file_request_id_value = None - self._file_request_id_present = False - self._previous_details_value = None - self._previous_details_present = False - if file_request_id is not None: - self.file_request_id = file_request_id - if previous_details is not None: - self.previous_details = previous_details + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def file_request_id(self): + def new_value(self): """ - File request id. Might be missing due to historical data gap. + New group users management policy. - :rtype: str + :rtype: team_policies.GroupCreation """ - if self._file_request_id_present: - return self._file_request_id_value + if self._new_value_present: + return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") - @file_request_id.setter - def file_request_id(self, val): - if val is None: - del self.file_request_id - return - val = self._file_request_id_validator.validate(val) - self._file_request_id_value = val - self._file_request_id_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @file_request_id.deleter - def file_request_id(self): - self._file_request_id_value = None - self._file_request_id_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False @property - def previous_details(self): + def previous_value(self): """ - Previous file request details. Might be missing due to historical data - gap. + Previous group users management policy. Might be missing due to + historical data gap. - :rtype: FileRequestDetails + :rtype: team_policies.GroupCreation """ - if self._previous_details_present: - return self._previous_details_value + if self._previous_value_present: + return self._previous_value_value else: return None - @previous_details.setter - def previous_details(self, val): + @previous_value.setter + def previous_value(self, val): if val is None: - del self.previous_details + del self.previous_value return - self._previous_details_validator.validate_type_only(val) - self._previous_details_value = val - self._previous_details_present = True + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @previous_details.deleter - def previous_details(self): - self._previous_details_value = None - self._previous_details_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestCloseDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupUserManagementChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestCloseDetails(file_request_id={!r}, previous_details={!r})'.format( - self._file_request_id_value, - self._previous_details_value, + return 'GroupUserManagementChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -FileRequestCloseDetails_validator = bv.Struct(FileRequestCloseDetails) +GroupUserManagementChangePolicyDetails_validator = bv.Struct(GroupUserManagementChangePolicyDetails) -class FileRequestCloseType(bb.Struct): +class GroupUserManagementChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -32044,110 +51172,240 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestCloseType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GroupUserManagementChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestCloseType(description={!r})'.format( + return 'GroupUserManagementChangePolicyType(description={!r})'.format( self._description_value, ) -FileRequestCloseType_validator = bv.Struct(FileRequestCloseType) +GroupUserManagementChangePolicyType_validator = bv.Struct(GroupUserManagementChangePolicyType) -class FileRequestCreateDetails(bb.Struct): +class GuestAdminChangeStatusDetails(bb.Struct): """ - Created file request. + Changed guest team admin status. - :ivar team_log.FileRequestCreateDetails.file_request_id: File request id. - Might be missing due to historical data gap. - :ivar team_log.FileRequestCreateDetails.request_details: File request - details. Might be missing due to historical data gap. + :ivar team_log.GuestAdminChangeStatusDetails.is_guest: True for guest, false + for host. + :ivar team_log.GuestAdminChangeStatusDetails.guest_team_name: The name of + the guest team. + :ivar team_log.GuestAdminChangeStatusDetails.host_team_name: The name of the + host team. + :ivar team_log.GuestAdminChangeStatusDetails.previous_value: Previous + request state. + :ivar team_log.GuestAdminChangeStatusDetails.new_value: New request state. + :ivar team_log.GuestAdminChangeStatusDetails.action_details: Action details. """ __slots__ = [ - '_file_request_id_value', - '_file_request_id_present', - '_request_details_value', - '_request_details_present', + '_is_guest_value', + '_is_guest_present', + '_guest_team_name_value', + '_guest_team_name_present', + '_host_team_name_value', + '_host_team_name_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + '_action_details_value', + '_action_details_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - file_request_id=None, - request_details=None): - self._file_request_id_value = None - self._file_request_id_present = False - self._request_details_value = None - self._request_details_present = False - if file_request_id is not None: - self.file_request_id = file_request_id - if request_details is not None: - self.request_details = request_details + is_guest=None, + previous_value=None, + new_value=None, + action_details=None, + guest_team_name=None, + host_team_name=None): + self._is_guest_value = None + self._is_guest_present = False + self._guest_team_name_value = None + self._guest_team_name_present = False + self._host_team_name_value = None + self._host_team_name_present = False + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + self._action_details_value = None + self._action_details_present = False + if is_guest is not None: + self.is_guest = is_guest + if guest_team_name is not None: + self.guest_team_name = guest_team_name + if host_team_name is not None: + self.host_team_name = host_team_name + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value + if action_details is not None: + self.action_details = action_details @property - def file_request_id(self): + def is_guest(self): """ - File request id. Might be missing due to historical data gap. + True for guest, false for host. + + :rtype: bool + """ + if self._is_guest_present: + return self._is_guest_value + else: + raise AttributeError("missing required field 'is_guest'") + + @is_guest.setter + def is_guest(self, val): + val = self._is_guest_validator.validate(val) + self._is_guest_value = val + self._is_guest_present = True + + @is_guest.deleter + def is_guest(self): + self._is_guest_value = None + self._is_guest_present = False + + @property + def guest_team_name(self): + """ + The name of the guest team. :rtype: str """ - if self._file_request_id_present: - return self._file_request_id_value + if self._guest_team_name_present: + return self._guest_team_name_value else: return None - @file_request_id.setter - def file_request_id(self, val): + @guest_team_name.setter + def guest_team_name(self, val): if val is None: - del self.file_request_id + del self.guest_team_name return - val = self._file_request_id_validator.validate(val) - self._file_request_id_value = val - self._file_request_id_present = True + val = self._guest_team_name_validator.validate(val) + self._guest_team_name_value = val + self._guest_team_name_present = True - @file_request_id.deleter - def file_request_id(self): - self._file_request_id_value = None - self._file_request_id_present = False + @guest_team_name.deleter + def guest_team_name(self): + self._guest_team_name_value = None + self._guest_team_name_present = False + + @property + def host_team_name(self): + """ + The name of the host team. + + :rtype: str + """ + if self._host_team_name_present: + return self._host_team_name_value + else: + return None + + @host_team_name.setter + def host_team_name(self, val): + if val is None: + del self.host_team_name + return + val = self._host_team_name_validator.validate(val) + self._host_team_name_value = val + self._host_team_name_present = True + + @host_team_name.deleter + def host_team_name(self): + self._host_team_name_value = None + self._host_team_name_present = False + + @property + def previous_value(self): + """ + Previous request state. + + :rtype: TrustedTeamsRequestState + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + @property + def new_value(self): + """ + New request state. + + :rtype: TrustedTeamsRequestState + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False @property - def request_details(self): + def action_details(self): """ - File request details. Might be missing due to historical data gap. + Action details. - :rtype: FileRequestDetails + :rtype: TrustedTeamsRequestAction """ - if self._request_details_present: - return self._request_details_value + if self._action_details_present: + return self._action_details_value else: - return None + raise AttributeError("missing required field 'action_details'") - @request_details.setter - def request_details(self, val): - if val is None: - del self.request_details - return - self._request_details_validator.validate_type_only(val) - self._request_details_value = val - self._request_details_present = True + @action_details.setter + def action_details(self, val): + self._action_details_validator.validate_type_only(val) + self._action_details_value = val + self._action_details_present = True - @request_details.deleter - def request_details(self): - self._request_details_value = None - self._request_details_present = False + @action_details.deleter + def action_details(self): + self._action_details_value = None + self._action_details_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GuestAdminChangeStatusDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestCreateDetails(file_request_id={!r}, request_details={!r})'.format( - self._file_request_id_value, - self._request_details_value, + return 'GuestAdminChangeStatusDetails(is_guest={!r}, previous_value={!r}, new_value={!r}, action_details={!r}, guest_team_name={!r}, host_team_name={!r})'.format( + self._is_guest_value, + self._previous_value_value, + self._new_value_value, + self._action_details_value, + self._guest_team_name_value, + self._host_team_name_value, ) -FileRequestCreateDetails_validator = bv.Struct(FileRequestCreateDetails) +GuestAdminChangeStatusDetails_validator = bv.Struct(GuestAdminChangeStatusDetails) -class FileRequestCreateType(bb.Struct): +class GuestAdminChangeStatusType(bb.Struct): __slots__ = [ '_description_value', @@ -32185,208 +51443,251 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GuestAdminChangeStatusType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestCreateType(description={!r})'.format( + return 'GuestAdminChangeStatusType(description={!r})'.format( self._description_value, ) -FileRequestCreateType_validator = bv.Struct(FileRequestCreateType) +GuestAdminChangeStatusType_validator = bv.Struct(GuestAdminChangeStatusType) -class FileRequestDeadline(bb.Struct): +class GuestAdminSignedInViaTrustedTeamsDetails(bb.Struct): """ - File request deadline + Started trusted team admin session. - :ivar team_log.FileRequestDeadline.deadline: The deadline for this file - request. Might be missing due to historical data gap. - :ivar team_log.FileRequestDeadline.allow_late_uploads: If set, allow uploads - after the deadline has passed. Might be missing due to historical data - gap. + :ivar team_log.GuestAdminSignedInViaTrustedTeamsDetails.team_name: Host team + name. + :ivar team_log.GuestAdminSignedInViaTrustedTeamsDetails.trusted_team_name: + Trusted team name. """ __slots__ = [ - '_deadline_value', - '_deadline_present', - '_allow_late_uploads_value', - '_allow_late_uploads_present', + '_team_name_value', + '_team_name_present', + '_trusted_team_name_value', + '_trusted_team_name_present', ] _has_required_fields = False def __init__(self, - deadline=None, - allow_late_uploads=None): - self._deadline_value = None - self._deadline_present = False - self._allow_late_uploads_value = None - self._allow_late_uploads_present = False - if deadline is not None: - self.deadline = deadline - if allow_late_uploads is not None: - self.allow_late_uploads = allow_late_uploads + team_name=None, + trusted_team_name=None): + self._team_name_value = None + self._team_name_present = False + self._trusted_team_name_value = None + self._trusted_team_name_present = False + if team_name is not None: + self.team_name = team_name + if trusted_team_name is not None: + self.trusted_team_name = trusted_team_name @property - def deadline(self): + def team_name(self): """ - The deadline for this file request. Might be missing due to historical - data gap. + Host team name. - :rtype: datetime.datetime + :rtype: str """ - if self._deadline_present: - return self._deadline_value + if self._team_name_present: + return self._team_name_value else: return None - @deadline.setter - def deadline(self, val): + @team_name.setter + def team_name(self, val): if val is None: - del self.deadline + del self.team_name return - val = self._deadline_validator.validate(val) - self._deadline_value = val - self._deadline_present = True + val = self._team_name_validator.validate(val) + self._team_name_value = val + self._team_name_present = True - @deadline.deleter - def deadline(self): - self._deadline_value = None - self._deadline_present = False + @team_name.deleter + def team_name(self): + self._team_name_value = None + self._team_name_present = False @property - def allow_late_uploads(self): + def trusted_team_name(self): """ - If set, allow uploads after the deadline has passed. Might be missing - due to historical data gap. + Trusted team name. :rtype: str """ - if self._allow_late_uploads_present: - return self._allow_late_uploads_value + if self._trusted_team_name_present: + return self._trusted_team_name_value else: return None - @allow_late_uploads.setter - def allow_late_uploads(self, val): + @trusted_team_name.setter + def trusted_team_name(self, val): if val is None: - del self.allow_late_uploads + del self.trusted_team_name return - val = self._allow_late_uploads_validator.validate(val) - self._allow_late_uploads_value = val - self._allow_late_uploads_present = True + val = self._trusted_team_name_validator.validate(val) + self._trusted_team_name_value = val + self._trusted_team_name_present = True - @allow_late_uploads.deleter - def allow_late_uploads(self): - self._allow_late_uploads_value = None - self._allow_late_uploads_present = False + @trusted_team_name.deleter + def trusted_team_name(self): + self._trusted_team_name_value = None + self._trusted_team_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestDeadline, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GuestAdminSignedInViaTrustedTeamsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestDeadline(deadline={!r}, allow_late_uploads={!r})'.format( - self._deadline_value, - self._allow_late_uploads_value, + return 'GuestAdminSignedInViaTrustedTeamsDetails(team_name={!r}, trusted_team_name={!r})'.format( + self._team_name_value, + self._trusted_team_name_value, ) -FileRequestDeadline_validator = bv.Struct(FileRequestDeadline) +GuestAdminSignedInViaTrustedTeamsDetails_validator = bv.Struct(GuestAdminSignedInViaTrustedTeamsDetails) -class FileRequestDeleteDetails(bb.Struct): +class GuestAdminSignedInViaTrustedTeamsType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(GuestAdminSignedInViaTrustedTeamsType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'GuestAdminSignedInViaTrustedTeamsType(description={!r})'.format( + self._description_value, + ) + +GuestAdminSignedInViaTrustedTeamsType_validator = bv.Struct(GuestAdminSignedInViaTrustedTeamsType) + +class GuestAdminSignedOutViaTrustedTeamsDetails(bb.Struct): """ - Delete file request. + Ended trusted team admin session. - :ivar team_log.FileRequestDeleteDetails.file_request_id: File request id. - Might be missing due to historical data gap. - :ivar team_log.FileRequestDeleteDetails.previous_details: Previous file - request details. Might be missing due to historical data gap. + :ivar team_log.GuestAdminSignedOutViaTrustedTeamsDetails.team_name: Host + team name. + :ivar team_log.GuestAdminSignedOutViaTrustedTeamsDetails.trusted_team_name: + Trusted team name. """ __slots__ = [ - '_file_request_id_value', - '_file_request_id_present', - '_previous_details_value', - '_previous_details_present', + '_team_name_value', + '_team_name_present', + '_trusted_team_name_value', + '_trusted_team_name_present', ] _has_required_fields = False def __init__(self, - file_request_id=None, - previous_details=None): - self._file_request_id_value = None - self._file_request_id_present = False - self._previous_details_value = None - self._previous_details_present = False - if file_request_id is not None: - self.file_request_id = file_request_id - if previous_details is not None: - self.previous_details = previous_details + team_name=None, + trusted_team_name=None): + self._team_name_value = None + self._team_name_present = False + self._trusted_team_name_value = None + self._trusted_team_name_present = False + if team_name is not None: + self.team_name = team_name + if trusted_team_name is not None: + self.trusted_team_name = trusted_team_name @property - def file_request_id(self): + def team_name(self): """ - File request id. Might be missing due to historical data gap. + Host team name. :rtype: str """ - if self._file_request_id_present: - return self._file_request_id_value + if self._team_name_present: + return self._team_name_value else: return None - @file_request_id.setter - def file_request_id(self, val): + @team_name.setter + def team_name(self, val): if val is None: - del self.file_request_id + del self.team_name return - val = self._file_request_id_validator.validate(val) - self._file_request_id_value = val - self._file_request_id_present = True + val = self._team_name_validator.validate(val) + self._team_name_value = val + self._team_name_present = True - @file_request_id.deleter - def file_request_id(self): - self._file_request_id_value = None - self._file_request_id_present = False + @team_name.deleter + def team_name(self): + self._team_name_value = None + self._team_name_present = False @property - def previous_details(self): + def trusted_team_name(self): """ - Previous file request details. Might be missing due to historical data - gap. + Trusted team name. - :rtype: FileRequestDetails + :rtype: str """ - if self._previous_details_present: - return self._previous_details_value + if self._trusted_team_name_present: + return self._trusted_team_name_value else: return None - @previous_details.setter - def previous_details(self, val): + @trusted_team_name.setter + def trusted_team_name(self, val): if val is None: - del self.previous_details + del self.trusted_team_name return - self._previous_details_validator.validate_type_only(val) - self._previous_details_value = val - self._previous_details_present = True + val = self._trusted_team_name_validator.validate(val) + self._trusted_team_name_value = val + self._trusted_team_name_present = True - @previous_details.deleter - def previous_details(self): - self._previous_details_value = None - self._previous_details_present = False + @trusted_team_name.deleter + def trusted_team_name(self): + self._trusted_team_name_value = None + self._trusted_team_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GuestAdminSignedOutViaTrustedTeamsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestDeleteDetails(file_request_id={!r}, previous_details={!r})'.format( - self._file_request_id_value, - self._previous_details_value, + return 'GuestAdminSignedOutViaTrustedTeamsDetails(team_name={!r}, trusted_team_name={!r})'.format( + self._team_name_value, + self._trusted_team_name_value, ) -FileRequestDeleteDetails_validator = bv.Struct(FileRequestDeleteDetails) +GuestAdminSignedOutViaTrustedTeamsDetails_validator = bv.Struct(GuestAdminSignedOutViaTrustedTeamsDetails) -class FileRequestDeleteType(bb.Struct): +class GuestAdminSignedOutViaTrustedTeamsType(bb.Struct): __slots__ = [ '_description_value', @@ -32424,308 +51725,220 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(GuestAdminSignedOutViaTrustedTeamsType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestDeleteType(description={!r})'.format( + return 'GuestAdminSignedOutViaTrustedTeamsType(description={!r})'.format( self._description_value, ) -FileRequestDeleteType_validator = bv.Struct(FileRequestDeleteType) +GuestAdminSignedOutViaTrustedTeamsType_validator = bv.Struct(GuestAdminSignedOutViaTrustedTeamsType) -class FileRequestDetails(bb.Struct): +class IdentifierType(bb.Union): """ - File request details - - :ivar team_log.FileRequestDetails.asset_index: Asset position in the Assets - list. - :ivar team_log.FileRequestDetails.deadline: File request deadline. Might be - missing due to historical data gap. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_asset_index_value', - '_asset_index_present', - '_deadline_value', - '_deadline_present', - ] - - _has_required_fields = True - - def __init__(self, - asset_index=None, - deadline=None): - self._asset_index_value = None - self._asset_index_present = False - self._deadline_value = None - self._deadline_present = False - if asset_index is not None: - self.asset_index = asset_index - if deadline is not None: - self.deadline = deadline + _catch_all = 'other' + # Attribute is overwritten below the class definition + email = None + # Attribute is overwritten below the class definition + facebook_profile_name = None + # Attribute is overwritten below the class definition + other = None - @property - def asset_index(self): + def is_email(self): """ - Asset position in the Assets list. + Check if the union tag is ``email``. - :rtype: int + :rtype: bool """ - if self._asset_index_present: - return self._asset_index_value - else: - raise AttributeError("missing required field 'asset_index'") - - @asset_index.setter - def asset_index(self, val): - val = self._asset_index_validator.validate(val) - self._asset_index_value = val - self._asset_index_present = True - - @asset_index.deleter - def asset_index(self): - self._asset_index_value = None - self._asset_index_present = False + return self._tag == 'email' - @property - def deadline(self): + def is_facebook_profile_name(self): """ - File request deadline. Might be missing due to historical data gap. + Check if the union tag is ``facebook_profile_name``. - :rtype: FileRequestDeadline + :rtype: bool """ - if self._deadline_present: - return self._deadline_value - else: - return None + return self._tag == 'facebook_profile_name' - @deadline.setter - def deadline(self, val): - if val is None: - del self.deadline - return - self._deadline_validator.validate_type_only(val) - self._deadline_value = val - self._deadline_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @deadline.deleter - def deadline(self): - self._deadline_value = None - self._deadline_present = False + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(IdentifierType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestDetails(asset_index={!r}, deadline={!r})'.format( - self._asset_index_value, - self._deadline_value, - ) + return 'IdentifierType(%r, %r)' % (self._tag, self._value) -FileRequestDetails_validator = bv.Struct(FileRequestDetails) +IdentifierType_validator = bv.Union(IdentifierType) -class FileRequestReceiveFileDetails(bb.Struct): +class IntegrationConnectedDetails(bb.Struct): """ - Received files for file request. + Connected integration for member. - :ivar team_log.FileRequestReceiveFileDetails.file_request_id: File request - id. Might be missing due to historical data gap. - :ivar team_log.FileRequestReceiveFileDetails.file_request_details: File - request details. Might be missing due to historical data gap. - :ivar team_log.FileRequestReceiveFileDetails.submitted_file_names: Submitted - file names. - :ivar team_log.FileRequestReceiveFileDetails.submitter_name: The name as - provided by the submitter. Might be missing due to historical data gap. - :ivar team_log.FileRequestReceiveFileDetails.submitter_email: The email as - provided by the submitter. Might be missing due to historical data gap. + :ivar team_log.IntegrationConnectedDetails.integration_name: Name of the + third-party integration. """ __slots__ = [ - '_file_request_id_value', - '_file_request_id_present', - '_file_request_details_value', - '_file_request_details_present', - '_submitted_file_names_value', - '_submitted_file_names_present', - '_submitter_name_value', - '_submitter_name_present', - '_submitter_email_value', - '_submitter_email_present', - ] - - _has_required_fields = True - - def __init__(self, - submitted_file_names=None, - file_request_id=None, - file_request_details=None, - submitter_name=None, - submitter_email=None): - self._file_request_id_value = None - self._file_request_id_present = False - self._file_request_details_value = None - self._file_request_details_present = False - self._submitted_file_names_value = None - self._submitted_file_names_present = False - self._submitter_name_value = None - self._submitter_name_present = False - self._submitter_email_value = None - self._submitter_email_present = False - if file_request_id is not None: - self.file_request_id = file_request_id - if file_request_details is not None: - self.file_request_details = file_request_details - if submitted_file_names is not None: - self.submitted_file_names = submitted_file_names - if submitter_name is not None: - self.submitter_name = submitter_name - if submitter_email is not None: - self.submitter_email = submitter_email - - @property - def file_request_id(self): - """ - File request id. Might be missing due to historical data gap. - - :rtype: str - """ - if self._file_request_id_present: - return self._file_request_id_value - else: - return None - - @file_request_id.setter - def file_request_id(self, val): - if val is None: - del self.file_request_id - return - val = self._file_request_id_validator.validate(val) - self._file_request_id_value = val - self._file_request_id_present = True + '_integration_name_value', + '_integration_name_present', + ] - @file_request_id.deleter - def file_request_id(self): - self._file_request_id_value = None - self._file_request_id_present = False + _has_required_fields = True + + def __init__(self, + integration_name=None): + self._integration_name_value = None + self._integration_name_present = False + if integration_name is not None: + self.integration_name = integration_name @property - def file_request_details(self): + def integration_name(self): """ - File request details. Might be missing due to historical data gap. + Name of the third-party integration. - :rtype: FileRequestDetails + :rtype: str """ - if self._file_request_details_present: - return self._file_request_details_value + if self._integration_name_present: + return self._integration_name_value else: - return None + raise AttributeError("missing required field 'integration_name'") - @file_request_details.setter - def file_request_details(self, val): - if val is None: - del self.file_request_details - return - self._file_request_details_validator.validate_type_only(val) - self._file_request_details_value = val - self._file_request_details_present = True + @integration_name.setter + def integration_name(self, val): + val = self._integration_name_validator.validate(val) + self._integration_name_value = val + self._integration_name_present = True - @file_request_details.deleter - def file_request_details(self): - self._file_request_details_value = None - self._file_request_details_present = False + @integration_name.deleter + def integration_name(self): + self._integration_name_value = None + self._integration_name_present = False - @property - def submitted_file_names(self): - """ - Submitted file names. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(IntegrationConnectedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: list of [str] - """ - if self._submitted_file_names_present: - return self._submitted_file_names_value - else: - raise AttributeError("missing required field 'submitted_file_names'") + def __repr__(self): + return 'IntegrationConnectedDetails(integration_name={!r})'.format( + self._integration_name_value, + ) - @submitted_file_names.setter - def submitted_file_names(self, val): - val = self._submitted_file_names_validator.validate(val) - self._submitted_file_names_value = val - self._submitted_file_names_present = True +IntegrationConnectedDetails_validator = bv.Struct(IntegrationConnectedDetails) - @submitted_file_names.deleter - def submitted_file_names(self): - self._submitted_file_names_value = None - self._submitted_file_names_present = False +class IntegrationConnectedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def submitter_name(self): + def description(self): """ - The name as provided by the submitter. Might be missing due to - historical data gap. - :rtype: str """ - if self._submitter_name_present: - return self._submitter_name_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @submitter_name.setter - def submitter_name(self, val): - if val is None: - del self.submitter_name - return - val = self._submitter_name_validator.validate(val) - self._submitter_name_value = val - self._submitter_name_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @submitter_name.deleter - def submitter_name(self): - self._submitter_name_value = None - self._submitter_name_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(IntegrationConnectedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'IntegrationConnectedType(description={!r})'.format( + self._description_value, + ) + +IntegrationConnectedType_validator = bv.Struct(IntegrationConnectedType) + +class IntegrationDisconnectedDetails(bb.Struct): + """ + Disconnected integration for member. + + :ivar team_log.IntegrationDisconnectedDetails.integration_name: Name of the + third-party integration. + """ + + __slots__ = [ + '_integration_name_value', + '_integration_name_present', + ] + + _has_required_fields = True + + def __init__(self, + integration_name=None): + self._integration_name_value = None + self._integration_name_present = False + if integration_name is not None: + self.integration_name = integration_name @property - def submitter_email(self): + def integration_name(self): """ - The email as provided by the submitter. Might be missing due to - historical data gap. + Name of the third-party integration. :rtype: str """ - if self._submitter_email_present: - return self._submitter_email_value + if self._integration_name_present: + return self._integration_name_value else: - return None + raise AttributeError("missing required field 'integration_name'") - @submitter_email.setter - def submitter_email(self, val): - if val is None: - del self.submitter_email - return - val = self._submitter_email_validator.validate(val) - self._submitter_email_value = val - self._submitter_email_present = True + @integration_name.setter + def integration_name(self, val): + val = self._integration_name_validator.validate(val) + self._integration_name_value = val + self._integration_name_present = True - @submitter_email.deleter - def submitter_email(self): - self._submitter_email_value = None - self._submitter_email_present = False + @integration_name.deleter + def integration_name(self): + self._integration_name_value = None + self._integration_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestReceiveFileDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(IntegrationDisconnectedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestReceiveFileDetails(submitted_file_names={!r}, file_request_id={!r}, file_request_details={!r}, submitter_name={!r}, submitter_email={!r})'.format( - self._submitted_file_names_value, - self._file_request_id_value, - self._file_request_details_value, - self._submitter_name_value, - self._submitter_email_value, + return 'IntegrationDisconnectedDetails(integration_name={!r})'.format( + self._integration_name_value, ) -FileRequestReceiveFileDetails_validator = bv.Struct(FileRequestReceiveFileDetails) +IntegrationDisconnectedDetails_validator = bv.Struct(IntegrationDisconnectedDetails) -class FileRequestReceiveFileType(bb.Struct): +class IntegrationDisconnectedType(bb.Struct): __slots__ = [ '_description_value', @@ -32763,26 +51976,80 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestReceiveFileType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(IntegrationDisconnectedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestReceiveFileType(description={!r})'.format( + return 'IntegrationDisconnectedType(description={!r})'.format( self._description_value, ) -FileRequestReceiveFileType_validator = bv.Struct(FileRequestReceiveFileType) +IntegrationDisconnectedType_validator = bv.Struct(IntegrationDisconnectedType) -class FileRequestsChangePolicyDetails(bb.Struct): +class IntegrationPolicy(bb.Union): """ - Enabled/disabled file requests. + Policy for controlling whether a service integration is enabled for the + team. - :ivar team_log.FileRequestsChangePolicyDetails.new_value: New file requests + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(IntegrationPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'IntegrationPolicy(%r, %r)' % (self._tag, self._value) + +IntegrationPolicy_validator = bv.Union(IntegrationPolicy) + +class IntegrationPolicyChangedDetails(bb.Struct): + """ + Changed integration policy for team. + + :ivar team_log.IntegrationPolicyChangedDetails.integration_name: Name of the + third-party integration. + :ivar team_log.IntegrationPolicyChangedDetails.new_value: New integration policy. - :ivar team_log.FileRequestsChangePolicyDetails.previous_value: Previous file - requests policy. Might be missing due to historical data gap. + :ivar team_log.IntegrationPolicyChangedDetails.previous_value: Previous + integration policy. """ __slots__ = [ + '_integration_name_value', + '_integration_name_present', '_new_value_value', '_new_value_present', '_previous_value_value', @@ -32792,23 +52059,51 @@ class FileRequestsChangePolicyDetails(bb.Struct): _has_required_fields = True def __init__(self, + integration_name=None, new_value=None, previous_value=None): + self._integration_name_value = None + self._integration_name_present = False self._new_value_value = None self._new_value_present = False self._previous_value_value = None self._previous_value_present = False + if integration_name is not None: + self.integration_name = integration_name if new_value is not None: self.new_value = new_value if previous_value is not None: self.previous_value = previous_value + @property + def integration_name(self): + """ + Name of the third-party integration. + + :rtype: str + """ + if self._integration_name_present: + return self._integration_name_value + else: + raise AttributeError("missing required field 'integration_name'") + + @integration_name.setter + def integration_name(self, val): + val = self._integration_name_validator.validate(val) + self._integration_name_value = val + self._integration_name_present = True + + @integration_name.deleter + def integration_name(self): + self._integration_name_value = None + self._integration_name_present = False + @property def new_value(self): """ - New file requests policy. + New integration policy. - :rtype: FileRequestsPolicy + :rtype: IntegrationPolicy """ if self._new_value_present: return self._new_value_value @@ -32829,21 +52124,17 @@ def new_value(self): @property def previous_value(self): """ - Previous file requests policy. Might be missing due to historical data - gap. + Previous integration policy. - :rtype: FileRequestsPolicy + :rtype: IntegrationPolicy """ if self._previous_value_present: return self._previous_value_value else: - return None + raise AttributeError("missing required field 'previous_value'") @previous_value.setter def previous_value(self, val): - if val is None: - del self.previous_value - return self._previous_value_validator.validate_type_only(val) self._previous_value_value = val self._previous_value_present = True @@ -32854,17 +52145,18 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(IntegrationPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'IntegrationPolicyChangedDetails(integration_name={!r}, new_value={!r}, previous_value={!r})'.format( + self._integration_name_value, self._new_value_value, self._previous_value_value, ) -FileRequestsChangePolicyDetails_validator = bv.Struct(FileRequestsChangePolicyDetails) +IntegrationPolicyChangedDetails_validator = bv.Struct(IntegrationPolicyChangedDetails) -class FileRequestsChangePolicyType(bb.Struct): +class IntegrationPolicyChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -32902,565 +52194,913 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(IntegrationPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestsChangePolicyType(description={!r})'.format( + return 'IntegrationPolicyChangedType(description={!r})'.format( self._description_value, ) -FileRequestsChangePolicyType_validator = bv.Struct(FileRequestsChangePolicyType) +IntegrationPolicyChangedType_validator = bv.Struct(IntegrationPolicyChangedType) -class FileRequestsEmailsEnabledDetails(bb.Struct): +class InviteMethod(bb.Union): """ - Enabled file request emails for everyone. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + invite_link = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = False + def is_invite_link(self): + """ + Check if the union tag is ``invite_link``. - def __init__(self): - pass + :rtype: bool + """ + return self._tag == 'invite_link' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestsEmailsEnabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(InviteMethod, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRequestsEmailsEnabledDetails()' + return 'InviteMethod(%r, %r)' % (self._tag, self._value) -FileRequestsEmailsEnabledDetails_validator = bv.Struct(FileRequestsEmailsEnabledDetails) +InviteMethod_validator = bv.Union(InviteMethod) -class FileRequestsEmailsEnabledType(bb.Struct): +class JoinTeamDetails(bb.Struct): + """ + Additional information relevant when a new member joins the team. + + :ivar team_log.JoinTeamDetails.linked_apps: Linked applications. + (Deprecated) Please use has_linked_apps boolean field instead. + :ivar team_log.JoinTeamDetails.linked_devices: Linked devices. (Deprecated) + Please use has_linked_devices boolean field instead. + :ivar team_log.JoinTeamDetails.linked_shared_folders: Linked shared folders. + (Deprecated) Please use has_linked_shared_folders boolean field instead. + :ivar team_log.JoinTeamDetails.was_linked_apps_truncated: (Deprecated) True + if the linked_apps list was truncated to the maximum supported length + (50). + :ivar team_log.JoinTeamDetails.was_linked_devices_truncated: (Deprecated) + True if the linked_devices list was truncated to the maximum supported + length (50). + :ivar team_log.JoinTeamDetails.was_linked_shared_folders_truncated: + (Deprecated) True if the linked_shared_folders list was truncated to the + maximum supported length (50). + :ivar team_log.JoinTeamDetails.has_linked_apps: True if the user had linked + apps at event time. + :ivar team_log.JoinTeamDetails.has_linked_devices: True if the user had + linked apps at event time. + :ivar team_log.JoinTeamDetails.has_linked_shared_folders: True if the user + had linked shared folders at event time. + """ __slots__ = [ - '_description_value', - '_description_present', + '_linked_apps_value', + '_linked_apps_present', + '_linked_devices_value', + '_linked_devices_present', + '_linked_shared_folders_value', + '_linked_shared_folders_present', + '_was_linked_apps_truncated_value', + '_was_linked_apps_truncated_present', + '_was_linked_devices_truncated_value', + '_was_linked_devices_truncated_present', + '_was_linked_shared_folders_truncated_value', + '_was_linked_shared_folders_truncated_present', + '_has_linked_apps_value', + '_has_linked_apps_present', + '_has_linked_devices_value', + '_has_linked_devices_present', + '_has_linked_shared_folders_value', + '_has_linked_shared_folders_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + linked_apps=None, + linked_devices=None, + linked_shared_folders=None, + was_linked_apps_truncated=None, + was_linked_devices_truncated=None, + was_linked_shared_folders_truncated=None, + has_linked_apps=None, + has_linked_devices=None, + has_linked_shared_folders=None): + self._linked_apps_value = None + self._linked_apps_present = False + self._linked_devices_value = None + self._linked_devices_present = False + self._linked_shared_folders_value = None + self._linked_shared_folders_present = False + self._was_linked_apps_truncated_value = None + self._was_linked_apps_truncated_present = False + self._was_linked_devices_truncated_value = None + self._was_linked_devices_truncated_present = False + self._was_linked_shared_folders_truncated_value = None + self._was_linked_shared_folders_truncated_present = False + self._has_linked_apps_value = None + self._has_linked_apps_present = False + self._has_linked_devices_value = None + self._has_linked_devices_present = False + self._has_linked_shared_folders_value = None + self._has_linked_shared_folders_present = False + if linked_apps is not None: + self.linked_apps = linked_apps + if linked_devices is not None: + self.linked_devices = linked_devices + if linked_shared_folders is not None: + self.linked_shared_folders = linked_shared_folders + if was_linked_apps_truncated is not None: + self.was_linked_apps_truncated = was_linked_apps_truncated + if was_linked_devices_truncated is not None: + self.was_linked_devices_truncated = was_linked_devices_truncated + if was_linked_shared_folders_truncated is not None: + self.was_linked_shared_folders_truncated = was_linked_shared_folders_truncated + if has_linked_apps is not None: + self.has_linked_apps = has_linked_apps + if has_linked_devices is not None: + self.has_linked_devices = has_linked_devices + if has_linked_shared_folders is not None: + self.has_linked_shared_folders = has_linked_shared_folders @property - def description(self): + def linked_apps(self): """ - :rtype: str + Linked applications. (Deprecated) Please use has_linked_apps boolean + field instead. + + :rtype: list of [UserLinkedAppLogInfo] """ - if self._description_present: - return self._description_value + if self._linked_apps_present: + return self._linked_apps_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestsEmailsEnabledType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FileRequestsEmailsEnabledType(description={!r})'.format( - self._description_value, - ) - -FileRequestsEmailsEnabledType_validator = bv.Struct(FileRequestsEmailsEnabledType) - -class FileRequestsEmailsRestrictedToTeamOnlyDetails(bb.Struct): - """ - Enabled file request emails for team. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestsEmailsRestrictedToTeamOnlyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + raise AttributeError("missing required field 'linked_apps'") - def __repr__(self): - return 'FileRequestsEmailsRestrictedToTeamOnlyDetails()' + @linked_apps.setter + def linked_apps(self, val): + val = self._linked_apps_validator.validate(val) + self._linked_apps_value = val + self._linked_apps_present = True -FileRequestsEmailsRestrictedToTeamOnlyDetails_validator = bv.Struct(FileRequestsEmailsRestrictedToTeamOnlyDetails) + @linked_apps.deleter + def linked_apps(self): + self._linked_apps_value = None + self._linked_apps_present = False -class FileRequestsEmailsRestrictedToTeamOnlyType(bb.Struct): + @property + def linked_devices(self): + """ + Linked devices. (Deprecated) Please use has_linked_devices boolean field + instead. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: list of [LinkedDeviceLogInfo] + """ + if self._linked_devices_present: + return self._linked_devices_value + else: + raise AttributeError("missing required field 'linked_devices'") - _has_required_fields = True + @linked_devices.setter + def linked_devices(self, val): + val = self._linked_devices_validator.validate(val) + self._linked_devices_value = val + self._linked_devices_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @linked_devices.deleter + def linked_devices(self): + self._linked_devices_value = None + self._linked_devices_present = False @property - def description(self): + def linked_shared_folders(self): """ - :rtype: str + Linked shared folders. (Deprecated) Please use has_linked_shared_folders + boolean field instead. + + :rtype: list of [FolderLogInfo] """ - if self._description_present: - return self._description_value + if self._linked_shared_folders_present: + return self._linked_shared_folders_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + raise AttributeError("missing required field 'linked_shared_folders'") - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestsEmailsRestrictedToTeamOnlyType, self)._process_custom_annotations(annotation_type, field_path, processor) + @linked_shared_folders.setter + def linked_shared_folders(self, val): + val = self._linked_shared_folders_validator.validate(val) + self._linked_shared_folders_value = val + self._linked_shared_folders_present = True - def __repr__(self): - return 'FileRequestsEmailsRestrictedToTeamOnlyType(description={!r})'.format( - self._description_value, - ) + @linked_shared_folders.deleter + def linked_shared_folders(self): + self._linked_shared_folders_value = None + self._linked_shared_folders_present = False -FileRequestsEmailsRestrictedToTeamOnlyType_validator = bv.Struct(FileRequestsEmailsRestrictedToTeamOnlyType) + @property + def was_linked_apps_truncated(self): + """ + (Deprecated) True if the linked_apps list was truncated to the maximum + supported length (50). -class FileRequestsPolicy(bb.Union): - """ - File requests policy + :rtype: bool + """ + if self._was_linked_apps_truncated_present: + return self._was_linked_apps_truncated_value + else: + return None - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ + @was_linked_apps_truncated.setter + def was_linked_apps_truncated(self, val): + if val is None: + del self.was_linked_apps_truncated + return + val = self._was_linked_apps_truncated_validator.validate(val) + self._was_linked_apps_truncated_value = val + self._was_linked_apps_truncated_present = True - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None + @was_linked_apps_truncated.deleter + def was_linked_apps_truncated(self): + self._was_linked_apps_truncated_value = None + self._was_linked_apps_truncated_present = False - def is_disabled(self): + @property + def was_linked_devices_truncated(self): """ - Check if the union tag is ``disabled``. + (Deprecated) True if the linked_devices list was truncated to the + maximum supported length (50). :rtype: bool """ - return self._tag == 'disabled' + if self._was_linked_devices_truncated_present: + return self._was_linked_devices_truncated_value + else: + return None - def is_enabled(self): + @was_linked_devices_truncated.setter + def was_linked_devices_truncated(self, val): + if val is None: + del self.was_linked_devices_truncated + return + val = self._was_linked_devices_truncated_validator.validate(val) + self._was_linked_devices_truncated_value = val + self._was_linked_devices_truncated_present = True + + @was_linked_devices_truncated.deleter + def was_linked_devices_truncated(self): + self._was_linked_devices_truncated_value = None + self._was_linked_devices_truncated_present = False + + @property + def was_linked_shared_folders_truncated(self): """ - Check if the union tag is ``enabled``. + (Deprecated) True if the linked_shared_folders list was truncated to the + maximum supported length (50). :rtype: bool """ - return self._tag == 'enabled' + if self._was_linked_shared_folders_truncated_present: + return self._was_linked_shared_folders_truncated_value + else: + return None - def is_other(self): + @was_linked_shared_folders_truncated.setter + def was_linked_shared_folders_truncated(self, val): + if val is None: + del self.was_linked_shared_folders_truncated + return + val = self._was_linked_shared_folders_truncated_validator.validate(val) + self._was_linked_shared_folders_truncated_value = val + self._was_linked_shared_folders_truncated_present = True + + @was_linked_shared_folders_truncated.deleter + def was_linked_shared_folders_truncated(self): + self._was_linked_shared_folders_truncated_value = None + self._was_linked_shared_folders_truncated_present = False + + @property + def has_linked_apps(self): """ - Check if the union tag is ``other``. + True if the user had linked apps at event time. :rtype: bool """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRequestsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FileRequestsPolicy(%r, %r)' % (self._tag, self._value) + if self._has_linked_apps_present: + return self._has_linked_apps_value + else: + return None -FileRequestsPolicy_validator = bv.Union(FileRequestsPolicy) + @has_linked_apps.setter + def has_linked_apps(self, val): + if val is None: + del self.has_linked_apps + return + val = self._has_linked_apps_validator.validate(val) + self._has_linked_apps_value = val + self._has_linked_apps_present = True -class FileResolveCommentDetails(bb.Struct): - """ - Resolved file comment. + @has_linked_apps.deleter + def has_linked_apps(self): + self._has_linked_apps_value = None + self._has_linked_apps_present = False - :ivar team_log.FileResolveCommentDetails.comment_text: Comment text. Might - be missing due to historical data gap. - """ + @property + def has_linked_devices(self): + """ + True if the user had linked apps at event time. - __slots__ = [ - '_comment_text_value', - '_comment_text_present', - ] + :rtype: bool + """ + if self._has_linked_devices_present: + return self._has_linked_devices_value + else: + return None - _has_required_fields = False + @has_linked_devices.setter + def has_linked_devices(self, val): + if val is None: + del self.has_linked_devices + return + val = self._has_linked_devices_validator.validate(val) + self._has_linked_devices_value = val + self._has_linked_devices_present = True - def __init__(self, - comment_text=None): - self._comment_text_value = None - self._comment_text_present = False - if comment_text is not None: - self.comment_text = comment_text + @has_linked_devices.deleter + def has_linked_devices(self): + self._has_linked_devices_value = None + self._has_linked_devices_present = False @property - def comment_text(self): + def has_linked_shared_folders(self): """ - Comment text. Might be missing due to historical data gap. + True if the user had linked shared folders at event time. - :rtype: str + :rtype: bool """ - if self._comment_text_present: - return self._comment_text_value + if self._has_linked_shared_folders_present: + return self._has_linked_shared_folders_value else: return None - @comment_text.setter - def comment_text(self, val): + @has_linked_shared_folders.setter + def has_linked_shared_folders(self, val): if val is None: - del self.comment_text + del self.has_linked_shared_folders return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + val = self._has_linked_shared_folders_validator.validate(val) + self._has_linked_shared_folders_value = val + self._has_linked_shared_folders_present = True - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + @has_linked_shared_folders.deleter + def has_linked_shared_folders(self): + self._has_linked_shared_folders_value = None + self._has_linked_shared_folders_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileResolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(JoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileResolveCommentDetails(comment_text={!r})'.format( - self._comment_text_value, + return 'JoinTeamDetails(linked_apps={!r}, linked_devices={!r}, linked_shared_folders={!r}, was_linked_apps_truncated={!r}, was_linked_devices_truncated={!r}, was_linked_shared_folders_truncated={!r}, has_linked_apps={!r}, has_linked_devices={!r}, has_linked_shared_folders={!r})'.format( + self._linked_apps_value, + self._linked_devices_value, + self._linked_shared_folders_value, + self._was_linked_apps_truncated_value, + self._was_linked_devices_truncated_value, + self._was_linked_shared_folders_truncated_value, + self._has_linked_apps_value, + self._has_linked_devices_value, + self._has_linked_shared_folders_value, ) -FileResolveCommentDetails_validator = bv.Struct(FileResolveCommentDetails) +JoinTeamDetails_validator = bv.Struct(JoinTeamDetails) -class FileResolveCommentType(bb.Struct): +class LegacyDeviceSessionLogInfo(DeviceSessionLogInfo): + """ + Information on sessions, in legacy format + + :ivar team_log.LegacyDeviceSessionLogInfo.session_info: Session unique id. + Might be missing due to historical data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.display_name: The device name. + Might be missing due to historical data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.is_emm_managed: Is device managed + by emm. Might be missing due to historical data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.platform: Information on the + hosting platform. Might be missing due to historical data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.mac_address: The mac address of + the last activity from this session. Might be missing due to historical + data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.os_version: The hosting OS + version. Might be missing due to historical data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.device_type: Information on the + hosting device type. Might be missing due to historical data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.client_version: The Dropbox client + version. Might be missing due to historical data gap. + :ivar team_log.LegacyDeviceSessionLogInfo.legacy_uniq_id: Alternative unique + device session id, instead of session id field. Might be missing due to + historical data gap. + """ __slots__ = [ - '_description_value', - '_description_present', + '_session_info_value', + '_session_info_present', + '_display_name_value', + '_display_name_present', + '_is_emm_managed_value', + '_is_emm_managed_present', + '_platform_value', + '_platform_present', + '_mac_address_value', + '_mac_address_present', + '_os_version_value', + '_os_version_present', + '_device_type_value', + '_device_type_present', + '_client_version_value', + '_client_version_present', + '_legacy_uniq_id_value', + '_legacy_uniq_id_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + ip_address=None, + created=None, + updated=None, + session_info=None, + display_name=None, + is_emm_managed=None, + platform=None, + mac_address=None, + os_version=None, + device_type=None, + client_version=None, + legacy_uniq_id=None): + super(LegacyDeviceSessionLogInfo, self).__init__(ip_address, + created, + updated) + self._session_info_value = None + self._session_info_present = False + self._display_name_value = None + self._display_name_present = False + self._is_emm_managed_value = None + self._is_emm_managed_present = False + self._platform_value = None + self._platform_present = False + self._mac_address_value = None + self._mac_address_present = False + self._os_version_value = None + self._os_version_present = False + self._device_type_value = None + self._device_type_present = False + self._client_version_value = None + self._client_version_present = False + self._legacy_uniq_id_value = None + self._legacy_uniq_id_present = False + if session_info is not None: + self.session_info = session_info + if display_name is not None: + self.display_name = display_name + if is_emm_managed is not None: + self.is_emm_managed = is_emm_managed + if platform is not None: + self.platform = platform + if mac_address is not None: + self.mac_address = mac_address + if os_version is not None: + self.os_version = os_version + if device_type is not None: + self.device_type = device_type + if client_version is not None: + self.client_version = client_version + if legacy_uniq_id is not None: + self.legacy_uniq_id = legacy_uniq_id @property - def description(self): + def session_info(self): """ - :rtype: str + Session unique id. Might be missing due to historical data gap. + + :rtype: SessionLogInfo """ - if self._description_present: - return self._description_value + if self._session_info_present: + return self._session_info_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + return None - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileResolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + @session_info.setter + def session_info(self, val): + if val is None: + del self.session_info + return + self._session_info_validator.validate_type_only(val) + self._session_info_value = val + self._session_info_present = True - def __repr__(self): - return 'FileResolveCommentType(description={!r})'.format( - self._description_value, - ) + @session_info.deleter + def session_info(self): + self._session_info_value = None + self._session_info_present = False -FileResolveCommentType_validator = bv.Struct(FileResolveCommentType) + @property + def display_name(self): + """ + The device name. Might be missing due to historical data gap. -class FileRestoreDetails(bb.Struct): - """ - Restored deleted files and/or folders. - """ + :rtype: str + """ + if self._display_name_present: + return self._display_name_value + else: + return None - __slots__ = [ - ] + @display_name.setter + def display_name(self, val): + if val is None: + del self.display_name + return + val = self._display_name_validator.validate(val) + self._display_name_value = val + self._display_name_present = True - _has_required_fields = False + @display_name.deleter + def display_name(self): + self._display_name_value = None + self._display_name_present = False - def __init__(self): - pass + @property + def is_emm_managed(self): + """ + Is device managed by emm. Might be missing due to historical data gap. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRestoreDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: bool + """ + if self._is_emm_managed_present: + return self._is_emm_managed_value + else: + return None - def __repr__(self): - return 'FileRestoreDetails()' + @is_emm_managed.setter + def is_emm_managed(self, val): + if val is None: + del self.is_emm_managed + return + val = self._is_emm_managed_validator.validate(val) + self._is_emm_managed_value = val + self._is_emm_managed_present = True -FileRestoreDetails_validator = bv.Struct(FileRestoreDetails) + @is_emm_managed.deleter + def is_emm_managed(self): + self._is_emm_managed_value = None + self._is_emm_managed_present = False -class FileRestoreType(bb.Struct): + @property + def platform(self): + """ + Information on the hosting platform. Might be missing due to historical + data gap. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: str + """ + if self._platform_present: + return self._platform_value + else: + return None - _has_required_fields = True + @platform.setter + def platform(self, val): + if val is None: + del self.platform + return + val = self._platform_validator.validate(val) + self._platform_value = val + self._platform_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @platform.deleter + def platform(self): + self._platform_value = None + self._platform_present = False @property - def description(self): + def mac_address(self): """ + The mac address of the last activity from this session. Might be missing + due to historical data gap. + :rtype: str """ - if self._description_present: - return self._description_value + if self._mac_address_present: + return self._mac_address_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + return None - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRestoreType, self)._process_custom_annotations(annotation_type, field_path, processor) + @mac_address.setter + def mac_address(self, val): + if val is None: + del self.mac_address + return + val = self._mac_address_validator.validate(val) + self._mac_address_value = val + self._mac_address_present = True - def __repr__(self): - return 'FileRestoreType(description={!r})'.format( - self._description_value, - ) + @mac_address.deleter + def mac_address(self): + self._mac_address_value = None + self._mac_address_present = False -FileRestoreType_validator = bv.Struct(FileRestoreType) + @property + def os_version(self): + """ + The hosting OS version. Might be missing due to historical data gap. -class FileRevertDetails(bb.Struct): - """ - Reverted files to previous version. - """ + :rtype: str + """ + if self._os_version_present: + return self._os_version_value + else: + return None - __slots__ = [ - ] + @os_version.setter + def os_version(self, val): + if val is None: + del self.os_version + return + val = self._os_version_validator.validate(val) + self._os_version_value = val + self._os_version_present = True - _has_required_fields = False + @os_version.deleter + def os_version(self): + self._os_version_value = None + self._os_version_present = False - def __init__(self): - pass + @property + def device_type(self): + """ + Information on the hosting device type. Might be missing due to + historical data gap. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRevertDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: str + """ + if self._device_type_present: + return self._device_type_value + else: + return None - def __repr__(self): - return 'FileRevertDetails()' + @device_type.setter + def device_type(self, val): + if val is None: + del self.device_type + return + val = self._device_type_validator.validate(val) + self._device_type_value = val + self._device_type_present = True -FileRevertDetails_validator = bv.Struct(FileRevertDetails) + @device_type.deleter + def device_type(self): + self._device_type_value = None + self._device_type_present = False -class FileRevertType(bb.Struct): + @property + def client_version(self): + """ + The Dropbox client version. Might be missing due to historical data gap. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: str + """ + if self._client_version_present: + return self._client_version_value + else: + return None - _has_required_fields = True + @client_version.setter + def client_version(self, val): + if val is None: + del self.client_version + return + val = self._client_version_validator.validate(val) + self._client_version_value = val + self._client_version_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @client_version.deleter + def client_version(self): + self._client_version_value = None + self._client_version_present = False @property - def description(self): + def legacy_uniq_id(self): """ + Alternative unique device session id, instead of session id field. Might + be missing due to historical data gap. + :rtype: str """ - if self._description_present: - return self._description_value + if self._legacy_uniq_id_present: + return self._legacy_uniq_id_value else: - raise AttributeError("missing required field 'description'") + return None - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @legacy_uniq_id.setter + def legacy_uniq_id(self, val): + if val is None: + del self.legacy_uniq_id + return + val = self._legacy_uniq_id_validator.validate(val) + self._legacy_uniq_id_value = val + self._legacy_uniq_id_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @legacy_uniq_id.deleter + def legacy_uniq_id(self): + self._legacy_uniq_id_value = None + self._legacy_uniq_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRevertType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegacyDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileRevertType(description={!r})'.format( - self._description_value, + return 'LegacyDeviceSessionLogInfo(ip_address={!r}, created={!r}, updated={!r}, session_info={!r}, display_name={!r}, is_emm_managed={!r}, platform={!r}, mac_address={!r}, os_version={!r}, device_type={!r}, client_version={!r}, legacy_uniq_id={!r})'.format( + self._ip_address_value, + self._created_value, + self._updated_value, + self._session_info_value, + self._display_name_value, + self._is_emm_managed_value, + self._platform_value, + self._mac_address_value, + self._os_version_value, + self._device_type_value, + self._client_version_value, + self._legacy_uniq_id_value, ) -FileRevertType_validator = bv.Struct(FileRevertType) +LegacyDeviceSessionLogInfo_validator = bv.Struct(LegacyDeviceSessionLogInfo) -class FileRollbackChangesDetails(bb.Struct): - """ - Rolled back file actions. +class LegalHoldsActivateAHoldDetails(bb.Struct): """ + Activated a hold. - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRollbackChangesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FileRollbackChangesDetails()' - -FileRollbackChangesDetails_validator = bv.Struct(FileRollbackChangesDetails) - -class FileRollbackChangesType(bb.Struct): + :ivar team_log.LegalHoldsActivateAHoldDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsActivateAHoldDetails.name: Hold name. + :ivar team_log.LegalHoldsActivateAHoldDetails.start_date: Hold start date. + :ivar team_log.LegalHoldsActivateAHoldDetails.end_date: Hold end date. + """ __slots__ = [ - '_description_value', - '_description_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + legal_hold_id=None, + name=None, + start_date=None, + end_date=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date @property - def description(self): + def legal_hold_id(self): """ + Hold ID. + :rtype: str """ - if self._description_present: - return self._description_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'legal_hold_id'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileRollbackChangesType, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def name(self): + """ + Hold name. - def __repr__(self): - return 'FileRollbackChangesType(description={!r})'.format( - self._description_value, - ) + :rtype: str + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") -FileRollbackChangesType_validator = bv.Struct(FileRollbackChangesType) + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True -class FileSaveCopyReferenceDetails(bb.Struct): - """ - Saved file/folder using copy reference. + @name.deleter + def name(self): + self._name_value = None + self._name_present = False - :ivar team_log.FileSaveCopyReferenceDetails.relocate_action_details: - Relocate action details. - """ + @property + def start_date(self): + """ + Hold start date. - __slots__ = [ - '_relocate_action_details_value', - '_relocate_action_details_present', - ] + :rtype: datetime.datetime + """ + if self._start_date_present: + return self._start_date_value + else: + raise AttributeError("missing required field 'start_date'") - _has_required_fields = True + @start_date.setter + def start_date(self, val): + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True - def __init__(self, - relocate_action_details=None): - self._relocate_action_details_value = None - self._relocate_action_details_present = False - if relocate_action_details is not None: - self.relocate_action_details = relocate_action_details + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False @property - def relocate_action_details(self): + def end_date(self): """ - Relocate action details. + Hold end date. - :rtype: list of [RelocateAssetReferencesLogInfo] + :rtype: datetime.datetime """ - if self._relocate_action_details_present: - return self._relocate_action_details_value + if self._end_date_present: + return self._end_date_value else: - raise AttributeError("missing required field 'relocate_action_details'") + return None - @relocate_action_details.setter - def relocate_action_details(self, val): - val = self._relocate_action_details_validator.validate(val) - self._relocate_action_details_value = val - self._relocate_action_details_present = True + @end_date.setter + def end_date(self, val): + if val is None: + del self.end_date + return + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True - @relocate_action_details.deleter - def relocate_action_details(self): - self._relocate_action_details_value = None - self._relocate_action_details_present = False + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileSaveCopyReferenceDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsActivateAHoldDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileSaveCopyReferenceDetails(relocate_action_details={!r})'.format( - self._relocate_action_details_value, + return 'LegalHoldsActivateAHoldDetails(legal_hold_id={!r}, name={!r}, start_date={!r}, end_date={!r})'.format( + self._legal_hold_id_value, + self._name_value, + self._start_date_value, + self._end_date_value, ) -FileSaveCopyReferenceDetails_validator = bv.Struct(FileSaveCopyReferenceDetails) +LegalHoldsActivateAHoldDetails_validator = bv.Struct(LegalHoldsActivateAHoldDetails) -class FileSaveCopyReferenceType(bb.Struct): +class LegalHoldsActivateAHoldType(bb.Struct): __slots__ = [ '_description_value', @@ -33498,74 +53138,102 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileSaveCopyReferenceType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsActivateAHoldType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileSaveCopyReferenceType(description={!r})'.format( + return 'LegalHoldsActivateAHoldType(description={!r})'.format( self._description_value, ) -FileSaveCopyReferenceType_validator = bv.Struct(FileSaveCopyReferenceType) +LegalHoldsActivateAHoldType_validator = bv.Struct(LegalHoldsActivateAHoldType) -class FileUnlikeCommentDetails(bb.Struct): +class LegalHoldsAddMembersDetails(bb.Struct): """ - Unliked file comment. + Added members to a hold. - :ivar team_log.FileUnlikeCommentDetails.comment_text: Comment text. Might be - missing due to historical data gap. + :ivar team_log.LegalHoldsAddMembersDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsAddMembersDetails.name: Hold name. """ __slots__ = [ - '_comment_text_value', - '_comment_text_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - comment_text=None): - self._comment_text_value = None - self._comment_text_present = False - if comment_text is not None: - self.comment_text = comment_text + legal_hold_id=None, + name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name @property - def comment_text(self): + def legal_hold_id(self): """ - Comment text. Might be missing due to historical data gap. + Hold ID. :rtype: str """ - if self._comment_text_present: - return self._comment_text_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - return None + raise AttributeError("missing required field 'legal_hold_id'") - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + + @property + def name(self): + """ + Hold name. + + :rtype: str + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") + + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileUnlikeCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsAddMembersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileUnlikeCommentDetails(comment_text={!r})'.format( - self._comment_text_value, + return 'LegalHoldsAddMembersDetails(legal_hold_id={!r}, name={!r})'.format( + self._legal_hold_id_value, + self._name_value, ) -FileUnlikeCommentDetails_validator = bv.Struct(FileUnlikeCommentDetails) +LegalHoldsAddMembersDetails_validator = bv.Struct(LegalHoldsAddMembersDetails) -class FileUnlikeCommentType(bb.Struct): +class LegalHoldsAddMembersType(bb.Struct): __slots__ = [ '_description_value', @@ -33603,74 +53271,167 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileUnlikeCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsAddMembersType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileUnlikeCommentType(description={!r})'.format( + return 'LegalHoldsAddMembersType(description={!r})'.format( self._description_value, ) -FileUnlikeCommentType_validator = bv.Struct(FileUnlikeCommentType) +LegalHoldsAddMembersType_validator = bv.Struct(LegalHoldsAddMembersType) -class FileUnresolveCommentDetails(bb.Struct): +class LegalHoldsChangeHoldDetailsDetails(bb.Struct): """ - Unresolved file comment. + Edited details for a hold. - :ivar team_log.FileUnresolveCommentDetails.comment_text: Comment text. Might - be missing due to historical data gap. + :ivar team_log.LegalHoldsChangeHoldDetailsDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsChangeHoldDetailsDetails.name: Hold name. + :ivar team_log.LegalHoldsChangeHoldDetailsDetails.previous_value: Previous + details. + :ivar team_log.LegalHoldsChangeHoldDetailsDetails.new_value: New details. """ __slots__ = [ - '_comment_text_value', - '_comment_text_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - comment_text=None): - self._comment_text_value = None - self._comment_text_present = False - if comment_text is not None: - self.comment_text = comment_text + legal_hold_id=None, + name=None, + previous_value=None, + new_value=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def comment_text(self): + def legal_hold_id(self): """ - Comment text. Might be missing due to historical data gap. + Hold ID. :rtype: str """ - if self._comment_text_present: - return self._comment_text_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - return None + raise AttributeError("missing required field 'legal_hold_id'") - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + + @property + def name(self): + """ + Hold name. + + :rtype: str + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") + + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False + + @property + def previous_value(self): + """ + Previous details. + + :rtype: str + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + @property + def new_value(self): + """ + New details. + + :rtype: str + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileUnresolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsChangeHoldDetailsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileUnresolveCommentDetails(comment_text={!r})'.format( - self._comment_text_value, + return 'LegalHoldsChangeHoldDetailsDetails(legal_hold_id={!r}, name={!r}, previous_value={!r}, new_value={!r})'.format( + self._legal_hold_id_value, + self._name_value, + self._previous_value_value, + self._new_value_value, ) -FileUnresolveCommentDetails_validator = bv.Struct(FileUnresolveCommentDetails) +LegalHoldsChangeHoldDetailsDetails_validator = bv.Struct(LegalHoldsChangeHoldDetailsDetails) -class FileUnresolveCommentType(bb.Struct): +class LegalHoldsChangeHoldDetailsType(bb.Struct): __slots__ = [ '_description_value', @@ -33708,803 +53469,703 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FileUnresolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsChangeHoldDetailsType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'FileUnresolveCommentType(description={!r})'.format( + return 'LegalHoldsChangeHoldDetailsType(description={!r})'.format( self._description_value, ) -FileUnresolveCommentType_validator = bv.Struct(FileUnresolveCommentType) - -class FolderLogInfo(FileOrFolderLogInfo): - """ - Folder's logged information. - """ - - __slots__ = [ - ] - - _has_required_fields = True - - def __init__(self, - path=None, - display_name=None, - file_id=None): - super(FolderLogInfo, self).__init__(path, - display_name, - file_id) - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(FolderLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'FolderLogInfo(path={!r}, display_name={!r}, file_id={!r})'.format( - self._path_value, - self._display_name_value, - self._file_id_value, - ) - -FolderLogInfo_validator = bv.Struct(FolderLogInfo) +LegalHoldsChangeHoldDetailsType_validator = bv.Struct(LegalHoldsChangeHoldDetailsType) -class GeoLocationLogInfo(bb.Struct): +class LegalHoldsChangeHoldNameDetails(bb.Struct): """ - Geographic location details. + Renamed a hold. - :ivar team_log.GeoLocationLogInfo.city: City name. - :ivar team_log.GeoLocationLogInfo.region: Region name. - :ivar team_log.GeoLocationLogInfo.country: Country code. - :ivar team_log.GeoLocationLogInfo.ip_address: IP address. + :ivar team_log.LegalHoldsChangeHoldNameDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsChangeHoldNameDetails.previous_value: Previous + Name. + :ivar team_log.LegalHoldsChangeHoldNameDetails.new_value: New Name. """ __slots__ = [ - '_city_value', - '_city_present', - '_region_value', - '_region_present', - '_country_value', - '_country_present', - '_ip_address_value', - '_ip_address_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', ] _has_required_fields = True def __init__(self, - ip_address=None, - city=None, - region=None, - country=None): - self._city_value = None - self._city_present = False - self._region_value = None - self._region_present = False - self._country_value = None - self._country_present = False - self._ip_address_value = None - self._ip_address_present = False - if city is not None: - self.city = city - if region is not None: - self.region = region - if country is not None: - self.country = country - if ip_address is not None: - self.ip_address = ip_address + legal_hold_id=None, + previous_value=None, + new_value=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def city(self): + def legal_hold_id(self): """ - City name. + Hold ID. :rtype: str """ - if self._city_present: - return self._city_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - return None + raise AttributeError("missing required field 'legal_hold_id'") - @city.setter - def city(self, val): - if val is None: - del self.city - return - val = self._city_validator.validate(val) - self._city_value = val - self._city_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @city.deleter - def city(self): - self._city_value = None - self._city_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False @property - def region(self): + def previous_value(self): """ - Region name. + Previous Name. :rtype: str """ - if self._region_present: - return self._region_value + if self._previous_value_present: + return self._previous_value_value else: - return None + raise AttributeError("missing required field 'previous_value'") - @region.setter - def region(self, val): - if val is None: - del self.region - return - val = self._region_validator.validate(val) - self._region_value = val - self._region_present = True + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - @region.deleter - def region(self): - self._region_value = None - self._region_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property - def country(self): + def new_value(self): """ - Country code. + New Name. :rtype: str """ - if self._country_present: - return self._country_value + if self._new_value_present: + return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") - @country.setter - def country(self, val): - if val is None: - del self.country - return - val = self._country_validator.validate(val) - self._country_value = val - self._country_present = True + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @country.deleter - def country(self): - self._country_value = None - self._country_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldsChangeHoldNameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LegalHoldsChangeHoldNameDetails(legal_hold_id={!r}, previous_value={!r}, new_value={!r})'.format( + self._legal_hold_id_value, + self._previous_value_value, + self._new_value_value, + ) + +LegalHoldsChangeHoldNameDetails_validator = bv.Struct(LegalHoldsChangeHoldNameDetails) + +class LegalHoldsChangeHoldNameType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def ip_address(self): + def description(self): """ - IP address. - :rtype: str """ - if self._ip_address_present: - return self._ip_address_value - else: - raise AttributeError("missing required field 'ip_address'") - - @ip_address.setter - def ip_address(self, val): - val = self._ip_address_validator.validate(val) - self._ip_address_value = val - self._ip_address_present = True + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @ip_address.deleter - def ip_address(self): - self._ip_address_value = None - self._ip_address_present = False + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GeoLocationLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsChangeHoldNameType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GeoLocationLogInfo(ip_address={!r}, city={!r}, region={!r}, country={!r})'.format( - self._ip_address_value, - self._city_value, - self._region_value, - self._country_value, + return 'LegalHoldsChangeHoldNameType(description={!r})'.format( + self._description_value, ) -GeoLocationLogInfo_validator = bv.Struct(GeoLocationLogInfo) +LegalHoldsChangeHoldNameType_validator = bv.Struct(LegalHoldsChangeHoldNameType) -class GetTeamEventsArg(bb.Struct): +class LegalHoldsExportAHoldDetails(bb.Struct): """ - :ivar team_log.GetTeamEventsArg.limit: The maximal number of results to - return per call. Note that some calls may not return ``limit`` number of - events, and may even return no events, even with `has_more` set to true. - In this case, callers should fetch again using - :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`. - :ivar team_log.GetTeamEventsArg.account_id: Filter the events by account ID. - Return ony events with this account_id as either Actor, Context, or - Participants. - :ivar team_log.GetTeamEventsArg.time: Filter by time range. - :ivar team_log.GetTeamEventsArg.category: Filter the returned events to a - single category. + Exported hold. + + :ivar team_log.LegalHoldsExportAHoldDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsExportAHoldDetails.name: Hold name. + :ivar team_log.LegalHoldsExportAHoldDetails.export_name: Export name. """ __slots__ = [ - '_limit_value', - '_limit_present', - '_account_id_value', - '_account_id_present', - '_time_value', - '_time_present', - '_category_value', - '_category_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', + '_export_name_value', + '_export_name_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - limit=None, - account_id=None, - time=None, - category=None): - self._limit_value = None - self._limit_present = False - self._account_id_value = None - self._account_id_present = False - self._time_value = None - self._time_present = False - self._category_value = None - self._category_present = False - if limit is not None: - self.limit = limit - if account_id is not None: - self.account_id = account_id - if time is not None: - self.time = time - if category is not None: - self.category = category - - @property - def limit(self): - """ - The maximal number of results to return per call. Note that some calls - may not return ``limit`` number of events, and may even return no - events, even with `has_more` set to true. In this case, callers should - fetch again using - :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`. - - :rtype: int - """ - if self._limit_present: - return self._limit_value - else: - return 1000 - - @limit.setter - def limit(self, val): - val = self._limit_validator.validate(val) - self._limit_value = val - self._limit_present = True - - @limit.deleter - def limit(self): - self._limit_value = None - self._limit_present = False + legal_hold_id=None, + name=None, + export_name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + self._export_name_value = None + self._export_name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name + if export_name is not None: + self.export_name = export_name @property - def account_id(self): + def legal_hold_id(self): """ - Filter the events by account ID. Return ony events with this account_id - as either Actor, Context, or Participants. + Hold ID. :rtype: str """ - if self._account_id_present: - return self._account_id_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - return None + raise AttributeError("missing required field 'legal_hold_id'") - @account_id.setter - def account_id(self, val): - if val is None: - del self.account_id - return - val = self._account_id_validator.validate(val) - self._account_id_value = val - self._account_id_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @account_id.deleter - def account_id(self): - self._account_id_value = None - self._account_id_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False @property - def time(self): + def name(self): """ - Filter by time range. + Hold name. - :rtype: team_common.TimeRange + :rtype: str """ - if self._time_present: - return self._time_value + if self._name_present: + return self._name_value else: - return None + raise AttributeError("missing required field 'name'") - @time.setter - def time(self, val): - if val is None: - del self.time - return - self._time_validator.validate_type_only(val) - self._time_value = val - self._time_present = True + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True - @time.deleter - def time(self): - self._time_value = None - self._time_present = False + @name.deleter + def name(self): + self._name_value = None + self._name_present = False @property - def category(self): + def export_name(self): """ - Filter the returned events to a single category. + Export name. - :rtype: EventCategory + :rtype: str """ - if self._category_present: - return self._category_value + if self._export_name_present: + return self._export_name_value else: return None - @category.setter - def category(self, val): + @export_name.setter + def export_name(self, val): if val is None: - del self.category + del self.export_name return - self._category_validator.validate_type_only(val) - self._category_value = val - self._category_present = True + val = self._export_name_validator.validate(val) + self._export_name_value = val + self._export_name_present = True - @category.deleter - def category(self): - self._category_value = None - self._category_present = False + @export_name.deleter + def export_name(self): + self._export_name_value = None + self._export_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetTeamEventsArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsExportAHoldDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetTeamEventsArg(limit={!r}, account_id={!r}, time={!r}, category={!r})'.format( - self._limit_value, - self._account_id_value, - self._time_value, - self._category_value, + return 'LegalHoldsExportAHoldDetails(legal_hold_id={!r}, name={!r}, export_name={!r})'.format( + self._legal_hold_id_value, + self._name_value, + self._export_name_value, ) -GetTeamEventsArg_validator = bv.Struct(GetTeamEventsArg) +LegalHoldsExportAHoldDetails_validator = bv.Struct(LegalHoldsExportAHoldDetails) -class GetTeamEventsContinueArg(bb.Struct): - """ - :ivar team_log.GetTeamEventsContinueArg.cursor: Indicates from what point to - get the next set of events. - """ +class LegalHoldsExportAHoldType(bb.Struct): __slots__ = [ - '_cursor_value', - '_cursor_present', + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - cursor=None): - self._cursor_value = None - self._cursor_present = False - if cursor is not None: - self.cursor = cursor + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def cursor(self): + def description(self): """ - Indicates from what point to get the next set of events. - :rtype: str """ - if self._cursor_present: - return self._cursor_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'cursor'") + raise AttributeError("missing required field 'description'") - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetTeamEventsContinueArg, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsExportAHoldType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetTeamEventsContinueArg(cursor={!r})'.format( - self._cursor_value, + return 'LegalHoldsExportAHoldType(description={!r})'.format( + self._description_value, ) -GetTeamEventsContinueArg_validator = bv.Struct(GetTeamEventsContinueArg) +LegalHoldsExportAHoldType_validator = bv.Struct(LegalHoldsExportAHoldType) -class GetTeamEventsContinueError(bb.Union): +class LegalHoldsExportCancelledDetails(bb.Struct): """ - Errors that can be raised when calling - :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Canceled export for a hold. - :ivar team_log.GetTeamEventsContinueError.bad_cursor: Bad cursor. - :ivar datetime.datetime team_log.GetTeamEventsContinueError.reset: Cursors - are intended to be used quickly. Individual cursor values are normally - valid for days, but in rare cases may be reset sooner. Cursor reset - errors should be handled by fetching a new cursor from - :route:`get_events`. The associated value is the approximate timestamp - of the most recent event returned by the cursor. This should be used as - a resumption point when calling :route:`get_events` to obtain a new - cursor. + :ivar team_log.LegalHoldsExportCancelledDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsExportCancelledDetails.name: Hold name. + :ivar team_log.LegalHoldsExportCancelledDetails.export_name: Export name. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - bad_cursor = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', + '_export_name_value', + '_export_name_present', + ] - @classmethod - def reset(cls, val): - """ - Create an instance of this class set to the ``reset`` tag with value - ``val``. + _has_required_fields = True - :param datetime.datetime val: - :rtype: GetTeamEventsContinueError - """ - return cls('reset', val) + def __init__(self, + legal_hold_id=None, + name=None, + export_name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + self._export_name_value = None + self._export_name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name + if export_name is not None: + self.export_name = export_name - def is_bad_cursor(self): + @property + def legal_hold_id(self): """ - Check if the union tag is ``bad_cursor``. + Hold ID. - :rtype: bool + :rtype: str """ - return self._tag == 'bad_cursor' + if self._legal_hold_id_present: + return self._legal_hold_id_value + else: + raise AttributeError("missing required field 'legal_hold_id'") - def is_reset(self): - """ - Check if the union tag is ``reset``. + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - :rtype: bool + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + + @property + def name(self): """ - return self._tag == 'reset' + Hold name. - def is_other(self): + :rtype: str """ - Check if the union tag is ``other``. + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") - :rtype: bool + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False + + @property + def export_name(self): """ - return self._tag == 'other' + Export name. - def get_reset(self): + :rtype: str """ - Cursors are intended to be used quickly. Individual cursor values are - normally valid for days, but in rare cases may be reset sooner. Cursor - reset errors should be handled by fetching a new cursor from - :meth:`dropbox.dropbox.Dropbox.team_log_get_events`. The associated - value is the approximate timestamp of the most recent event returned by - the cursor. This should be used as a resumption point when calling - :meth:`dropbox.dropbox.Dropbox.team_log_get_events` to obtain a new - cursor. + if self._export_name_present: + return self._export_name_value + else: + raise AttributeError("missing required field 'export_name'") - Only call this if :meth:`is_reset` is true. + @export_name.setter + def export_name(self, val): + val = self._export_name_validator.validate(val) + self._export_name_value = val + self._export_name_present = True - :rtype: datetime.datetime - """ - if not self.is_reset(): - raise AttributeError("tag 'reset' not set") - return self._value + @export_name.deleter + def export_name(self): + self._export_name_value = None + self._export_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetTeamEventsContinueError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsExportCancelledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetTeamEventsContinueError(%r, %r)' % (self._tag, self._value) - -GetTeamEventsContinueError_validator = bv.Union(GetTeamEventsContinueError) - -class GetTeamEventsError(bb.Union): - """ - Errors that can be raised when calling - :meth:`dropbox.dropbox.Dropbox.team_log_get_events`. + return 'LegalHoldsExportCancelledDetails(legal_hold_id={!r}, name={!r}, export_name={!r})'.format( + self._legal_hold_id_value, + self._name_value, + self._export_name_value, + ) - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. +LegalHoldsExportCancelledDetails_validator = bv.Struct(LegalHoldsExportCancelledDetails) - :ivar team_log.GetTeamEventsError.account_id_not_found: No user found - matching the provided account_id. - :ivar team_log.GetTeamEventsError.invalid_time_range: Invalid time range. - """ +class LegalHoldsExportCancelledType(bb.Struct): - _catch_all = 'other' - # Attribute is overwritten below the class definition - account_id_not_found = None - # Attribute is overwritten below the class definition - invalid_time_range = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_description_value', + '_description_present', + ] - def is_account_id_not_found(self): - """ - Check if the union tag is ``account_id_not_found``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'account_id_not_found' + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def is_invalid_time_range(self): + @property + def description(self): """ - Check if the union tag is ``invalid_time_range``. - - :rtype: bool + :rtype: str """ - return self._tag == 'invalid_time_range' + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - def is_other(self): - """ - Check if the union tag is ``other``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: bool - """ - return self._tag == 'other' + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetTeamEventsError, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsExportCancelledType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GetTeamEventsError(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsExportCancelledType(description={!r})'.format( + self._description_value, + ) -GetTeamEventsError_validator = bv.Union(GetTeamEventsError) +LegalHoldsExportCancelledType_validator = bv.Struct(LegalHoldsExportCancelledType) -class GetTeamEventsResult(bb.Struct): +class LegalHoldsExportDownloadedDetails(bb.Struct): """ - :ivar team_log.GetTeamEventsResult.events: List of events. Note that events - are not guaranteed to be sorted by their timestamp value. - :ivar team_log.GetTeamEventsResult.cursor: Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` to obtain - additional events. The value of ``cursor`` may change for each response - from :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`, - regardless of the value of ``has_more``; older cursor strings may - expire. Thus, callers should ensure that they update their cursor based - on the latest value of ``cursor`` after each call, and poll regularly if - they wish to poll for new events. Callers should handle reset exceptions - for expired cursors. - :ivar team_log.GetTeamEventsResult.has_more: Is true if there may be - additional events that have not been returned yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` can - retrieve them. Note that ``has_more`` may be ``True``, even if - ``events`` is empty. + Downloaded export for a hold. + + :ivar team_log.LegalHoldsExportDownloadedDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsExportDownloadedDetails.name: Hold name. + :ivar team_log.LegalHoldsExportDownloadedDetails.export_name: Export name. + :ivar team_log.LegalHoldsExportDownloadedDetails.part: Part. + :ivar team_log.LegalHoldsExportDownloadedDetails.file_name: Filename. """ __slots__ = [ - '_events_value', - '_events_present', - '_cursor_value', - '_cursor_present', - '_has_more_value', - '_has_more_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', + '_export_name_value', + '_export_name_present', + '_part_value', + '_part_present', + '_file_name_value', + '_file_name_present', ] _has_required_fields = True def __init__(self, - events=None, - cursor=None, - has_more=None): - self._events_value = None - self._events_present = False - self._cursor_value = None - self._cursor_present = False - self._has_more_value = None - self._has_more_present = False - if events is not None: - self.events = events - if cursor is not None: - self.cursor = cursor - if has_more is not None: - self.has_more = has_more + legal_hold_id=None, + name=None, + export_name=None, + part=None, + file_name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + self._export_name_value = None + self._export_name_present = False + self._part_value = None + self._part_present = False + self._file_name_value = None + self._file_name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name + if export_name is not None: + self.export_name = export_name + if part is not None: + self.part = part + if file_name is not None: + self.file_name = file_name @property - def events(self): + def legal_hold_id(self): """ - List of events. Note that events are not guaranteed to be sorted by - their timestamp value. + Hold ID. - :rtype: list of [TeamEvent] + :rtype: str """ - if self._events_present: - return self._events_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - raise AttributeError("missing required field 'events'") + raise AttributeError("missing required field 'legal_hold_id'") - @events.setter - def events(self, val): - val = self._events_validator.validate(val) - self._events_value = val - self._events_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @events.deleter - def events(self): - self._events_value = None - self._events_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False @property - def cursor(self): + def name(self): """ - Pass the cursor into - :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` to obtain - additional events. The value of ``cursor`` may change for each response - from :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue`, - regardless of the value of ``has_more``; older cursor strings may - expire. Thus, callers should ensure that they update their cursor based - on the latest value of ``cursor`` after each call, and poll regularly if - they wish to poll for new events. Callers should handle reset exceptions - for expired cursors. + Hold name. :rtype: str """ - if self._cursor_present: - return self._cursor_value + if self._name_present: + return self._name_value else: - raise AttributeError("missing required field 'cursor'") + raise AttributeError("missing required field 'name'") - @cursor.setter - def cursor(self, val): - val = self._cursor_validator.validate(val) - self._cursor_value = val - self._cursor_present = True + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True - @cursor.deleter - def cursor(self): - self._cursor_value = None - self._cursor_present = False + @name.deleter + def name(self): + self._name_value = None + self._name_present = False @property - def has_more(self): + def export_name(self): """ - Is true if there may be additional events that have not been returned - yet. An additional call to - :meth:`dropbox.dropbox.Dropbox.team_log_get_events_continue` can - retrieve them. Note that ``has_more`` may be ``True``, even if - ``events`` is empty. + Export name. - :rtype: bool + :rtype: str """ - if self._has_more_present: - return self._has_more_value + if self._export_name_present: + return self._export_name_value else: - raise AttributeError("missing required field 'has_more'") - - @has_more.setter - def has_more(self, val): - val = self._has_more_validator.validate(val) - self._has_more_value = val - self._has_more_present = True - - @has_more.deleter - def has_more(self): - self._has_more_value = None - self._has_more_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GetTeamEventsResult, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'GetTeamEventsResult(events={!r}, cursor={!r}, has_more={!r})'.format( - self._events_value, - self._cursor_value, - self._has_more_value, - ) - -GetTeamEventsResult_validator = bv.Struct(GetTeamEventsResult) - -class GoogleSsoChangePolicyDetails(bb.Struct): - """ - Enabled/disabled Google single sign-on for team. - - :ivar team_log.GoogleSsoChangePolicyDetails.new_value: New Google single - sign-on policy. - :ivar team_log.GoogleSsoChangePolicyDetails.previous_value: Previous Google - single sign-on policy. Might be missing due to historical data gap. - """ - - __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', - ] + raise AttributeError("missing required field 'export_name'") - _has_required_fields = True + @export_name.setter + def export_name(self, val): + val = self._export_name_validator.validate(val) + self._export_name_value = val + self._export_name_present = True - def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + @export_name.deleter + def export_name(self): + self._export_name_value = None + self._export_name_present = False @property - def new_value(self): + def part(self): """ - New Google single sign-on policy. + Part. - :rtype: GoogleSsoPolicy + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._part_present: + return self._part_value else: - raise AttributeError("missing required field 'new_value'") + return None - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @part.setter + def part(self, val): + if val is None: + del self.part + return + val = self._part_validator.validate(val) + self._part_value = val + self._part_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @part.deleter + def part(self): + self._part_value = None + self._part_present = False @property - def previous_value(self): + def file_name(self): """ - Previous Google single sign-on policy. Might be missing due to - historical data gap. + Filename. - :rtype: GoogleSsoPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._file_name_present: + return self._file_name_value else: return None - @previous_value.setter - def previous_value(self, val): + @file_name.setter + def file_name(self, val): if val is None: - del self.previous_value + del self.file_name return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + val = self._file_name_validator.validate(val) + self._file_name_value = val + self._file_name_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @file_name.deleter + def file_name(self): + self._file_name_value = None + self._file_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GoogleSsoChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsExportDownloadedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GoogleSsoChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'LegalHoldsExportDownloadedDetails(legal_hold_id={!r}, name={!r}, export_name={!r}, part={!r}, file_name={!r})'.format( + self._legal_hold_id_value, + self._name_value, + self._export_name_value, + self._part_value, + self._file_name_value, ) -GoogleSsoChangePolicyDetails_validator = bv.Struct(GoogleSsoChangePolicyDetails) +LegalHoldsExportDownloadedDetails_validator = bv.Struct(LegalHoldsExportDownloadedDetails) -class GoogleSsoChangePolicyType(bb.Struct): +class LegalHoldsExportDownloadedType(bb.Struct): __slots__ = [ '_description_value', @@ -34542,119 +54203,267 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GoogleSsoChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsExportDownloadedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GoogleSsoChangePolicyType(description={!r})'.format( + return 'LegalHoldsExportDownloadedType(description={!r})'.format( self._description_value, ) -GoogleSsoChangePolicyType_validator = bv.Struct(GoogleSsoChangePolicyType) +LegalHoldsExportDownloadedType_validator = bv.Struct(LegalHoldsExportDownloadedType) -class GoogleSsoPolicy(bb.Union): +class LegalHoldsExportRemovedDetails(bb.Struct): """ - Google SSO policy + Removed export for a hold. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team_log.LegalHoldsExportRemovedDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsExportRemovedDetails.name: Hold name. + :ivar team_log.LegalHoldsExportRemovedDetails.export_name: Export name. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', + '_export_name_value', + '_export_name_present', + ] - def is_disabled(self): + _has_required_fields = True + + def __init__(self, + legal_hold_id=None, + name=None, + export_name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + self._export_name_value = None + self._export_name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name + if export_name is not None: + self.export_name = export_name + + @property + def legal_hold_id(self): """ - Check if the union tag is ``disabled``. + Hold ID. - :rtype: bool + :rtype: str """ - return self._tag == 'disabled' + if self._legal_hold_id_present: + return self._legal_hold_id_value + else: + raise AttributeError("missing required field 'legal_hold_id'") - def is_enabled(self): + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True + + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + + @property + def name(self): """ - Check if the union tag is ``enabled``. + Hold name. - :rtype: bool + :rtype: str """ - return self._tag == 'enabled' + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") - def is_other(self): + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False + + @property + def export_name(self): """ - Check if the union tag is ``other``. + Export name. - :rtype: bool + :rtype: str """ - return self._tag == 'other' + if self._export_name_present: + return self._export_name_value + else: + raise AttributeError("missing required field 'export_name'") + + @export_name.setter + def export_name(self, val): + val = self._export_name_validator.validate(val) + self._export_name_value = val + self._export_name_present = True + + @export_name.deleter + def export_name(self): + self._export_name_value = None + self._export_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GoogleSsoPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsExportRemovedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GoogleSsoPolicy(%r, %r)' % (self._tag, self._value) + return 'LegalHoldsExportRemovedDetails(legal_hold_id={!r}, name={!r}, export_name={!r})'.format( + self._legal_hold_id_value, + self._name_value, + self._export_name_value, + ) -GoogleSsoPolicy_validator = bv.Union(GoogleSsoPolicy) +LegalHoldsExportRemovedDetails_validator = bv.Struct(LegalHoldsExportRemovedDetails) -class GroupAddExternalIdDetails(bb.Struct): +class LegalHoldsExportRemovedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LegalHoldsExportRemovedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LegalHoldsExportRemovedType(description={!r})'.format( + self._description_value, + ) + +LegalHoldsExportRemovedType_validator = bv.Struct(LegalHoldsExportRemovedType) + +class LegalHoldsReleaseAHoldDetails(bb.Struct): """ - Added external ID for group. + Released a hold. - :ivar team_log.GroupAddExternalIdDetails.new_value: Current external id. + :ivar team_log.LegalHoldsReleaseAHoldDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsReleaseAHoldDetails.name: Hold name. """ __slots__ = [ - '_new_value_value', - '_new_value_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', ] _has_required_fields = True def __init__(self, - new_value=None): - self._new_value_value = None - self._new_value_present = False - if new_value is not None: - self.new_value = new_value + legal_hold_id=None, + name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name @property - def new_value(self): + def legal_hold_id(self): """ - Current external id. + Hold ID. :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'legal_hold_id'") - @new_value.setter - def new_value(self, val): - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + + @property + def name(self): + """ + Hold name. + + :rtype: str + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") + + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupAddExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsReleaseAHoldDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupAddExternalIdDetails(new_value={!r})'.format( - self._new_value_value, + return 'LegalHoldsReleaseAHoldDetails(legal_hold_id={!r}, name={!r})'.format( + self._legal_hold_id_value, + self._name_value, ) -GroupAddExternalIdDetails_validator = bv.Struct(GroupAddExternalIdDetails) +LegalHoldsReleaseAHoldDetails_validator = bv.Struct(LegalHoldsReleaseAHoldDetails) -class GroupAddExternalIdType(bb.Struct): +class LegalHoldsReleaseAHoldType(bb.Struct): __slots__ = [ '_description_value', @@ -34692,70 +54501,102 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupAddExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsReleaseAHoldType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupAddExternalIdType(description={!r})'.format( + return 'LegalHoldsReleaseAHoldType(description={!r})'.format( self._description_value, ) -GroupAddExternalIdType_validator = bv.Struct(GroupAddExternalIdType) +LegalHoldsReleaseAHoldType_validator = bv.Struct(LegalHoldsReleaseAHoldType) -class GroupAddMemberDetails(bb.Struct): +class LegalHoldsRemoveMembersDetails(bb.Struct): """ - Added team members to group. + Removed members from a hold. - :ivar team_log.GroupAddMemberDetails.is_group_owner: Is group owner. + :ivar team_log.LegalHoldsRemoveMembersDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsRemoveMembersDetails.name: Hold name. """ __slots__ = [ - '_is_group_owner_value', - '_is_group_owner_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', ] _has_required_fields = True def __init__(self, - is_group_owner=None): - self._is_group_owner_value = None - self._is_group_owner_present = False - if is_group_owner is not None: - self.is_group_owner = is_group_owner + legal_hold_id=None, + name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name @property - def is_group_owner(self): + def legal_hold_id(self): """ - Is group owner. + Hold ID. - :rtype: bool + :rtype: str """ - if self._is_group_owner_present: - return self._is_group_owner_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - raise AttributeError("missing required field 'is_group_owner'") + raise AttributeError("missing required field 'legal_hold_id'") - @is_group_owner.setter - def is_group_owner(self, val): - val = self._is_group_owner_validator.validate(val) - self._is_group_owner_value = val - self._is_group_owner_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @is_group_owner.deleter - def is_group_owner(self): - self._is_group_owner_value = None - self._is_group_owner_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + + @property + def name(self): + """ + Hold name. + + :rtype: str + """ + if self._name_present: + return self._name_value + else: + raise AttributeError("missing required field 'name'") + + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True + + @name.deleter + def name(self): + self._name_value = None + self._name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupAddMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsRemoveMembersDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupAddMemberDetails(is_group_owner={!r})'.format( - self._is_group_owner_value, + return 'LegalHoldsRemoveMembersDetails(legal_hold_id={!r}, name={!r})'.format( + self._legal_hold_id_value, + self._name_value, ) -GroupAddMemberDetails_validator = bv.Struct(GroupAddMemberDetails) +LegalHoldsRemoveMembersDetails_validator = bv.Struct(LegalHoldsRemoveMembersDetails) -class GroupAddMemberType(bb.Struct): +class LegalHoldsRemoveMembersType(bb.Struct): __slots__ = [ '_description_value', @@ -34793,102 +54634,102 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupAddMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsRemoveMembersType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupAddMemberType(description={!r})'.format( + return 'LegalHoldsRemoveMembersType(description={!r})'.format( self._description_value, ) -GroupAddMemberType_validator = bv.Struct(GroupAddMemberType) +LegalHoldsRemoveMembersType_validator = bv.Struct(LegalHoldsRemoveMembersType) -class GroupChangeExternalIdDetails(bb.Struct): +class LegalHoldsReportAHoldDetails(bb.Struct): """ - Changed external ID for group. + Created a summary report for a hold. - :ivar team_log.GroupChangeExternalIdDetails.new_value: Current external id. - :ivar team_log.GroupChangeExternalIdDetails.previous_value: Old external id. + :ivar team_log.LegalHoldsReportAHoldDetails.legal_hold_id: Hold ID. + :ivar team_log.LegalHoldsReportAHoldDetails.name: Hold name. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_legal_hold_id_value', + '_legal_hold_id_present', + '_name_value', + '_name_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + legal_hold_id=None, + name=None): + self._legal_hold_id_value = None + self._legal_hold_id_present = False + self._name_value = None + self._name_present = False + if legal_hold_id is not None: + self.legal_hold_id = legal_hold_id + if name is not None: + self.name = name @property - def new_value(self): + def legal_hold_id(self): """ - Current external id. + Hold ID. :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._legal_hold_id_present: + return self._legal_hold_id_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'legal_hold_id'") - @new_value.setter - def new_value(self, val): - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + @legal_hold_id.setter + def legal_hold_id(self, val): + val = self._legal_hold_id_validator.validate(val) + self._legal_hold_id_value = val + self._legal_hold_id_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @legal_hold_id.deleter + def legal_hold_id(self): + self._legal_hold_id_value = None + self._legal_hold_id_present = False @property - def previous_value(self): + def name(self): """ - Old external id. + Hold name. :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._name_present: + return self._name_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'name'") - @previous_value.setter - def previous_value(self, val): - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + @name.setter + def name(self, val): + val = self._name_validator.validate(val) + self._name_value = val + self._name_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @name.deleter + def name(self): + self._name_value = None + self._name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupChangeExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsReportAHoldDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupChangeExternalIdDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'LegalHoldsReportAHoldDetails(legal_hold_id={!r}, name={!r})'.format( + self._legal_hold_id_value, + self._name_value, ) -GroupChangeExternalIdDetails_validator = bv.Struct(GroupChangeExternalIdDetails) +LegalHoldsReportAHoldDetails_validator = bv.Struct(LegalHoldsReportAHoldDetails) -class GroupChangeExternalIdType(bb.Struct): +class LegalHoldsReportAHoldType(bb.Struct): __slots__ = [ '_description_value', @@ -34926,108 +54767,351 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupChangeExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LegalHoldsReportAHoldType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupChangeExternalIdType(description={!r})'.format( + return 'LegalHoldsReportAHoldType(description={!r})'.format( self._description_value, ) -GroupChangeExternalIdType_validator = bv.Struct(GroupChangeExternalIdType) +LegalHoldsReportAHoldType_validator = bv.Struct(LegalHoldsReportAHoldType) -class GroupChangeManagementTypeDetails(bb.Struct): +class LinkedDeviceLogInfo(bb.Union): """ - Changed group management type. + The device sessions that user is linked to. - :ivar team_log.GroupChangeManagementTypeDetails.new_value: New group - management type. - :ivar team_log.GroupChangeManagementTypeDetails.previous_value: Previous - group management type. Might be missing due to historical data gap. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar MobileDeviceSessionLogInfo LinkedDeviceLogInfo.mobile_device_session: + mobile device session's details. + :ivar DesktopDeviceSessionLogInfo + LinkedDeviceLogInfo.desktop_device_session: desktop device session's + details. + :ivar WebDeviceSessionLogInfo LinkedDeviceLogInfo.web_device_session: web + device session's details. + :ivar LegacyDeviceSessionLogInfo LinkedDeviceLogInfo.legacy_device_session: + legacy device session's details. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def mobile_device_session(cls, val): + """ + Create an instance of this class set to the ``mobile_device_session`` + tag with value ``val``. + + :param MobileDeviceSessionLogInfo val: + :rtype: LinkedDeviceLogInfo + """ + return cls('mobile_device_session', val) + + @classmethod + def desktop_device_session(cls, val): + """ + Create an instance of this class set to the ``desktop_device_session`` + tag with value ``val``. + + :param DesktopDeviceSessionLogInfo val: + :rtype: LinkedDeviceLogInfo + """ + return cls('desktop_device_session', val) + + @classmethod + def web_device_session(cls, val): + """ + Create an instance of this class set to the ``web_device_session`` tag + with value ``val``. + + :param WebDeviceSessionLogInfo val: + :rtype: LinkedDeviceLogInfo + """ + return cls('web_device_session', val) + + @classmethod + def legacy_device_session(cls, val): + """ + Create an instance of this class set to the ``legacy_device_session`` + tag with value ``val``. + + :param LegacyDeviceSessionLogInfo val: + :rtype: LinkedDeviceLogInfo + """ + return cls('legacy_device_session', val) + + def is_mobile_device_session(self): + """ + Check if the union tag is ``mobile_device_session``. + + :rtype: bool + """ + return self._tag == 'mobile_device_session' + + def is_desktop_device_session(self): + """ + Check if the union tag is ``desktop_device_session``. + + :rtype: bool + """ + return self._tag == 'desktop_device_session' + + def is_web_device_session(self): + """ + Check if the union tag is ``web_device_session``. + + :rtype: bool + """ + return self._tag == 'web_device_session' + + def is_legacy_device_session(self): + """ + Check if the union tag is ``legacy_device_session``. + + :rtype: bool + """ + return self._tag == 'legacy_device_session' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_mobile_device_session(self): + """ + mobile device session's details. + + Only call this if :meth:`is_mobile_device_session` is true. + + :rtype: MobileDeviceSessionLogInfo + """ + if not self.is_mobile_device_session(): + raise AttributeError("tag 'mobile_device_session' not set") + return self._value + + def get_desktop_device_session(self): + """ + desktop device session's details. + + Only call this if :meth:`is_desktop_device_session` is true. + + :rtype: DesktopDeviceSessionLogInfo + """ + if not self.is_desktop_device_session(): + raise AttributeError("tag 'desktop_device_session' not set") + return self._value + + def get_web_device_session(self): + """ + web device session's details. + + Only call this if :meth:`is_web_device_session` is true. + + :rtype: WebDeviceSessionLogInfo + """ + if not self.is_web_device_session(): + raise AttributeError("tag 'web_device_session' not set") + return self._value + + def get_legacy_device_session(self): + """ + legacy device session's details. + + Only call this if :meth:`is_legacy_device_session` is true. + + :rtype: LegacyDeviceSessionLogInfo + """ + if not self.is_legacy_device_session(): + raise AttributeError("tag 'legacy_device_session' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LinkedDeviceLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LinkedDeviceLogInfo(%r, %r)' % (self._tag, self._value) + +LinkedDeviceLogInfo_validator = bv.Union(LinkedDeviceLogInfo) + +class LockStatus(bb.Union): + """ + File lock status + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + locked = None + # Attribute is overwritten below the class definition + unlocked = None + # Attribute is overwritten below the class definition + other = None + + def is_locked(self): + """ + Check if the union tag is ``locked``. + + :rtype: bool + """ + return self._tag == 'locked' + + def is_unlocked(self): + """ + Check if the union tag is ``unlocked``. + + :rtype: bool + """ + return self._tag == 'unlocked' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(LockStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'LockStatus(%r, %r)' % (self._tag, self._value) + +LockStatus_validator = bv.Union(LockStatus) + +class LoginFailDetails(bb.Struct): + """ + Failed to sign in. + + :ivar team_log.LoginFailDetails.is_emm_managed: Tells if the login device is + EMM managed. Might be missing due to historical data gap. + :ivar team_log.LoginFailDetails.login_method: Login method. + :ivar team_log.LoginFailDetails.error_details: Error details. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_is_emm_managed_value', + '_is_emm_managed_present', + '_login_method_value', + '_login_method_present', + '_error_details_value', + '_error_details_present', ] _has_required_fields = True - def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + def __init__(self, + login_method=None, + error_details=None, + is_emm_managed=None): + self._is_emm_managed_value = None + self._is_emm_managed_present = False + self._login_method_value = None + self._login_method_present = False + self._error_details_value = None + self._error_details_present = False + if is_emm_managed is not None: + self.is_emm_managed = is_emm_managed + if login_method is not None: + self.login_method = login_method + if error_details is not None: + self.error_details = error_details + + @property + def is_emm_managed(self): + """ + Tells if the login device is EMM managed. Might be missing due to + historical data gap. + + :rtype: bool + """ + if self._is_emm_managed_present: + return self._is_emm_managed_value + else: + return None + + @is_emm_managed.setter + def is_emm_managed(self, val): + if val is None: + del self.is_emm_managed + return + val = self._is_emm_managed_validator.validate(val) + self._is_emm_managed_value = val + self._is_emm_managed_present = True + + @is_emm_managed.deleter + def is_emm_managed(self): + self._is_emm_managed_value = None + self._is_emm_managed_present = False @property - def new_value(self): + def login_method(self): """ - New group management type. + Login method. - :rtype: team_common.GroupManagementType + :rtype: LoginMethod """ - if self._new_value_present: - return self._new_value_value + if self._login_method_present: + return self._login_method_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'login_method'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @login_method.setter + def login_method(self, val): + self._login_method_validator.validate_type_only(val) + self._login_method_value = val + self._login_method_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @login_method.deleter + def login_method(self): + self._login_method_value = None + self._login_method_present = False @property - def previous_value(self): + def error_details(self): """ - Previous group management type. Might be missing due to historical data - gap. + Error details. - :rtype: team_common.GroupManagementType + :rtype: FailureDetailsLogInfo """ - if self._previous_value_present: - return self._previous_value_value + if self._error_details_present: + return self._error_details_value else: - return None + raise AttributeError("missing required field 'error_details'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @error_details.setter + def error_details(self, val): + self._error_details_validator.validate_type_only(val) + self._error_details_value = val + self._error_details_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @error_details.deleter + def error_details(self): + self._error_details_value = None + self._error_details_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupChangeManagementTypeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LoginFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupChangeManagementTypeDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'LoginFailDetails(login_method={!r}, error_details={!r}, is_emm_managed={!r})'.format( + self._login_method_value, + self._error_details_value, + self._is_emm_managed_value, ) -GroupChangeManagementTypeDetails_validator = bv.Struct(GroupChangeManagementTypeDetails) +LoginFailDetails_validator = bv.Struct(LoginFailDetails) -class GroupChangeManagementTypeType(bb.Struct): +class LoginFailType(bb.Struct): __slots__ = [ '_description_value', @@ -35065,210 +55149,214 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupChangeManagementTypeType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LoginFailType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupChangeManagementTypeType(description={!r})'.format( + return 'LoginFailType(description={!r})'.format( self._description_value, ) -GroupChangeManagementTypeType_validator = bv.Struct(GroupChangeManagementTypeType) +LoginFailType_validator = bv.Struct(LoginFailType) -class GroupChangeMemberRoleDetails(bb.Struct): +class LoginMethod(bb.Union): """ - Changed manager permissions of group member. - - :ivar team_log.GroupChangeMemberRoleDetails.is_group_owner: Is group owner. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_is_group_owner_value', - '_is_group_owner_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + password = None + # Attribute is overwritten below the class definition + two_factor_authentication = None + # Attribute is overwritten below the class definition + saml = None + # Attribute is overwritten below the class definition + google_oauth = None + # Attribute is overwritten below the class definition + web_session = None + # Attribute is overwritten below the class definition + qr_code = None + # Attribute is overwritten below the class definition + apple_oauth = None + # Attribute is overwritten below the class definition + first_party_token_exchange = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_password(self): + """ + Check if the union tag is ``password``. - def __init__(self, - is_group_owner=None): - self._is_group_owner_value = None - self._is_group_owner_present = False - if is_group_owner is not None: - self.is_group_owner = is_group_owner + :rtype: bool + """ + return self._tag == 'password' - @property - def is_group_owner(self): + def is_two_factor_authentication(self): """ - Is group owner. + Check if the union tag is ``two_factor_authentication``. :rtype: bool """ - if self._is_group_owner_present: - return self._is_group_owner_value - else: - raise AttributeError("missing required field 'is_group_owner'") + return self._tag == 'two_factor_authentication' - @is_group_owner.setter - def is_group_owner(self, val): - val = self._is_group_owner_validator.validate(val) - self._is_group_owner_value = val - self._is_group_owner_present = True + def is_saml(self): + """ + Check if the union tag is ``saml``. - @is_group_owner.deleter - def is_group_owner(self): - self._is_group_owner_value = None - self._is_group_owner_present = False + :rtype: bool + """ + return self._tag == 'saml' - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupChangeMemberRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + def is_google_oauth(self): + """ + Check if the union tag is ``google_oauth``. - def __repr__(self): - return 'GroupChangeMemberRoleDetails(is_group_owner={!r})'.format( - self._is_group_owner_value, - ) + :rtype: bool + """ + return self._tag == 'google_oauth' -GroupChangeMemberRoleDetails_validator = bv.Struct(GroupChangeMemberRoleDetails) + def is_web_session(self): + """ + Check if the union tag is ``web_session``. -class GroupChangeMemberRoleType(bb.Struct): + :rtype: bool + """ + return self._tag == 'web_session' - __slots__ = [ - '_description_value', - '_description_present', - ] + def is_qr_code(self): + """ + Check if the union tag is ``qr_code``. - _has_required_fields = True + :rtype: bool + """ + return self._tag == 'qr_code' - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + def is_apple_oauth(self): + """ + Check if the union tag is ``apple_oauth``. - @property - def description(self): + :rtype: bool """ - :rtype: str + return self._tag == 'apple_oauth' + + def is_first_party_token_exchange(self): """ - if self._description_present: - return self._description_value - else: - raise AttributeError("missing required field 'description'") + Check if the union tag is ``first_party_token_exchange``. - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + :rtype: bool + """ + return self._tag == 'first_party_token_exchange' - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupChangeMemberRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LoginMethod, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupChangeMemberRoleType(description={!r})'.format( - self._description_value, - ) + return 'LoginMethod(%r, %r)' % (self._tag, self._value) -GroupChangeMemberRoleType_validator = bv.Struct(GroupChangeMemberRoleType) +LoginMethod_validator = bv.Union(LoginMethod) -class GroupCreateDetails(bb.Struct): +class LoginSuccessDetails(bb.Struct): """ - Created group. + Signed in. - :ivar team_log.GroupCreateDetails.is_company_managed: Is company managed - group. Might be missing due to historical data gap. - :ivar team_log.GroupCreateDetails.join_policy: Group join policy. + :ivar team_log.LoginSuccessDetails.is_emm_managed: Tells if the login device + is EMM managed. Might be missing due to historical data gap. + :ivar team_log.LoginSuccessDetails.login_method: Login method. """ __slots__ = [ - '_is_company_managed_value', - '_is_company_managed_present', - '_join_policy_value', - '_join_policy_present', + '_is_emm_managed_value', + '_is_emm_managed_present', + '_login_method_value', + '_login_method_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - is_company_managed=None, - join_policy=None): - self._is_company_managed_value = None - self._is_company_managed_present = False - self._join_policy_value = None - self._join_policy_present = False - if is_company_managed is not None: - self.is_company_managed = is_company_managed - if join_policy is not None: - self.join_policy = join_policy + login_method=None, + is_emm_managed=None): + self._is_emm_managed_value = None + self._is_emm_managed_present = False + self._login_method_value = None + self._login_method_present = False + if is_emm_managed is not None: + self.is_emm_managed = is_emm_managed + if login_method is not None: + self.login_method = login_method @property - def is_company_managed(self): + def is_emm_managed(self): """ - Is company managed group. Might be missing due to historical data gap. + Tells if the login device is EMM managed. Might be missing due to + historical data gap. :rtype: bool """ - if self._is_company_managed_present: - return self._is_company_managed_value + if self._is_emm_managed_present: + return self._is_emm_managed_value else: return None - @is_company_managed.setter - def is_company_managed(self, val): + @is_emm_managed.setter + def is_emm_managed(self, val): if val is None: - del self.is_company_managed + del self.is_emm_managed return - val = self._is_company_managed_validator.validate(val) - self._is_company_managed_value = val - self._is_company_managed_present = True + val = self._is_emm_managed_validator.validate(val) + self._is_emm_managed_value = val + self._is_emm_managed_present = True - @is_company_managed.deleter - def is_company_managed(self): - self._is_company_managed_value = None - self._is_company_managed_present = False + @is_emm_managed.deleter + def is_emm_managed(self): + self._is_emm_managed_value = None + self._is_emm_managed_present = False @property - def join_policy(self): + def login_method(self): """ - Group join policy. + Login method. - :rtype: GroupJoinPolicy + :rtype: LoginMethod """ - if self._join_policy_present: - return self._join_policy_value + if self._login_method_present: + return self._login_method_value else: - return None + raise AttributeError("missing required field 'login_method'") - @join_policy.setter - def join_policy(self, val): - if val is None: - del self.join_policy - return - self._join_policy_validator.validate_type_only(val) - self._join_policy_value = val - self._join_policy_present = True + @login_method.setter + def login_method(self, val): + self._login_method_validator.validate_type_only(val) + self._login_method_value = val + self._login_method_present = True - @join_policy.deleter - def join_policy(self): - self._join_policy_value = None - self._join_policy_present = False + @login_method.deleter + def login_method(self): + self._login_method_value = None + self._login_method_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LoginSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupCreateDetails(is_company_managed={!r}, join_policy={!r})'.format( - self._is_company_managed_value, - self._join_policy_value, + return 'LoginSuccessDetails(login_method={!r}, is_emm_managed={!r})'.format( + self._login_method_value, + self._is_emm_managed_value, ) -GroupCreateDetails_validator = bv.Struct(GroupCreateDetails) +LoginSuccessDetails_validator = bv.Struct(LoginSuccessDetails) -class GroupCreateType(bb.Struct): +class LoginSuccessType(bb.Struct): __slots__ = [ '_description_value', @@ -35306,74 +55394,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LoginSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupCreateType(description={!r})'.format( + return 'LoginSuccessType(description={!r})'.format( self._description_value, ) -GroupCreateType_validator = bv.Struct(GroupCreateType) +LoginSuccessType_validator = bv.Struct(LoginSuccessType) -class GroupDeleteDetails(bb.Struct): +class LogoutDetails(bb.Struct): """ - Deleted group. - - :ivar team_log.GroupDeleteDetails.is_company_managed: Is company managed - group. Might be missing due to historical data gap. + Signed out. """ __slots__ = [ - '_is_company_managed_value', - '_is_company_managed_present', ] _has_required_fields = False - def __init__(self, - is_company_managed=None): - self._is_company_managed_value = None - self._is_company_managed_present = False - if is_company_managed is not None: - self.is_company_managed = is_company_managed - - @property - def is_company_managed(self): - """ - Is company managed group. Might be missing due to historical data gap. - - :rtype: bool - """ - if self._is_company_managed_present: - return self._is_company_managed_value - else: - return None - - @is_company_managed.setter - def is_company_managed(self, val): - if val is None: - del self.is_company_managed - return - val = self._is_company_managed_validator.validate(val) - self._is_company_managed_value = val - self._is_company_managed_present = True - - @is_company_managed.deleter - def is_company_managed(self): - self._is_company_managed_value = None - self._is_company_managed_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LogoutDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupDeleteDetails(is_company_managed={!r})'.format( - self._is_company_managed_value, - ) + return 'LogoutDetails()' -GroupDeleteDetails_validator = bv.Struct(GroupDeleteDetails) +LogoutDetails_validator = bv.Struct(LogoutDetails) -class GroupDeleteType(bb.Struct): +class LogoutType(bb.Struct): __slots__ = [ '_description_value', @@ -35411,37 +55462,70 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(LogoutType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupDeleteType(description={!r})'.format( + return 'LogoutType(description={!r})'.format( self._description_value, ) -GroupDeleteType_validator = bv.Struct(GroupDeleteType) +LogoutType_validator = bv.Struct(LogoutType) -class GroupDescriptionUpdatedDetails(bb.Struct): +class MemberAddExternalIdDetails(bb.Struct): """ - Updated group. + Added an external ID for team member. + + :ivar team_log.MemberAddExternalIdDetails.new_value: Current external id. """ __slots__ = [ + '_new_value_value', + '_new_value_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + new_value=None): + self._new_value_value = None + self._new_value_present = False + if new_value is not None: + self.new_value = new_value + + @property + def new_value(self): + """ + Current external id. + + :rtype: str + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupDescriptionUpdatedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberAddExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupDescriptionUpdatedDetails()' + return 'MemberAddExternalIdDetails(new_value={!r})'.format( + self._new_value_value, + ) -GroupDescriptionUpdatedDetails_validator = bv.Struct(GroupDescriptionUpdatedDetails) +MemberAddExternalIdDetails_validator = bv.Struct(MemberAddExternalIdDetails) -class GroupDescriptionUpdatedType(bb.Struct): +class MemberAddExternalIdType(bb.Struct): __slots__ = [ '_description_value', @@ -35476,159 +55560,73 @@ def description(self, val): @description.deleter def description(self): self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupDescriptionUpdatedType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'GroupDescriptionUpdatedType(description={!r})'.format( - self._description_value, - ) - -GroupDescriptionUpdatedType_validator = bv.Struct(GroupDescriptionUpdatedType) - -class GroupJoinPolicy(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - open = None - # Attribute is overwritten below the class definition - request_to_join = None - # Attribute is overwritten below the class definition - other = None - - def is_open(self): - """ - Check if the union tag is ``open``. - - :rtype: bool - """ - return self._tag == 'open' - - def is_request_to_join(self): - """ - Check if the union tag is ``request_to_join``. - - :rtype: bool - """ - return self._tag == 'request_to_join' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupJoinPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberAddExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupJoinPolicy(%r, %r)' % (self._tag, self._value) + return 'MemberAddExternalIdType(description={!r})'.format( + self._description_value, + ) -GroupJoinPolicy_validator = bv.Union(GroupJoinPolicy) +MemberAddExternalIdType_validator = bv.Struct(MemberAddExternalIdType) -class GroupJoinPolicyUpdatedDetails(bb.Struct): +class MemberAddNameDetails(bb.Struct): """ - Updated group join policy. + Added team member name. - :ivar team_log.GroupJoinPolicyUpdatedDetails.is_company_managed: Is company - managed group. Might be missing due to historical data gap. - :ivar team_log.GroupJoinPolicyUpdatedDetails.join_policy: Group join policy. + :ivar team_log.MemberAddNameDetails.new_value: New user's name. """ __slots__ = [ - '_is_company_managed_value', - '_is_company_managed_present', - '_join_policy_value', - '_join_policy_present', + '_new_value_value', + '_new_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - is_company_managed=None, - join_policy=None): - self._is_company_managed_value = None - self._is_company_managed_present = False - self._join_policy_value = None - self._join_policy_present = False - if is_company_managed is not None: - self.is_company_managed = is_company_managed - if join_policy is not None: - self.join_policy = join_policy - - @property - def is_company_managed(self): - """ - Is company managed group. Might be missing due to historical data gap. - - :rtype: bool - """ - if self._is_company_managed_present: - return self._is_company_managed_value - else: - return None - - @is_company_managed.setter - def is_company_managed(self, val): - if val is None: - del self.is_company_managed - return - val = self._is_company_managed_validator.validate(val) - self._is_company_managed_value = val - self._is_company_managed_present = True - - @is_company_managed.deleter - def is_company_managed(self): - self._is_company_managed_value = None - self._is_company_managed_present = False + new_value=None): + self._new_value_value = None + self._new_value_present = False + if new_value is not None: + self.new_value = new_value @property - def join_policy(self): + def new_value(self): """ - Group join policy. + New user's name. - :rtype: GroupJoinPolicy + :rtype: UserNameLogInfo """ - if self._join_policy_present: - return self._join_policy_value + if self._new_value_present: + return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") - @join_policy.setter - def join_policy(self, val): - if val is None: - del self.join_policy - return - self._join_policy_validator.validate_type_only(val) - self._join_policy_value = val - self._join_policy_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @join_policy.deleter - def join_policy(self): - self._join_policy_value = None - self._join_policy_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupJoinPolicyUpdatedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberAddNameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupJoinPolicyUpdatedDetails(is_company_managed={!r}, join_policy={!r})'.format( - self._is_company_managed_value, - self._join_policy_value, + return 'MemberAddNameDetails(new_value={!r})'.format( + self._new_value_value, ) -GroupJoinPolicyUpdatedDetails_validator = bv.Struct(GroupJoinPolicyUpdatedDetails) +MemberAddNameDetails_validator = bv.Struct(MemberAddNameDetails) -class GroupJoinPolicyUpdatedType(bb.Struct): +class MemberAddNameType(bb.Struct): __slots__ = [ '_description_value', @@ -35666,164 +55664,114 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupJoinPolicyUpdatedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberAddNameType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupJoinPolicyUpdatedType(description={!r})'.format( + return 'MemberAddNameType(description={!r})'.format( self._description_value, ) -GroupJoinPolicyUpdatedType_validator = bv.Struct(GroupJoinPolicyUpdatedType) +MemberAddNameType_validator = bv.Struct(MemberAddNameType) -class GroupLogInfo(bb.Struct): +class MemberChangeAdminRoleDetails(bb.Struct): """ - Group's logged information. + Changed team member admin role. - :ivar team_log.GroupLogInfo.group_id: The unique id of this group. Might be - missing due to historical data gap. - :ivar team_log.GroupLogInfo.display_name: The name of this group. - :ivar team_log.GroupLogInfo.external_id: External group ID. Might be missing - due to historical data gap. + :ivar team_log.MemberChangeAdminRoleDetails.new_value: New admin role. This + field is relevant when the admin role is changed or whenthe user role + changes from no admin rights to with admin rights. + :ivar team_log.MemberChangeAdminRoleDetails.previous_value: Previous admin + role. This field is relevant when the admin role is changed or when the + admin role is removed. """ __slots__ = [ - '_group_id_value', - '_group_id_present', - '_display_name_value', - '_display_name_present', - '_external_id_value', - '_external_id_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - display_name=None, - group_id=None, - external_id=None): - self._group_id_value = None - self._group_id_present = False - self._display_name_value = None - self._display_name_present = False - self._external_id_value = None - self._external_id_present = False - if group_id is not None: - self.group_id = group_id - if display_name is not None: - self.display_name = display_name - if external_id is not None: - self.external_id = external_id + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def group_id(self): + def new_value(self): """ - The unique id of this group. Might be missing due to historical data - gap. + New admin role. This field is relevant when the admin role is changed or + whenthe user role changes from no admin rights to with admin rights. - :rtype: str + :rtype: AdminRole """ - if self._group_id_present: - return self._group_id_value + if self._new_value_present: + return self._new_value_value else: return None - @group_id.setter - def group_id(self, val): + @new_value.setter + def new_value(self, val): if val is None: - del self.group_id + del self.new_value return - val = self._group_id_validator.validate(val) - self._group_id_value = val - self._group_id_present = True - - @group_id.deleter - def group_id(self): - self._group_id_value = None - self._group_id_present = False - - @property - def display_name(self): - """ - The name of this group. - - :rtype: str - """ - if self._display_name_present: - return self._display_name_value - else: - raise AttributeError("missing required field 'display_name'") - - @display_name.setter - def display_name(self, val): - val = self._display_name_validator.validate(val) - self._display_name_value = val - self._display_name_present = True + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @display_name.deleter - def display_name(self): - self._display_name_value = None - self._display_name_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False @property - def external_id(self): + def previous_value(self): """ - External group ID. Might be missing due to historical data gap. + Previous admin role. This field is relevant when the admin role is + changed or when the admin role is removed. - :rtype: str + :rtype: AdminRole """ - if self._external_id_present: - return self._external_id_value + if self._previous_value_present: + return self._previous_value_value else: return None - @external_id.setter - def external_id(self, val): + @previous_value.setter + def previous_value(self, val): if val is None: - del self.external_id + del self.previous_value return - val = self._external_id_validator.validate(val) - self._external_id_value = val - self._external_id_present = True + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @external_id.deleter - def external_id(self): - self._external_id_value = None - self._external_id_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeAdminRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupLogInfo(display_name={!r}, group_id={!r}, external_id={!r})'.format( - self._display_name_value, - self._group_id_value, - self._external_id_value, + return 'MemberChangeAdminRoleDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -GroupLogInfo_validator = bv.Struct(GroupLogInfo) - -class GroupMovedDetails(bb.Struct): - """ - Moved group. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMovedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'GroupMovedDetails()' - -GroupMovedDetails_validator = bv.Struct(GroupMovedDetails) +MemberChangeAdminRoleDetails_validator = bv.Struct(MemberChangeAdminRoleDetails) -class GroupMovedType(bb.Struct): +class MemberChangeAdminRoleType(bb.Struct): __slots__ = [ '_description_value', @@ -35861,23 +55809,27 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupMovedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeAdminRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupMovedType(description={!r})'.format( + return 'MemberChangeAdminRoleType(description={!r})'.format( self._description_value, ) -GroupMovedType_validator = bv.Struct(GroupMovedType) +MemberChangeAdminRoleType_validator = bv.Struct(MemberChangeAdminRoleType) -class GroupRemoveExternalIdDetails(bb.Struct): +class MemberChangeEmailDetails(bb.Struct): """ - Removed external ID for group. + Changed team member email. - :ivar team_log.GroupRemoveExternalIdDetails.previous_value: Old external id. + :ivar team_log.MemberChangeEmailDetails.new_value: New email. + :ivar team_log.MemberChangeEmailDetails.previous_value: Previous email. + Might be missing due to historical data gap. """ __slots__ = [ + '_new_value_value', + '_new_value_present', '_previous_value_value', '_previous_value_present', ] @@ -35885,26 +55837,57 @@ class GroupRemoveExternalIdDetails(bb.Struct): _has_required_fields = True def __init__(self, + new_value=None, previous_value=None): + self._new_value_value = None + self._new_value_present = False self._previous_value_value = None self._previous_value_present = False + if new_value is not None: + self.new_value = new_value if previous_value is not None: self.previous_value = previous_value + @property + def new_value(self): + """ + New email. + + :rtype: str + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + @property def previous_value(self): """ - Old external id. + Previous email. Might be missing due to historical data gap. :rtype: str """ if self._previous_value_present: return self._previous_value_value else: - raise AttributeError("missing required field 'previous_value'") + return None @previous_value.setter def previous_value(self, val): + if val is None: + del self.previous_value + return val = self._previous_value_validator.validate(val) self._previous_value_value = val self._previous_value_present = True @@ -35915,16 +55898,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupRemoveExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeEmailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupRemoveExternalIdDetails(previous_value={!r})'.format( + return 'MemberChangeEmailDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, self._previous_value_value, ) -GroupRemoveExternalIdDetails_validator = bv.Struct(GroupRemoveExternalIdDetails) +MemberChangeEmailDetails_validator = bv.Struct(MemberChangeEmailDetails) -class GroupRemoveExternalIdType(bb.Struct): +class MemberChangeEmailType(bb.Struct): __slots__ = [ '_description_value', @@ -35962,37 +55946,103 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupRemoveExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeEmailType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupRemoveExternalIdType(description={!r})'.format( + return 'MemberChangeEmailType(description={!r})'.format( self._description_value, ) -GroupRemoveExternalIdType_validator = bv.Struct(GroupRemoveExternalIdType) +MemberChangeEmailType_validator = bv.Struct(MemberChangeEmailType) -class GroupRemoveMemberDetails(bb.Struct): +class MemberChangeExternalIdDetails(bb.Struct): """ - Removed team members from group. + Changed the external ID for team member. + + :ivar team_log.MemberChangeExternalIdDetails.new_value: Current external id. + :ivar team_log.MemberChangeExternalIdDetails.previous_value: Old external + id. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + Current external id. + + :rtype: str + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Old external id. + + :rtype: str + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupRemoveMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupRemoveMemberDetails()' + return 'MemberChangeExternalIdDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -GroupRemoveMemberDetails_validator = bv.Struct(GroupRemoveMemberDetails) +MemberChangeExternalIdDetails_validator = bv.Struct(MemberChangeExternalIdDetails) -class GroupRemoveMemberType(bb.Struct): +class MemberChangeExternalIdType(bb.Struct): __slots__ = [ '_description_value', @@ -36030,26 +56080,28 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupRemoveMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupRemoveMemberType(description={!r})'.format( + return 'MemberChangeExternalIdType(description={!r})'.format( self._description_value, ) -GroupRemoveMemberType_validator = bv.Struct(GroupRemoveMemberType) +MemberChangeExternalIdType_validator = bv.Struct(MemberChangeExternalIdType) -class GroupRenameDetails(bb.Struct): +class MemberChangeMembershipTypeDetails(bb.Struct): """ - Renamed group. + Changed membership type (limited/full) of member. - :ivar team_log.GroupRenameDetails.previous_value: Previous display name. - :ivar team_log.GroupRenameDetails.new_value: New display name. + :ivar team_log.MemberChangeMembershipTypeDetails.prev_value: Previous + membership type. + :ivar team_log.MemberChangeMembershipTypeDetails.new_value: New membership + type. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', + '_prev_value_value', + '_prev_value_present', '_new_value_value', '_new_value_present', ] @@ -36057,46 +56109,46 @@ class GroupRenameDetails(bb.Struct): _has_required_fields = True def __init__(self, - previous_value=None, + prev_value=None, new_value=None): - self._previous_value_value = None - self._previous_value_present = False + self._prev_value_value = None + self._prev_value_present = False self._new_value_value = None self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value + if prev_value is not None: + self.prev_value = prev_value if new_value is not None: self.new_value = new_value @property - def previous_value(self): + def prev_value(self): """ - Previous display name. + Previous membership type. - :rtype: str + :rtype: TeamMembershipType """ - if self._previous_value_present: - return self._previous_value_value + if self._prev_value_present: + return self._prev_value_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'prev_value'") - @previous_value.setter - def previous_value(self, val): - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + @prev_value.setter + def prev_value(self, val): + self._prev_value_validator.validate_type_only(val) + self._prev_value_value = val + self._prev_value_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @prev_value.deleter + def prev_value(self): + self._prev_value_value = None + self._prev_value_present = False @property def new_value(self): """ - New display name. + New membership type. - :rtype: str + :rtype: TeamMembershipType """ if self._new_value_present: return self._new_value_value @@ -36105,7 +56157,7 @@ def new_value(self): @new_value.setter def new_value(self, val): - val = self._new_value_validator.validate(val) + self._new_value_validator.validate_type_only(val) self._new_value_value = val self._new_value_present = True @@ -36115,17 +56167,17 @@ def new_value(self): self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupRenameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeMembershipTypeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupRenameDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, + return 'MemberChangeMembershipTypeDetails(prev_value={!r}, new_value={!r})'.format( + self._prev_value_value, self._new_value_value, ) -GroupRenameDetails_validator = bv.Struct(GroupRenameDetails) +MemberChangeMembershipTypeDetails_validator = bv.Struct(MemberChangeMembershipTypeDetails) -class GroupRenameType(bb.Struct): +class MemberChangeMembershipTypeType(bb.Struct): __slots__ = [ '_description_value', @@ -36163,24 +56215,22 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupRenameType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeMembershipTypeType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupRenameType(description={!r})'.format( + return 'MemberChangeMembershipTypeType(description={!r})'.format( self._description_value, ) -GroupRenameType_validator = bv.Struct(GroupRenameType) +MemberChangeMembershipTypeType_validator = bv.Struct(MemberChangeMembershipTypeType) -class GroupUserManagementChangePolicyDetails(bb.Struct): +class MemberChangeNameDetails(bb.Struct): """ - Changed who can create groups. + Changed team member name. - :ivar team_log.GroupUserManagementChangePolicyDetails.new_value: New group - users management policy. - :ivar team_log.GroupUserManagementChangePolicyDetails.previous_value: - Previous group users management policy. Might be missing due to - historical data gap. + :ivar team_log.MemberChangeNameDetails.new_value: New user's name. + :ivar team_log.MemberChangeNameDetails.previous_value: Previous user's name. + Might be missing due to historical data gap. """ __slots__ = [ @@ -36207,9 +56257,9 @@ def __init__(self, @property def new_value(self): """ - New group users management policy. + New user's name. - :rtype: team_policies.GroupCreation + :rtype: UserNameLogInfo """ if self._new_value_present: return self._new_value_value @@ -36230,10 +56280,9 @@ def new_value(self): @property def previous_value(self): """ - Previous group users management policy. Might be missing due to - historical data gap. + Previous user's name. Might be missing due to historical data gap. - :rtype: team_policies.GroupCreation + :rtype: UserNameLogInfo """ if self._previous_value_present: return self._previous_value_value @@ -36255,17 +56304,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupUserManagementChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeNameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupUserManagementChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'MemberChangeNameDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -GroupUserManagementChangePolicyDetails_validator = bv.Struct(GroupUserManagementChangePolicyDetails) +MemberChangeNameDetails_validator = bv.Struct(MemberChangeNameDetails) -class GroupUserManagementChangePolicyType(bb.Struct): +class MemberChangeNameType(bb.Struct): __slots__ = [ '_description_value', @@ -36303,169 +56352,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GroupUserManagementChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeNameType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GroupUserManagementChangePolicyType(description={!r})'.format( + return 'MemberChangeNameType(description={!r})'.format( self._description_value, ) -GroupUserManagementChangePolicyType_validator = bv.Struct(GroupUserManagementChangePolicyType) +MemberChangeNameType_validator = bv.Struct(MemberChangeNameType) -class GuestAdminChangeStatusDetails(bb.Struct): +class MemberChangeStatusDetails(bb.Struct): """ - Changed guest team admin status. + Changed member status (invited, joined, suspended, etc.). - :ivar team_log.GuestAdminChangeStatusDetails.is_guest: True for guest, false - for host. - :ivar team_log.GuestAdminChangeStatusDetails.guest_team_name: The name of - the guest team. - :ivar team_log.GuestAdminChangeStatusDetails.host_team_name: The name of the - host team. - :ivar team_log.GuestAdminChangeStatusDetails.previous_value: Previous - request state. - :ivar team_log.GuestAdminChangeStatusDetails.new_value: New request state. - :ivar team_log.GuestAdminChangeStatusDetails.action_details: Action details. + :ivar team_log.MemberChangeStatusDetails.previous_value: Previous member + status. Might be missing due to historical data gap. + :ivar team_log.MemberChangeStatusDetails.new_value: New member status. + :ivar team_log.MemberChangeStatusDetails.action: Additional information + indicating the action taken that caused status change. """ __slots__ = [ - '_is_guest_value', - '_is_guest_present', - '_guest_team_name_value', - '_guest_team_name_present', - '_host_team_name_value', - '_host_team_name_present', '_previous_value_value', '_previous_value_present', '_new_value_value', '_new_value_present', - '_action_details_value', - '_action_details_present', + '_action_value', + '_action_present', ] _has_required_fields = True def __init__(self, - is_guest=None, - previous_value=None, new_value=None, - action_details=None, - guest_team_name=None, - host_team_name=None): - self._is_guest_value = None - self._is_guest_present = False - self._guest_team_name_value = None - self._guest_team_name_present = False - self._host_team_name_value = None - self._host_team_name_present = False + previous_value=None, + action=None): self._previous_value_value = None self._previous_value_present = False self._new_value_value = None self._new_value_present = False - self._action_details_value = None - self._action_details_present = False - if is_guest is not None: - self.is_guest = is_guest - if guest_team_name is not None: - self.guest_team_name = guest_team_name - if host_team_name is not None: - self.host_team_name = host_team_name + self._action_value = None + self._action_present = False if previous_value is not None: self.previous_value = previous_value if new_value is not None: self.new_value = new_value - if action_details is not None: - self.action_details = action_details - - @property - def is_guest(self): - """ - True for guest, false for host. - - :rtype: bool - """ - if self._is_guest_present: - return self._is_guest_value - else: - raise AttributeError("missing required field 'is_guest'") - - @is_guest.setter - def is_guest(self, val): - val = self._is_guest_validator.validate(val) - self._is_guest_value = val - self._is_guest_present = True - - @is_guest.deleter - def is_guest(self): - self._is_guest_value = None - self._is_guest_present = False - - @property - def guest_team_name(self): - """ - The name of the guest team. - - :rtype: str - """ - if self._guest_team_name_present: - return self._guest_team_name_value - else: - return None - - @guest_team_name.setter - def guest_team_name(self, val): - if val is None: - del self.guest_team_name - return - val = self._guest_team_name_validator.validate(val) - self._guest_team_name_value = val - self._guest_team_name_present = True - - @guest_team_name.deleter - def guest_team_name(self): - self._guest_team_name_value = None - self._guest_team_name_present = False - - @property - def host_team_name(self): - """ - The name of the host team. - - :rtype: str - """ - if self._host_team_name_present: - return self._host_team_name_value - else: - return None - - @host_team_name.setter - def host_team_name(self, val): - if val is None: - del self.host_team_name - return - val = self._host_team_name_validator.validate(val) - self._host_team_name_value = val - self._host_team_name_present = True - - @host_team_name.deleter - def host_team_name(self): - self._host_team_name_value = None - self._host_team_name_present = False + if action is not None: + self.action = action @property def previous_value(self): """ - Previous request state. + Previous member status. Might be missing due to historical data gap. - :rtype: TrustedTeamsRequestState + :rtype: MemberStatus """ if self._previous_value_present: return self._previous_value_value else: - raise AttributeError("missing required field 'previous_value'") + return None @previous_value.setter def previous_value(self, val): + if val is None: + del self.previous_value + return self._previous_value_validator.validate_type_only(val) self._previous_value_value = val self._previous_value_present = True @@ -36478,9 +56429,9 @@ def previous_value(self): @property def new_value(self): """ - New request state. + New member status. - :rtype: TrustedTeamsRequestState + :rtype: MemberStatus """ if self._new_value_present: return self._new_value_value @@ -36499,44 +56450,45 @@ def new_value(self): self._new_value_present = False @property - def action_details(self): + def action(self): """ - Action details. + Additional information indicating the action taken that caused status + change. - :rtype: TrustedTeamsRequestAction + :rtype: ActionDetails """ - if self._action_details_present: - return self._action_details_value + if self._action_present: + return self._action_value else: - raise AttributeError("missing required field 'action_details'") + return None - @action_details.setter - def action_details(self, val): - self._action_details_validator.validate_type_only(val) - self._action_details_value = val - self._action_details_present = True + @action.setter + def action(self, val): + if val is None: + del self.action + return + self._action_validator.validate_type_only(val) + self._action_value = val + self._action_present = True - @action_details.deleter - def action_details(self): - self._action_details_value = None - self._action_details_present = False + @action.deleter + def action(self): + self._action_value = None + self._action_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GuestAdminChangeStatusDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeStatusDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GuestAdminChangeStatusDetails(is_guest={!r}, previous_value={!r}, new_value={!r}, action_details={!r}, guest_team_name={!r}, host_team_name={!r})'.format( - self._is_guest_value, - self._previous_value_value, + return 'MemberChangeStatusDetails(new_value={!r}, previous_value={!r}, action={!r})'.format( self._new_value_value, - self._action_details_value, - self._guest_team_name_value, - self._host_team_name_value, + self._previous_value_value, + self._action_value, ) -GuestAdminChangeStatusDetails_validator = bv.Struct(GuestAdminChangeStatusDetails) +MemberChangeStatusDetails_validator = bv.Struct(MemberChangeStatusDetails) -class GuestAdminChangeStatusType(bb.Struct): +class MemberChangeStatusType(bb.Struct): __slots__ = [ '_description_value', @@ -36574,110 +56526,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GuestAdminChangeStatusType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberChangeStatusType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GuestAdminChangeStatusType(description={!r})'.format( + return 'MemberChangeStatusType(description={!r})'.format( self._description_value, ) -GuestAdminChangeStatusType_validator = bv.Struct(GuestAdminChangeStatusType) +MemberChangeStatusType_validator = bv.Struct(MemberChangeStatusType) -class GuestAdminSignedInViaTrustedTeamsDetails(bb.Struct): +class MemberDeleteManualContactsDetails(bb.Struct): """ - Started trusted team admin session. - - :ivar team_log.GuestAdminSignedInViaTrustedTeamsDetails.team_name: Host team - name. - :ivar team_log.GuestAdminSignedInViaTrustedTeamsDetails.trusted_team_name: - Trusted team name. + Cleared manually added contacts. """ __slots__ = [ - '_team_name_value', - '_team_name_present', - '_trusted_team_name_value', - '_trusted_team_name_present', ] _has_required_fields = False - def __init__(self, - team_name=None, - trusted_team_name=None): - self._team_name_value = None - self._team_name_present = False - self._trusted_team_name_value = None - self._trusted_team_name_present = False - if team_name is not None: - self.team_name = team_name - if trusted_team_name is not None: - self.trusted_team_name = trusted_team_name - - @property - def team_name(self): - """ - Host team name. - - :rtype: str - """ - if self._team_name_present: - return self._team_name_value - else: - return None - - @team_name.setter - def team_name(self, val): - if val is None: - del self.team_name - return - val = self._team_name_validator.validate(val) - self._team_name_value = val - self._team_name_present = True - - @team_name.deleter - def team_name(self): - self._team_name_value = None - self._team_name_present = False - - @property - def trusted_team_name(self): - """ - Trusted team name. - - :rtype: str - """ - if self._trusted_team_name_present: - return self._trusted_team_name_value - else: - return None - - @trusted_team_name.setter - def trusted_team_name(self, val): - if val is None: - del self.trusted_team_name - return - val = self._trusted_team_name_validator.validate(val) - self._trusted_team_name_value = val - self._trusted_team_name_present = True - - @trusted_team_name.deleter - def trusted_team_name(self): - self._trusted_team_name_value = None - self._trusted_team_name_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GuestAdminSignedInViaTrustedTeamsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberDeleteManualContactsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GuestAdminSignedInViaTrustedTeamsDetails(team_name={!r}, trusted_team_name={!r})'.format( - self._team_name_value, - self._trusted_team_name_value, - ) + return 'MemberDeleteManualContactsDetails()' -GuestAdminSignedInViaTrustedTeamsDetails_validator = bv.Struct(GuestAdminSignedInViaTrustedTeamsDetails) +MemberDeleteManualContactsDetails_validator = bv.Struct(MemberDeleteManualContactsDetails) -class GuestAdminSignedInViaTrustedTeamsType(bb.Struct): +class MemberDeleteManualContactsType(bb.Struct): __slots__ = [ '_description_value', @@ -36715,110 +56594,105 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GuestAdminSignedInViaTrustedTeamsType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberDeleteManualContactsType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GuestAdminSignedInViaTrustedTeamsType(description={!r})'.format( + return 'MemberDeleteManualContactsType(description={!r})'.format( self._description_value, ) -GuestAdminSignedInViaTrustedTeamsType_validator = bv.Struct(GuestAdminSignedInViaTrustedTeamsType) +MemberDeleteManualContactsType_validator = bv.Struct(MemberDeleteManualContactsType) -class GuestAdminSignedOutViaTrustedTeamsDetails(bb.Struct): +class MemberDeleteProfilePhotoDetails(bb.Struct): """ - Ended trusted team admin session. - - :ivar team_log.GuestAdminSignedOutViaTrustedTeamsDetails.team_name: Host - team name. - :ivar team_log.GuestAdminSignedOutViaTrustedTeamsDetails.trusted_team_name: - Trusted team name. + Deleted team member profile photo. """ __slots__ = [ - '_team_name_value', - '_team_name_present', - '_trusted_team_name_value', - '_trusted_team_name_present', ] _has_required_fields = False - def __init__(self, - team_name=None, - trusted_team_name=None): - self._team_name_value = None - self._team_name_present = False - self._trusted_team_name_value = None - self._trusted_team_name_present = False - if team_name is not None: - self.team_name = team_name - if trusted_team_name is not None: - self.trusted_team_name = trusted_team_name + def __init__(self): + pass - @property - def team_name(self): - """ - Host team name. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberDeleteProfilePhotoDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: str - """ - if self._team_name_present: - return self._team_name_value - else: - return None + def __repr__(self): + return 'MemberDeleteProfilePhotoDetails()' - @team_name.setter - def team_name(self, val): - if val is None: - del self.team_name - return - val = self._team_name_validator.validate(val) - self._team_name_value = val - self._team_name_present = True +MemberDeleteProfilePhotoDetails_validator = bv.Struct(MemberDeleteProfilePhotoDetails) - @team_name.deleter - def team_name(self): - self._team_name_value = None - self._team_name_present = False +class MemberDeleteProfilePhotoType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def trusted_team_name(self): + def description(self): """ - Trusted team name. - :rtype: str """ - if self._trusted_team_name_present: - return self._trusted_team_name_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @trusted_team_name.setter - def trusted_team_name(self, val): - if val is None: - del self.trusted_team_name - return - val = self._trusted_team_name_validator.validate(val) - self._trusted_team_name_value = val - self._trusted_team_name_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @trusted_team_name.deleter - def trusted_team_name(self): - self._trusted_team_name_value = None - self._trusted_team_name_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GuestAdminSignedOutViaTrustedTeamsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberDeleteProfilePhotoType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GuestAdminSignedOutViaTrustedTeamsDetails(team_name={!r}, trusted_team_name={!r})'.format( - self._team_name_value, - self._trusted_team_name_value, + return 'MemberDeleteProfilePhotoType(description={!r})'.format( + self._description_value, ) -GuestAdminSignedOutViaTrustedTeamsDetails_validator = bv.Struct(GuestAdminSignedOutViaTrustedTeamsDetails) +MemberDeleteProfilePhotoType_validator = bv.Struct(MemberDeleteProfilePhotoType) -class GuestAdminSignedOutViaTrustedTeamsType(bb.Struct): +class MemberPermanentlyDeleteAccountContentsDetails(bb.Struct): + """ + Permanently deleted contents of deleted team member account. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberPermanentlyDeleteAccountContentsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberPermanentlyDeleteAccountContentsDetails()' + +MemberPermanentlyDeleteAccountContentsDetails_validator = bv.Struct(MemberPermanentlyDeleteAccountContentsDetails) + +class MemberPermanentlyDeleteAccountContentsType(bb.Struct): __slots__ = [ '_description_value', @@ -36856,16 +56730,16 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(GuestAdminSignedOutViaTrustedTeamsType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberPermanentlyDeleteAccountContentsType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'GuestAdminSignedOutViaTrustedTeamsType(description={!r})'.format( + return 'MemberPermanentlyDeleteAccountContentsType(description={!r})'.format( self._description_value, ) -GuestAdminSignedOutViaTrustedTeamsType_validator = bv.Struct(GuestAdminSignedOutViaTrustedTeamsType) +MemberPermanentlyDeleteAccountContentsType_validator = bv.Struct(MemberPermanentlyDeleteAccountContentsType) -class IdentifierType(bb.Union): +class MemberRemoveActionType(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the @@ -36874,27 +56748,47 @@ class IdentifierType(bb.Union): _catch_all = 'other' # Attribute is overwritten below the class definition - email = None + delete = None # Attribute is overwritten below the class definition - facebook_profile_name = None + offboard = None + # Attribute is overwritten below the class definition + leave = None + # Attribute is overwritten below the class definition + offboard_and_retain_team_folders = None # Attribute is overwritten below the class definition other = None - def is_email(self): + def is_delete(self): """ - Check if the union tag is ``email``. + Check if the union tag is ``delete``. :rtype: bool """ - return self._tag == 'email' + return self._tag == 'delete' - def is_facebook_profile_name(self): + def is_offboard(self): """ - Check if the union tag is ``facebook_profile_name``. + Check if the union tag is ``offboard``. :rtype: bool """ - return self._tag == 'facebook_profile_name' + return self._tag == 'offboard' + + def is_leave(self): + """ + Check if the union tag is ``leave``. + + :rtype: bool + """ + return self._tag == 'leave' + + def is_offboard_and_retain_team_folders(self): + """ + Check if the union tag is ``offboard_and_retain_team_folders``. + + :rtype: bool + """ + return self._tag == 'offboard_and_retain_team_folders' def is_other(self): """ @@ -36905,69 +56799,69 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IdentifierType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberRemoveActionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IdentifierType(%r, %r)' % (self._tag, self._value) + return 'MemberRemoveActionType(%r, %r)' % (self._tag, self._value) -IdentifierType_validator = bv.Union(IdentifierType) +MemberRemoveActionType_validator = bv.Union(MemberRemoveActionType) -class IntegrationConnectedDetails(bb.Struct): +class MemberRemoveExternalIdDetails(bb.Struct): """ - Connected integration for member. + Removed the external ID for team member. - :ivar team_log.IntegrationConnectedDetails.integration_name: Name of the - third-party integration. + :ivar team_log.MemberRemoveExternalIdDetails.previous_value: Old external + id. """ __slots__ = [ - '_integration_name_value', - '_integration_name_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - integration_name=None): - self._integration_name_value = None - self._integration_name_present = False - if integration_name is not None: - self.integration_name = integration_name + previous_value=None): + self._previous_value_value = None + self._previous_value_present = False + if previous_value is not None: + self.previous_value = previous_value @property - def integration_name(self): + def previous_value(self): """ - Name of the third-party integration. + Old external id. :rtype: str """ - if self._integration_name_present: - return self._integration_name_value + if self._previous_value_present: + return self._previous_value_value else: - raise AttributeError("missing required field 'integration_name'") + raise AttributeError("missing required field 'previous_value'") - @integration_name.setter - def integration_name(self, val): - val = self._integration_name_validator.validate(val) - self._integration_name_value = val - self._integration_name_present = True + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - @integration_name.deleter - def integration_name(self): - self._integration_name_value = None - self._integration_name_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IntegrationConnectedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberRemoveExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IntegrationConnectedDetails(integration_name={!r})'.format( - self._integration_name_value, + return 'MemberRemoveExternalIdDetails(previous_value={!r})'.format( + self._previous_value_value, ) -IntegrationConnectedDetails_validator = bv.Struct(IntegrationConnectedDetails) +MemberRemoveExternalIdDetails_validator = bv.Struct(MemberRemoveExternalIdDetails) -class IntegrationConnectedType(bb.Struct): +class MemberRemoveExternalIdType(bb.Struct): __slots__ = [ '_description_value', @@ -37005,71 +56899,109 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IntegrationConnectedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberRemoveExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IntegrationConnectedType(description={!r})'.format( + return 'MemberRemoveExternalIdType(description={!r})'.format( self._description_value, ) -IntegrationConnectedType_validator = bv.Struct(IntegrationConnectedType) +MemberRemoveExternalIdType_validator = bv.Struct(MemberRemoveExternalIdType) -class IntegrationDisconnectedDetails(bb.Struct): +class MemberRequestsChangePolicyDetails(bb.Struct): """ - Disconnected integration for member. + Changed whether users can find team when not invited. - :ivar team_log.IntegrationDisconnectedDetails.integration_name: Name of the - third-party integration. + :ivar team_log.MemberRequestsChangePolicyDetails.new_value: New member + change requests policy. + :ivar team_log.MemberRequestsChangePolicyDetails.previous_value: Previous + member change requests policy. Might be missing due to historical data + gap. """ __slots__ = [ - '_integration_name_value', - '_integration_name_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - integration_name=None): - self._integration_name_value = None - self._integration_name_present = False - if integration_name is not None: - self.integration_name = integration_name + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def integration_name(self): + def new_value(self): """ - Name of the third-party integration. + New member change requests policy. - :rtype: str + :rtype: MemberRequestsPolicy """ - if self._integration_name_present: - return self._integration_name_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'integration_name'") + raise AttributeError("missing required field 'new_value'") - @integration_name.setter - def integration_name(self, val): - val = self._integration_name_validator.validate(val) - self._integration_name_value = val - self._integration_name_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @integration_name.deleter - def integration_name(self): - self._integration_name_value = None - self._integration_name_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous member change requests policy. Might be missing due to + historical data gap. + + :rtype: MemberRequestsPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IntegrationDisconnectedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberRequestsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IntegrationDisconnectedDetails(integration_name={!r})'.format( - self._integration_name_value, + return 'MemberRequestsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -IntegrationDisconnectedDetails_validator = bv.Struct(IntegrationDisconnectedDetails) +MemberRequestsChangePolicyDetails_validator = bv.Struct(MemberRequestsChangePolicyDetails) -class IntegrationDisconnectedType(bb.Struct): +class MemberRequestsChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -37107,19 +57039,75 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IntegrationDisconnectedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberRequestsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IntegrationDisconnectedType(description={!r})'.format( + return 'MemberRequestsChangePolicyType(description={!r})'.format( self._description_value, ) -IntegrationDisconnectedType_validator = bv.Struct(IntegrationDisconnectedType) +MemberRequestsChangePolicyType_validator = bv.Struct(MemberRequestsChangePolicyType) -class IntegrationPolicy(bb.Union): +class MemberRequestsPolicy(bb.Union): """ - Policy for controlling whether a service integration is enabled for the - team. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + auto_accept = None + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + require_approval = None + # Attribute is overwritten below the class definition + other = None + + def is_auto_accept(self): + """ + Check if the union tag is ``auto_accept``. + + :rtype: bool + """ + return self._tag == 'auto_accept' + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_require_approval(self): + """ + Check if the union tag is ``require_approval``. + + :rtype: bool + """ + return self._tag == 'require_approval' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberRequestsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberRequestsPolicy(%r, %r)' % (self._tag, self._value) + +MemberRequestsPolicy_validator = bv.Union(MemberRequestsPolicy) + +class MemberSendInvitePolicy(bb.Union): + """ + Policy for controlling whether team members can send team invites This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the @@ -37130,7 +57118,9 @@ class IntegrationPolicy(bb.Union): # Attribute is overwritten below the class definition disabled = None # Attribute is overwritten below the class definition - enabled = None + specific_members = None + # Attribute is overwritten below the class definition + everyone = None # Attribute is overwritten below the class definition other = None @@ -37142,13 +57132,21 @@ def is_disabled(self): """ return self._tag == 'disabled' - def is_enabled(self): + def is_specific_members(self): """ - Check if the union tag is ``enabled``. + Check if the union tag is ``specific_members``. :rtype: bool """ - return self._tag == 'enabled' + return self._tag == 'specific_members' + + def is_everyone(self): + """ + Check if the union tag is ``everyone``. + + :rtype: bool + """ + return self._tag == 'everyone' def is_other(self): """ @@ -37159,28 +57157,24 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IntegrationPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSendInvitePolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IntegrationPolicy(%r, %r)' % (self._tag, self._value) + return 'MemberSendInvitePolicy(%r, %r)' % (self._tag, self._value) -IntegrationPolicy_validator = bv.Union(IntegrationPolicy) +MemberSendInvitePolicy_validator = bv.Union(MemberSendInvitePolicy) -class IntegrationPolicyChangedDetails(bb.Struct): +class MemberSendInvitePolicyChangedDetails(bb.Struct): """ - Changed integration policy for team. + Changed member send invite policy for team. - :ivar team_log.IntegrationPolicyChangedDetails.integration_name: Name of the - third-party integration. - :ivar team_log.IntegrationPolicyChangedDetails.new_value: New integration - policy. - :ivar team_log.IntegrationPolicyChangedDetails.previous_value: Previous - integration policy. + :ivar team_log.MemberSendInvitePolicyChangedDetails.new_value: New team + member send invite policy. + :ivar team_log.MemberSendInvitePolicyChangedDetails.previous_value: Previous + team member send invite policy. """ __slots__ = [ - '_integration_name_value', - '_integration_name_present', '_new_value_value', '_new_value_present', '_previous_value_value', @@ -37190,51 +57184,23 @@ class IntegrationPolicyChangedDetails(bb.Struct): _has_required_fields = True def __init__(self, - integration_name=None, new_value=None, previous_value=None): - self._integration_name_value = None - self._integration_name_present = False self._new_value_value = None self._new_value_present = False self._previous_value_value = None self._previous_value_present = False - if integration_name is not None: - self.integration_name = integration_name if new_value is not None: self.new_value = new_value if previous_value is not None: self.previous_value = previous_value - @property - def integration_name(self): - """ - Name of the third-party integration. - - :rtype: str - """ - if self._integration_name_present: - return self._integration_name_value - else: - raise AttributeError("missing required field 'integration_name'") - - @integration_name.setter - def integration_name(self, val): - val = self._integration_name_validator.validate(val) - self._integration_name_value = val - self._integration_name_present = True - - @integration_name.deleter - def integration_name(self): - self._integration_name_value = None - self._integration_name_present = False - @property def new_value(self): """ - New integration policy. + New team member send invite policy. - :rtype: IntegrationPolicy + :rtype: MemberSendInvitePolicy """ if self._new_value_present: return self._new_value_value @@ -37255,9 +57221,9 @@ def new_value(self): @property def previous_value(self): """ - Previous integration policy. + Previous team member send invite policy. - :rtype: IntegrationPolicy + :rtype: MemberSendInvitePolicy """ if self._previous_value_present: return self._previous_value_value @@ -37276,18 +57242,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IntegrationPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSendInvitePolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IntegrationPolicyChangedDetails(integration_name={!r}, new_value={!r}, previous_value={!r})'.format( - self._integration_name_value, + return 'MemberSendInvitePolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -IntegrationPolicyChangedDetails_validator = bv.Struct(IntegrationPolicyChangedDetails) +MemberSendInvitePolicyChangedDetails_validator = bv.Struct(MemberSendInvitePolicyChangedDetails) -class IntegrationPolicyChangedType(bb.Struct): +class MemberSendInvitePolicyChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -37325,781 +57290,622 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(IntegrationPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSendInvitePolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'IntegrationPolicyChangedType(description={!r})'.format( + return 'MemberSendInvitePolicyChangedType(description={!r})'.format( self._description_value, ) -IntegrationPolicyChangedType_validator = bv.Struct(IntegrationPolicyChangedType) +MemberSendInvitePolicyChangedType_validator = bv.Struct(MemberSendInvitePolicyChangedType) -class JoinTeamDetails(bb.Struct): +class MemberSetProfilePhotoDetails(bb.Struct): """ - Additional information relevant when a new member joins the team. - - :ivar team_log.JoinTeamDetails.linked_apps: Linked applications. - :ivar team_log.JoinTeamDetails.linked_devices: Linked devices. - :ivar team_log.JoinTeamDetails.linked_shared_folders: Linked shared folders. + Set team member profile photo. """ __slots__ = [ - '_linked_apps_value', - '_linked_apps_present', - '_linked_devices_value', - '_linked_devices_present', - '_linked_shared_folders_value', - '_linked_shared_folders_present', ] - _has_required_fields = True - - def __init__(self, - linked_apps=None, - linked_devices=None, - linked_shared_folders=None): - self._linked_apps_value = None - self._linked_apps_present = False - self._linked_devices_value = None - self._linked_devices_present = False - self._linked_shared_folders_value = None - self._linked_shared_folders_present = False - if linked_apps is not None: - self.linked_apps = linked_apps - if linked_devices is not None: - self.linked_devices = linked_devices - if linked_shared_folders is not None: - self.linked_shared_folders = linked_shared_folders + _has_required_fields = False - @property - def linked_apps(self): - """ - Linked applications. + def __init__(self): + pass - :rtype: list of [UserLinkedAppLogInfo] - """ - if self._linked_apps_present: - return self._linked_apps_value - else: - raise AttributeError("missing required field 'linked_apps'") + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSetProfilePhotoDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @linked_apps.setter - def linked_apps(self, val): - val = self._linked_apps_validator.validate(val) - self._linked_apps_value = val - self._linked_apps_present = True + def __repr__(self): + return 'MemberSetProfilePhotoDetails()' - @linked_apps.deleter - def linked_apps(self): - self._linked_apps_value = None - self._linked_apps_present = False +MemberSetProfilePhotoDetails_validator = bv.Struct(MemberSetProfilePhotoDetails) - @property - def linked_devices(self): - """ - Linked devices. +class MemberSetProfilePhotoType(bb.Struct): - :rtype: list of [LinkedDeviceLogInfo] - """ - if self._linked_devices_present: - return self._linked_devices_value - else: - raise AttributeError("missing required field 'linked_devices'") + __slots__ = [ + '_description_value', + '_description_present', + ] - @linked_devices.setter - def linked_devices(self, val): - val = self._linked_devices_validator.validate(val) - self._linked_devices_value = val - self._linked_devices_present = True + _has_required_fields = True - @linked_devices.deleter - def linked_devices(self): - self._linked_devices_value = None - self._linked_devices_present = False + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def linked_shared_folders(self): + def description(self): """ - Linked shared folders. - - :rtype: list of [FolderLogInfo] + :rtype: str """ - if self._linked_shared_folders_present: - return self._linked_shared_folders_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'linked_shared_folders'") + raise AttributeError("missing required field 'description'") - @linked_shared_folders.setter - def linked_shared_folders(self, val): - val = self._linked_shared_folders_validator.validate(val) - self._linked_shared_folders_value = val - self._linked_shared_folders_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @linked_shared_folders.deleter - def linked_shared_folders(self): - self._linked_shared_folders_value = None - self._linked_shared_folders_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(JoinTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSetProfilePhotoType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'JoinTeamDetails(linked_apps={!r}, linked_devices={!r}, linked_shared_folders={!r})'.format( - self._linked_apps_value, - self._linked_devices_value, - self._linked_shared_folders_value, + return 'MemberSetProfilePhotoType(description={!r})'.format( + self._description_value, ) -JoinTeamDetails_validator = bv.Struct(JoinTeamDetails) +MemberSetProfilePhotoType_validator = bv.Struct(MemberSetProfilePhotoType) -class LegacyDeviceSessionLogInfo(DeviceSessionLogInfo): +class MemberSpaceLimitsAddCustomQuotaDetails(bb.Struct): """ - Information on sessions, in legacy format + Set custom member space limit. - :ivar team_log.LegacyDeviceSessionLogInfo.session_info: Session unique id. - Might be missing due to historical data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.display_name: The device name. - Might be missing due to historical data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.is_emm_managed: Is device managed - by emm. Might be missing due to historical data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.platform: Information on the - hosting platform. Might be missing due to historical data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.mac_address: The mac address of - the last activity from this session. Might be missing due to historical - data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.os_version: The hosting OS - version. Might be missing due to historical data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.device_type: Information on the - hosting device type. Might be missing due to historical data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.client_version: The Dropbox client - version. Might be missing due to historical data gap. - :ivar team_log.LegacyDeviceSessionLogInfo.legacy_uniq_id: Alternative unique - device session id, instead of session id field. Might be missing due to - historical data gap. + :ivar team_log.MemberSpaceLimitsAddCustomQuotaDetails.new_value: New custom + quota value in bytes. """ __slots__ = [ - '_session_info_value', - '_session_info_present', - '_display_name_value', - '_display_name_present', - '_is_emm_managed_value', - '_is_emm_managed_present', - '_platform_value', - '_platform_present', - '_mac_address_value', - '_mac_address_present', - '_os_version_value', - '_os_version_present', - '_device_type_value', - '_device_type_present', - '_client_version_value', - '_client_version_present', - '_legacy_uniq_id_value', - '_legacy_uniq_id_present', + '_new_value_value', + '_new_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - ip_address=None, - created=None, - updated=None, - session_info=None, - display_name=None, - is_emm_managed=None, - platform=None, - mac_address=None, - os_version=None, - device_type=None, - client_version=None, - legacy_uniq_id=None): - super(LegacyDeviceSessionLogInfo, self).__init__(ip_address, - created, - updated) - self._session_info_value = None - self._session_info_present = False - self._display_name_value = None - self._display_name_present = False - self._is_emm_managed_value = None - self._is_emm_managed_present = False - self._platform_value = None - self._platform_present = False - self._mac_address_value = None - self._mac_address_present = False - self._os_version_value = None - self._os_version_present = False - self._device_type_value = None - self._device_type_present = False - self._client_version_value = None - self._client_version_present = False - self._legacy_uniq_id_value = None - self._legacy_uniq_id_present = False - if session_info is not None: - self.session_info = session_info - if display_name is not None: - self.display_name = display_name - if is_emm_managed is not None: - self.is_emm_managed = is_emm_managed - if platform is not None: - self.platform = platform - if mac_address is not None: - self.mac_address = mac_address - if os_version is not None: - self.os_version = os_version - if device_type is not None: - self.device_type = device_type - if client_version is not None: - self.client_version = client_version - if legacy_uniq_id is not None: - self.legacy_uniq_id = legacy_uniq_id + new_value=None): + self._new_value_value = None + self._new_value_present = False + if new_value is not None: + self.new_value = new_value @property - def session_info(self): + def new_value(self): """ - Session unique id. Might be missing due to historical data gap. + New custom quota value in bytes. - :rtype: SessionLogInfo + :rtype: int """ - if self._session_info_present: - return self._session_info_value + if self._new_value_present: + return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") - @session_info.setter - def session_info(self, val): - if val is None: - del self.session_info - return - self._session_info_validator.validate_type_only(val) - self._session_info_value = val - self._session_info_present = True + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @session_info.deleter - def session_info(self): - self._session_info_value = None - self._session_info_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsAddCustomQuotaDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberSpaceLimitsAddCustomQuotaDetails(new_value={!r})'.format( + self._new_value_value, + ) + +MemberSpaceLimitsAddCustomQuotaDetails_validator = bv.Struct(MemberSpaceLimitsAddCustomQuotaDetails) + +class MemberSpaceLimitsAddCustomQuotaType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def display_name(self): + def description(self): """ - The device name. Might be missing due to historical data gap. - :rtype: str """ - if self._display_name_present: - return self._display_name_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @display_name.setter - def display_name(self, val): - if val is None: - del self.display_name - return - val = self._display_name_validator.validate(val) - self._display_name_value = val - self._display_name_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @display_name.deleter - def display_name(self): - self._display_name_value = None - self._display_name_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @property - def is_emm_managed(self): - """ - Is device managed by emm. Might be missing due to historical data gap. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsAddCustomQuotaType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - if self._is_emm_managed_present: - return self._is_emm_managed_value - else: - return None + def __repr__(self): + return 'MemberSpaceLimitsAddCustomQuotaType(description={!r})'.format( + self._description_value, + ) - @is_emm_managed.setter - def is_emm_managed(self, val): - if val is None: - del self.is_emm_managed - return - val = self._is_emm_managed_validator.validate(val) - self._is_emm_managed_value = val - self._is_emm_managed_present = True +MemberSpaceLimitsAddCustomQuotaType_validator = bv.Struct(MemberSpaceLimitsAddCustomQuotaType) - @is_emm_managed.deleter - def is_emm_managed(self): - self._is_emm_managed_value = None - self._is_emm_managed_present = False +class MemberSpaceLimitsAddExceptionDetails(bb.Struct): + """ + Added members to member space limit exception list. + """ - @property - def platform(self): - """ - Information on the hosting platform. Might be missing due to historical - data gap. + __slots__ = [ + ] - :rtype: str - """ - if self._platform_present: - return self._platform_value - else: - return None + _has_required_fields = False - @platform.setter - def platform(self, val): - if val is None: - del self.platform - return - val = self._platform_validator.validate(val) - self._platform_value = val - self._platform_present = True + def __init__(self): + pass - @platform.deleter - def platform(self): - self._platform_value = None - self._platform_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsAddExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - @property - def mac_address(self): - """ - The mac address of the last activity from this session. Might be missing - due to historical data gap. + def __repr__(self): + return 'MemberSpaceLimitsAddExceptionDetails()' - :rtype: str - """ - if self._mac_address_present: - return self._mac_address_value - else: - return None +MemberSpaceLimitsAddExceptionDetails_validator = bv.Struct(MemberSpaceLimitsAddExceptionDetails) - @mac_address.setter - def mac_address(self, val): - if val is None: - del self.mac_address - return - val = self._mac_address_validator.validate(val) - self._mac_address_value = val - self._mac_address_present = True +class MemberSpaceLimitsAddExceptionType(bb.Struct): - @mac_address.deleter - def mac_address(self): - self._mac_address_value = None - self._mac_address_present = False + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def os_version(self): + def description(self): """ - The hosting OS version. Might be missing due to historical data gap. - :rtype: str """ - if self._os_version_present: - return self._os_version_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @os_version.setter - def os_version(self, val): - if val is None: - del self.os_version - return - val = self._os_version_validator.validate(val) - self._os_version_value = val - self._os_version_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @os_version.deleter - def os_version(self): - self._os_version_value = None - self._os_version_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @property - def device_type(self): - """ - Information on the hosting device type. Might be missing due to - historical data gap. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsAddExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: str - """ - if self._device_type_present: - return self._device_type_value - else: - return None + def __repr__(self): + return 'MemberSpaceLimitsAddExceptionType(description={!r})'.format( + self._description_value, + ) - @device_type.setter - def device_type(self, val): - if val is None: - del self.device_type - return - val = self._device_type_validator.validate(val) - self._device_type_value = val - self._device_type_present = True +MemberSpaceLimitsAddExceptionType_validator = bv.Struct(MemberSpaceLimitsAddExceptionType) - @device_type.deleter - def device_type(self): - self._device_type_value = None - self._device_type_present = False +class MemberSpaceLimitsChangeCapsTypePolicyDetails(bb.Struct): + """ + Changed member space limit type for team. + + :ivar team_log.MemberSpaceLimitsChangeCapsTypePolicyDetails.previous_value: + Previous space limit type. + :ivar team_log.MemberSpaceLimitsChangeCapsTypePolicyDetails.new_value: New + space limit type. + """ + + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] + + _has_required_fields = True + + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def client_version(self): + def previous_value(self): """ - The Dropbox client version. Might be missing due to historical data gap. + Previous space limit type. - :rtype: str + :rtype: SpaceCapsType """ - if self._client_version_present: - return self._client_version_value + if self._previous_value_present: + return self._previous_value_value else: - return None + raise AttributeError("missing required field 'previous_value'") - @client_version.setter - def client_version(self, val): - if val is None: - del self.client_version - return - val = self._client_version_validator.validate(val) - self._client_version_value = val - self._client_version_present = True + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @client_version.deleter - def client_version(self): - self._client_version_value = None - self._client_version_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property - def legacy_uniq_id(self): + def new_value(self): """ - Alternative unique device session id, instead of session id field. Might - be missing due to historical data gap. + New space limit type. - :rtype: str + :rtype: SpaceCapsType """ - if self._legacy_uniq_id_present: - return self._legacy_uniq_id_value + if self._new_value_present: + return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") - @legacy_uniq_id.setter - def legacy_uniq_id(self, val): - if val is None: - del self.legacy_uniq_id - return - val = self._legacy_uniq_id_validator.validate(val) - self._legacy_uniq_id_value = val - self._legacy_uniq_id_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @legacy_uniq_id.deleter - def legacy_uniq_id(self): - self._legacy_uniq_id_value = None - self._legacy_uniq_id_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LegacyDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSpaceLimitsChangeCapsTypePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LegacyDeviceSessionLogInfo(ip_address={!r}, created={!r}, updated={!r}, session_info={!r}, display_name={!r}, is_emm_managed={!r}, platform={!r}, mac_address={!r}, os_version={!r}, device_type={!r}, client_version={!r}, legacy_uniq_id={!r})'.format( - self._ip_address_value, - self._created_value, - self._updated_value, - self._session_info_value, - self._display_name_value, - self._is_emm_managed_value, - self._platform_value, - self._mac_address_value, - self._os_version_value, - self._device_type_value, - self._client_version_value, - self._legacy_uniq_id_value, + return 'MemberSpaceLimitsChangeCapsTypePolicyDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, ) -LegacyDeviceSessionLogInfo_validator = bv.Struct(LegacyDeviceSessionLogInfo) +MemberSpaceLimitsChangeCapsTypePolicyDetails_validator = bv.Struct(MemberSpaceLimitsChangeCapsTypePolicyDetails) -class LinkedDeviceLogInfo(bb.Union): - """ - The device sessions that user is linked to. +class MemberSpaceLimitsChangeCapsTypePolicyType(bb.Struct): - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + __slots__ = [ + '_description_value', + '_description_present', + ] - :ivar MobileDeviceSessionLogInfo LinkedDeviceLogInfo.mobile_device_session: - mobile device session's details. - :ivar DesktopDeviceSessionLogInfo - LinkedDeviceLogInfo.desktop_device_session: desktop device session's - details. - :ivar WebDeviceSessionLogInfo LinkedDeviceLogInfo.web_device_session: web - device session's details. - :ivar LegacyDeviceSessionLogInfo LinkedDeviceLogInfo.legacy_device_session: - legacy device session's details. - """ + _has_required_fields = True - _catch_all = 'other' - # Attribute is overwritten below the class definition - other = None + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - @classmethod - def mobile_device_session(cls, val): + @property + def description(self): """ - Create an instance of this class set to the ``mobile_device_session`` - tag with value ``val``. - - :param MobileDeviceSessionLogInfo val: - :rtype: LinkedDeviceLogInfo + :rtype: str """ - return cls('mobile_device_session', val) + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - @classmethod - def desktop_device_session(cls, val): - """ - Create an instance of this class set to the ``desktop_device_session`` - tag with value ``val``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :param DesktopDeviceSessionLogInfo val: - :rtype: LinkedDeviceLogInfo - """ - return cls('desktop_device_session', val) + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @classmethod - def web_device_session(cls, val): - """ - Create an instance of this class set to the ``web_device_session`` tag - with value ``val``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsChangeCapsTypePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) - :param WebDeviceSessionLogInfo val: - :rtype: LinkedDeviceLogInfo - """ - return cls('web_device_session', val) + def __repr__(self): + return 'MemberSpaceLimitsChangeCapsTypePolicyType(description={!r})'.format( + self._description_value, + ) - @classmethod - def legacy_device_session(cls, val): - """ - Create an instance of this class set to the ``legacy_device_session`` - tag with value ``val``. +MemberSpaceLimitsChangeCapsTypePolicyType_validator = bv.Struct(MemberSpaceLimitsChangeCapsTypePolicyType) - :param LegacyDeviceSessionLogInfo val: - :rtype: LinkedDeviceLogInfo - """ - return cls('legacy_device_session', val) +class MemberSpaceLimitsChangeCustomQuotaDetails(bb.Struct): + """ + Changed custom member space limit. - def is_mobile_device_session(self): - """ - Check if the union tag is ``mobile_device_session``. + :ivar team_log.MemberSpaceLimitsChangeCustomQuotaDetails.previous_value: + Previous custom quota value in bytes. + :ivar team_log.MemberSpaceLimitsChangeCustomQuotaDetails.new_value: New + custom quota value in bytes. + """ - :rtype: bool - """ - return self._tag == 'mobile_device_session' + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] - def is_desktop_device_session(self): - """ - Check if the union tag is ``desktop_device_session``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'desktop_device_session' + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value - def is_web_device_session(self): + @property + def previous_value(self): """ - Check if the union tag is ``web_device_session``. + Previous custom quota value in bytes. - :rtype: bool + :rtype: int """ - return self._tag == 'web_device_session' + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - def is_legacy_device_session(self): - """ - Check if the union tag is ``legacy_device_session``. + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - :rtype: bool + @property + def new_value(self): """ - return self._tag == 'legacy_device_session' + New custom quota value in bytes. - def is_other(self): + :rtype: int """ - Check if the union tag is ``other``. + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - :rtype: bool - """ - return self._tag == 'other' + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - def get_mobile_device_session(self): - """ - mobile device session's details. + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - Only call this if :meth:`is_mobile_device_session` is true. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsChangeCustomQuotaDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: MobileDeviceSessionLogInfo - """ - if not self.is_mobile_device_session(): - raise AttributeError("tag 'mobile_device_session' not set") - return self._value + def __repr__(self): + return 'MemberSpaceLimitsChangeCustomQuotaDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, + ) - def get_desktop_device_session(self): - """ - desktop device session's details. +MemberSpaceLimitsChangeCustomQuotaDetails_validator = bv.Struct(MemberSpaceLimitsChangeCustomQuotaDetails) - Only call this if :meth:`is_desktop_device_session` is true. +class MemberSpaceLimitsChangeCustomQuotaType(bb.Struct): - :rtype: DesktopDeviceSessionLogInfo - """ - if not self.is_desktop_device_session(): - raise AttributeError("tag 'desktop_device_session' not set") - return self._value + __slots__ = [ + '_description_value', + '_description_present', + ] - def get_web_device_session(self): - """ - web device session's details. + _has_required_fields = True - Only call this if :meth:`is_web_device_session` is true. + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - :rtype: WebDeviceSessionLogInfo + @property + def description(self): """ - if not self.is_web_device_session(): - raise AttributeError("tag 'web_device_session' not set") - return self._value - - def get_legacy_device_session(self): + :rtype: str """ - legacy device session's details. + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - Only call this if :meth:`is_legacy_device_session` is true. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: LegacyDeviceSessionLogInfo - """ - if not self.is_legacy_device_session(): - raise AttributeError("tag 'legacy_device_session' not set") - return self._value + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LinkedDeviceLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSpaceLimitsChangeCustomQuotaType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LinkedDeviceLogInfo(%r, %r)' % (self._tag, self._value) + return 'MemberSpaceLimitsChangeCustomQuotaType(description={!r})'.format( + self._description_value, + ) -LinkedDeviceLogInfo_validator = bv.Union(LinkedDeviceLogInfo) +MemberSpaceLimitsChangeCustomQuotaType_validator = bv.Struct(MemberSpaceLimitsChangeCustomQuotaType) -class LoginFailDetails(bb.Struct): +class MemberSpaceLimitsChangePolicyDetails(bb.Struct): """ - Failed to sign in. + Changed team default member space limit. - :ivar team_log.LoginFailDetails.is_emm_managed: Tells if the login device is - EMM managed. Might be missing due to historical data gap. - :ivar team_log.LoginFailDetails.login_method: Login method. - :ivar team_log.LoginFailDetails.error_details: Error details. + :ivar team_log.MemberSpaceLimitsChangePolicyDetails.previous_value: Previous + team default limit value in bytes. Might be missing due to historical + data gap. + :ivar team_log.MemberSpaceLimitsChangePolicyDetails.new_value: New team + default limit value in bytes. Might be missing due to historical data + gap. """ __slots__ = [ - '_is_emm_managed_value', - '_is_emm_managed_present', - '_login_method_value', - '_login_method_present', - '_error_details_value', - '_error_details_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - login_method=None, - error_details=None, - is_emm_managed=None): - self._is_emm_managed_value = None - self._is_emm_managed_present = False - self._login_method_value = None - self._login_method_present = False - self._error_details_value = None - self._error_details_present = False - if is_emm_managed is not None: - self.is_emm_managed = is_emm_managed - if login_method is not None: - self.login_method = login_method - if error_details is not None: - self.error_details = error_details + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def is_emm_managed(self): + def previous_value(self): """ - Tells if the login device is EMM managed. Might be missing due to + Previous team default limit value in bytes. Might be missing due to historical data gap. - :rtype: bool + :rtype: int """ - if self._is_emm_managed_present: - return self._is_emm_managed_value + if self._previous_value_present: + return self._previous_value_value else: return None - @is_emm_managed.setter - def is_emm_managed(self, val): + @previous_value.setter + def previous_value(self, val): if val is None: - del self.is_emm_managed + del self.previous_value return - val = self._is_emm_managed_validator.validate(val) - self._is_emm_managed_value = val - self._is_emm_managed_present = True - - @is_emm_managed.deleter - def is_emm_managed(self): - self._is_emm_managed_value = None - self._is_emm_managed_present = False - - @property - def login_method(self): - """ - Login method. - - :rtype: LoginMethod - """ - if self._login_method_present: - return self._login_method_value - else: - raise AttributeError("missing required field 'login_method'") - - @login_method.setter - def login_method(self, val): - self._login_method_validator.validate_type_only(val) - self._login_method_value = val - self._login_method_present = True + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - @login_method.deleter - def login_method(self): - self._login_method_value = None - self._login_method_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property - def error_details(self): + def new_value(self): """ - Error details. + New team default limit value in bytes. Might be missing due to + historical data gap. - :rtype: FailureDetailsLogInfo + :rtype: int """ - if self._error_details_present: - return self._error_details_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'error_details'") + return None - @error_details.setter - def error_details(self, val): - self._error_details_validator.validate_type_only(val) - self._error_details_value = val - self._error_details_present = True + @new_value.setter + def new_value(self, val): + if val is None: + del self.new_value + return + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @error_details.deleter - def error_details(self): - self._error_details_value = None - self._error_details_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LoginFailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSpaceLimitsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LoginFailDetails(login_method={!r}, error_details={!r}, is_emm_managed={!r})'.format( - self._login_method_value, - self._error_details_value, - self._is_emm_managed_value, + return 'MemberSpaceLimitsChangePolicyDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, ) -LoginFailDetails_validator = bv.Struct(LoginFailDetails) +MemberSpaceLimitsChangePolicyDetails_validator = bv.Struct(MemberSpaceLimitsChangePolicyDetails) -class LoginFailType(bb.Struct): +class MemberSpaceLimitsChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -38137,174 +57943,240 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LoginFailType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSpaceLimitsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LoginFailType(description={!r})'.format( + return 'MemberSpaceLimitsChangePolicyType(description={!r})'.format( self._description_value, ) -LoginFailType_validator = bv.Struct(LoginFailType) +MemberSpaceLimitsChangePolicyType_validator = bv.Struct(MemberSpaceLimitsChangePolicyType) -class LoginMethod(bb.Union): +class MemberSpaceLimitsChangeStatusDetails(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Changed space limit status. + + :ivar team_log.MemberSpaceLimitsChangeStatusDetails.previous_value: Previous + storage quota status. + :ivar team_log.MemberSpaceLimitsChangeStatusDetails.new_value: New storage + quota status. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - password = None - # Attribute is overwritten below the class definition - two_factor_authentication = None - # Attribute is overwritten below the class definition - saml = None - # Attribute is overwritten below the class definition - google_oauth = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] - def is_password(self): - """ - Check if the union tag is ``password``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'password' + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value - def is_two_factor_authentication(self): + @property + def previous_value(self): """ - Check if the union tag is ``two_factor_authentication``. + Previous storage quota status. - :rtype: bool + :rtype: SpaceLimitsStatus """ - return self._tag == 'two_factor_authentication' + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") - def is_saml(self): - """ - Check if the union tag is ``saml``. + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - :rtype: bool - """ - return self._tag == 'saml' + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False - def is_google_oauth(self): + @property + def new_value(self): """ - Check if the union tag is ``google_oauth``. + New storage quota status. - :rtype: bool + :rtype: SpaceLimitsStatus """ - return self._tag == 'google_oauth' + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - def is_other(self): - """ - Check if the union tag is ``other``. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - :rtype: bool + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsChangeStatusDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberSpaceLimitsChangeStatusDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, + ) + +MemberSpaceLimitsChangeStatusDetails_validator = bv.Struct(MemberSpaceLimitsChangeStatusDetails) + +class MemberSpaceLimitsChangeStatusType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - return self._tag == 'other' + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LoginMethod, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSpaceLimitsChangeStatusType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LoginMethod(%r, %r)' % (self._tag, self._value) + return 'MemberSpaceLimitsChangeStatusType(description={!r})'.format( + self._description_value, + ) -LoginMethod_validator = bv.Union(LoginMethod) +MemberSpaceLimitsChangeStatusType_validator = bv.Struct(MemberSpaceLimitsChangeStatusType) -class LoginSuccessDetails(bb.Struct): +class MemberSpaceLimitsRemoveCustomQuotaDetails(bb.Struct): """ - Signed in. - - :ivar team_log.LoginSuccessDetails.is_emm_managed: Tells if the login device - is EMM managed. Might be missing due to historical data gap. - :ivar team_log.LoginSuccessDetails.login_method: Login method. + Removed custom member space limit. """ __slots__ = [ - '_is_emm_managed_value', - '_is_emm_managed_present', - '_login_method_value', - '_login_method_present', + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsRemoveCustomQuotaDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberSpaceLimitsRemoveCustomQuotaDetails()' + +MemberSpaceLimitsRemoveCustomQuotaDetails_validator = bv.Struct(MemberSpaceLimitsRemoveCustomQuotaDetails) + +class MemberSpaceLimitsRemoveCustomQuotaType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - login_method=None, - is_emm_managed=None): - self._is_emm_managed_value = None - self._is_emm_managed_present = False - self._login_method_value = None - self._login_method_present = False - if is_emm_managed is not None: - self.is_emm_managed = is_emm_managed - if login_method is not None: - self.login_method = login_method + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def is_emm_managed(self): + def description(self): """ - Tells if the login device is EMM managed. Might be missing due to - historical data gap. - - :rtype: bool + :rtype: str """ - if self._is_emm_managed_present: - return self._is_emm_managed_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @is_emm_managed.setter - def is_emm_managed(self, val): - if val is None: - del self.is_emm_managed - return - val = self._is_emm_managed_validator.validate(val) - self._is_emm_managed_value = val - self._is_emm_managed_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @is_emm_managed.deleter - def is_emm_managed(self): - self._is_emm_managed_value = None - self._is_emm_managed_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberSpaceLimitsRemoveCustomQuotaType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberSpaceLimitsRemoveCustomQuotaType(description={!r})'.format( + self._description_value, + ) - @property - def login_method(self): - """ - Login method. +MemberSpaceLimitsRemoveCustomQuotaType_validator = bv.Struct(MemberSpaceLimitsRemoveCustomQuotaType) - :rtype: LoginMethod - """ - if self._login_method_present: - return self._login_method_value - else: - raise AttributeError("missing required field 'login_method'") +class MemberSpaceLimitsRemoveExceptionDetails(bb.Struct): + """ + Removed members from member space limit exception list. + """ - @login_method.setter - def login_method(self, val): - self._login_method_validator.validate_type_only(val) - self._login_method_value = val - self._login_method_present = True + __slots__ = [ + ] - @login_method.deleter - def login_method(self): - self._login_method_value = None - self._login_method_present = False + _has_required_fields = False + + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LoginSuccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSpaceLimitsRemoveExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LoginSuccessDetails(login_method={!r}, is_emm_managed={!r})'.format( - self._login_method_value, - self._is_emm_managed_value, - ) + return 'MemberSpaceLimitsRemoveExceptionDetails()' -LoginSuccessDetails_validator = bv.Struct(LoginSuccessDetails) +MemberSpaceLimitsRemoveExceptionDetails_validator = bv.Struct(MemberSpaceLimitsRemoveExceptionDetails) -class LoginSuccessType(bb.Struct): +class MemberSpaceLimitsRemoveExceptionType(bb.Struct): __slots__ = [ '_description_value', @@ -38342,37 +58214,148 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LoginSuccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSpaceLimitsRemoveExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LoginSuccessType(description={!r})'.format( + return 'MemberSpaceLimitsRemoveExceptionType(description={!r})'.format( self._description_value, ) -LoginSuccessType_validator = bv.Struct(LoginSuccessType) +MemberSpaceLimitsRemoveExceptionType_validator = bv.Struct(MemberSpaceLimitsRemoveExceptionType) -class LogoutDetails(bb.Struct): +class MemberStatus(bb.Union): """ - Signed out. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + not_joined = None + # Attribute is overwritten below the class definition + invited = None + # Attribute is overwritten below the class definition + active = None + # Attribute is overwritten below the class definition + suspended = None + # Attribute is overwritten below the class definition + removed = None + # Attribute is overwritten below the class definition + other = None + + def is_not_joined(self): + """ + Check if the union tag is ``not_joined``. + + :rtype: bool + """ + return self._tag == 'not_joined' + + def is_invited(self): + """ + Check if the union tag is ``invited``. + + :rtype: bool + """ + return self._tag == 'invited' + + def is_active(self): + """ + Check if the union tag is ``active``. + + :rtype: bool + """ + return self._tag == 'active' + + def is_suspended(self): + """ + Check if the union tag is ``suspended``. + + :rtype: bool + """ + return self._tag == 'suspended' + + def is_removed(self): + """ + Check if the union tag is ``removed``. + + :rtype: bool + """ + return self._tag == 'removed' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberStatus(%r, %r)' % (self._tag, self._value) + +MemberStatus_validator = bv.Union(MemberStatus) + +class MemberSuggestDetails(bb.Struct): + """ + Suggested person to add to team. + + :ivar team_log.MemberSuggestDetails.suggested_members: suggested users + emails. """ __slots__ = [ + '_suggested_members_value', + '_suggested_members_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + suggested_members=None): + self._suggested_members_value = None + self._suggested_members_present = False + if suggested_members is not None: + self.suggested_members = suggested_members + + @property + def suggested_members(self): + """ + suggested users emails. + + :rtype: list of [str] + """ + if self._suggested_members_present: + return self._suggested_members_value + else: + raise AttributeError("missing required field 'suggested_members'") + + @suggested_members.setter + def suggested_members(self, val): + val = self._suggested_members_validator.validate(val) + self._suggested_members_value = val + self._suggested_members_present = True + + @suggested_members.deleter + def suggested_members(self): + self._suggested_members_value = None + self._suggested_members_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LogoutDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSuggestDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LogoutDetails()' + return 'MemberSuggestDetails(suggested_members={!r})'.format( + self._suggested_members_value, + ) -LogoutDetails_validator = bv.Struct(LogoutDetails) +MemberSuggestDetails_validator = bv.Struct(MemberSuggestDetails) -class LogoutType(bb.Struct): +class MemberSuggestType(bb.Struct): __slots__ = [ '_description_value', @@ -38410,42 +58393,53 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(LogoutType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSuggestType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'LogoutType(description={!r})'.format( + return 'MemberSuggestType(description={!r})'.format( self._description_value, ) -LogoutType_validator = bv.Struct(LogoutType) +MemberSuggestType_validator = bv.Struct(MemberSuggestType) -class MemberAddExternalIdDetails(bb.Struct): +class MemberSuggestionsChangePolicyDetails(bb.Struct): """ - Added an external ID for team member. + Enabled/disabled option for team members to suggest people to add to team. - :ivar team_log.MemberAddExternalIdDetails.new_value: Current external id. + :ivar team_log.MemberSuggestionsChangePolicyDetails.new_value: New team + member suggestions policy. + :ivar team_log.MemberSuggestionsChangePolicyDetails.previous_value: Previous + team member suggestions policy. Might be missing due to historical data + gap. """ __slots__ = [ '_new_value_value', '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - new_value=None): + new_value=None, + previous_value=None): self._new_value_value = None self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False if new_value is not None: self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property def new_value(self): """ - Current external id. + New team member suggestions policy. - :rtype: str + :rtype: MemberSuggestionsPolicy """ if self._new_value_present: return self._new_value_value @@ -38454,7 +58448,7 @@ def new_value(self): @new_value.setter def new_value(self, val): - val = self._new_value_validator.validate(val) + self._new_value_validator.validate_type_only(val) self._new_value_value = val self._new_value_present = True @@ -38463,17 +58457,45 @@ def new_value(self): self._new_value_value = None self._new_value_present = False + @property + def previous_value(self): + """ + Previous team member suggestions policy. Might be missing due to + historical data gap. + + :rtype: MemberSuggestionsPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberAddExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSuggestionsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberAddExternalIdDetails(new_value={!r})'.format( + return 'MemberSuggestionsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, + self._previous_value_value, ) -MemberAddExternalIdDetails_validator = bv.Struct(MemberAddExternalIdDetails) +MemberSuggestionsChangePolicyDetails_validator = bv.Struct(MemberSuggestionsChangePolicyDetails) -class MemberAddExternalIdType(bb.Struct): +class MemberSuggestionsChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -38511,70 +58533,86 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberAddExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSuggestionsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberAddExternalIdType(description={!r})'.format( + return 'MemberSuggestionsChangePolicyType(description={!r})'.format( self._description_value, ) -MemberAddExternalIdType_validator = bv.Struct(MemberAddExternalIdType) +MemberSuggestionsChangePolicyType_validator = bv.Struct(MemberSuggestionsChangePolicyType) -class MemberAddNameDetails(bb.Struct): +class MemberSuggestionsPolicy(bb.Union): """ - Added team member name. + Member suggestions policy - :ivar team_log.MemberAddNameDetails.new_value: New user's name. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_new_value_value', - '_new_value_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_disabled(self): + """ + Check if the union tag is ``disabled``. - def __init__(self, - new_value=None): - self._new_value_value = None - self._new_value_present = False - if new_value is not None: - self.new_value = new_value + :rtype: bool + """ + return self._tag == 'disabled' - @property - def new_value(self): + def is_enabled(self): """ - New user's name. + Check if the union tag is ``enabled``. - :rtype: UserNameLogInfo + :rtype: bool """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") + return self._tag == 'enabled' - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberAddNameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberSuggestionsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberAddNameDetails(new_value={!r})'.format( - self._new_value_value, - ) + return 'MemberSuggestionsPolicy(%r, %r)' % (self._tag, self._value) -MemberAddNameDetails_validator = bv.Struct(MemberAddNameDetails) +MemberSuggestionsPolicy_validator = bv.Union(MemberSuggestionsPolicy) -class MemberAddNameType(bb.Struct): +class MemberTransferAccountContentsDetails(bb.Struct): + """ + Transferred contents of deleted member account to another member. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MemberTransferAccountContentsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MemberTransferAccountContentsDetails()' + +MemberTransferAccountContentsDetails_validator = bv.Struct(MemberTransferAccountContentsDetails) + +class MemberTransferAccountContentsType(bb.Struct): __slots__ = [ '_description_value', @@ -38612,25 +58650,24 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberAddNameType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MemberTransferAccountContentsType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberAddNameType(description={!r})'.format( + return 'MemberTransferAccountContentsType(description={!r})'.format( self._description_value, ) -MemberAddNameType_validator = bv.Struct(MemberAddNameType) +MemberTransferAccountContentsType_validator = bv.Struct(MemberTransferAccountContentsType) -class MemberChangeAdminRoleDetails(bb.Struct): +class MicrosoftOfficeAddinChangePolicyDetails(bb.Struct): """ - Changed team member admin role. + Enabled/disabled Microsoft Office add-in. - :ivar team_log.MemberChangeAdminRoleDetails.new_value: New admin role. This - field is relevant when the admin role is changed or whenthe user role - changes from no admin rights to with admin rights. - :ivar team_log.MemberChangeAdminRoleDetails.previous_value: Previous admin - role. This field is relevant when the admin role is changed or when the - admin role is removed. + :ivar team_log.MicrosoftOfficeAddinChangePolicyDetails.new_value: New + Microsoft Office addin policy. + :ivar team_log.MicrosoftOfficeAddinChangePolicyDetails.previous_value: + Previous Microsoft Office addin policy. Might be missing due to + historical data gap. """ __slots__ = [ @@ -38640,7 +58677,7 @@ class MemberChangeAdminRoleDetails(bb.Struct): '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, new_value=None, @@ -38657,21 +58694,17 @@ def __init__(self, @property def new_value(self): """ - New admin role. This field is relevant when the admin role is changed or - whenthe user role changes from no admin rights to with admin rights. + New Microsoft Office addin policy. - :rtype: AdminRole + :rtype: MicrosoftOfficeAddinPolicy """ if self._new_value_present: return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") @new_value.setter def new_value(self, val): - if val is None: - del self.new_value - return self._new_value_validator.validate_type_only(val) self._new_value_value = val self._new_value_present = True @@ -38684,10 +58717,10 @@ def new_value(self): @property def previous_value(self): """ - Previous admin role. This field is relevant when the admin role is - changed or when the admin role is removed. + Previous Microsoft Office addin policy. Might be missing due to + historical data gap. - :rtype: AdminRole + :rtype: MicrosoftOfficeAddinPolicy """ if self._previous_value_present: return self._previous_value_value @@ -38709,17 +58742,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeAdminRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MicrosoftOfficeAddinChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeAdminRoleDetails(new_value={!r}, previous_value={!r})'.format( + return 'MicrosoftOfficeAddinChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -MemberChangeAdminRoleDetails_validator = bv.Struct(MemberChangeAdminRoleDetails) +MicrosoftOfficeAddinChangePolicyDetails_validator = bv.Struct(MicrosoftOfficeAddinChangePolicyDetails) -class MemberChangeAdminRoleType(bb.Struct): +class MicrosoftOfficeAddinChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -38757,428 +58790,529 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeAdminRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MicrosoftOfficeAddinChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeAdminRoleType(description={!r})'.format( + return 'MicrosoftOfficeAddinChangePolicyType(description={!r})'.format( self._description_value, ) -MemberChangeAdminRoleType_validator = bv.Struct(MemberChangeAdminRoleType) +MicrosoftOfficeAddinChangePolicyType_validator = bv.Struct(MicrosoftOfficeAddinChangePolicyType) -class MemberChangeEmailDetails(bb.Struct): +class MicrosoftOfficeAddinPolicy(bb.Union): """ - Changed team member email. + Microsoft Office addin policy - :ivar team_log.MemberChangeEmailDetails.new_value: New email. - :ivar team_log.MemberChangeEmailDetails.previous_value: Previous email. - Might be missing due to historical data gap. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_disabled(self): + """ + Check if the union tag is ``disabled``. - def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + :rtype: bool + """ + return self._tag == 'disabled' - @property - def new_value(self): + def is_enabled(self): """ - New email. + Check if the union tag is ``enabled``. - :rtype: str + :rtype: bool """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") + return self._tag == 'enabled' - @new_value.setter - def new_value(self, val): - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(MicrosoftOfficeAddinPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'MicrosoftOfficeAddinPolicy(%r, %r)' % (self._tag, self._value) + +MicrosoftOfficeAddinPolicy_validator = bv.Union(MicrosoftOfficeAddinPolicy) + +class MissingDetails(bb.Struct): + """ + An indication that an error occurred while retrieving the event. Some + attributes of the event may be omitted as a result. + + :ivar team_log.MissingDetails.source_event_fields: All the data that could + be retrieved and converted from the source event. + """ + + __slots__ = [ + '_source_event_fields_value', + '_source_event_fields_present', + ] + + _has_required_fields = False + + def __init__(self, + source_event_fields=None): + self._source_event_fields_value = None + self._source_event_fields_present = False + if source_event_fields is not None: + self.source_event_fields = source_event_fields @property - def previous_value(self): + def source_event_fields(self): """ - Previous email. Might be missing due to historical data gap. + All the data that could be retrieved and converted from the source + event. :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._source_event_fields_present: + return self._source_event_fields_value else: return None - @previous_value.setter - def previous_value(self, val): + @source_event_fields.setter + def source_event_fields(self, val): if val is None: - del self.previous_value + del self.source_event_fields return - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + val = self._source_event_fields_validator.validate(val) + self._source_event_fields_value = val + self._source_event_fields_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @source_event_fields.deleter + def source_event_fields(self): + self._source_event_fields_value = None + self._source_event_fields_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeEmailDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MissingDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeEmailDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'MissingDetails(source_event_fields={!r})'.format( + self._source_event_fields_value, ) -MemberChangeEmailDetails_validator = bv.Struct(MemberChangeEmailDetails) +MissingDetails_validator = bv.Struct(MissingDetails) -class MemberChangeEmailType(bb.Struct): +class MobileDeviceSessionLogInfo(DeviceSessionLogInfo): + """ + Information about linked Dropbox mobile client sessions + + :ivar team_log.MobileDeviceSessionLogInfo.session_info: Mobile session + unique id. Might be missing due to historical data gap. + :ivar team_log.MobileDeviceSessionLogInfo.device_name: The device name. + :ivar team_log.MobileDeviceSessionLogInfo.client_type: The mobile + application type. + :ivar team_log.MobileDeviceSessionLogInfo.client_version: The Dropbox client + version. + :ivar team_log.MobileDeviceSessionLogInfo.os_version: The hosting OS + version. + :ivar team_log.MobileDeviceSessionLogInfo.last_carrier: last carrier used by + the device. + """ __slots__ = [ - '_description_value', - '_description_present', + '_session_info_value', + '_session_info_present', + '_device_name_value', + '_device_name_present', + '_client_type_value', + '_client_type_present', + '_client_version_value', + '_client_version_present', + '_os_version_value', + '_os_version_present', + '_last_carrier_value', + '_last_carrier_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + device_name=None, + client_type=None, + ip_address=None, + created=None, + updated=None, + session_info=None, + client_version=None, + os_version=None, + last_carrier=None): + super(MobileDeviceSessionLogInfo, self).__init__(ip_address, + created, + updated) + self._session_info_value = None + self._session_info_present = False + self._device_name_value = None + self._device_name_present = False + self._client_type_value = None + self._client_type_present = False + self._client_version_value = None + self._client_version_present = False + self._os_version_value = None + self._os_version_present = False + self._last_carrier_value = None + self._last_carrier_present = False + if session_info is not None: + self.session_info = session_info + if device_name is not None: + self.device_name = device_name + if client_type is not None: + self.client_type = client_type + if client_version is not None: + self.client_version = client_version + if os_version is not None: + self.os_version = os_version + if last_carrier is not None: + self.last_carrier = last_carrier @property - def description(self): + def session_info(self): + """ + Mobile session unique id. Might be missing due to historical data gap. + + :rtype: MobileSessionLogInfo """ + if self._session_info_present: + return self._session_info_value + else: + return None + + @session_info.setter + def session_info(self, val): + if val is None: + del self.session_info + return + self._session_info_validator.validate_type_only(val) + self._session_info_value = val + self._session_info_present = True + + @session_info.deleter + def session_info(self): + self._session_info_value = None + self._session_info_present = False + + @property + def device_name(self): + """ + The device name. + :rtype: str """ - if self._description_present: - return self._description_value + if self._device_name_present: + return self._device_name_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'device_name'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @device_name.setter + def device_name(self, val): + val = self._device_name_validator.validate(val) + self._device_name_value = val + self._device_name_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @device_name.deleter + def device_name(self): + self._device_name_value = None + self._device_name_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeEmailType, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def client_type(self): + """ + The mobile application type. - def __repr__(self): - return 'MemberChangeEmailType(description={!r})'.format( - self._description_value, - ) + :rtype: team.MobileClientPlatform + """ + if self._client_type_present: + return self._client_type_value + else: + raise AttributeError("missing required field 'client_type'") -MemberChangeEmailType_validator = bv.Struct(MemberChangeEmailType) + @client_type.setter + def client_type(self, val): + self._client_type_validator.validate_type_only(val) + self._client_type_value = val + self._client_type_present = True -class MemberChangeExternalIdDetails(bb.Struct): - """ - Changed the external ID for team member. + @client_type.deleter + def client_type(self): + self._client_type_value = None + self._client_type_present = False - :ivar team_log.MemberChangeExternalIdDetails.new_value: Current external id. - :ivar team_log.MemberChangeExternalIdDetails.previous_value: Old external - id. - """ + @property + def client_version(self): + """ + The Dropbox client version. - __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', - ] + :rtype: str + """ + if self._client_version_present: + return self._client_version_value + else: + return None - _has_required_fields = True + @client_version.setter + def client_version(self, val): + if val is None: + del self.client_version + return + val = self._client_version_validator.validate(val) + self._client_version_value = val + self._client_version_present = True - def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + @client_version.deleter + def client_version(self): + self._client_version_value = None + self._client_version_present = False @property - def new_value(self): + def os_version(self): """ - Current external id. + The hosting OS version. :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._os_version_present: + return self._os_version_value else: - raise AttributeError("missing required field 'new_value'") + return None - @new_value.setter - def new_value(self, val): - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + @os_version.setter + def os_version(self, val): + if val is None: + del self.os_version + return + val = self._os_version_validator.validate(val) + self._os_version_value = val + self._os_version_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @os_version.deleter + def os_version(self): + self._os_version_value = None + self._os_version_present = False @property - def previous_value(self): + def last_carrier(self): """ - Old external id. + last carrier used by the device. :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._last_carrier_present: + return self._last_carrier_value else: - raise AttributeError("missing required field 'previous_value'") + return None - @previous_value.setter - def previous_value(self, val): - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + @last_carrier.setter + def last_carrier(self, val): + if val is None: + del self.last_carrier + return + val = self._last_carrier_validator.validate(val) + self._last_carrier_value = val + self._last_carrier_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @last_carrier.deleter + def last_carrier(self): + self._last_carrier_value = None + self._last_carrier_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MobileDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeExternalIdDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'MobileDeviceSessionLogInfo(device_name={!r}, client_type={!r}, ip_address={!r}, created={!r}, updated={!r}, session_info={!r}, client_version={!r}, os_version={!r}, last_carrier={!r})'.format( + self._device_name_value, + self._client_type_value, + self._ip_address_value, + self._created_value, + self._updated_value, + self._session_info_value, + self._client_version_value, + self._os_version_value, + self._last_carrier_value, ) -MemberChangeExternalIdDetails_validator = bv.Struct(MemberChangeExternalIdDetails) +MobileDeviceSessionLogInfo_validator = bv.Struct(MobileDeviceSessionLogInfo) -class MemberChangeExternalIdType(bb.Struct): +class MobileSessionLogInfo(SessionLogInfo): + """ + Mobile session. + """ __slots__ = [ - '_description_value', - '_description_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description - - @property - def description(self): - """ - :rtype: str - """ - if self._description_present: - return self._description_value - else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + session_id=None): + super(MobileSessionLogInfo, self).__init__(session_id) def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(MobileSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeExternalIdType(description={!r})'.format( - self._description_value, + return 'MobileSessionLogInfo(session_id={!r})'.format( + self._session_id_value, ) -MemberChangeExternalIdType_validator = bv.Struct(MemberChangeExternalIdType) +MobileSessionLogInfo_validator = bv.Struct(MobileSessionLogInfo) -class MemberChangeMembershipTypeDetails(bb.Struct): +class NamespaceRelativePathLogInfo(bb.Struct): """ - Changed membership type (limited/full) of member. + Namespace relative path details. - :ivar team_log.MemberChangeMembershipTypeDetails.prev_value: Previous - membership type. - :ivar team_log.MemberChangeMembershipTypeDetails.new_value: New membership - type. + :ivar team_log.NamespaceRelativePathLogInfo.ns_id: Namespace ID. Might be + missing due to historical data gap. + :ivar team_log.NamespaceRelativePathLogInfo.relative_path: A path relative + to the specified namespace ID. Might be missing due to historical data + gap. + :ivar team_log.NamespaceRelativePathLogInfo.is_shared_namespace: True if the + namespace is shared. Might be missing due to historical data gap. """ __slots__ = [ - '_prev_value_value', - '_prev_value_present', - '_new_value_value', - '_new_value_present', + '_ns_id_value', + '_ns_id_present', + '_relative_path_value', + '_relative_path_present', + '_is_shared_namespace_value', + '_is_shared_namespace_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - prev_value=None, - new_value=None): - self._prev_value_value = None - self._prev_value_present = False - self._new_value_value = None - self._new_value_present = False - if prev_value is not None: - self.prev_value = prev_value - if new_value is not None: - self.new_value = new_value + ns_id=None, + relative_path=None, + is_shared_namespace=None): + self._ns_id_value = None + self._ns_id_present = False + self._relative_path_value = None + self._relative_path_present = False + self._is_shared_namespace_value = None + self._is_shared_namespace_present = False + if ns_id is not None: + self.ns_id = ns_id + if relative_path is not None: + self.relative_path = relative_path + if is_shared_namespace is not None: + self.is_shared_namespace = is_shared_namespace @property - def prev_value(self): + def ns_id(self): """ - Previous membership type. + Namespace ID. Might be missing due to historical data gap. - :rtype: TeamMembershipType + :rtype: str """ - if self._prev_value_present: - return self._prev_value_value + if self._ns_id_present: + return self._ns_id_value else: - raise AttributeError("missing required field 'prev_value'") + return None - @prev_value.setter - def prev_value(self, val): - self._prev_value_validator.validate_type_only(val) - self._prev_value_value = val - self._prev_value_present = True + @ns_id.setter + def ns_id(self, val): + if val is None: + del self.ns_id + return + val = self._ns_id_validator.validate(val) + self._ns_id_value = val + self._ns_id_present = True - @prev_value.deleter - def prev_value(self): - self._prev_value_value = None - self._prev_value_present = False + @ns_id.deleter + def ns_id(self): + self._ns_id_value = None + self._ns_id_present = False @property - def new_value(self): + def relative_path(self): """ - New membership type. + A path relative to the specified namespace ID. Might be missing due to + historical data gap. - :rtype: TeamMembershipType + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._relative_path_present: + return self._relative_path_value else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeMembershipTypeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MemberChangeMembershipTypeDetails(prev_value={!r}, new_value={!r})'.format( - self._prev_value_value, - self._new_value_value, - ) - -MemberChangeMembershipTypeDetails_validator = bv.Struct(MemberChangeMembershipTypeDetails) - -class MemberChangeMembershipTypeType(bb.Struct): - - __slots__ = [ - '_description_value', - '_description_present', - ] + return None - _has_required_fields = True + @relative_path.setter + def relative_path(self, val): + if val is None: + del self.relative_path + return + val = self._relative_path_validator.validate(val) + self._relative_path_value = val + self._relative_path_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @relative_path.deleter + def relative_path(self): + self._relative_path_value = None + self._relative_path_present = False @property - def description(self): + def is_shared_namespace(self): """ - :rtype: str + True if the namespace is shared. Might be missing due to historical data + gap. + + :rtype: bool """ - if self._description_present: - return self._description_value + if self._is_shared_namespace_present: + return self._is_shared_namespace_value else: - raise AttributeError("missing required field 'description'") + return None - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @is_shared_namespace.setter + def is_shared_namespace(self, val): + if val is None: + del self.is_shared_namespace + return + val = self._is_shared_namespace_validator.validate(val) + self._is_shared_namespace_value = val + self._is_shared_namespace_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @is_shared_namespace.deleter + def is_shared_namespace(self): + self._is_shared_namespace_value = None + self._is_shared_namespace_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeMembershipTypeType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NamespaceRelativePathLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeMembershipTypeType(description={!r})'.format( - self._description_value, + return 'NamespaceRelativePathLogInfo(ns_id={!r}, relative_path={!r}, is_shared_namespace={!r})'.format( + self._ns_id_value, + self._relative_path_value, + self._is_shared_namespace_value, ) -MemberChangeMembershipTypeType_validator = bv.Struct(MemberChangeMembershipTypeType) +NamespaceRelativePathLogInfo_validator = bv.Struct(NamespaceRelativePathLogInfo) -class MemberChangeNameDetails(bb.Struct): +class NetworkControlChangePolicyDetails(bb.Struct): """ - Changed team member name. - - :ivar team_log.MemberChangeNameDetails.new_value: New user's name. - :ivar team_log.MemberChangeNameDetails.previous_value: Previous user's name. - Might be missing due to historical data gap. + Enabled/disabled network control. + + :ivar team_log.NetworkControlChangePolicyDetails.new_value: New network + control policy. + :ivar team_log.NetworkControlChangePolicyDetails.previous_value: Previous + network control policy. Might be missing due to historical data gap. """ __slots__ = [ @@ -39205,9 +59339,9 @@ def __init__(self, @property def new_value(self): """ - New user's name. + New network control policy. - :rtype: UserNameLogInfo + :rtype: NetworkControlPolicy """ if self._new_value_present: return self._new_value_value @@ -39228,9 +59362,10 @@ def new_value(self): @property def previous_value(self): """ - Previous user's name. Might be missing due to historical data gap. + Previous network control policy. Might be missing due to historical data + gap. - :rtype: UserNameLogInfo + :rtype: NetworkControlPolicy """ if self._previous_value_present: return self._previous_value_value @@ -39252,17 +59387,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeNameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NetworkControlChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeNameDetails(new_value={!r}, previous_value={!r})'.format( + return 'NetworkControlChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -MemberChangeNameDetails_validator = bv.Struct(MemberChangeNameDetails) +NetworkControlChangePolicyDetails_validator = bv.Struct(NetworkControlChangePolicyDetails) -class MemberChangeNameType(bb.Struct): +class NetworkControlChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -39300,143 +59435,153 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeNameType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NetworkControlChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeNameType(description={!r})'.format( + return 'NetworkControlChangePolicyType(description={!r})'.format( self._description_value, ) -MemberChangeNameType_validator = bv.Struct(MemberChangeNameType) +NetworkControlChangePolicyType_validator = bv.Struct(NetworkControlChangePolicyType) -class MemberChangeStatusDetails(bb.Struct): +class NetworkControlPolicy(bb.Union): """ - Changed member status (invited, joined, suspended, etc.). + Network control policy - :ivar team_log.MemberChangeStatusDetails.previous_value: Previous member - status. Might be missing due to historical data gap. - :ivar team_log.MemberChangeStatusDetails.new_value: New member status. - :ivar team_log.MemberChangeStatusDetails.action: Additional information - indicating the action taken that caused status change. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', - '_action_value', - '_action_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_disabled(self): + """ + Check if the union tag is ``disabled``. - def __init__(self, - new_value=None, - previous_value=None, - action=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - self._action_value = None - self._action_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value - if action is not None: - self.action = action + :rtype: bool + """ + return self._tag == 'disabled' - @property - def previous_value(self): + def is_enabled(self): """ - Previous member status. Might be missing due to historical data gap. + Check if the union tag is ``enabled``. - :rtype: MemberStatus + :rtype: bool """ - if self._previous_value_present: - return self._previous_value_value - else: - return None + return self._tag == 'enabled' - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(NetworkControlPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'NetworkControlPolicy(%r, %r)' % (self._tag, self._value) + +NetworkControlPolicy_validator = bv.Union(NetworkControlPolicy) + +class NoExpirationLinkGenCreateReportDetails(bb.Struct): + """ + Report created: Links created with no expiration. + + :ivar team_log.NoExpirationLinkGenCreateReportDetails.start_date: Report + start date. + :ivar team_log.NoExpirationLinkGenCreateReportDetails.end_date: Report end + date. + """ + + __slots__ = [ + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', + ] + + _has_required_fields = True + + def __init__(self, + start_date=None, + end_date=None): + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date @property - def new_value(self): + def start_date(self): """ - New member status. + Report start date. - :rtype: MemberStatus + :rtype: datetime.datetime """ - if self._new_value_present: - return self._new_value_value + if self._start_date_present: + return self._start_date_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'start_date'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @start_date.setter + def start_date(self, val): + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False @property - def action(self): + def end_date(self): """ - Additional information indicating the action taken that caused status - change. + Report end date. - :rtype: ActionDetails + :rtype: datetime.datetime """ - if self._action_present: - return self._action_value + if self._end_date_present: + return self._end_date_value else: - return None + raise AttributeError("missing required field 'end_date'") - @action.setter - def action(self, val): - if val is None: - del self.action - return - self._action_validator.validate_type_only(val) - self._action_value = val - self._action_present = True + @end_date.setter + def end_date(self, val): + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True - @action.deleter - def action(self): - self._action_value = None - self._action_present = False + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeStatusDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoExpirationLinkGenCreateReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeStatusDetails(new_value={!r}, previous_value={!r}, action={!r})'.format( - self._new_value_value, - self._previous_value_value, - self._action_value, + return 'NoExpirationLinkGenCreateReportDetails(start_date={!r}, end_date={!r})'.format( + self._start_date_value, + self._end_date_value, ) -MemberChangeStatusDetails_validator = bv.Struct(MemberChangeStatusDetails) +NoExpirationLinkGenCreateReportDetails_validator = bv.Struct(NoExpirationLinkGenCreateReportDetails) -class MemberChangeStatusType(bb.Struct): +class NoExpirationLinkGenCreateReportType(bb.Struct): __slots__ = [ '_description_value', @@ -39474,37 +59619,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberChangeStatusType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoExpirationLinkGenCreateReportType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberChangeStatusType(description={!r})'.format( + return 'NoExpirationLinkGenCreateReportType(description={!r})'.format( self._description_value, ) -MemberChangeStatusType_validator = bv.Struct(MemberChangeStatusType) +NoExpirationLinkGenCreateReportType_validator = bv.Struct(NoExpirationLinkGenCreateReportType) -class MemberDeleteManualContactsDetails(bb.Struct): +class NoExpirationLinkGenReportFailedDetails(bb.Struct): """ - Cleared manually added contacts. + Couldn't create report: Links created with no expiration. + + :ivar team_log.NoExpirationLinkGenReportFailedDetails.failure_reason: + Failure reason. """ __slots__ = [ + '_failure_reason_value', + '_failure_reason_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + failure_reason=None): + self._failure_reason_value = None + self._failure_reason_present = False + if failure_reason is not None: + self.failure_reason = failure_reason + + @property + def failure_reason(self): + """ + Failure reason. + + :rtype: team.TeamReportFailureReason + """ + if self._failure_reason_present: + return self._failure_reason_value + else: + raise AttributeError("missing required field 'failure_reason'") + + @failure_reason.setter + def failure_reason(self, val): + self._failure_reason_validator.validate_type_only(val) + self._failure_reason_value = val + self._failure_reason_present = True + + @failure_reason.deleter + def failure_reason(self): + self._failure_reason_value = None + self._failure_reason_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberDeleteManualContactsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoExpirationLinkGenReportFailedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberDeleteManualContactsDetails()' + return 'NoExpirationLinkGenReportFailedDetails(failure_reason={!r})'.format( + self._failure_reason_value, + ) -MemberDeleteManualContactsDetails_validator = bv.Struct(MemberDeleteManualContactsDetails) +NoExpirationLinkGenReportFailedDetails_validator = bv.Struct(NoExpirationLinkGenReportFailedDetails) -class MemberDeleteManualContactsType(bb.Struct): +class NoExpirationLinkGenReportFailedType(bb.Struct): __slots__ = [ '_description_value', @@ -39542,37 +59721,104 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberDeleteManualContactsType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoExpirationLinkGenReportFailedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberDeleteManualContactsType(description={!r})'.format( + return 'NoExpirationLinkGenReportFailedType(description={!r})'.format( self._description_value, ) -MemberDeleteManualContactsType_validator = bv.Struct(MemberDeleteManualContactsType) +NoExpirationLinkGenReportFailedType_validator = bv.Struct(NoExpirationLinkGenReportFailedType) -class MemberPermanentlyDeleteAccountContentsDetails(bb.Struct): +class NoPasswordLinkGenCreateReportDetails(bb.Struct): """ - Permanently deleted contents of deleted team member account. + Report created: Links created without passwords. + + :ivar team_log.NoPasswordLinkGenCreateReportDetails.start_date: Report start + date. + :ivar team_log.NoPasswordLinkGenCreateReportDetails.end_date: Report end + date. """ __slots__ = [ + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + start_date=None, + end_date=None): + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date + + @property + def start_date(self): + """ + Report start date. + + :rtype: datetime.datetime + """ + if self._start_date_present: + return self._start_date_value + else: + raise AttributeError("missing required field 'start_date'") + + @start_date.setter + def start_date(self, val): + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True + + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False + + @property + def end_date(self): + """ + Report end date. + + :rtype: datetime.datetime + """ + if self._end_date_present: + return self._end_date_value + else: + raise AttributeError("missing required field 'end_date'") + + @end_date.setter + def end_date(self, val): + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True + + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberPermanentlyDeleteAccountContentsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoPasswordLinkGenCreateReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberPermanentlyDeleteAccountContentsDetails()' + return 'NoPasswordLinkGenCreateReportDetails(start_date={!r}, end_date={!r})'.format( + self._start_date_value, + self._end_date_value, + ) -MemberPermanentlyDeleteAccountContentsDetails_validator = bv.Struct(MemberPermanentlyDeleteAccountContentsDetails) +NoPasswordLinkGenCreateReportDetails_validator = bv.Struct(NoPasswordLinkGenCreateReportDetails) -class MemberPermanentlyDeleteAccountContentsType(bb.Struct): +class NoPasswordLinkGenCreateReportType(bb.Struct): __slots__ = [ '_description_value', @@ -39610,138 +59856,206 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberPermanentlyDeleteAccountContentsType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoPasswordLinkGenCreateReportType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberPermanentlyDeleteAccountContentsType(description={!r})'.format( + return 'NoPasswordLinkGenCreateReportType(description={!r})'.format( self._description_value, ) -MemberPermanentlyDeleteAccountContentsType_validator = bv.Struct(MemberPermanentlyDeleteAccountContentsType) +NoPasswordLinkGenCreateReportType_validator = bv.Struct(NoPasswordLinkGenCreateReportType) -class MemberRemoveActionType(bb.Union): +class NoPasswordLinkGenReportFailedDetails(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Couldn't create report: Links created without passwords. + + :ivar team_log.NoPasswordLinkGenReportFailedDetails.failure_reason: Failure + reason. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - delete = None - # Attribute is overwritten below the class definition - offboard = None - # Attribute is overwritten below the class definition - leave = None - # Attribute is overwritten below the class definition - offboard_and_retain_team_folders = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_failure_reason_value', + '_failure_reason_present', + ] - def is_delete(self): - """ - Check if the union tag is ``delete``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'delete' + def __init__(self, + failure_reason=None): + self._failure_reason_value = None + self._failure_reason_present = False + if failure_reason is not None: + self.failure_reason = failure_reason - def is_offboard(self): + @property + def failure_reason(self): """ - Check if the union tag is ``offboard``. + Failure reason. - :rtype: bool + :rtype: team.TeamReportFailureReason """ - return self._tag == 'offboard' + if self._failure_reason_present: + return self._failure_reason_value + else: + raise AttributeError("missing required field 'failure_reason'") - def is_leave(self): - """ - Check if the union tag is ``leave``. + @failure_reason.setter + def failure_reason(self, val): + self._failure_reason_validator.validate_type_only(val) + self._failure_reason_value = val + self._failure_reason_present = True - :rtype: bool - """ - return self._tag == 'leave' + @failure_reason.deleter + def failure_reason(self): + self._failure_reason_value = None + self._failure_reason_present = False - def is_offboard_and_retain_team_folders(self): - """ - Check if the union tag is ``offboard_and_retain_team_folders``. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(NoPasswordLinkGenReportFailedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: bool - """ - return self._tag == 'offboard_and_retain_team_folders' + def __repr__(self): + return 'NoPasswordLinkGenReportFailedDetails(failure_reason={!r})'.format( + self._failure_reason_value, + ) - def is_other(self): - """ - Check if the union tag is ``other``. +NoPasswordLinkGenReportFailedDetails_validator = bv.Struct(NoPasswordLinkGenReportFailedDetails) - :rtype: bool +class NoPasswordLinkGenReportFailedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - return self._tag == 'other' + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberRemoveActionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoPasswordLinkGenReportFailedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberRemoveActionType(%r, %r)' % (self._tag, self._value) + return 'NoPasswordLinkGenReportFailedType(description={!r})'.format( + self._description_value, + ) -MemberRemoveActionType_validator = bv.Union(MemberRemoveActionType) +NoPasswordLinkGenReportFailedType_validator = bv.Struct(NoPasswordLinkGenReportFailedType) -class MemberRemoveExternalIdDetails(bb.Struct): +class NoPasswordLinkViewCreateReportDetails(bb.Struct): """ - Removed the external ID for team member. + Report created: Views of links without passwords. - :ivar team_log.MemberRemoveExternalIdDetails.previous_value: Old external - id. + :ivar team_log.NoPasswordLinkViewCreateReportDetails.start_date: Report + start date. + :ivar team_log.NoPasswordLinkViewCreateReportDetails.end_date: Report end + date. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', ] _has_required_fields = True def __init__(self, - previous_value=None): - self._previous_value_value = None - self._previous_value_present = False - if previous_value is not None: - self.previous_value = previous_value + start_date=None, + end_date=None): + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date @property - def previous_value(self): + def start_date(self): + """ + Report start date. + + :rtype: datetime.datetime + """ + if self._start_date_present: + return self._start_date_value + else: + raise AttributeError("missing required field 'start_date'") + + @start_date.setter + def start_date(self, val): + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True + + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False + + @property + def end_date(self): """ - Old external id. + Report end date. - :rtype: str + :rtype: datetime.datetime """ - if self._previous_value_present: - return self._previous_value_value + if self._end_date_present: + return self._end_date_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'end_date'") - @previous_value.setter - def previous_value(self, val): - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + @end_date.setter + def end_date(self, val): + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberRemoveExternalIdDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoPasswordLinkViewCreateReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberRemoveExternalIdDetails(previous_value={!r})'.format( - self._previous_value_value, + return 'NoPasswordLinkViewCreateReportDetails(start_date={!r}, end_date={!r})'.format( + self._start_date_value, + self._end_date_value, ) -MemberRemoveExternalIdDetails_validator = bv.Struct(MemberRemoveExternalIdDetails) +NoPasswordLinkViewCreateReportDetails_validator = bv.Struct(NoPasswordLinkViewCreateReportDetails) -class MemberRemoveExternalIdType(bb.Struct): +class NoPasswordLinkViewCreateReportType(bb.Struct): __slots__ = [ '_description_value', @@ -39779,109 +60093,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberRemoveExternalIdType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoPasswordLinkViewCreateReportType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberRemoveExternalIdType(description={!r})'.format( + return 'NoPasswordLinkViewCreateReportType(description={!r})'.format( self._description_value, ) -MemberRemoveExternalIdType_validator = bv.Struct(MemberRemoveExternalIdType) +NoPasswordLinkViewCreateReportType_validator = bv.Struct(NoPasswordLinkViewCreateReportType) -class MemberRequestsChangePolicyDetails(bb.Struct): +class NoPasswordLinkViewReportFailedDetails(bb.Struct): """ - Changed whether users can find team when not invited. + Couldn't create report: Views of links without passwords. - :ivar team_log.MemberRequestsChangePolicyDetails.new_value: New member - change requests policy. - :ivar team_log.MemberRequestsChangePolicyDetails.previous_value: Previous - member change requests policy. Might be missing due to historical data - gap. + :ivar team_log.NoPasswordLinkViewReportFailedDetails.failure_reason: Failure + reason. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_failure_reason_value', + '_failure_reason_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New member change requests policy. - - :rtype: MemberRequestsPolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + failure_reason=None): + self._failure_reason_value = None + self._failure_reason_present = False + if failure_reason is not None: + self.failure_reason = failure_reason @property - def previous_value(self): + def failure_reason(self): """ - Previous member change requests policy. Might be missing due to - historical data gap. + Failure reason. - :rtype: MemberRequestsPolicy + :rtype: team.TeamReportFailureReason """ - if self._previous_value_present: - return self._previous_value_value + if self._failure_reason_present: + return self._failure_reason_value else: - return None + raise AttributeError("missing required field 'failure_reason'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @failure_reason.setter + def failure_reason(self, val): + self._failure_reason_validator.validate_type_only(val) + self._failure_reason_value = val + self._failure_reason_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @failure_reason.deleter + def failure_reason(self): + self._failure_reason_value = None + self._failure_reason_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberRequestsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoPasswordLinkViewReportFailedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberRequestsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'NoPasswordLinkViewReportFailedDetails(failure_reason={!r})'.format( + self._failure_reason_value, ) -MemberRequestsChangePolicyDetails_validator = bv.Struct(MemberRequestsChangePolicyDetails) +NoPasswordLinkViewReportFailedDetails_validator = bv.Struct(NoPasswordLinkViewReportFailedDetails) -class MemberRequestsChangePolicyType(bb.Struct): +class NoPasswordLinkViewReportFailedType(bb.Struct): __slots__ = [ '_description_value', @@ -39919,128 +60195,252 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberRequestsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoPasswordLinkViewReportFailedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberRequestsChangePolicyType(description={!r})'.format( + return 'NoPasswordLinkViewReportFailedType(description={!r})'.format( self._description_value, ) -MemberRequestsChangePolicyType_validator = bv.Struct(MemberRequestsChangePolicyType) +NoPasswordLinkViewReportFailedType_validator = bv.Struct(NoPasswordLinkViewReportFailedType) -class MemberRequestsPolicy(bb.Union): +class UserLogInfo(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + User's logged information. + + :ivar team_log.UserLogInfo.account_id: User unique ID. Might be missing due + to historical data gap. + :ivar team_log.UserLogInfo.display_name: User display name. Might be missing + due to historical data gap. + :ivar team_log.UserLogInfo.email: User email address. Might be missing due + to historical data gap. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - auto_accept = None - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - require_approval = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_account_id_value', + '_account_id_present', + '_display_name_value', + '_display_name_present', + '_email_value', + '_email_present', + ] - def is_auto_accept(self): - """ - Check if the union tag is ``auto_accept``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'auto_accept' + def __init__(self, + account_id=None, + display_name=None, + email=None): + self._account_id_value = None + self._account_id_present = False + self._display_name_value = None + self._display_name_present = False + self._email_value = None + self._email_present = False + if account_id is not None: + self.account_id = account_id + if display_name is not None: + self.display_name = display_name + if email is not None: + self.email = email - def is_disabled(self): + @property + def account_id(self): """ - Check if the union tag is ``disabled``. + User unique ID. Might be missing due to historical data gap. - :rtype: bool + :rtype: str """ - return self._tag == 'disabled' + if self._account_id_present: + return self._account_id_value + else: + return None - def is_require_approval(self): + @account_id.setter + def account_id(self, val): + if val is None: + del self.account_id + return + val = self._account_id_validator.validate(val) + self._account_id_value = val + self._account_id_present = True + + @account_id.deleter + def account_id(self): + self._account_id_value = None + self._account_id_present = False + + @property + def display_name(self): """ - Check if the union tag is ``require_approval``. + User display name. Might be missing due to historical data gap. - :rtype: bool + :rtype: str """ - return self._tag == 'require_approval' + if self._display_name_present: + return self._display_name_value + else: + return None - def is_other(self): + @display_name.setter + def display_name(self, val): + if val is None: + del self.display_name + return + val = self._display_name_validator.validate(val) + self._display_name_value = val + self._display_name_present = True + + @display_name.deleter + def display_name(self): + self._display_name_value = None + self._display_name_present = False + + @property + def email(self): """ - Check if the union tag is ``other``. + User email address. Might be missing due to historical data gap. - :rtype: bool + :rtype: str """ - return self._tag == 'other' + if self._email_present: + return self._email_value + else: + return None + + @email.setter + def email(self, val): + if val is None: + del self.email + return + val = self._email_validator.validate(val) + self._email_value = val + self._email_present = True + + @email.deleter + def email(self): + self._email_value = None + self._email_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberRequestsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(UserLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberRequestsPolicy(%r, %r)' % (self._tag, self._value) + return 'UserLogInfo(account_id={!r}, display_name={!r}, email={!r})'.format( + self._account_id_value, + self._display_name_value, + self._email_value, + ) -MemberRequestsPolicy_validator = bv.Union(MemberRequestsPolicy) +UserLogInfo_validator = bv.StructTree(UserLogInfo) -class MemberSpaceLimitsAddCustomQuotaDetails(bb.Struct): +class NonTeamMemberLogInfo(UserLogInfo): + """ + Non team member's logged information. """ - Set custom member space limit. - :ivar team_log.MemberSpaceLimitsAddCustomQuotaDetails.new_value: New custom - quota value in bytes. + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self, + account_id=None, + display_name=None, + email=None): + super(NonTeamMemberLogInfo, self).__init__(account_id, + display_name, + email) + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(NonTeamMemberLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'NonTeamMemberLogInfo(account_id={!r}, display_name={!r}, email={!r})'.format( + self._account_id_value, + self._display_name_value, + self._email_value, + ) + +NonTeamMemberLogInfo_validator = bv.Struct(NonTeamMemberLogInfo) + +class NonTrustedTeamDetails(bb.Struct): + """ + The email to which the request was sent + + :ivar team_log.NonTrustedTeamDetails.team: The email to which the request + was sent. """ __slots__ = [ - '_new_value_value', - '_new_value_present', + '_team_value', + '_team_present', ] _has_required_fields = True def __init__(self, - new_value=None): - self._new_value_value = None - self._new_value_present = False - if new_value is not None: - self.new_value = new_value + team=None): + self._team_value = None + self._team_present = False + if team is not None: + self.team = team @property - def new_value(self): + def team(self): """ - New custom quota value in bytes. + The email to which the request was sent. - :rtype: int + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._team_present: + return self._team_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'team'") - @new_value.setter - def new_value(self, val): - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + @team.setter + def team(self, val): + val = self._team_validator.validate(val) + self._team_value = val + self._team_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @team.deleter + def team(self): + self._team_value = None + self._team_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsAddCustomQuotaDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NonTrustedTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsAddCustomQuotaDetails(new_value={!r})'.format( - self._new_value_value, + return 'NonTrustedTeamDetails(team={!r})'.format( + self._team_value, ) -MemberSpaceLimitsAddCustomQuotaDetails_validator = bv.Struct(MemberSpaceLimitsAddCustomQuotaDetails) +NonTrustedTeamDetails_validator = bv.Struct(NonTrustedTeamDetails) -class MemberSpaceLimitsAddCustomQuotaType(bb.Struct): +class NoteAclInviteOnlyDetails(bb.Struct): + """ + Changed Paper doc to invite-only. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(NoteAclInviteOnlyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'NoteAclInviteOnlyDetails()' + +NoteAclInviteOnlyDetails_validator = bv.Struct(NoteAclInviteOnlyDetails) + +class NoteAclInviteOnlyType(bb.Struct): __slots__ = [ '_description_value', @@ -40078,18 +60478,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsAddCustomQuotaType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoteAclInviteOnlyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsAddCustomQuotaType(description={!r})'.format( + return 'NoteAclInviteOnlyType(description={!r})'.format( self._description_value, ) -MemberSpaceLimitsAddCustomQuotaType_validator = bv.Struct(MemberSpaceLimitsAddCustomQuotaType) +NoteAclInviteOnlyType_validator = bv.Struct(NoteAclInviteOnlyType) -class MemberSpaceLimitsAddExceptionDetails(bb.Struct): +class NoteAclLinkDetails(bb.Struct): """ - Added members to member space limit exception list. + Changed Paper doc to link-accessible. """ __slots__ = [ @@ -40101,14 +60501,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsAddExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoteAclLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsAddExceptionDetails()' + return 'NoteAclLinkDetails()' -MemberSpaceLimitsAddExceptionDetails_validator = bv.Struct(MemberSpaceLimitsAddExceptionDetails) +NoteAclLinkDetails_validator = bv.Struct(NoteAclLinkDetails) -class MemberSpaceLimitsAddExceptionType(bb.Struct): +class NoteAclLinkType(bb.Struct): __slots__ = [ '_description_value', @@ -40146,104 +60546,105 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsAddExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoteAclLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsAddExceptionType(description={!r})'.format( + return 'NoteAclLinkType(description={!r})'.format( self._description_value, ) -MemberSpaceLimitsAddExceptionType_validator = bv.Struct(MemberSpaceLimitsAddExceptionType) +NoteAclLinkType_validator = bv.Struct(NoteAclLinkType) -class MemberSpaceLimitsChangeCapsTypePolicyDetails(bb.Struct): +class NoteAclTeamLinkDetails(bb.Struct): """ - Changed member space limit type for team. - - :ivar team_log.MemberSpaceLimitsChangeCapsTypePolicyDetails.previous_value: - Previous space limit type. - :ivar team_log.MemberSpaceLimitsChangeCapsTypePolicyDetails.new_value: New - space limit type. + Changed Paper doc to link-accessible for team. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(NoteAclTeamLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'NoteAclTeamLinkDetails()' + +NoteAclTeamLinkDetails_validator = bv.Struct(NoteAclTeamLinkDetails) + +class NoteAclTeamLinkType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - previous_value=None, - new_value=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def previous_value(self): + def description(self): """ - Previous space limit type. - - :rtype: SpaceCapsType + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'description'") - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @property - def new_value(self): - """ - New space limit type. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(NoteAclTeamLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: SpaceCapsType - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") + def __repr__(self): + return 'NoteAclTeamLinkType(description={!r})'.format( + self._description_value, + ) - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True +NoteAclTeamLinkType_validator = bv.Struct(NoteAclTeamLinkType) + +class NoteShareReceiveDetails(bb.Struct): + """ + Shared received Paper doc. + """ + + __slots__ = [ + ] - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + _has_required_fields = False + + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangeCapsTypePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoteShareReceiveDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangeCapsTypePolicyDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, - self._new_value_value, - ) + return 'NoteShareReceiveDetails()' -MemberSpaceLimitsChangeCapsTypePolicyDetails_validator = bv.Struct(MemberSpaceLimitsChangeCapsTypePolicyDetails) +NoteShareReceiveDetails_validator = bv.Struct(NoteShareReceiveDetails) -class MemberSpaceLimitsChangeCapsTypePolicyType(bb.Struct): +class NoteShareReceiveType(bb.Struct): __slots__ = [ '_description_value', @@ -40281,104 +60682,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangeCapsTypePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoteShareReceiveType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangeCapsTypePolicyType(description={!r})'.format( + return 'NoteShareReceiveType(description={!r})'.format( self._description_value, ) -MemberSpaceLimitsChangeCapsTypePolicyType_validator = bv.Struct(MemberSpaceLimitsChangeCapsTypePolicyType) +NoteShareReceiveType_validator = bv.Struct(NoteShareReceiveType) -class MemberSpaceLimitsChangeCustomQuotaDetails(bb.Struct): +class NoteSharedDetails(bb.Struct): """ - Changed custom member space limit. - - :ivar team_log.MemberSpaceLimitsChangeCustomQuotaDetails.previous_value: - Previous custom quota value in bytes. - :ivar team_log.MemberSpaceLimitsChangeCustomQuotaDetails.new_value: New - custom quota value in bytes. + Shared Paper doc. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', ] - _has_required_fields = True - - def __init__(self, - previous_value=None, - new_value=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value - - @property - def previous_value(self): - """ - Previous custom quota value in bytes. - - :rtype: int - """ - if self._previous_value_present: - return self._previous_value_value - else: - raise AttributeError("missing required field 'previous_value'") - - @previous_value.setter - def previous_value(self, val): - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True - - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False - - @property - def new_value(self): - """ - New custom quota value in bytes. - - :rtype: int - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + _has_required_fields = False - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangeCustomQuotaDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoteSharedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangeCustomQuotaDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, - self._new_value_value, - ) + return 'NoteSharedDetails()' -MemberSpaceLimitsChangeCustomQuotaDetails_validator = bv.Struct(MemberSpaceLimitsChangeCustomQuotaDetails) +NoteSharedDetails_validator = bv.Struct(NoteSharedDetails) -class MemberSpaceLimitsChangeCustomQuotaType(bb.Struct): +class NoteSharedType(bb.Struct): __slots__ = [ '_description_value', @@ -40416,114 +60750,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangeCustomQuotaType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(NoteSharedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangeCustomQuotaType(description={!r})'.format( + return 'NoteSharedType(description={!r})'.format( self._description_value, ) -MemberSpaceLimitsChangeCustomQuotaType_validator = bv.Struct(MemberSpaceLimitsChangeCustomQuotaType) +NoteSharedType_validator = bv.Struct(NoteSharedType) -class MemberSpaceLimitsChangePolicyDetails(bb.Struct): +class OpenNoteSharedDetails(bb.Struct): """ - Changed team default member space limit. - - :ivar team_log.MemberSpaceLimitsChangePolicyDetails.previous_value: Previous - team default limit value in bytes. Might be missing due to historical - data gap. - :ivar team_log.MemberSpaceLimitsChangePolicyDetails.new_value: New team - default limit value in bytes. Might be missing due to historical data - gap. + Opened shared Paper doc. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', ] _has_required_fields = False - def __init__(self, - previous_value=None, - new_value=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value - - @property - def previous_value(self): - """ - Previous team default limit value in bytes. Might be missing due to - historical data gap. - - :rtype: int - """ - if self._previous_value_present: - return self._previous_value_value - else: - return None - - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True - - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False - - @property - def new_value(self): - """ - New team default limit value in bytes. Might be missing due to - historical data gap. - - :rtype: int - """ - if self._new_value_present: - return self._new_value_value - else: - return None - - @new_value.setter - def new_value(self, val): - if val is None: - del self.new_value - return - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OpenNoteSharedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangePolicyDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, - self._new_value_value, - ) + return 'OpenNoteSharedDetails()' -MemberSpaceLimitsChangePolicyDetails_validator = bv.Struct(MemberSpaceLimitsChangePolicyDetails) +OpenNoteSharedDetails_validator = bv.Struct(OpenNoteSharedDetails) -class MemberSpaceLimitsChangePolicyType(bb.Struct): +class OpenNoteSharedType(bb.Struct): __slots__ = [ '_description_value', @@ -40561,172 +60818,303 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OpenNoteSharedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangePolicyType(description={!r})'.format( + return 'OpenNoteSharedType(description={!r})'.format( self._description_value, ) -MemberSpaceLimitsChangePolicyType_validator = bv.Struct(MemberSpaceLimitsChangePolicyType) +OpenNoteSharedType_validator = bv.Struct(OpenNoteSharedType) -class MemberSpaceLimitsChangeStatusDetails(bb.Struct): +class OrganizationDetails(bb.Struct): """ - Changed space limit status. + More details about the organization. - :ivar team_log.MemberSpaceLimitsChangeStatusDetails.previous_value: Previous - storage quota status. - :ivar team_log.MemberSpaceLimitsChangeStatusDetails.new_value: New storage - quota status. + :ivar team_log.OrganizationDetails.organization: The name of the + organization. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', + '_organization_value', + '_organization_present', ] _has_required_fields = True def __init__(self, - previous_value=None, - new_value=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value + organization=None): + self._organization_value = None + self._organization_present = False + if organization is not None: + self.organization = organization @property - def previous_value(self): + def organization(self): """ - Previous storage quota status. + The name of the organization. - :rtype: SpaceLimitsStatus + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._organization_present: + return self._organization_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'organization'") - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @organization.setter + def organization(self, val): + val = self._organization_validator.validate(val) + self._organization_value = val + self._organization_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @organization.deleter + def organization(self): + self._organization_value = None + self._organization_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(OrganizationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'OrganizationDetails(organization={!r})'.format( + self._organization_value, + ) + +OrganizationDetails_validator = bv.Struct(OrganizationDetails) + +class OrganizationName(bb.Struct): + """ + The name of the organization + + :ivar team_log.OrganizationName.organization: The name of the organization. + """ + + __slots__ = [ + '_organization_value', + '_organization_present', + ] + + _has_required_fields = True + + def __init__(self, + organization=None): + self._organization_value = None + self._organization_present = False + if organization is not None: + self.organization = organization @property - def new_value(self): + def organization(self): """ - New storage quota status. + The name of the organization. - :rtype: SpaceLimitsStatus + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._organization_present: + return self._organization_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'organization'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @organization.setter + def organization(self, val): + val = self._organization_validator.validate(val) + self._organization_value = val + self._organization_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @organization.deleter + def organization(self): + self._organization_value = None + self._organization_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangeStatusDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OrganizationName, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangeStatusDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, - self._new_value_value, + return 'OrganizationName(organization={!r})'.format( + self._organization_value, ) -MemberSpaceLimitsChangeStatusDetails_validator = bv.Struct(MemberSpaceLimitsChangeStatusDetails) +OrganizationName_validator = bv.Struct(OrganizationName) -class MemberSpaceLimitsChangeStatusType(bb.Struct): +class OriginLogInfo(bb.Struct): + """ + The origin from which the actor performed the action. + + :ivar team_log.OriginLogInfo.geo_location: Geographic location details. + :ivar team_log.OriginLogInfo.access_method: The method that was used to + perform the action. + """ __slots__ = [ - '_description_value', - '_description_present', + '_geo_location_value', + '_geo_location_present', + '_access_method_value', + '_access_method_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + access_method=None, + geo_location=None): + self._geo_location_value = None + self._geo_location_present = False + self._access_method_value = None + self._access_method_present = False + if geo_location is not None: + self.geo_location = geo_location + if access_method is not None: + self.access_method = access_method @property - def description(self): + def geo_location(self): """ - :rtype: str + Geographic location details. + + :rtype: GeoLocationLogInfo """ - if self._description_present: - return self._description_value + if self._geo_location_present: + return self._geo_location_value else: - raise AttributeError("missing required field 'description'") + return None - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @geo_location.setter + def geo_location(self, val): + if val is None: + del self.geo_location + return + self._geo_location_validator.validate_type_only(val) + self._geo_location_value = val + self._geo_location_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @geo_location.deleter + def geo_location(self): + self._geo_location_value = None + self._geo_location_present = False + + @property + def access_method(self): + """ + The method that was used to perform the action. + + :rtype: AccessMethodLogInfo + """ + if self._access_method_present: + return self._access_method_value + else: + raise AttributeError("missing required field 'access_method'") + + @access_method.setter + def access_method(self, val): + self._access_method_validator.validate_type_only(val) + self._access_method_value = val + self._access_method_present = True + + @access_method.deleter + def access_method(self): + self._access_method_value = None + self._access_method_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsChangeStatusType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OriginLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsChangeStatusType(description={!r})'.format( - self._description_value, + return 'OriginLogInfo(access_method={!r}, geo_location={!r})'.format( + self._access_method_value, + self._geo_location_value, ) -MemberSpaceLimitsChangeStatusType_validator = bv.Struct(MemberSpaceLimitsChangeStatusType) +OriginLogInfo_validator = bv.Struct(OriginLogInfo) -class MemberSpaceLimitsRemoveCustomQuotaDetails(bb.Struct): +class OutdatedLinkViewCreateReportDetails(bb.Struct): """ - Removed custom member space limit. + Report created: Views of old links. + + :ivar team_log.OutdatedLinkViewCreateReportDetails.start_date: Report start + date. + :ivar team_log.OutdatedLinkViewCreateReportDetails.end_date: Report end + date. """ __slots__ = [ + '_start_date_value', + '_start_date_present', + '_end_date_value', + '_end_date_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + start_date=None, + end_date=None): + self._start_date_value = None + self._start_date_present = False + self._end_date_value = None + self._end_date_present = False + if start_date is not None: + self.start_date = start_date + if end_date is not None: + self.end_date = end_date + + @property + def start_date(self): + """ + Report start date. + + :rtype: datetime.datetime + """ + if self._start_date_present: + return self._start_date_value + else: + raise AttributeError("missing required field 'start_date'") + + @start_date.setter + def start_date(self, val): + val = self._start_date_validator.validate(val) + self._start_date_value = val + self._start_date_present = True + + @start_date.deleter + def start_date(self): + self._start_date_value = None + self._start_date_present = False + + @property + def end_date(self): + """ + Report end date. + + :rtype: datetime.datetime + """ + if self._end_date_present: + return self._end_date_value + else: + raise AttributeError("missing required field 'end_date'") + + @end_date.setter + def end_date(self, val): + val = self._end_date_validator.validate(val) + self._end_date_value = val + self._end_date_present = True + + @end_date.deleter + def end_date(self): + self._end_date_value = None + self._end_date_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsRemoveCustomQuotaDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OutdatedLinkViewCreateReportDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsRemoveCustomQuotaDetails()' + return 'OutdatedLinkViewCreateReportDetails(start_date={!r}, end_date={!r})'.format( + self._start_date_value, + self._end_date_value, + ) -MemberSpaceLimitsRemoveCustomQuotaDetails_validator = bv.Struct(MemberSpaceLimitsRemoveCustomQuotaDetails) +OutdatedLinkViewCreateReportDetails_validator = bv.Struct(OutdatedLinkViewCreateReportDetails) -class MemberSpaceLimitsRemoveCustomQuotaType(bb.Struct): +class OutdatedLinkViewCreateReportType(bb.Struct): __slots__ = [ '_description_value', @@ -40764,37 +61152,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsRemoveCustomQuotaType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OutdatedLinkViewCreateReportType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsRemoveCustomQuotaType(description={!r})'.format( + return 'OutdatedLinkViewCreateReportType(description={!r})'.format( self._description_value, ) -MemberSpaceLimitsRemoveCustomQuotaType_validator = bv.Struct(MemberSpaceLimitsRemoveCustomQuotaType) +OutdatedLinkViewCreateReportType_validator = bv.Struct(OutdatedLinkViewCreateReportType) -class MemberSpaceLimitsRemoveExceptionDetails(bb.Struct): +class OutdatedLinkViewReportFailedDetails(bb.Struct): """ - Removed members from member space limit exception list. + Couldn't create report: Views of old links. + + :ivar team_log.OutdatedLinkViewReportFailedDetails.failure_reason: Failure + reason. """ __slots__ = [ + '_failure_reason_value', + '_failure_reason_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + failure_reason=None): + self._failure_reason_value = None + self._failure_reason_present = False + if failure_reason is not None: + self.failure_reason = failure_reason + + @property + def failure_reason(self): + """ + Failure reason. + + :rtype: team.TeamReportFailureReason + """ + if self._failure_reason_present: + return self._failure_reason_value + else: + raise AttributeError("missing required field 'failure_reason'") + + @failure_reason.setter + def failure_reason(self, val): + self._failure_reason_validator.validate_type_only(val) + self._failure_reason_value = val + self._failure_reason_present = True + + @failure_reason.deleter + def failure_reason(self): + self._failure_reason_value = None + self._failure_reason_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsRemoveExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OutdatedLinkViewReportFailedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsRemoveExceptionDetails()' + return 'OutdatedLinkViewReportFailedDetails(failure_reason={!r})'.format( + self._failure_reason_value, + ) -MemberSpaceLimitsRemoveExceptionDetails_validator = bv.Struct(MemberSpaceLimitsRemoveExceptionDetails) +OutdatedLinkViewReportFailedDetails_validator = bv.Struct(OutdatedLinkViewReportFailedDetails) -class MemberSpaceLimitsRemoveExceptionType(bb.Struct): +class OutdatedLinkViewReportFailedType(bb.Struct): __slots__ = [ '_description_value', @@ -40832,16 +61254,16 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSpaceLimitsRemoveExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(OutdatedLinkViewReportFailedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSpaceLimitsRemoveExceptionType(description={!r})'.format( + return 'OutdatedLinkViewReportFailedType(description={!r})'.format( self._description_value, ) -MemberSpaceLimitsRemoveExceptionType_validator = bv.Struct(MemberSpaceLimitsRemoveExceptionType) +OutdatedLinkViewReportFailedType_validator = bv.Struct(OutdatedLinkViewReportFailedType) -class MemberStatus(bb.Union): +class PaperAccessType(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the @@ -40850,57 +61272,37 @@ class MemberStatus(bb.Union): _catch_all = 'other' # Attribute is overwritten below the class definition - not_joined = None - # Attribute is overwritten below the class definition - invited = None - # Attribute is overwritten below the class definition - active = None + viewer = None # Attribute is overwritten below the class definition - suspended = None + commenter = None # Attribute is overwritten below the class definition - removed = None + editor = None # Attribute is overwritten below the class definition other = None - def is_not_joined(self): - """ - Check if the union tag is ``not_joined``. - - :rtype: bool - """ - return self._tag == 'not_joined' - - def is_invited(self): - """ - Check if the union tag is ``invited``. - - :rtype: bool - """ - return self._tag == 'invited' - - def is_active(self): + def is_viewer(self): """ - Check if the union tag is ``active``. + Check if the union tag is ``viewer``. :rtype: bool """ - return self._tag == 'active' + return self._tag == 'viewer' - def is_suspended(self): + def is_commenter(self): """ - Check if the union tag is ``suspended``. + Check if the union tag is ``commenter``. :rtype: bool """ - return self._tag == 'suspended' + return self._tag == 'commenter' - def is_removed(self): + def is_editor(self): """ - Check if the union tag is ``removed``. + Check if the union tag is ``editor``. :rtype: bool """ - return self._tag == 'removed' + return self._tag == 'editor' def is_other(self): """ @@ -40911,69 +61313,35 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberStatus, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberStatus(%r, %r)' % (self._tag, self._value) + return 'PaperAccessType(%r, %r)' % (self._tag, self._value) -MemberStatus_validator = bv.Union(MemberStatus) +PaperAccessType_validator = bv.Union(PaperAccessType) -class MemberSuggestDetails(bb.Struct): +class PaperAdminExportStartDetails(bb.Struct): """ - Suggested person to add to team. - - :ivar team_log.MemberSuggestDetails.suggested_members: suggested users - emails. + Exported all team Paper docs. """ __slots__ = [ - '_suggested_members_value', - '_suggested_members_present', ] - _has_required_fields = True - - def __init__(self, - suggested_members=None): - self._suggested_members_value = None - self._suggested_members_present = False - if suggested_members is not None: - self.suggested_members = suggested_members - - @property - def suggested_members(self): - """ - suggested users emails. - - :rtype: list of [str] - """ - if self._suggested_members_present: - return self._suggested_members_value - else: - raise AttributeError("missing required field 'suggested_members'") - - @suggested_members.setter - def suggested_members(self, val): - val = self._suggested_members_validator.validate(val) - self._suggested_members_value = val - self._suggested_members_present = True + _has_required_fields = False - @suggested_members.deleter - def suggested_members(self): - self._suggested_members_value = None - self._suggested_members_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSuggestDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperAdminExportStartDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSuggestDetails(suggested_members={!r})'.format( - self._suggested_members_value, - ) + return 'PaperAdminExportStartDetails()' -MemberSuggestDetails_validator = bv.Struct(MemberSuggestDetails) +PaperAdminExportStartDetails_validator = bv.Struct(PaperAdminExportStartDetails) -class MemberSuggestType(bb.Struct): +class PaperAdminExportStartType(bb.Struct): __slots__ = [ '_description_value', @@ -41011,23 +61379,24 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSuggestType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperAdminExportStartType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSuggestType(description={!r})'.format( + return 'PaperAdminExportStartType(description={!r})'.format( self._description_value, ) -MemberSuggestType_validator = bv.Struct(MemberSuggestType) +PaperAdminExportStartType_validator = bv.Struct(PaperAdminExportStartType) -class MemberSuggestionsChangePolicyDetails(bb.Struct): +class PaperChangeDeploymentPolicyDetails(bb.Struct): """ - Enabled/disabled option for team members to suggest people to add to team. + Changed whether Dropbox Paper, when enabled, is deployed to all members or + to specific members. - :ivar team_log.MemberSuggestionsChangePolicyDetails.new_value: New team - member suggestions policy. - :ivar team_log.MemberSuggestionsChangePolicyDetails.previous_value: Previous - team member suggestions policy. Might be missing due to historical data + :ivar team_log.PaperChangeDeploymentPolicyDetails.new_value: New Dropbox + Paper deployment policy. + :ivar team_log.PaperChangeDeploymentPolicyDetails.previous_value: Previous + Dropbox Paper deployment policy. Might be missing due to historical data gap. """ @@ -41055,9 +61424,9 @@ def __init__(self, @property def new_value(self): """ - New team member suggestions policy. + New Dropbox Paper deployment policy. - :rtype: MemberSuggestionsPolicy + :rtype: team_policies.PaperDeploymentPolicy """ if self._new_value_present: return self._new_value_value @@ -41078,10 +61447,10 @@ def new_value(self): @property def previous_value(self): """ - Previous team member suggestions policy. Might be missing due to + Previous Dropbox Paper deployment policy. Might be missing due to historical data gap. - :rtype: MemberSuggestionsPolicy + :rtype: team_policies.PaperDeploymentPolicy """ if self._previous_value_present: return self._previous_value_value @@ -41103,17 +61472,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSuggestionsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangeDeploymentPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSuggestionsChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'PaperChangeDeploymentPolicyDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -MemberSuggestionsChangePolicyDetails_validator = bv.Struct(MemberSuggestionsChangePolicyDetails) +PaperChangeDeploymentPolicyDetails_validator = bv.Struct(PaperChangeDeploymentPolicyDetails) -class MemberSuggestionsChangePolicyType(bb.Struct): +class PaperChangeDeploymentPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -41151,86 +61520,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSuggestionsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangeDeploymentPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberSuggestionsChangePolicyType(description={!r})'.format( + return 'PaperChangeDeploymentPolicyType(description={!r})'.format( self._description_value, ) -MemberSuggestionsChangePolicyType_validator = bv.Struct(MemberSuggestionsChangePolicyType) +PaperChangeDeploymentPolicyType_validator = bv.Struct(PaperChangeDeploymentPolicyType) -class MemberSuggestionsPolicy(bb.Union): +class PaperChangeMemberLinkPolicyDetails(bb.Struct): """ - Member suggestions policy + Changed whether non-members can view Paper docs with link. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team_log.PaperChangeMemberLinkPolicyDetails.new_value: New paper + external link accessibility policy. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None - - def is_disabled(self): - """ - Check if the union tag is ``disabled``. - - :rtype: bool - """ - return self._tag == 'disabled' + __slots__ = [ + '_new_value_value', + '_new_value_present', + ] - def is_enabled(self): - """ - Check if the union tag is ``enabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'enabled' + def __init__(self, + new_value=None): + self._new_value_value = None + self._new_value_present = False + if new_value is not None: + self.new_value = new_value - def is_other(self): + @property + def new_value(self): """ - Check if the union tag is ``other``. + New paper external link accessibility policy. - :rtype: bool + :rtype: PaperMemberPolicy """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberSuggestionsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'MemberSuggestionsPolicy(%r, %r)' % (self._tag, self._value) - -MemberSuggestionsPolicy_validator = bv.Union(MemberSuggestionsPolicy) - -class MemberTransferAccountContentsDetails(bb.Struct): - """ - Transferred contents of deleted member account to another member. - """ - - __slots__ = [ - ] + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - _has_required_fields = False + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - def __init__(self): - pass + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberTransferAccountContentsDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangeMemberLinkPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberTransferAccountContentsDetails()' + return 'PaperChangeMemberLinkPolicyDetails(new_value={!r})'.format( + self._new_value_value, + ) -MemberTransferAccountContentsDetails_validator = bv.Struct(MemberTransferAccountContentsDetails) +PaperChangeMemberLinkPolicyDetails_validator = bv.Struct(PaperChangeMemberLinkPolicyDetails) -class MemberTransferAccountContentsType(bb.Struct): +class PaperChangeMemberLinkPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -41268,24 +61622,25 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MemberTransferAccountContentsType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangeMemberLinkPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MemberTransferAccountContentsType(description={!r})'.format( + return 'PaperChangeMemberLinkPolicyType(description={!r})'.format( self._description_value, ) -MemberTransferAccountContentsType_validator = bv.Struct(MemberTransferAccountContentsType) +PaperChangeMemberLinkPolicyType_validator = bv.Struct(PaperChangeMemberLinkPolicyType) -class MicrosoftOfficeAddinChangePolicyDetails(bb.Struct): +class PaperChangeMemberPolicyDetails(bb.Struct): """ - Enabled/disabled Microsoft Office add-in. + Changed whether members can share Paper docs outside team, and if docs are + accessible only by team members or anyone by default. - :ivar team_log.MicrosoftOfficeAddinChangePolicyDetails.new_value: New - Microsoft Office addin policy. - :ivar team_log.MicrosoftOfficeAddinChangePolicyDetails.previous_value: - Previous Microsoft Office addin policy. Might be missing due to - historical data gap. + :ivar team_log.PaperChangeMemberPolicyDetails.new_value: New paper external + accessibility policy. + :ivar team_log.PaperChangeMemberPolicyDetails.previous_value: Previous paper + external accessibility policy. Might be missing due to historical data + gap. """ __slots__ = [ @@ -41312,9 +61667,9 @@ def __init__(self, @property def new_value(self): """ - New Microsoft Office addin policy. + New paper external accessibility policy. - :rtype: MicrosoftOfficeAddinPolicy + :rtype: PaperMemberPolicy """ if self._new_value_present: return self._new_value_value @@ -41335,10 +61690,10 @@ def new_value(self): @property def previous_value(self): """ - Previous Microsoft Office addin policy. Might be missing due to + Previous paper external accessibility policy. Might be missing due to historical data gap. - :rtype: MicrosoftOfficeAddinPolicy + :rtype: PaperMemberPolicy """ if self._previous_value_present: return self._previous_value_value @@ -41360,17 +61715,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MicrosoftOfficeAddinChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangeMemberPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MicrosoftOfficeAddinChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'PaperChangeMemberPolicyDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -MicrosoftOfficeAddinChangePolicyDetails_validator = bv.Struct(MicrosoftOfficeAddinChangePolicyDetails) +PaperChangeMemberPolicyDetails_validator = bv.Struct(PaperChangeMemberPolicyDetails) -class MicrosoftOfficeAddinChangePolicyType(bb.Struct): +class PaperChangeMemberPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -41408,577 +61763,581 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MicrosoftOfficeAddinChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangeMemberPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MicrosoftOfficeAddinChangePolicyType(description={!r})'.format( + return 'PaperChangeMemberPolicyType(description={!r})'.format( self._description_value, ) -MicrosoftOfficeAddinChangePolicyType_validator = bv.Struct(MicrosoftOfficeAddinChangePolicyType) +PaperChangeMemberPolicyType_validator = bv.Struct(PaperChangeMemberPolicyType) -class MicrosoftOfficeAddinPolicy(bb.Union): +class PaperChangePolicyDetails(bb.Struct): """ - Microsoft Office addin policy + Enabled/disabled Dropbox Paper for team. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team_log.PaperChangePolicyDetails.new_value: New Dropbox Paper policy. + :ivar team_log.PaperChangePolicyDetails.previous_value: Previous Dropbox + Paper policy. Might be missing due to historical data gap. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] - def is_disabled(self): - """ - Check if the union tag is ``disabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'disabled' + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value - def is_enabled(self): + @property + def new_value(self): """ - Check if the union tag is ``enabled``. + New Dropbox Paper policy. - :rtype: bool + :rtype: team_policies.PaperEnabledPolicy """ - return self._tag == 'enabled' + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - def is_other(self): + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): """ - Check if the union tag is ``other``. + Previous Dropbox Paper policy. Might be missing due to historical data + gap. - :rtype: bool + :rtype: team_policies.PaperEnabledPolicy """ - return self._tag == 'other' + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MicrosoftOfficeAddinPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MicrosoftOfficeAddinPolicy(%r, %r)' % (self._tag, self._value) - -MicrosoftOfficeAddinPolicy_validator = bv.Union(MicrosoftOfficeAddinPolicy) + return 'PaperChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -class MissingDetails(bb.Struct): - """ - An indication that an error occurred while retrieving the event. Some - attributes of the event may be omitted as a result. +PaperChangePolicyDetails_validator = bv.Struct(PaperChangePolicyDetails) - :ivar team_log.MissingDetails.source_event_fields: All the data that could - be retrieved and converted from the source event. - """ +class PaperChangePolicyType(bb.Struct): __slots__ = [ - '_source_event_fields_value', - '_source_event_fields_present', + '_description_value', + '_description_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - source_event_fields=None): - self._source_event_fields_value = None - self._source_event_fields_present = False - if source_event_fields is not None: - self.source_event_fields = source_event_fields + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def source_event_fields(self): + def description(self): """ - All the data that could be retrieved and converted from the source - event. - :rtype: str """ - if self._source_event_fields_present: - return self._source_event_fields_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @source_event_fields.setter - def source_event_fields(self, val): - if val is None: - del self.source_event_fields - return - val = self._source_event_fields_validator.validate(val) - self._source_event_fields_value = val - self._source_event_fields_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @source_event_fields.deleter - def source_event_fields(self): - self._source_event_fields_value = None - self._source_event_fields_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MissingDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MissingDetails(source_event_fields={!r})'.format( - self._source_event_fields_value, + return 'PaperChangePolicyType(description={!r})'.format( + self._description_value, ) -MissingDetails_validator = bv.Struct(MissingDetails) +PaperChangePolicyType_validator = bv.Struct(PaperChangePolicyType) -class MobileDeviceSessionLogInfo(DeviceSessionLogInfo): +class PaperContentAddMemberDetails(bb.Struct): """ - Information about linked Dropbox mobile client sessions + Added users and/or groups to Paper doc/folder. - :ivar team_log.MobileDeviceSessionLogInfo.session_info: Mobile session - unique id. Might be missing due to historical data gap. - :ivar team_log.MobileDeviceSessionLogInfo.device_name: The device name. - :ivar team_log.MobileDeviceSessionLogInfo.client_type: The mobile - application type. - :ivar team_log.MobileDeviceSessionLogInfo.client_version: The Dropbox client - version. - :ivar team_log.MobileDeviceSessionLogInfo.os_version: The hosting OS - version. - :ivar team_log.MobileDeviceSessionLogInfo.last_carrier: last carrier used by - the device. + :ivar team_log.PaperContentAddMemberDetails.event_uuid: Event unique + identifier. """ __slots__ = [ - '_session_info_value', - '_session_info_present', - '_device_name_value', - '_device_name_present', - '_client_type_value', - '_client_type_present', - '_client_version_value', - '_client_version_present', - '_os_version_value', - '_os_version_present', - '_last_carrier_value', - '_last_carrier_present', + '_event_uuid_value', + '_event_uuid_present', ] _has_required_fields = True def __init__(self, - device_name=None, - client_type=None, - ip_address=None, - created=None, - updated=None, - session_info=None, - client_version=None, - os_version=None, - last_carrier=None): - super(MobileDeviceSessionLogInfo, self).__init__(ip_address, - created, - updated) - self._session_info_value = None - self._session_info_present = False - self._device_name_value = None - self._device_name_present = False - self._client_type_value = None - self._client_type_present = False - self._client_version_value = None - self._client_version_present = False - self._os_version_value = None - self._os_version_present = False - self._last_carrier_value = None - self._last_carrier_present = False - if session_info is not None: - self.session_info = session_info - if device_name is not None: - self.device_name = device_name - if client_type is not None: - self.client_type = client_type - if client_version is not None: - self.client_version = client_version - if os_version is not None: - self.os_version = os_version - if last_carrier is not None: - self.last_carrier = last_carrier + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid @property - def session_info(self): + def event_uuid(self): """ - Mobile session unique id. Might be missing due to historical data gap. + Event unique identifier. - :rtype: MobileSessionLogInfo + :rtype: str """ - if self._session_info_present: - return self._session_info_value + if self._event_uuid_present: + return self._event_uuid_value else: - return None + raise AttributeError("missing required field 'event_uuid'") - @session_info.setter - def session_info(self, val): - if val is None: - del self.session_info - return - self._session_info_validator.validate_type_only(val) - self._session_info_value = val - self._session_info_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @session_info.deleter - def session_info(self): - self._session_info_value = None - self._session_info_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperContentAddMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperContentAddMemberDetails(event_uuid={!r})'.format( + self._event_uuid_value, + ) + +PaperContentAddMemberDetails_validator = bv.Struct(PaperContentAddMemberDetails) + +class PaperContentAddMemberType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def device_name(self): + def description(self): """ - The device name. - :rtype: str """ - if self._device_name_present: - return self._device_name_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'device_name'") + raise AttributeError("missing required field 'description'") - @device_name.setter - def device_name(self, val): - val = self._device_name_validator.validate(val) - self._device_name_value = val - self._device_name_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @device_name.deleter - def device_name(self): - self._device_name_value = None - self._device_name_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @property - def client_type(self): - """ - The mobile application type. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperContentAddMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: team.MobileClientPlatform - """ - if self._client_type_present: - return self._client_type_value - else: - raise AttributeError("missing required field 'client_type'") + def __repr__(self): + return 'PaperContentAddMemberType(description={!r})'.format( + self._description_value, + ) - @client_type.setter - def client_type(self, val): - self._client_type_validator.validate_type_only(val) - self._client_type_value = val - self._client_type_present = True +PaperContentAddMemberType_validator = bv.Struct(PaperContentAddMemberType) - @client_type.deleter - def client_type(self): - self._client_type_value = None - self._client_type_present = False +class PaperContentAddToFolderDetails(bb.Struct): + """ + Added Paper doc/folder to folder. + + :ivar team_log.PaperContentAddToFolderDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperContentAddToFolderDetails.target_asset_index: Target + asset position in the Assets list. + :ivar team_log.PaperContentAddToFolderDetails.parent_asset_index: Parent + asset position in the Assets list. + """ + + __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', + '_target_asset_index_value', + '_target_asset_index_present', + '_parent_asset_index_value', + '_parent_asset_index_present', + ] + + _has_required_fields = True + + def __init__(self, + event_uuid=None, + target_asset_index=None, + parent_asset_index=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._target_asset_index_value = None + self._target_asset_index_present = False + self._parent_asset_index_value = None + self._parent_asset_index_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if target_asset_index is not None: + self.target_asset_index = target_asset_index + if parent_asset_index is not None: + self.parent_asset_index = parent_asset_index @property - def client_version(self): + def event_uuid(self): """ - The Dropbox client version. + Event unique identifier. :rtype: str """ - if self._client_version_present: - return self._client_version_value + if self._event_uuid_present: + return self._event_uuid_value else: - return None + raise AttributeError("missing required field 'event_uuid'") - @client_version.setter - def client_version(self, val): - if val is None: - del self.client_version - return - val = self._client_version_validator.validate(val) - self._client_version_value = val - self._client_version_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @client_version.deleter - def client_version(self): - self._client_version_value = None - self._client_version_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def os_version(self): + def target_asset_index(self): """ - The hosting OS version. + Target asset position in the Assets list. - :rtype: str + :rtype: int """ - if self._os_version_present: - return self._os_version_value + if self._target_asset_index_present: + return self._target_asset_index_value else: - return None + raise AttributeError("missing required field 'target_asset_index'") - @os_version.setter - def os_version(self, val): - if val is None: - del self.os_version - return - val = self._os_version_validator.validate(val) - self._os_version_value = val - self._os_version_present = True + @target_asset_index.setter + def target_asset_index(self, val): + val = self._target_asset_index_validator.validate(val) + self._target_asset_index_value = val + self._target_asset_index_present = True - @os_version.deleter - def os_version(self): - self._os_version_value = None - self._os_version_present = False + @target_asset_index.deleter + def target_asset_index(self): + self._target_asset_index_value = None + self._target_asset_index_present = False @property - def last_carrier(self): + def parent_asset_index(self): """ - last carrier used by the device. + Parent asset position in the Assets list. - :rtype: str + :rtype: int """ - if self._last_carrier_present: - return self._last_carrier_value + if self._parent_asset_index_present: + return self._parent_asset_index_value else: - return None + raise AttributeError("missing required field 'parent_asset_index'") - @last_carrier.setter - def last_carrier(self, val): - if val is None: - del self.last_carrier - return - val = self._last_carrier_validator.validate(val) - self._last_carrier_value = val - self._last_carrier_present = True + @parent_asset_index.setter + def parent_asset_index(self, val): + val = self._parent_asset_index_validator.validate(val) + self._parent_asset_index_value = val + self._parent_asset_index_present = True - @last_carrier.deleter - def last_carrier(self): - self._last_carrier_value = None - self._last_carrier_present = False + @parent_asset_index.deleter + def parent_asset_index(self): + self._parent_asset_index_value = None + self._parent_asset_index_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MobileDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentAddToFolderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MobileDeviceSessionLogInfo(device_name={!r}, client_type={!r}, ip_address={!r}, created={!r}, updated={!r}, session_info={!r}, client_version={!r}, os_version={!r}, last_carrier={!r})'.format( - self._device_name_value, - self._client_type_value, - self._ip_address_value, - self._created_value, - self._updated_value, - self._session_info_value, - self._client_version_value, - self._os_version_value, - self._last_carrier_value, + return 'PaperContentAddToFolderDetails(event_uuid={!r}, target_asset_index={!r}, parent_asset_index={!r})'.format( + self._event_uuid_value, + self._target_asset_index_value, + self._parent_asset_index_value, ) -MobileDeviceSessionLogInfo_validator = bv.Struct(MobileDeviceSessionLogInfo) +PaperContentAddToFolderDetails_validator = bv.Struct(PaperContentAddToFolderDetails) -class MobileSessionLogInfo(SessionLogInfo): - """ - Mobile session. - """ +class PaperContentAddToFolderType(bb.Struct): __slots__ = [ + '_description_value', + '_description_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - session_id=None): - super(MobileSessionLogInfo, self).__init__(session_id) + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(MobileSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentAddToFolderType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'MobileSessionLogInfo(session_id={!r})'.format( - self._session_id_value, + return 'PaperContentAddToFolderType(description={!r})'.format( + self._description_value, ) -MobileSessionLogInfo_validator = bv.Struct(MobileSessionLogInfo) +PaperContentAddToFolderType_validator = bv.Struct(PaperContentAddToFolderType) -class NamespaceRelativePathLogInfo(bb.Struct): +class PaperContentArchiveDetails(bb.Struct): """ - Namespace relative path details. + Archived Paper doc/folder. - :ivar team_log.NamespaceRelativePathLogInfo.ns_id: Namespace ID. Might be - missing due to historical data gap. - :ivar team_log.NamespaceRelativePathLogInfo.relative_path: A path relative - to the specified namespace ID. Might be missing due to historical data - gap. + :ivar team_log.PaperContentArchiveDetails.event_uuid: Event unique + identifier. """ __slots__ = [ - '_ns_id_value', - '_ns_id_present', - '_relative_path_value', - '_relative_path_present', + '_event_uuid_value', + '_event_uuid_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - ns_id=None, - relative_path=None): - self._ns_id_value = None - self._ns_id_present = False - self._relative_path_value = None - self._relative_path_present = False - if ns_id is not None: - self.ns_id = ns_id - if relative_path is not None: - self.relative_path = relative_path + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid @property - def ns_id(self): + def event_uuid(self): """ - Namespace ID. Might be missing due to historical data gap. + Event unique identifier. :rtype: str """ - if self._ns_id_present: - return self._ns_id_value + if self._event_uuid_present: + return self._event_uuid_value else: - return None + raise AttributeError("missing required field 'event_uuid'") - @ns_id.setter - def ns_id(self, val): - if val is None: - del self.ns_id - return - val = self._ns_id_validator.validate(val) - self._ns_id_value = val - self._ns_id_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @ns_id.deleter - def ns_id(self): - self._ns_id_value = None - self._ns_id_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperContentArchiveDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperContentArchiveDetails(event_uuid={!r})'.format( + self._event_uuid_value, + ) + +PaperContentArchiveDetails_validator = bv.Struct(PaperContentArchiveDetails) + +class PaperContentArchiveType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def relative_path(self): + def description(self): """ - A path relative to the specified namespace ID. Might be missing due to - historical data gap. - :rtype: str """ - if self._relative_path_present: - return self._relative_path_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @relative_path.setter - def relative_path(self, val): - if val is None: - del self.relative_path - return - val = self._relative_path_validator.validate(val) - self._relative_path_value = val - self._relative_path_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @relative_path.deleter - def relative_path(self): - self._relative_path_value = None - self._relative_path_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NamespaceRelativePathLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentArchiveType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NamespaceRelativePathLogInfo(ns_id={!r}, relative_path={!r})'.format( - self._ns_id_value, - self._relative_path_value, + return 'PaperContentArchiveType(description={!r})'.format( + self._description_value, ) -NamespaceRelativePathLogInfo_validator = bv.Struct(NamespaceRelativePathLogInfo) +PaperContentArchiveType_validator = bv.Struct(PaperContentArchiveType) -class NetworkControlChangePolicyDetails(bb.Struct): +class PaperContentCreateDetails(bb.Struct): """ - Enabled/disabled network control. + Created Paper doc/folder. - :ivar team_log.NetworkControlChangePolicyDetails.new_value: New network - control policy. - :ivar team_log.NetworkControlChangePolicyDetails.previous_value: Previous - network control policy. Might be missing due to historical data gap. + :ivar team_log.PaperContentCreateDetails.event_uuid: Event unique + identifier. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_event_uuid_value', + '_event_uuid_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New network control policy. - - :rtype: NetworkControlPolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid @property - def previous_value(self): + def event_uuid(self): """ - Previous network control policy. Might be missing due to historical data - gap. + Event unique identifier. - :rtype: NetworkControlPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - return None + raise AttributeError("missing required field 'event_uuid'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NetworkControlChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NetworkControlChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'PaperContentCreateDetails(event_uuid={!r})'.format( + self._event_uuid_value, ) -NetworkControlChangePolicyDetails_validator = bv.Struct(NetworkControlChangePolicyDetails) +PaperContentCreateDetails_validator = bv.Struct(PaperContentCreateDetails) -class NetworkControlChangePolicyType(bb.Struct): +class PaperContentCreateType(bb.Struct): __slots__ = [ '_description_value', @@ -42016,246 +62375,347 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NetworkControlChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NetworkControlChangePolicyType(description={!r})'.format( + return 'PaperContentCreateType(description={!r})'.format( self._description_value, ) -NetworkControlChangePolicyType_validator = bv.Struct(NetworkControlChangePolicyType) +PaperContentCreateType_validator = bv.Struct(PaperContentCreateType) -class NetworkControlPolicy(bb.Union): +class PaperContentPermanentlyDeleteDetails(bb.Struct): """ - Network control policy + Permanently deleted Paper doc/folder. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team_log.PaperContentPermanentlyDeleteDetails.event_uuid: Event unique + identifier. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', + ] - def is_disabled(self): - """ - Check if the union tag is ``disabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'disabled' + def __init__(self, + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid - def is_enabled(self): + @property + def event_uuid(self): """ - Check if the union tag is ``enabled``. + Event unique identifier. - :rtype: bool + :rtype: str """ - return self._tag == 'enabled' + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") - def is_other(self): - """ - Check if the union tag is ``other``. + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - :rtype: bool + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperContentPermanentlyDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperContentPermanentlyDeleteDetails(event_uuid={!r})'.format( + self._event_uuid_value, + ) + +PaperContentPermanentlyDeleteDetails_validator = bv.Struct(PaperContentPermanentlyDeleteDetails) + +class PaperContentPermanentlyDeleteType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): """ - return self._tag == 'other' + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NetworkControlPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentPermanentlyDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NetworkControlPolicy(%r, %r)' % (self._tag, self._value) + return 'PaperContentPermanentlyDeleteType(description={!r})'.format( + self._description_value, + ) -NetworkControlPolicy_validator = bv.Union(NetworkControlPolicy) +PaperContentPermanentlyDeleteType_validator = bv.Struct(PaperContentPermanentlyDeleteType) -class UserLogInfo(bb.Struct): +class PaperContentRemoveFromFolderDetails(bb.Struct): """ - User's logged information. + Removed Paper doc/folder from folder. - :ivar team_log.UserLogInfo.account_id: User unique ID. Might be missing due - to historical data gap. - :ivar team_log.UserLogInfo.display_name: User display name. Might be missing - due to historical data gap. - :ivar team_log.UserLogInfo.email: User email address. Might be missing due - to historical data gap. + :ivar team_log.PaperContentRemoveFromFolderDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperContentRemoveFromFolderDetails.target_asset_index: + Target asset position in the Assets list. + :ivar team_log.PaperContentRemoveFromFolderDetails.parent_asset_index: + Parent asset position in the Assets list. """ __slots__ = [ - '_account_id_value', - '_account_id_present', - '_display_name_value', - '_display_name_present', - '_email_value', - '_email_present', + '_event_uuid_value', + '_event_uuid_present', + '_target_asset_index_value', + '_target_asset_index_present', + '_parent_asset_index_value', + '_parent_asset_index_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - account_id=None, - display_name=None, - email=None): - self._account_id_value = None - self._account_id_present = False - self._display_name_value = None - self._display_name_present = False - self._email_value = None - self._email_present = False - if account_id is not None: - self.account_id = account_id - if display_name is not None: - self.display_name = display_name - if email is not None: - self.email = email + event_uuid=None, + target_asset_index=None, + parent_asset_index=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._target_asset_index_value = None + self._target_asset_index_present = False + self._parent_asset_index_value = None + self._parent_asset_index_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if target_asset_index is not None: + self.target_asset_index = target_asset_index + if parent_asset_index is not None: + self.parent_asset_index = parent_asset_index @property - def account_id(self): + def event_uuid(self): """ - User unique ID. Might be missing due to historical data gap. + Event unique identifier. :rtype: str """ - if self._account_id_present: - return self._account_id_value + if self._event_uuid_present: + return self._event_uuid_value else: - return None + raise AttributeError("missing required field 'event_uuid'") - @account_id.setter - def account_id(self, val): - if val is None: - del self.account_id - return - val = self._account_id_validator.validate(val) - self._account_id_value = val - self._account_id_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @account_id.deleter - def account_id(self): - self._account_id_value = None - self._account_id_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def display_name(self): + def target_asset_index(self): """ - User display name. Might be missing due to historical data gap. + Target asset position in the Assets list. - :rtype: str + :rtype: int """ - if self._display_name_present: - return self._display_name_value + if self._target_asset_index_present: + return self._target_asset_index_value else: return None - @display_name.setter - def display_name(self, val): + @target_asset_index.setter + def target_asset_index(self, val): if val is None: - del self.display_name + del self.target_asset_index return - val = self._display_name_validator.validate(val) - self._display_name_value = val - self._display_name_present = True + val = self._target_asset_index_validator.validate(val) + self._target_asset_index_value = val + self._target_asset_index_present = True - @display_name.deleter - def display_name(self): - self._display_name_value = None - self._display_name_present = False + @target_asset_index.deleter + def target_asset_index(self): + self._target_asset_index_value = None + self._target_asset_index_present = False @property - def email(self): + def parent_asset_index(self): """ - User email address. Might be missing due to historical data gap. + Parent asset position in the Assets list. - :rtype: str + :rtype: int """ - if self._email_present: - return self._email_value + if self._parent_asset_index_present: + return self._parent_asset_index_value else: return None - @email.setter - def email(self, val): + @parent_asset_index.setter + def parent_asset_index(self, val): if val is None: - del self.email + del self.parent_asset_index return - val = self._email_validator.validate(val) - self._email_value = val - self._email_present = True + val = self._parent_asset_index_validator.validate(val) + self._parent_asset_index_value = val + self._parent_asset_index_present = True - @email.deleter - def email(self): - self._email_value = None - self._email_present = False + @parent_asset_index.deleter + def parent_asset_index(self): + self._parent_asset_index_value = None + self._parent_asset_index_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(UserLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRemoveFromFolderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'UserLogInfo(account_id={!r}, display_name={!r}, email={!r})'.format( - self._account_id_value, - self._display_name_value, - self._email_value, + return 'PaperContentRemoveFromFolderDetails(event_uuid={!r}, target_asset_index={!r}, parent_asset_index={!r})'.format( + self._event_uuid_value, + self._target_asset_index_value, + self._parent_asset_index_value, ) -UserLogInfo_validator = bv.StructTree(UserLogInfo) +PaperContentRemoveFromFolderDetails_validator = bv.Struct(PaperContentRemoveFromFolderDetails) -class NonTeamMemberLogInfo(UserLogInfo): - """ - Non team member's logged information. - """ +class PaperContentRemoveFromFolderType(bb.Struct): __slots__ = [ + '_description_value', + '_description_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - account_id=None, - display_name=None, - email=None): - super(NonTeamMemberLogInfo, self).__init__(account_id, - display_name, - email) + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NonTeamMemberLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRemoveFromFolderType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NonTeamMemberLogInfo(account_id={!r}, display_name={!r}, email={!r})'.format( - self._account_id_value, - self._display_name_value, - self._email_value, + return 'PaperContentRemoveFromFolderType(description={!r})'.format( + self._description_value, ) -NonTeamMemberLogInfo_validator = bv.Struct(NonTeamMemberLogInfo) +PaperContentRemoveFromFolderType_validator = bv.Struct(PaperContentRemoveFromFolderType) -class NoteAclInviteOnlyDetails(bb.Struct): +class PaperContentRemoveMemberDetails(bb.Struct): """ - Changed Paper doc to invite-only. + Removed users and/or groups from Paper doc/folder. + + :ivar team_log.PaperContentRemoveMemberDetails.event_uuid: Event unique + identifier. """ __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + + @property + def event_uuid(self): + """ + Event unique identifier. + + :rtype: str + """ + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") + + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True + + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteAclInviteOnlyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRemoveMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteAclInviteOnlyDetails()' + return 'PaperContentRemoveMemberDetails(event_uuid={!r})'.format( + self._event_uuid_value, + ) -NoteAclInviteOnlyDetails_validator = bv.Struct(NoteAclInviteOnlyDetails) +PaperContentRemoveMemberDetails_validator = bv.Struct(PaperContentRemoveMemberDetails) -class NoteAclInviteOnlyType(bb.Struct): +class PaperContentRemoveMemberType(bb.Struct): __slots__ = [ '_description_value', @@ -42293,37 +62753,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteAclInviteOnlyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRemoveMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteAclInviteOnlyType(description={!r})'.format( + return 'PaperContentRemoveMemberType(description={!r})'.format( self._description_value, ) -NoteAclInviteOnlyType_validator = bv.Struct(NoteAclInviteOnlyType) +PaperContentRemoveMemberType_validator = bv.Struct(PaperContentRemoveMemberType) -class NoteAclLinkDetails(bb.Struct): +class PaperContentRenameDetails(bb.Struct): """ - Changed Paper doc to link-accessible. + Renamed Paper doc/folder. + + :ivar team_log.PaperContentRenameDetails.event_uuid: Event unique + identifier. """ __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + + @property + def event_uuid(self): + """ + Event unique identifier. + + :rtype: str + """ + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") + + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True + + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteAclLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRenameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteAclLinkDetails()' + return 'PaperContentRenameDetails(event_uuid={!r})'.format( + self._event_uuid_value, + ) -NoteAclLinkDetails_validator = bv.Struct(NoteAclLinkDetails) +PaperContentRenameDetails_validator = bv.Struct(PaperContentRenameDetails) -class NoteAclLinkType(bb.Struct): +class PaperContentRenameType(bb.Struct): __slots__ = [ '_description_value', @@ -42361,37 +62855,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteAclLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRenameType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteAclLinkType(description={!r})'.format( + return 'PaperContentRenameType(description={!r})'.format( self._description_value, ) -NoteAclLinkType_validator = bv.Struct(NoteAclLinkType) +PaperContentRenameType_validator = bv.Struct(PaperContentRenameType) -class NoteAclTeamLinkDetails(bb.Struct): +class PaperContentRestoreDetails(bb.Struct): """ - Changed Paper doc to link-accessible for team. + Restored archived Paper doc/folder. + + :ivar team_log.PaperContentRestoreDetails.event_uuid: Event unique + identifier. """ __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', ] - _has_required_fields = False + _has_required_fields = True + + def __init__(self, + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + + @property + def event_uuid(self): + """ + Event unique identifier. + + :rtype: str + """ + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") + + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - def __init__(self): - pass + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteAclTeamLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRestoreDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteAclTeamLinkDetails()' + return 'PaperContentRestoreDetails(event_uuid={!r})'.format( + self._event_uuid_value, + ) -NoteAclTeamLinkDetails_validator = bv.Struct(NoteAclTeamLinkDetails) +PaperContentRestoreDetails_validator = bv.Struct(PaperContentRestoreDetails) -class NoteAclTeamLinkType(bb.Struct): +class PaperContentRestoreType(bb.Struct): __slots__ = [ '_description_value', @@ -42429,105 +62957,153 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteAclTeamLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperContentRestoreType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteAclTeamLinkType(description={!r})'.format( + return 'PaperContentRestoreType(description={!r})'.format( self._description_value, ) -NoteAclTeamLinkType_validator = bv.Struct(NoteAclTeamLinkType) +PaperContentRestoreType_validator = bv.Struct(PaperContentRestoreType) -class NoteShareReceiveDetails(bb.Struct): +class PaperDefaultFolderPolicy(bb.Union): """ - Shared received Paper doc. + Policy to set default access for newly created Paper folders. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + everyone_in_team = None + # Attribute is overwritten below the class definition + invite_only = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = False + def is_everyone_in_team(self): + """ + Check if the union tag is ``everyone_in_team``. - def __init__(self): - pass + :rtype: bool + """ + return self._tag == 'everyone_in_team' + + def is_invite_only(self): + """ + Check if the union tag is ``invite_only``. + + :rtype: bool + """ + return self._tag == 'invite_only' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteShareReceiveDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDefaultFolderPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteShareReceiveDetails()' + return 'PaperDefaultFolderPolicy(%r, %r)' % (self._tag, self._value) -NoteShareReceiveDetails_validator = bv.Struct(NoteShareReceiveDetails) +PaperDefaultFolderPolicy_validator = bv.Union(PaperDefaultFolderPolicy) -class NoteShareReceiveType(bb.Struct): +class PaperDefaultFolderPolicyChangedDetails(bb.Struct): + """ + Changed Paper Default Folder Policy setting for team. + + :ivar team_log.PaperDefaultFolderPolicyChangedDetails.new_value: New Paper + Default Folder Policy. + :ivar team_log.PaperDefaultFolderPolicyChangedDetails.previous_value: + Previous Paper Default Folder Policy. + """ __slots__ = [ - '_description_value', - '_description_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def description(self): + def new_value(self): """ - :rtype: str + New Paper Default Folder Policy. + + :rtype: PaperDefaultFolderPolicy """ - if self._description_present: - return self._description_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteShareReceiveType, self)._process_custom_annotations(annotation_type, field_path, processor) + raise AttributeError("missing required field 'new_value'") - def __repr__(self): - return 'NoteShareReceiveType(description={!r})'.format( - self._description_value, - ) + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True -NoteShareReceiveType_validator = bv.Struct(NoteShareReceiveType) + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False -class NoteSharedDetails(bb.Struct): - """ - Shared Paper doc. - """ + @property + def previous_value(self): + """ + Previous Paper Default Folder Policy. - __slots__ = [ - ] + :rtype: PaperDefaultFolderPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") - _has_required_fields = False + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - def __init__(self): - pass + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteSharedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDefaultFolderPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteSharedDetails()' + return 'PaperDefaultFolderPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -NoteSharedDetails_validator = bv.Struct(NoteSharedDetails) +PaperDefaultFolderPolicyChangedDetails_validator = bv.Struct(PaperDefaultFolderPolicyChangedDetails) -class NoteSharedType(bb.Struct): +class PaperDefaultFolderPolicyChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -42565,37 +63141,153 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(NoteSharedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDefaultFolderPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'NoteSharedType(description={!r})'.format( + return 'PaperDefaultFolderPolicyChangedType(description={!r})'.format( self._description_value, ) -NoteSharedType_validator = bv.Struct(NoteSharedType) +PaperDefaultFolderPolicyChangedType_validator = bv.Struct(PaperDefaultFolderPolicyChangedType) -class OpenNoteSharedDetails(bb.Struct): +class PaperDesktopPolicy(bb.Union): """ - Opened shared Paper doc. + Policy for controlling if team members can use Paper Desktop + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperDesktopPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperDesktopPolicy(%r, %r)' % (self._tag, self._value) + +PaperDesktopPolicy_validator = bv.Union(PaperDesktopPolicy) + +class PaperDesktopPolicyChangedDetails(bb.Struct): + """ + Enabled/disabled Paper Desktop for team. + + :ivar team_log.PaperDesktopPolicyChangedDetails.new_value: New Paper Desktop + policy. + :ivar team_log.PaperDesktopPolicyChangedDetails.previous_value: Previous + Paper Desktop policy. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New Paper Desktop policy. + + :rtype: PaperDesktopPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous Paper Desktop policy. + + :rtype: PaperDesktopPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(OpenNoteSharedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDesktopPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'OpenNoteSharedDetails()' + return 'PaperDesktopPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -OpenNoteSharedDetails_validator = bv.Struct(OpenNoteSharedDetails) +PaperDesktopPolicyChangedDetails_validator = bv.Struct(PaperDesktopPolicyChangedDetails) -class OpenNoteSharedType(bb.Struct): +class PaperDesktopPolicyChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -42633,184 +63325,242 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(OpenNoteSharedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDesktopPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'OpenNoteSharedType(description={!r})'.format( + return 'PaperDesktopPolicyChangedType(description={!r})'.format( self._description_value, ) -OpenNoteSharedType_validator = bv.Struct(OpenNoteSharedType) +PaperDesktopPolicyChangedType_validator = bv.Struct(PaperDesktopPolicyChangedType) -class OriginLogInfo(bb.Struct): +class PaperDocAddCommentDetails(bb.Struct): """ - The origin from which the actor performed the action. + Added Paper doc comment. - :ivar team_log.OriginLogInfo.geo_location: Geographic location details. - :ivar team_log.OriginLogInfo.access_method: The method that was used to - perform the action. + :ivar team_log.PaperDocAddCommentDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperDocAddCommentDetails.comment_text: Comment text. Might + be missing due to historical data gap. """ __slots__ = [ - '_geo_location_value', - '_geo_location_present', - '_access_method_value', - '_access_method_present', + '_event_uuid_value', + '_event_uuid_present', + '_comment_text_value', + '_comment_text_present', ] _has_required_fields = True def __init__(self, - access_method=None, - geo_location=None): - self._geo_location_value = None - self._geo_location_present = False - self._access_method_value = None - self._access_method_present = False - if geo_location is not None: - self.geo_location = geo_location - if access_method is not None: - self.access_method = access_method + event_uuid=None, + comment_text=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._comment_text_value = None + self._comment_text_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if comment_text is not None: + self.comment_text = comment_text @property - def geo_location(self): + def event_uuid(self): """ - Geographic location details. + Event unique identifier. - :rtype: GeoLocationLogInfo + :rtype: str """ - if self._geo_location_present: - return self._geo_location_value + if self._event_uuid_present: + return self._event_uuid_value else: - return None + raise AttributeError("missing required field 'event_uuid'") - @geo_location.setter - def geo_location(self, val): - if val is None: - del self.geo_location - return - self._geo_location_validator.validate_type_only(val) - self._geo_location_value = val - self._geo_location_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @geo_location.deleter - def geo_location(self): - self._geo_location_value = None - self._geo_location_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def access_method(self): + def comment_text(self): """ - The method that was used to perform the action. + Comment text. Might be missing due to historical data gap. - :rtype: AccessMethodLogInfo + :rtype: str """ - if self._access_method_present: - return self._access_method_value + if self._comment_text_present: + return self._comment_text_value else: - raise AttributeError("missing required field 'access_method'") + return None - @access_method.setter - def access_method(self, val): - self._access_method_validator.validate_type_only(val) - self._access_method_value = val - self._access_method_present = True + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - @access_method.deleter - def access_method(self): - self._access_method_value = None - self._access_method_present = False + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(OriginLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocAddCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'OriginLogInfo(access_method={!r}, geo_location={!r})'.format( - self._access_method_value, - self._geo_location_value, + return 'PaperDocAddCommentDetails(event_uuid={!r}, comment_text={!r})'.format( + self._event_uuid_value, + self._comment_text_value, ) -OriginLogInfo_validator = bv.Struct(OriginLogInfo) - -class PaperAccessType(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - viewer = None - # Attribute is overwritten below the class definition - commenter = None - # Attribute is overwritten below the class definition - editor = None - # Attribute is overwritten below the class definition - other = None +PaperDocAddCommentDetails_validator = bv.Struct(PaperDocAddCommentDetails) - def is_viewer(self): - """ - Check if the union tag is ``viewer``. +class PaperDocAddCommentType(bb.Struct): - :rtype: bool - """ - return self._tag == 'viewer' + __slots__ = [ + '_description_value', + '_description_present', + ] - def is_commenter(self): - """ - Check if the union tag is ``commenter``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'commenter' + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description - def is_editor(self): + @property + def description(self): """ - Check if the union tag is ``editor``. - - :rtype: bool + :rtype: str """ - return self._tag == 'editor' + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") - def is_other(self): - """ - Check if the union tag is ``other``. + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - :rtype: bool - """ - return self._tag == 'other' + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocAddCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperAccessType(%r, %r)' % (self._tag, self._value) + return 'PaperDocAddCommentType(description={!r})'.format( + self._description_value, + ) -PaperAccessType_validator = bv.Union(PaperAccessType) +PaperDocAddCommentType_validator = bv.Struct(PaperDocAddCommentType) -class PaperAdminExportStartDetails(bb.Struct): +class PaperDocChangeMemberRoleDetails(bb.Struct): """ - Exported all team Paper docs. + Changed member permissions for Paper doc. + + :ivar team_log.PaperDocChangeMemberRoleDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperDocChangeMemberRoleDetails.access_type: Paper doc access + type. """ __slots__ = [ + '_event_uuid_value', + '_event_uuid_present', + '_access_type_value', + '_access_type_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + event_uuid=None, + access_type=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._access_type_value = None + self._access_type_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if access_type is not None: + self.access_type = access_type + + @property + def event_uuid(self): + """ + Event unique identifier. + + :rtype: str + """ + if self._event_uuid_present: + return self._event_uuid_value + else: + raise AttributeError("missing required field 'event_uuid'") + + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True + + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + @property + def access_type(self): + """ + Paper doc access type. + + :rtype: PaperAccessType + """ + if self._access_type_present: + return self._access_type_value + else: + raise AttributeError("missing required field 'access_type'") + + @access_type.setter + def access_type(self, val): + self._access_type_validator.validate_type_only(val) + self._access_type_value = val + self._access_type_present = True + + @access_type.deleter + def access_type(self): + self._access_type_value = None + self._access_type_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperAdminExportStartDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocChangeMemberRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperAdminExportStartDetails()' + return 'PaperDocChangeMemberRoleDetails(event_uuid={!r}, access_type={!r})'.format( + self._event_uuid_value, + self._access_type_value, + ) -PaperAdminExportStartDetails_validator = bv.Struct(PaperAdminExportStartDetails) +PaperDocChangeMemberRoleDetails_validator = bv.Struct(PaperDocChangeMemberRoleDetails) -class PaperAdminExportStartType(bb.Struct): +class PaperDocChangeMemberRoleType(bb.Struct): __slots__ = [ '_description_value', @@ -42848,110 +63598,145 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperAdminExportStartType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocChangeMemberRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperAdminExportStartType(description={!r})'.format( + return 'PaperDocChangeMemberRoleType(description={!r})'.format( self._description_value, ) -PaperAdminExportStartType_validator = bv.Struct(PaperAdminExportStartType) +PaperDocChangeMemberRoleType_validator = bv.Struct(PaperDocChangeMemberRoleType) -class PaperChangeDeploymentPolicyDetails(bb.Struct): +class PaperDocChangeSharingPolicyDetails(bb.Struct): """ - Changed whether Dropbox Paper, when enabled, is deployed to all members or - to specific members. + Changed sharing setting for Paper doc. - :ivar team_log.PaperChangeDeploymentPolicyDetails.new_value: New Dropbox - Paper deployment policy. - :ivar team_log.PaperChangeDeploymentPolicyDetails.previous_value: Previous - Dropbox Paper deployment policy. Might be missing due to historical data - gap. + :ivar team_log.PaperDocChangeSharingPolicyDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperDocChangeSharingPolicyDetails.public_sharing_policy: + Sharing policy with external users. Might be missing due to historical + data gap. + :ivar team_log.PaperDocChangeSharingPolicyDetails.team_sharing_policy: + Sharing policy with team. Might be missing due to historical data gap. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_event_uuid_value', + '_event_uuid_present', + '_public_sharing_policy_value', + '_public_sharing_policy_present', + '_team_sharing_policy_value', + '_team_sharing_policy_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + event_uuid=None, + public_sharing_policy=None, + team_sharing_policy=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._public_sharing_policy_value = None + self._public_sharing_policy_present = False + self._team_sharing_policy_value = None + self._team_sharing_policy_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if public_sharing_policy is not None: + self.public_sharing_policy = public_sharing_policy + if team_sharing_policy is not None: + self.team_sharing_policy = team_sharing_policy @property - def new_value(self): + def event_uuid(self): """ - New Dropbox Paper deployment policy. + Event unique identifier. - :rtype: team_policies.PaperDeploymentPolicy + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'event_uuid'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def previous_value(self): + def public_sharing_policy(self): """ - Previous Dropbox Paper deployment policy. Might be missing due to - historical data gap. + Sharing policy with external users. Might be missing due to historical + data gap. - :rtype: team_policies.PaperDeploymentPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._public_sharing_policy_present: + return self._public_sharing_policy_value else: return None - @previous_value.setter - def previous_value(self, val): + @public_sharing_policy.setter + def public_sharing_policy(self, val): if val is None: - del self.previous_value + del self.public_sharing_policy return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + val = self._public_sharing_policy_validator.validate(val) + self._public_sharing_policy_value = val + self._public_sharing_policy_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @public_sharing_policy.deleter + def public_sharing_policy(self): + self._public_sharing_policy_value = None + self._public_sharing_policy_present = False + + @property + def team_sharing_policy(self): + """ + Sharing policy with team. Might be missing due to historical data gap. + + :rtype: str + """ + if self._team_sharing_policy_present: + return self._team_sharing_policy_value + else: + return None + + @team_sharing_policy.setter + def team_sharing_policy(self, val): + if val is None: + del self.team_sharing_policy + return + val = self._team_sharing_policy_validator.validate(val) + self._team_sharing_policy_value = val + self._team_sharing_policy_present = True + + @team_sharing_policy.deleter + def team_sharing_policy(self): + self._team_sharing_policy_value = None + self._team_sharing_policy_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangeDeploymentPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocChangeSharingPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangeDeploymentPolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'PaperDocChangeSharingPolicyDetails(event_uuid={!r}, public_sharing_policy={!r}, team_sharing_policy={!r})'.format( + self._event_uuid_value, + self._public_sharing_policy_value, + self._team_sharing_policy_value, ) -PaperChangeDeploymentPolicyDetails_validator = bv.Struct(PaperChangeDeploymentPolicyDetails) +PaperDocChangeSharingPolicyDetails_validator = bv.Struct(PaperDocChangeSharingPolicyDetails) -class PaperChangeDeploymentPolicyType(bb.Struct): +class PaperDocChangeSharingPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -42989,71 +63774,143 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangeDeploymentPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocChangeSharingPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangeDeploymentPolicyType(description={!r})'.format( + return 'PaperDocChangeSharingPolicyType(description={!r})'.format( self._description_value, ) -PaperChangeDeploymentPolicyType_validator = bv.Struct(PaperChangeDeploymentPolicyType) +PaperDocChangeSharingPolicyType_validator = bv.Struct(PaperDocChangeSharingPolicyType) -class PaperChangeMemberLinkPolicyDetails(bb.Struct): +class PaperDocChangeSubscriptionDetails(bb.Struct): """ - Changed whether non-members can view Paper docs with link. + Followed/unfollowed Paper doc. - :ivar team_log.PaperChangeMemberLinkPolicyDetails.new_value: New paper - external link accessibility policy. + :ivar team_log.PaperDocChangeSubscriptionDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperDocChangeSubscriptionDetails.new_subscription_level: New + doc subscription level. + :ivar + team_log.PaperDocChangeSubscriptionDetails.previous_subscription_level: + Previous doc subscription level. Might be missing due to historical data + gap. """ __slots__ = [ - '_new_value_value', - '_new_value_present', + '_event_uuid_value', + '_event_uuid_present', + '_new_subscription_level_value', + '_new_subscription_level_present', + '_previous_subscription_level_value', + '_previous_subscription_level_present', ] _has_required_fields = True def __init__(self, - new_value=None): - self._new_value_value = None - self._new_value_present = False - if new_value is not None: - self.new_value = new_value + event_uuid=None, + new_subscription_level=None, + previous_subscription_level=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._new_subscription_level_value = None + self._new_subscription_level_present = False + self._previous_subscription_level_value = None + self._previous_subscription_level_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if new_subscription_level is not None: + self.new_subscription_level = new_subscription_level + if previous_subscription_level is not None: + self.previous_subscription_level = previous_subscription_level @property - def new_value(self): + def event_uuid(self): """ - New paper external link accessibility policy. + Event unique identifier. - :rtype: PaperMemberPolicy + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'event_uuid'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False + + @property + def new_subscription_level(self): + """ + New doc subscription level. + + :rtype: str + """ + if self._new_subscription_level_present: + return self._new_subscription_level_value + else: + raise AttributeError("missing required field 'new_subscription_level'") + + @new_subscription_level.setter + def new_subscription_level(self, val): + val = self._new_subscription_level_validator.validate(val) + self._new_subscription_level_value = val + self._new_subscription_level_present = True + + @new_subscription_level.deleter + def new_subscription_level(self): + self._new_subscription_level_value = None + self._new_subscription_level_present = False + + @property + def previous_subscription_level(self): + """ + Previous doc subscription level. Might be missing due to historical data + gap. + + :rtype: str + """ + if self._previous_subscription_level_present: + return self._previous_subscription_level_value + else: + return None + + @previous_subscription_level.setter + def previous_subscription_level(self, val): + if val is None: + del self.previous_subscription_level + return + val = self._previous_subscription_level_validator.validate(val) + self._previous_subscription_level_value = val + self._previous_subscription_level_present = True + + @previous_subscription_level.deleter + def previous_subscription_level(self): + self._previous_subscription_level_value = None + self._previous_subscription_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangeMemberLinkPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocChangeSubscriptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangeMemberLinkPolicyDetails(new_value={!r})'.format( - self._new_value_value, + return 'PaperDocChangeSubscriptionDetails(event_uuid={!r}, new_subscription_level={!r}, previous_subscription_level={!r})'.format( + self._event_uuid_value, + self._new_subscription_level_value, + self._previous_subscription_level_value, ) -PaperChangeMemberLinkPolicyDetails_validator = bv.Struct(PaperChangeMemberLinkPolicyDetails) +PaperDocChangeSubscriptionDetails_validator = bv.Struct(PaperDocChangeSubscriptionDetails) -class PaperChangeMemberLinkPolicyType(bb.Struct): +class PaperDocChangeSubscriptionType(bb.Struct): __slots__ = [ '_description_value', @@ -43091,110 +63948,107 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangeMemberLinkPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocChangeSubscriptionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangeMemberLinkPolicyType(description={!r})'.format( + return 'PaperDocChangeSubscriptionType(description={!r})'.format( self._description_value, ) -PaperChangeMemberLinkPolicyType_validator = bv.Struct(PaperChangeMemberLinkPolicyType) +PaperDocChangeSubscriptionType_validator = bv.Struct(PaperDocChangeSubscriptionType) -class PaperChangeMemberPolicyDetails(bb.Struct): +class PaperDocDeleteCommentDetails(bb.Struct): """ - Changed whether members can share Paper docs outside team, and if docs are - accessible only by team members or anyone by default. + Deleted Paper doc comment. - :ivar team_log.PaperChangeMemberPolicyDetails.new_value: New paper external - accessibility policy. - :ivar team_log.PaperChangeMemberPolicyDetails.previous_value: Previous paper - external accessibility policy. Might be missing due to historical data - gap. + :ivar team_log.PaperDocDeleteCommentDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperDocDeleteCommentDetails.comment_text: Comment text. + Might be missing due to historical data gap. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_event_uuid_value', + '_event_uuid_present', + '_comment_text_value', + '_comment_text_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + event_uuid=None, + comment_text=None): + self._event_uuid_value = None + self._event_uuid_present = False + self._comment_text_value = None + self._comment_text_present = False + if event_uuid is not None: + self.event_uuid = event_uuid + if comment_text is not None: + self.comment_text = comment_text @property - def new_value(self): + def event_uuid(self): """ - New paper external accessibility policy. + Event unique identifier. - :rtype: PaperMemberPolicy + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'event_uuid'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False @property - def previous_value(self): + def comment_text(self): """ - Previous paper external accessibility policy. Might be missing due to - historical data gap. + Comment text. Might be missing due to historical data gap. - :rtype: PaperMemberPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._comment_text_present: + return self._comment_text_value else: return None - @previous_value.setter - def previous_value(self, val): + @comment_text.setter + def comment_text(self, val): if val is None: - del self.previous_value + del self.comment_text return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangeMemberPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocDeleteCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangeMemberPolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'PaperDocDeleteCommentDetails(event_uuid={!r}, comment_text={!r})'.format( + self._event_uuid_value, + self._comment_text_value, ) -PaperChangeMemberPolicyDetails_validator = bv.Struct(PaperChangeMemberPolicyDetails) +PaperDocDeleteCommentDetails_validator = bv.Struct(PaperDocDeleteCommentDetails) -class PaperChangeMemberPolicyType(bb.Struct): +class PaperDocDeleteCommentType(bb.Struct): __slots__ = [ '_description_value', @@ -43232,107 +64086,70 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangeMemberPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocDeleteCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangeMemberPolicyType(description={!r})'.format( + return 'PaperDocDeleteCommentType(description={!r})'.format( self._description_value, ) -PaperChangeMemberPolicyType_validator = bv.Struct(PaperChangeMemberPolicyType) +PaperDocDeleteCommentType_validator = bv.Struct(PaperDocDeleteCommentType) -class PaperChangePolicyDetails(bb.Struct): +class PaperDocDeletedDetails(bb.Struct): """ - Enabled/disabled Dropbox Paper for team. + Archived Paper doc. - :ivar team_log.PaperChangePolicyDetails.new_value: New Dropbox Paper policy. - :ivar team_log.PaperChangePolicyDetails.previous_value: Previous Dropbox - Paper policy. Might be missing due to historical data gap. + :ivar team_log.PaperDocDeletedDetails.event_uuid: Event unique identifier. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_event_uuid_value', + '_event_uuid_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New Dropbox Paper policy. - - :rtype: team_policies.PaperEnabledPolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid @property - def previous_value(self): + def event_uuid(self): """ - Previous Dropbox Paper policy. Might be missing due to historical data - gap. + Event unique identifier. - :rtype: team_policies.PaperEnabledPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - return None + raise AttributeError("missing required field 'event_uuid'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocDeletedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'PaperDocDeletedDetails(event_uuid={!r})'.format( + self._event_uuid_value, ) -PaperChangePolicyDetails_validator = bv.Struct(PaperChangePolicyDetails) +PaperDocDeletedDetails_validator = bv.Struct(PaperDocDeletedDetails) -class PaperChangePolicyType(bb.Struct): +class PaperDocDeletedType(bb.Struct): __slots__ = [ '_description_value', @@ -43370,36 +64187,44 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocDeletedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperChangePolicyType(description={!r})'.format( + return 'PaperDocDeletedType(description={!r})'.format( self._description_value, ) -PaperChangePolicyType_validator = bv.Struct(PaperChangePolicyType) +PaperDocDeletedType_validator = bv.Struct(PaperDocDeletedType) -class PaperContentAddMemberDetails(bb.Struct): +class PaperDocDownloadDetails(bb.Struct): """ - Added team member to Paper doc/folder. + Downloaded Paper doc in specific format. - :ivar team_log.PaperContentAddMemberDetails.event_uuid: Event unique - identifier. + :ivar team_log.PaperDocDownloadDetails.event_uuid: Event unique identifier. + :ivar team_log.PaperDocDownloadDetails.export_file_format: Export file + format. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', + '_export_file_format_value', + '_export_file_format_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): + event_uuid=None, + export_file_format=None): self._event_uuid_value = None self._event_uuid_present = False + self._export_file_format_value = None + self._export_file_format_present = False if event_uuid is not None: self.event_uuid = event_uuid + if export_file_format is not None: + self.export_file_format = export_file_format @property def event_uuid(self): @@ -43424,17 +64249,41 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False + @property + def export_file_format(self): + """ + Export file format. + + :rtype: PaperDownloadFormat + """ + if self._export_file_format_present: + return self._export_file_format_value + else: + raise AttributeError("missing required field 'export_file_format'") + + @export_file_format.setter + def export_file_format(self, val): + self._export_file_format_validator.validate_type_only(val) + self._export_file_format_value = val + self._export_file_format_present = True + + @export_file_format.deleter + def export_file_format(self): + self._export_file_format_value = None + self._export_file_format_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentAddMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentAddMemberDetails(event_uuid={!r})'.format( + return 'PaperDocDownloadDetails(event_uuid={!r}, export_file_format={!r})'.format( self._event_uuid_value, + self._export_file_format_value, ) -PaperContentAddMemberDetails_validator = bv.Struct(PaperContentAddMemberDetails) +PaperDocDownloadDetails_validator = bv.Struct(PaperDocDownloadDetails) -class PaperContentAddMemberType(bb.Struct): +class PaperDocDownloadType(bb.Struct): __slots__ = [ '_description_value', @@ -43472,54 +64321,45 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentAddMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentAddMemberType(description={!r})'.format( + return 'PaperDocDownloadType(description={!r})'.format( self._description_value, ) -PaperContentAddMemberType_validator = bv.Struct(PaperContentAddMemberType) +PaperDocDownloadType_validator = bv.Struct(PaperDocDownloadType) -class PaperContentAddToFolderDetails(bb.Struct): +class PaperDocEditCommentDetails(bb.Struct): """ - Added Paper doc/folder to folder. + Edited Paper doc comment. - :ivar team_log.PaperContentAddToFolderDetails.event_uuid: Event unique + :ivar team_log.PaperDocEditCommentDetails.event_uuid: Event unique identifier. - :ivar team_log.PaperContentAddToFolderDetails.target_asset_index: Target - asset position in the Assets list. - :ivar team_log.PaperContentAddToFolderDetails.parent_asset_index: Parent - asset position in the Assets list. + :ivar team_log.PaperDocEditCommentDetails.comment_text: Comment text. Might + be missing due to historical data gap. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_target_asset_index_value', - '_target_asset_index_present', - '_parent_asset_index_value', - '_parent_asset_index_present', + '_comment_text_value', + '_comment_text_present', ] _has_required_fields = True def __init__(self, event_uuid=None, - target_asset_index=None, - parent_asset_index=None): + comment_text=None): self._event_uuid_value = None self._event_uuid_present = False - self._target_asset_index_value = None - self._target_asset_index_present = False - self._parent_asset_index_value = None - self._parent_asset_index_present = False + self._comment_text_value = None + self._comment_text_present = False if event_uuid is not None: self.event_uuid = event_uuid - if target_asset_index is not None: - self.target_asset_index = target_asset_index - if parent_asset_index is not None: - self.parent_asset_index = parent_asset_index + if comment_text is not None: + self.comment_text = comment_text @property def event_uuid(self): @@ -43545,64 +64385,43 @@ def event_uuid(self): self._event_uuid_present = False @property - def target_asset_index(self): - """ - Target asset position in the Assets list. - - :rtype: int - """ - if self._target_asset_index_present: - return self._target_asset_index_value - else: - raise AttributeError("missing required field 'target_asset_index'") - - @target_asset_index.setter - def target_asset_index(self, val): - val = self._target_asset_index_validator.validate(val) - self._target_asset_index_value = val - self._target_asset_index_present = True - - @target_asset_index.deleter - def target_asset_index(self): - self._target_asset_index_value = None - self._target_asset_index_present = False - - @property - def parent_asset_index(self): + def comment_text(self): """ - Parent asset position in the Assets list. + Comment text. Might be missing due to historical data gap. - :rtype: int + :rtype: str """ - if self._parent_asset_index_present: - return self._parent_asset_index_value + if self._comment_text_present: + return self._comment_text_value else: - raise AttributeError("missing required field 'parent_asset_index'") + return None - @parent_asset_index.setter - def parent_asset_index(self, val): - val = self._parent_asset_index_validator.validate(val) - self._parent_asset_index_value = val - self._parent_asset_index_present = True + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - @parent_asset_index.deleter - def parent_asset_index(self): - self._parent_asset_index_value = None - self._parent_asset_index_present = False + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentAddToFolderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocEditCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentAddToFolderDetails(event_uuid={!r}, target_asset_index={!r}, parent_asset_index={!r})'.format( + return 'PaperDocEditCommentDetails(event_uuid={!r}, comment_text={!r})'.format( self._event_uuid_value, - self._target_asset_index_value, - self._parent_asset_index_value, + self._comment_text_value, ) -PaperContentAddToFolderDetails_validator = bv.Struct(PaperContentAddToFolderDetails) +PaperDocEditCommentDetails_validator = bv.Struct(PaperDocEditCommentDetails) -class PaperContentAddToFolderType(bb.Struct): +class PaperDocEditCommentType(bb.Struct): __slots__ = [ '_description_value', @@ -43640,21 +64459,20 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentAddToFolderType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocEditCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentAddToFolderType(description={!r})'.format( + return 'PaperDocEditCommentType(description={!r})'.format( self._description_value, ) -PaperContentAddToFolderType_validator = bv.Struct(PaperContentAddToFolderType) +PaperDocEditCommentType_validator = bv.Struct(PaperDocEditCommentType) -class PaperContentArchiveDetails(bb.Struct): +class PaperDocEditDetails(bb.Struct): """ - Archived Paper doc/folder. + Edited Paper doc. - :ivar team_log.PaperContentArchiveDetails.event_uuid: Event unique - identifier. + :ivar team_log.PaperDocEditDetails.event_uuid: Event unique identifier. """ __slots__ = [ @@ -43695,16 +64513,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentArchiveDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocEditDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentArchiveDetails(event_uuid={!r})'.format( + return 'PaperDocEditDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperContentArchiveDetails_validator = bv.Struct(PaperContentArchiveDetails) +PaperDocEditDetails_validator = bv.Struct(PaperDocEditDetails) -class PaperContentArchiveType(bb.Struct): +class PaperDocEditType(bb.Struct): __slots__ = [ '_description_value', @@ -43742,21 +64560,20 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentArchiveType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocEditType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentArchiveType(description={!r})'.format( + return 'PaperDocEditType(description={!r})'.format( self._description_value, ) -PaperContentArchiveType_validator = bv.Struct(PaperContentArchiveType) +PaperDocEditType_validator = bv.Struct(PaperDocEditType) -class PaperContentCreateDetails(bb.Struct): +class PaperDocFollowedDetails(bb.Struct): """ - Created Paper doc/folder. + Followed Paper doc. - :ivar team_log.PaperContentCreateDetails.event_uuid: Event unique - identifier. + :ivar team_log.PaperDocFollowedDetails.event_uuid: Event unique identifier. """ __slots__ = [ @@ -43797,16 +64614,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocFollowedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentCreateDetails(event_uuid={!r})'.format( + return 'PaperDocFollowedDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperContentCreateDetails_validator = bv.Struct(PaperContentCreateDetails) +PaperDocFollowedDetails_validator = bv.Struct(PaperDocFollowedDetails) -class PaperContentCreateType(bb.Struct): +class PaperDocFollowedType(bb.Struct): __slots__ = [ '_description_value', @@ -43844,21 +64661,20 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocFollowedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentCreateType(description={!r})'.format( + return 'PaperDocFollowedType(description={!r})'.format( self._description_value, ) -PaperContentCreateType_validator = bv.Struct(PaperContentCreateType) +PaperDocFollowedType_validator = bv.Struct(PaperDocFollowedType) -class PaperContentPermanentlyDeleteDetails(bb.Struct): +class PaperDocMentionDetails(bb.Struct): """ - Permanently deleted Paper doc/folder. + Mentioned user in Paper doc. - :ivar team_log.PaperContentPermanentlyDeleteDetails.event_uuid: Event unique - identifier. + :ivar team_log.PaperDocMentionDetails.event_uuid: Event unique identifier. """ __slots__ = [ @@ -43899,16 +64715,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentPermanentlyDeleteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocMentionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentPermanentlyDeleteDetails(event_uuid={!r})'.format( + return 'PaperDocMentionDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperContentPermanentlyDeleteDetails_validator = bv.Struct(PaperContentPermanentlyDeleteDetails) +PaperDocMentionDetails_validator = bv.Struct(PaperDocMentionDetails) -class PaperContentPermanentlyDeleteType(bb.Struct): +class PaperDocMentionType(bb.Struct): __slots__ = [ '_description_value', @@ -43946,54 +64762,53 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentPermanentlyDeleteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocMentionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentPermanentlyDeleteType(description={!r})'.format( + return 'PaperDocMentionType(description={!r})'.format( self._description_value, ) -PaperContentPermanentlyDeleteType_validator = bv.Struct(PaperContentPermanentlyDeleteType) +PaperDocMentionType_validator = bv.Struct(PaperDocMentionType) -class PaperContentRemoveFromFolderDetails(bb.Struct): +class PaperDocOwnershipChangedDetails(bb.Struct): """ - Removed Paper doc/folder from folder. + Transferred ownership of Paper doc. - :ivar team_log.PaperContentRemoveFromFolderDetails.event_uuid: Event unique + :ivar team_log.PaperDocOwnershipChangedDetails.event_uuid: Event unique identifier. - :ivar team_log.PaperContentRemoveFromFolderDetails.target_asset_index: - Target asset position in the Assets list. - :ivar team_log.PaperContentRemoveFromFolderDetails.parent_asset_index: - Parent asset position in the Assets list. + :ivar team_log.PaperDocOwnershipChangedDetails.old_owner_user_id: Previous + owner. + :ivar team_log.PaperDocOwnershipChangedDetails.new_owner_user_id: New owner. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_target_asset_index_value', - '_target_asset_index_present', - '_parent_asset_index_value', - '_parent_asset_index_present', + '_old_owner_user_id_value', + '_old_owner_user_id_present', + '_new_owner_user_id_value', + '_new_owner_user_id_present', ] _has_required_fields = True def __init__(self, event_uuid=None, - target_asset_index=None, - parent_asset_index=None): + new_owner_user_id=None, + old_owner_user_id=None): self._event_uuid_value = None self._event_uuid_present = False - self._target_asset_index_value = None - self._target_asset_index_present = False - self._parent_asset_index_value = None - self._parent_asset_index_present = False + self._old_owner_user_id_value = None + self._old_owner_user_id_present = False + self._new_owner_user_id_value = None + self._new_owner_user_id_present = False if event_uuid is not None: self.event_uuid = event_uuid - if target_asset_index is not None: - self.target_asset_index = target_asset_index - if parent_asset_index is not None: - self.parent_asset_index = parent_asset_index + if old_owner_user_id is not None: + self.old_owner_user_id = old_owner_user_id + if new_owner_user_id is not None: + self.new_owner_user_id = new_owner_user_id @property def event_uuid(self): @@ -44019,64 +64834,67 @@ def event_uuid(self): self._event_uuid_present = False @property - def target_asset_index(self): + def old_owner_user_id(self): """ - Target asset position in the Assets list. + Previous owner. - :rtype: int + :rtype: str """ - if self._target_asset_index_present: - return self._target_asset_index_value + if self._old_owner_user_id_present: + return self._old_owner_user_id_value else: - raise AttributeError("missing required field 'target_asset_index'") + return None - @target_asset_index.setter - def target_asset_index(self, val): - val = self._target_asset_index_validator.validate(val) - self._target_asset_index_value = val - self._target_asset_index_present = True + @old_owner_user_id.setter + def old_owner_user_id(self, val): + if val is None: + del self.old_owner_user_id + return + val = self._old_owner_user_id_validator.validate(val) + self._old_owner_user_id_value = val + self._old_owner_user_id_present = True - @target_asset_index.deleter - def target_asset_index(self): - self._target_asset_index_value = None - self._target_asset_index_present = False + @old_owner_user_id.deleter + def old_owner_user_id(self): + self._old_owner_user_id_value = None + self._old_owner_user_id_present = False @property - def parent_asset_index(self): + def new_owner_user_id(self): """ - Parent asset position in the Assets list. + New owner. - :rtype: int + :rtype: str """ - if self._parent_asset_index_present: - return self._parent_asset_index_value + if self._new_owner_user_id_present: + return self._new_owner_user_id_value else: - raise AttributeError("missing required field 'parent_asset_index'") + raise AttributeError("missing required field 'new_owner_user_id'") - @parent_asset_index.setter - def parent_asset_index(self, val): - val = self._parent_asset_index_validator.validate(val) - self._parent_asset_index_value = val - self._parent_asset_index_present = True + @new_owner_user_id.setter + def new_owner_user_id(self, val): + val = self._new_owner_user_id_validator.validate(val) + self._new_owner_user_id_value = val + self._new_owner_user_id_present = True - @parent_asset_index.deleter - def parent_asset_index(self): - self._parent_asset_index_value = None - self._parent_asset_index_present = False + @new_owner_user_id.deleter + def new_owner_user_id(self): + self._new_owner_user_id_value = None + self._new_owner_user_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRemoveFromFolderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocOwnershipChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRemoveFromFolderDetails(event_uuid={!r}, target_asset_index={!r}, parent_asset_index={!r})'.format( + return 'PaperDocOwnershipChangedDetails(event_uuid={!r}, new_owner_user_id={!r}, old_owner_user_id={!r})'.format( self._event_uuid_value, - self._target_asset_index_value, - self._parent_asset_index_value, + self._new_owner_user_id_value, + self._old_owner_user_id_value, ) -PaperContentRemoveFromFolderDetails_validator = bv.Struct(PaperContentRemoveFromFolderDetails) +PaperDocOwnershipChangedDetails_validator = bv.Struct(PaperDocOwnershipChangedDetails) -class PaperContentRemoveFromFolderType(bb.Struct): +class PaperDocOwnershipChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -44114,20 +64932,20 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRemoveFromFolderType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocOwnershipChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRemoveFromFolderType(description={!r})'.format( + return 'PaperDocOwnershipChangedType(description={!r})'.format( self._description_value, ) -PaperContentRemoveFromFolderType_validator = bv.Struct(PaperContentRemoveFromFolderType) +PaperDocOwnershipChangedType_validator = bv.Struct(PaperDocOwnershipChangedType) -class PaperContentRemoveMemberDetails(bb.Struct): +class PaperDocRequestAccessDetails(bb.Struct): """ - Removed team member from Paper doc/folder. + Requested access to Paper doc. - :ivar team_log.PaperContentRemoveMemberDetails.event_uuid: Event unique + :ivar team_log.PaperDocRequestAccessDetails.event_uuid: Event unique identifier. """ @@ -44169,16 +64987,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRemoveMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocRequestAccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRemoveMemberDetails(event_uuid={!r})'.format( + return 'PaperDocRequestAccessDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperContentRemoveMemberDetails_validator = bv.Struct(PaperContentRemoveMemberDetails) +PaperDocRequestAccessDetails_validator = bv.Struct(PaperDocRequestAccessDetails) -class PaperContentRemoveMemberType(bb.Struct): +class PaperDocRequestAccessType(bb.Struct): __slots__ = [ '_description_value', @@ -44216,36 +65034,45 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRemoveMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocRequestAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRemoveMemberType(description={!r})'.format( + return 'PaperDocRequestAccessType(description={!r})'.format( self._description_value, ) -PaperContentRemoveMemberType_validator = bv.Struct(PaperContentRemoveMemberType) +PaperDocRequestAccessType_validator = bv.Struct(PaperDocRequestAccessType) -class PaperContentRenameDetails(bb.Struct): +class PaperDocResolveCommentDetails(bb.Struct): """ - Renamed Paper doc/folder. + Resolved Paper doc comment. - :ivar team_log.PaperContentRenameDetails.event_uuid: Event unique + :ivar team_log.PaperDocResolveCommentDetails.event_uuid: Event unique identifier. + :ivar team_log.PaperDocResolveCommentDetails.comment_text: Comment text. + Might be missing due to historical data gap. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', + '_comment_text_value', + '_comment_text_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): + event_uuid=None, + comment_text=None): self._event_uuid_value = None self._event_uuid_present = False + self._comment_text_value = None + self._comment_text_present = False if event_uuid is not None: self.event_uuid = event_uuid + if comment_text is not None: + self.comment_text = comment_text @property def event_uuid(self): @@ -44270,17 +65097,44 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False + @property + def comment_text(self): + """ + Comment text. Might be missing due to historical data gap. + + :rtype: str + """ + if self._comment_text_present: + return self._comment_text_value + else: + return None + + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True + + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRenameDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocResolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRenameDetails(event_uuid={!r})'.format( + return 'PaperDocResolveCommentDetails(event_uuid={!r}, comment_text={!r})'.format( self._event_uuid_value, + self._comment_text_value, ) -PaperContentRenameDetails_validator = bv.Struct(PaperContentRenameDetails) +PaperDocResolveCommentDetails_validator = bv.Struct(PaperDocResolveCommentDetails) -class PaperContentRenameType(bb.Struct): +class PaperDocResolveCommentType(bb.Struct): __slots__ = [ '_description_value', @@ -44318,21 +65172,20 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRenameType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocResolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRenameType(description={!r})'.format( + return 'PaperDocResolveCommentType(description={!r})'.format( self._description_value, ) -PaperContentRenameType_validator = bv.Struct(PaperContentRenameType) +PaperDocResolveCommentType_validator = bv.Struct(PaperDocResolveCommentType) -class PaperContentRestoreDetails(bb.Struct): +class PaperDocRevertDetails(bb.Struct): """ - Restored archived Paper doc/folder. + Restored Paper doc to previous version. - :ivar team_log.PaperContentRestoreDetails.event_uuid: Event unique - identifier. + :ivar team_log.PaperDocRevertDetails.event_uuid: Event unique identifier. """ __slots__ = [ @@ -44373,16 +65226,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRestoreDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocRevertDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRestoreDetails(event_uuid={!r})'.format( + return 'PaperDocRevertDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperContentRestoreDetails_validator = bv.Struct(PaperContentRestoreDetails) +PaperDocRevertDetails_validator = bv.Struct(PaperDocRevertDetails) -class PaperContentRestoreType(bb.Struct): +class PaperDocRevertType(bb.Struct): __slots__ = [ '_description_value', @@ -44420,153 +65273,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperContentRestoreType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocRevertType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperContentRestoreType(description={!r})'.format( + return 'PaperDocRevertType(description={!r})'.format( self._description_value, ) -PaperContentRestoreType_validator = bv.Struct(PaperContentRestoreType) - -class PaperDefaultFolderPolicy(bb.Union): - """ - Policy to set default access for newly created Paper folders. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - everyone_in_team = None - # Attribute is overwritten below the class definition - invite_only = None - # Attribute is overwritten below the class definition - other = None - - def is_everyone_in_team(self): - """ - Check if the union tag is ``everyone_in_team``. - - :rtype: bool - """ - return self._tag == 'everyone_in_team' - - def is_invite_only(self): - """ - Check if the union tag is ``invite_only``. - - :rtype: bool - """ - return self._tag == 'invite_only' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDefaultFolderPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PaperDefaultFolderPolicy(%r, %r)' % (self._tag, self._value) - -PaperDefaultFolderPolicy_validator = bv.Union(PaperDefaultFolderPolicy) +PaperDocRevertType_validator = bv.Struct(PaperDocRevertType) -class PaperDefaultFolderPolicyChangedDetails(bb.Struct): +class PaperDocSlackShareDetails(bb.Struct): """ - Changed Paper Default Folder Policy setting for team. + Shared Paper doc via Slack. - :ivar team_log.PaperDefaultFolderPolicyChangedDetails.new_value: New Paper - Default Folder Policy. - :ivar team_log.PaperDefaultFolderPolicyChangedDetails.previous_value: - Previous Paper Default Folder Policy. + :ivar team_log.PaperDocSlackShareDetails.event_uuid: Event unique + identifier. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_event_uuid_value', + '_event_uuid_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New Paper Default Folder Policy. - - :rtype: PaperDefaultFolderPolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid @property - def previous_value(self): + def event_uuid(self): """ - Previous Paper Default Folder Policy. + Event unique identifier. - :rtype: PaperDefaultFolderPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'event_uuid'") - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDefaultFolderPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocSlackShareDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDefaultFolderPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'PaperDocSlackShareDetails(event_uuid={!r})'.format( + self._event_uuid_value, ) -PaperDefaultFolderPolicyChangedDetails_validator = bv.Struct(PaperDefaultFolderPolicyChangedDetails) +PaperDocSlackShareDetails_validator = bv.Struct(PaperDocSlackShareDetails) -class PaperDefaultFolderPolicyChangedType(bb.Struct): +class PaperDocSlackShareType(bb.Struct): __slots__ = [ '_description_value', @@ -44604,153 +65375,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDefaultFolderPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocSlackShareType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDefaultFolderPolicyChangedType(description={!r})'.format( + return 'PaperDocSlackShareType(description={!r})'.format( self._description_value, ) -PaperDefaultFolderPolicyChangedType_validator = bv.Struct(PaperDefaultFolderPolicyChangedType) - -class PaperDesktopPolicy(bb.Union): - """ - Policy for controlling if team members can use Paper Desktop - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None - - def is_disabled(self): - """ - Check if the union tag is ``disabled``. - - :rtype: bool - """ - return self._tag == 'disabled' - - def is_enabled(self): - """ - Check if the union tag is ``enabled``. - - :rtype: bool - """ - return self._tag == 'enabled' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDesktopPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PaperDesktopPolicy(%r, %r)' % (self._tag, self._value) - -PaperDesktopPolicy_validator = bv.Union(PaperDesktopPolicy) +PaperDocSlackShareType_validator = bv.Struct(PaperDocSlackShareType) -class PaperDesktopPolicyChangedDetails(bb.Struct): +class PaperDocTeamInviteDetails(bb.Struct): """ - Enabled/disabled Paper Desktop for team. + Shared Paper doc with users and/or groups. - :ivar team_log.PaperDesktopPolicyChangedDetails.new_value: New Paper Desktop - policy. - :ivar team_log.PaperDesktopPolicyChangedDetails.previous_value: Previous - Paper Desktop policy. + :ivar team_log.PaperDocTeamInviteDetails.event_uuid: Event unique + identifier. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_event_uuid_value', + '_event_uuid_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New Paper Desktop policy. - - :rtype: PaperDesktopPolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + event_uuid=None): + self._event_uuid_value = None + self._event_uuid_present = False + if event_uuid is not None: + self.event_uuid = event_uuid @property - def previous_value(self): + def event_uuid(self): """ - Previous Paper Desktop policy. + Event unique identifier. - :rtype: PaperDesktopPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._event_uuid_present: + return self._event_uuid_value else: - raise AttributeError("missing required field 'previous_value'") - - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + raise AttributeError("missing required field 'event_uuid'") - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @event_uuid.setter + def event_uuid(self, val): + val = self._event_uuid_validator.validate(val) + self._event_uuid_value = val + self._event_uuid_present = True + + @event_uuid.deleter + def event_uuid(self): + self._event_uuid_value = None + self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDesktopPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocTeamInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDesktopPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'PaperDocTeamInviteDetails(event_uuid={!r})'.format( + self._event_uuid_value, ) -PaperDesktopPolicyChangedDetails_validator = bv.Struct(PaperDesktopPolicyChangedDetails) +PaperDocTeamInviteDetails_validator = bv.Struct(PaperDocTeamInviteDetails) -class PaperDesktopPolicyChangedType(bb.Struct): +class PaperDocTeamInviteType(bb.Struct): __slots__ = [ '_description_value', @@ -44788,45 +65477,35 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDesktopPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocTeamInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDesktopPolicyChangedType(description={!r})'.format( + return 'PaperDocTeamInviteType(description={!r})'.format( self._description_value, ) -PaperDesktopPolicyChangedType_validator = bv.Struct(PaperDesktopPolicyChangedType) +PaperDocTeamInviteType_validator = bv.Struct(PaperDocTeamInviteType) -class PaperDocAddCommentDetails(bb.Struct): +class PaperDocTrashedDetails(bb.Struct): """ - Added Paper doc comment. + Deleted Paper doc. - :ivar team_log.PaperDocAddCommentDetails.event_uuid: Event unique - identifier. - :ivar team_log.PaperDocAddCommentDetails.comment_text: Comment text. Might - be missing due to historical data gap. + :ivar team_log.PaperDocTrashedDetails.event_uuid: Event unique identifier. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_comment_text_value', - '_comment_text_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - comment_text=None): + event_uuid=None): self._event_uuid_value = None self._event_uuid_present = False - self._comment_text_value = None - self._comment_text_present = False if event_uuid is not None: self.event_uuid = event_uuid - if comment_text is not None: - self.comment_text = comment_text @property def event_uuid(self): @@ -44851,44 +65530,17 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False - @property - def comment_text(self): - """ - Comment text. Might be missing due to historical data gap. - - :rtype: str - """ - if self._comment_text_present: - return self._comment_text_value - else: - return None - - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True - - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocAddCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocTrashedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocAddCommentDetails(event_uuid={!r}, comment_text={!r})'.format( + return 'PaperDocTrashedDetails(event_uuid={!r})'.format( self._event_uuid_value, - self._comment_text_value, ) -PaperDocAddCommentDetails_validator = bv.Struct(PaperDocAddCommentDetails) +PaperDocTrashedDetails_validator = bv.Struct(PaperDocTrashedDetails) -class PaperDocAddCommentType(bb.Struct): +class PaperDocTrashedType(bb.Struct): __slots__ = [ '_description_value', @@ -44926,45 +65578,45 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocAddCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocTrashedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocAddCommentType(description={!r})'.format( + return 'PaperDocTrashedType(description={!r})'.format( self._description_value, ) -PaperDocAddCommentType_validator = bv.Struct(PaperDocAddCommentType) +PaperDocTrashedType_validator = bv.Struct(PaperDocTrashedType) -class PaperDocChangeMemberRoleDetails(bb.Struct): +class PaperDocUnresolveCommentDetails(bb.Struct): """ - Changed team member permissions for Paper doc. + Unresolved Paper doc comment. - :ivar team_log.PaperDocChangeMemberRoleDetails.event_uuid: Event unique + :ivar team_log.PaperDocUnresolveCommentDetails.event_uuid: Event unique identifier. - :ivar team_log.PaperDocChangeMemberRoleDetails.access_type: Paper doc access - type. + :ivar team_log.PaperDocUnresolveCommentDetails.comment_text: Comment text. + Might be missing due to historical data gap. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_access_type_value', - '_access_type_present', + '_comment_text_value', + '_comment_text_present', ] _has_required_fields = True def __init__(self, event_uuid=None, - access_type=None): + comment_text=None): self._event_uuid_value = None self._event_uuid_present = False - self._access_type_value = None - self._access_type_present = False + self._comment_text_value = None + self._comment_text_present = False if event_uuid is not None: self.event_uuid = event_uuid - if access_type is not None: - self.access_type = access_type + if comment_text is not None: + self.comment_text = comment_text @property def event_uuid(self): @@ -44990,40 +65642,43 @@ def event_uuid(self): self._event_uuid_present = False @property - def access_type(self): + def comment_text(self): """ - Paper doc access type. + Comment text. Might be missing due to historical data gap. - :rtype: PaperAccessType + :rtype: str """ - if self._access_type_present: - return self._access_type_value + if self._comment_text_present: + return self._comment_text_value else: - raise AttributeError("missing required field 'access_type'") + return None - @access_type.setter - def access_type(self, val): - self._access_type_validator.validate_type_only(val) - self._access_type_value = val - self._access_type_present = True + @comment_text.setter + def comment_text(self, val): + if val is None: + del self.comment_text + return + val = self._comment_text_validator.validate(val) + self._comment_text_value = val + self._comment_text_present = True - @access_type.deleter - def access_type(self): - self._access_type_value = None - self._access_type_present = False + @comment_text.deleter + def comment_text(self): + self._comment_text_value = None + self._comment_text_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocChangeMemberRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocUnresolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocChangeMemberRoleDetails(event_uuid={!r}, access_type={!r})'.format( + return 'PaperDocUnresolveCommentDetails(event_uuid={!r}, comment_text={!r})'.format( self._event_uuid_value, - self._access_type_value, + self._comment_text_value, ) -PaperDocChangeMemberRoleDetails_validator = bv.Struct(PaperDocChangeMemberRoleDetails) +PaperDocUnresolveCommentDetails_validator = bv.Struct(PaperDocUnresolveCommentDetails) -class PaperDocChangeMemberRoleType(bb.Struct): +class PaperDocUnresolveCommentType(bb.Struct): __slots__ = [ '_description_value', @@ -45061,55 +65716,35 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocChangeMemberRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocUnresolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocChangeMemberRoleType(description={!r})'.format( + return 'PaperDocUnresolveCommentType(description={!r})'.format( self._description_value, ) -PaperDocChangeMemberRoleType_validator = bv.Struct(PaperDocChangeMemberRoleType) +PaperDocUnresolveCommentType_validator = bv.Struct(PaperDocUnresolveCommentType) -class PaperDocChangeSharingPolicyDetails(bb.Struct): +class PaperDocUntrashedDetails(bb.Struct): """ - Changed sharing setting for Paper doc. + Restored Paper doc. - :ivar team_log.PaperDocChangeSharingPolicyDetails.event_uuid: Event unique - identifier. - :ivar team_log.PaperDocChangeSharingPolicyDetails.public_sharing_policy: - Sharing policy with external users. Might be missing due to historical - data gap. - :ivar team_log.PaperDocChangeSharingPolicyDetails.team_sharing_policy: - Sharing policy with team. Might be missing due to historical data gap. + :ivar team_log.PaperDocUntrashedDetails.event_uuid: Event unique identifier. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_public_sharing_policy_value', - '_public_sharing_policy_present', - '_team_sharing_policy_value', - '_team_sharing_policy_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - public_sharing_policy=None, - team_sharing_policy=None): + event_uuid=None): self._event_uuid_value = None self._event_uuid_present = False - self._public_sharing_policy_value = None - self._public_sharing_policy_present = False - self._team_sharing_policy_value = None - self._team_sharing_policy_present = False if event_uuid is not None: self.event_uuid = event_uuid - if public_sharing_policy is not None: - self.public_sharing_policy = public_sharing_policy - if team_sharing_policy is not None: - self.team_sharing_policy = team_sharing_policy @property def event_uuid(self): @@ -45134,72 +65769,17 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False - @property - def public_sharing_policy(self): - """ - Sharing policy with external users. Might be missing due to historical - data gap. - - :rtype: str - """ - if self._public_sharing_policy_present: - return self._public_sharing_policy_value - else: - return None - - @public_sharing_policy.setter - def public_sharing_policy(self, val): - if val is None: - del self.public_sharing_policy - return - val = self._public_sharing_policy_validator.validate(val) - self._public_sharing_policy_value = val - self._public_sharing_policy_present = True - - @public_sharing_policy.deleter - def public_sharing_policy(self): - self._public_sharing_policy_value = None - self._public_sharing_policy_present = False - - @property - def team_sharing_policy(self): - """ - Sharing policy with team. Might be missing due to historical data gap. - - :rtype: str - """ - if self._team_sharing_policy_present: - return self._team_sharing_policy_value - else: - return None - - @team_sharing_policy.setter - def team_sharing_policy(self, val): - if val is None: - del self.team_sharing_policy - return - val = self._team_sharing_policy_validator.validate(val) - self._team_sharing_policy_value = val - self._team_sharing_policy_present = True - - @team_sharing_policy.deleter - def team_sharing_policy(self): - self._team_sharing_policy_value = None - self._team_sharing_policy_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocChangeSharingPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocUntrashedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocChangeSharingPolicyDetails(event_uuid={!r}, public_sharing_policy={!r}, team_sharing_policy={!r})'.format( + return 'PaperDocUntrashedDetails(event_uuid={!r})'.format( self._event_uuid_value, - self._public_sharing_policy_value, - self._team_sharing_policy_value, ) -PaperDocChangeSharingPolicyDetails_validator = bv.Struct(PaperDocChangeSharingPolicyDetails) +PaperDocUntrashedDetails_validator = bv.Struct(PaperDocUntrashedDetails) -class PaperDocChangeSharingPolicyType(bb.Struct): +class PaperDocUntrashedType(bb.Struct): __slots__ = [ '_description_value', @@ -45237,56 +65817,35 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocChangeSharingPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocUntrashedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocChangeSharingPolicyType(description={!r})'.format( + return 'PaperDocUntrashedType(description={!r})'.format( self._description_value, ) -PaperDocChangeSharingPolicyType_validator = bv.Struct(PaperDocChangeSharingPolicyType) +PaperDocUntrashedType_validator = bv.Struct(PaperDocUntrashedType) -class PaperDocChangeSubscriptionDetails(bb.Struct): +class PaperDocViewDetails(bb.Struct): """ - Followed/unfollowed Paper doc. + Viewed Paper doc. - :ivar team_log.PaperDocChangeSubscriptionDetails.event_uuid: Event unique - identifier. - :ivar team_log.PaperDocChangeSubscriptionDetails.new_subscription_level: New - doc subscription level. - :ivar - team_log.PaperDocChangeSubscriptionDetails.previous_subscription_level: - Previous doc subscription level. Might be missing due to historical data - gap. + :ivar team_log.PaperDocViewDetails.event_uuid: Event unique identifier. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_new_subscription_level_value', - '_new_subscription_level_present', - '_previous_subscription_level_value', - '_previous_subscription_level_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - new_subscription_level=None, - previous_subscription_level=None): + event_uuid=None): self._event_uuid_value = None self._event_uuid_present = False - self._new_subscription_level_value = None - self._new_subscription_level_present = False - self._previous_subscription_level_value = None - self._previous_subscription_level_present = False if event_uuid is not None: self.event_uuid = event_uuid - if new_subscription_level is not None: - self.new_subscription_level = new_subscription_level - if previous_subscription_level is not None: - self.previous_subscription_level = previous_subscription_level @property def event_uuid(self): @@ -45311,69 +65870,17 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False - @property - def new_subscription_level(self): - """ - New doc subscription level. - - :rtype: str - """ - if self._new_subscription_level_present: - return self._new_subscription_level_value - else: - raise AttributeError("missing required field 'new_subscription_level'") - - @new_subscription_level.setter - def new_subscription_level(self, val): - val = self._new_subscription_level_validator.validate(val) - self._new_subscription_level_value = val - self._new_subscription_level_present = True - - @new_subscription_level.deleter - def new_subscription_level(self): - self._new_subscription_level_value = None - self._new_subscription_level_present = False - - @property - def previous_subscription_level(self): - """ - Previous doc subscription level. Might be missing due to historical data - gap. - - :rtype: str - """ - if self._previous_subscription_level_present: - return self._previous_subscription_level_value - else: - return None - - @previous_subscription_level.setter - def previous_subscription_level(self, val): - if val is None: - del self.previous_subscription_level - return - val = self._previous_subscription_level_validator.validate(val) - self._previous_subscription_level_value = val - self._previous_subscription_level_present = True - - @previous_subscription_level.deleter - def previous_subscription_level(self): - self._previous_subscription_level_value = None - self._previous_subscription_level_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocChangeSubscriptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocViewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocChangeSubscriptionDetails(event_uuid={!r}, new_subscription_level={!r}, previous_subscription_level={!r})'.format( + return 'PaperDocViewDetails(event_uuid={!r})'.format( self._event_uuid_value, - self._new_subscription_level_value, - self._previous_subscription_level_value, ) -PaperDocChangeSubscriptionDetails_validator = bv.Struct(PaperDocChangeSubscriptionDetails) +PaperDocViewDetails_validator = bv.Struct(PaperDocViewDetails) -class PaperDocChangeSubscriptionType(bb.Struct): +class PaperDocViewType(bb.Struct): __slots__ = [ '_description_value', @@ -45411,107 +65918,190 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocChangeSubscriptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperDocViewType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocChangeSubscriptionType(description={!r})'.format( + return 'PaperDocViewType(description={!r})'.format( self._description_value, ) -PaperDocChangeSubscriptionType_validator = bv.Struct(PaperDocChangeSubscriptionType) +PaperDocViewType_validator = bv.Struct(PaperDocViewType) -class PaperDocDeleteCommentDetails(bb.Struct): +class PaperDocumentLogInfo(bb.Struct): """ - Deleted Paper doc comment. + Paper document's logged information. - :ivar team_log.PaperDocDeleteCommentDetails.event_uuid: Event unique - identifier. - :ivar team_log.PaperDocDeleteCommentDetails.comment_text: Comment text. - Might be missing due to historical data gap. + :ivar team_log.PaperDocumentLogInfo.doc_id: Papers document Id. + :ivar team_log.PaperDocumentLogInfo.doc_title: Paper document title. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - '_comment_text_value', - '_comment_text_present', + '_doc_id_value', + '_doc_id_present', + '_doc_title_value', + '_doc_title_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - comment_text=None): - self._event_uuid_value = None - self._event_uuid_present = False - self._comment_text_value = None - self._comment_text_present = False - if event_uuid is not None: - self.event_uuid = event_uuid - if comment_text is not None: - self.comment_text = comment_text + doc_id=None, + doc_title=None): + self._doc_id_value = None + self._doc_id_present = False + self._doc_title_value = None + self._doc_title_present = False + if doc_id is not None: + self.doc_id = doc_id + if doc_title is not None: + self.doc_title = doc_title @property - def event_uuid(self): + def doc_id(self): """ - Event unique identifier. + Papers document Id. :rtype: str """ - if self._event_uuid_present: - return self._event_uuid_value + if self._doc_id_present: + return self._doc_id_value else: - raise AttributeError("missing required field 'event_uuid'") + raise AttributeError("missing required field 'doc_id'") - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + @doc_id.setter + def doc_id(self, val): + val = self._doc_id_validator.validate(val) + self._doc_id_value = val + self._doc_id_present = True - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + @doc_id.deleter + def doc_id(self): + self._doc_id_value = None + self._doc_id_present = False @property - def comment_text(self): + def doc_title(self): """ - Comment text. Might be missing due to historical data gap. + Paper document title. + + :rtype: str + """ + if self._doc_title_present: + return self._doc_title_value + else: + raise AttributeError("missing required field 'doc_title'") + + @doc_title.setter + def doc_title(self, val): + val = self._doc_title_validator.validate(val) + self._doc_title_value = val + self._doc_title_present = True + + @doc_title.deleter + def doc_title(self): + self._doc_title_value = None + self._doc_title_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperDocumentLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperDocumentLogInfo(doc_id={!r}, doc_title={!r})'.format( + self._doc_id_value, + self._doc_title_value, + ) + +PaperDocumentLogInfo_validator = bv.Struct(PaperDocumentLogInfo) + +class PaperDownloadFormat(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + docx = None + # Attribute is overwritten below the class definition + html = None + # Attribute is overwritten below the class definition + markdown = None + # Attribute is overwritten below the class definition + pdf = None + # Attribute is overwritten below the class definition + other = None + + def is_docx(self): + """ + Check if the union tag is ``docx``. + + :rtype: bool + """ + return self._tag == 'docx' + + def is_html(self): + """ + Check if the union tag is ``html``. + + :rtype: bool + """ + return self._tag == 'html' + + def is_markdown(self): + """ + Check if the union tag is ``markdown``. + + :rtype: bool + """ + return self._tag == 'markdown' + + def is_pdf(self): + """ + Check if the union tag is ``pdf``. + + :rtype: bool + """ + return self._tag == 'pdf' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperDownloadFormat, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperDownloadFormat(%r, %r)' % (self._tag, self._value) + +PaperDownloadFormat_validator = bv.Union(PaperDownloadFormat) + +class PaperEnabledUsersGroupAdditionDetails(bb.Struct): + """ + Added users to Paper-enabled users list. + """ - :rtype: str - """ - if self._comment_text_present: - return self._comment_text_value - else: - return None + __slots__ = [ + ] - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + _has_required_fields = False - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocDeleteCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperEnabledUsersGroupAdditionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocDeleteCommentDetails(event_uuid={!r}, comment_text={!r})'.format( - self._event_uuid_value, - self._comment_text_value, - ) + return 'PaperEnabledUsersGroupAdditionDetails()' -PaperDocDeleteCommentDetails_validator = bv.Struct(PaperDocDeleteCommentDetails) +PaperEnabledUsersGroupAdditionDetails_validator = bv.Struct(PaperEnabledUsersGroupAdditionDetails) -class PaperDocDeleteCommentType(bb.Struct): +class PaperEnabledUsersGroupAdditionType(bb.Struct): __slots__ = [ '_description_value', @@ -45549,70 +66139,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocDeleteCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperEnabledUsersGroupAdditionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocDeleteCommentType(description={!r})'.format( + return 'PaperEnabledUsersGroupAdditionType(description={!r})'.format( self._description_value, ) -PaperDocDeleteCommentType_validator = bv.Struct(PaperDocDeleteCommentType) +PaperEnabledUsersGroupAdditionType_validator = bv.Struct(PaperEnabledUsersGroupAdditionType) -class PaperDocDeletedDetails(bb.Struct): +class PaperEnabledUsersGroupRemovalDetails(bb.Struct): """ - Archived Paper doc. - - :ivar team_log.PaperDocDeletedDetails.event_uuid: Event unique identifier. + Removed users from Paper-enabled users list. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', ] - _has_required_fields = True - - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid - - @property - def event_uuid(self): - """ - Event unique identifier. - - :rtype: str - """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") - - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + _has_required_fields = False - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocDeletedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperEnabledUsersGroupRemovalDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocDeletedDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + return 'PaperEnabledUsersGroupRemovalDetails()' -PaperDocDeletedDetails_validator = bv.Struct(PaperDocDeletedDetails) +PaperEnabledUsersGroupRemovalDetails_validator = bv.Struct(PaperEnabledUsersGroupRemovalDetails) -class PaperDocDeletedType(bb.Struct): +class PaperEnabledUsersGroupRemovalType(bb.Struct): __slots__ = [ '_description_value', @@ -45650,44 +66207,36 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocDeletedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperEnabledUsersGroupRemovalType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocDeletedType(description={!r})'.format( + return 'PaperEnabledUsersGroupRemovalType(description={!r})'.format( self._description_value, ) -PaperDocDeletedType_validator = bv.Struct(PaperDocDeletedType) +PaperEnabledUsersGroupRemovalType_validator = bv.Struct(PaperEnabledUsersGroupRemovalType) -class PaperDocDownloadDetails(bb.Struct): +class PaperExternalViewAllowDetails(bb.Struct): """ - Downloaded Paper doc in specific format. + Changed Paper external sharing setting to anyone. - :ivar team_log.PaperDocDownloadDetails.event_uuid: Event unique identifier. - :ivar team_log.PaperDocDownloadDetails.export_file_format: Export file - format. + :ivar team_log.PaperExternalViewAllowDetails.event_uuid: Event unique + identifier. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_export_file_format_value', - '_export_file_format_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - export_file_format=None): + event_uuid=None): self._event_uuid_value = None self._event_uuid_present = False - self._export_file_format_value = None - self._export_file_format_present = False if event_uuid is not None: self.event_uuid = event_uuid - if export_file_format is not None: - self.export_file_format = export_file_format @property def event_uuid(self): @@ -45712,41 +66261,17 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False - @property - def export_file_format(self): - """ - Export file format. - - :rtype: PaperDownloadFormat - """ - if self._export_file_format_present: - return self._export_file_format_value - else: - raise AttributeError("missing required field 'export_file_format'") - - @export_file_format.setter - def export_file_format(self, val): - self._export_file_format_validator.validate_type_only(val) - self._export_file_format_value = val - self._export_file_format_present = True - - @export_file_format.deleter - def export_file_format(self): - self._export_file_format_value = None - self._export_file_format_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperExternalViewAllowDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocDownloadDetails(event_uuid={!r}, export_file_format={!r})'.format( + return 'PaperExternalViewAllowDetails(event_uuid={!r})'.format( self._event_uuid_value, - self._export_file_format_value, ) -PaperDocDownloadDetails_validator = bv.Struct(PaperDocDownloadDetails) +PaperExternalViewAllowDetails_validator = bv.Struct(PaperExternalViewAllowDetails) -class PaperDocDownloadType(bb.Struct): +class PaperExternalViewAllowType(bb.Struct): __slots__ = [ '_description_value', @@ -45784,45 +66309,36 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperExternalViewAllowType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocDownloadType(description={!r})'.format( + return 'PaperExternalViewAllowType(description={!r})'.format( self._description_value, ) -PaperDocDownloadType_validator = bv.Struct(PaperDocDownloadType) +PaperExternalViewAllowType_validator = bv.Struct(PaperExternalViewAllowType) -class PaperDocEditCommentDetails(bb.Struct): +class PaperExternalViewDefaultTeamDetails(bb.Struct): """ - Edited Paper doc comment. + Changed Paper external sharing setting to default team. - :ivar team_log.PaperDocEditCommentDetails.event_uuid: Event unique + :ivar team_log.PaperExternalViewDefaultTeamDetails.event_uuid: Event unique identifier. - :ivar team_log.PaperDocEditCommentDetails.comment_text: Comment text. Might - be missing due to historical data gap. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_comment_text_value', - '_comment_text_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - comment_text=None): + event_uuid=None): self._event_uuid_value = None self._event_uuid_present = False - self._comment_text_value = None - self._comment_text_present = False if event_uuid is not None: self.event_uuid = event_uuid - if comment_text is not None: - self.comment_text = comment_text @property def event_uuid(self): @@ -45847,44 +66363,17 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False - @property - def comment_text(self): - """ - Comment text. Might be missing due to historical data gap. - - :rtype: str - """ - if self._comment_text_present: - return self._comment_text_value - else: - return None - - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True - - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocEditCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperExternalViewDefaultTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocEditCommentDetails(event_uuid={!r}, comment_text={!r})'.format( + return 'PaperExternalViewDefaultTeamDetails(event_uuid={!r})'.format( self._event_uuid_value, - self._comment_text_value, ) -PaperDocEditCommentDetails_validator = bv.Struct(PaperDocEditCommentDetails) +PaperExternalViewDefaultTeamDetails_validator = bv.Struct(PaperExternalViewDefaultTeamDetails) -class PaperDocEditCommentType(bb.Struct): +class PaperExternalViewDefaultTeamType(bb.Struct): __slots__ = [ '_description_value', @@ -45922,20 +66411,21 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocEditCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperExternalViewDefaultTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocEditCommentType(description={!r})'.format( + return 'PaperExternalViewDefaultTeamType(description={!r})'.format( self._description_value, ) -PaperDocEditCommentType_validator = bv.Struct(PaperDocEditCommentType) +PaperExternalViewDefaultTeamType_validator = bv.Struct(PaperExternalViewDefaultTeamType) -class PaperDocEditDetails(bb.Struct): +class PaperExternalViewForbidDetails(bb.Struct): """ - Edited Paper doc. + Changed Paper external sharing setting to team-only. - :ivar team_log.PaperDocEditDetails.event_uuid: Event unique identifier. + :ivar team_log.PaperExternalViewForbidDetails.event_uuid: Event unique + identifier. """ __slots__ = [ @@ -45976,16 +66466,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocEditDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperExternalViewForbidDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocEditDetails(event_uuid={!r})'.format( + return 'PaperExternalViewForbidDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperDocEditDetails_validator = bv.Struct(PaperDocEditDetails) +PaperExternalViewForbidDetails_validator = bv.Struct(PaperExternalViewForbidDetails) -class PaperDocEditType(bb.Struct): +class PaperExternalViewForbidType(bb.Struct): __slots__ = [ '_description_value', @@ -46023,35 +66513,56 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocEditType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperExternalViewForbidType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocEditType(description={!r})'.format( + return 'PaperExternalViewForbidType(description={!r})'.format( self._description_value, ) -PaperDocEditType_validator = bv.Struct(PaperDocEditType) +PaperExternalViewForbidType_validator = bv.Struct(PaperExternalViewForbidType) -class PaperDocFollowedDetails(bb.Struct): +class PaperFolderChangeSubscriptionDetails(bb.Struct): """ - Followed Paper doc. + Followed/unfollowed Paper folder. - :ivar team_log.PaperDocFollowedDetails.event_uuid: Event unique identifier. + :ivar team_log.PaperFolderChangeSubscriptionDetails.event_uuid: Event unique + identifier. + :ivar team_log.PaperFolderChangeSubscriptionDetails.new_subscription_level: + New folder subscription level. + :ivar + team_log.PaperFolderChangeSubscriptionDetails.previous_subscription_level: + Previous folder subscription level. Might be missing due to historical + data gap. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', + '_new_subscription_level_value', + '_new_subscription_level_present', + '_previous_subscription_level_value', + '_previous_subscription_level_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): + event_uuid=None, + new_subscription_level=None, + previous_subscription_level=None): self._event_uuid_value = None self._event_uuid_present = False + self._new_subscription_level_value = None + self._new_subscription_level_present = False + self._previous_subscription_level_value = None + self._previous_subscription_level_present = False if event_uuid is not None: self.event_uuid = event_uuid + if new_subscription_level is not None: + self.new_subscription_level = new_subscription_level + if previous_subscription_level is not None: + self.previous_subscription_level = previous_subscription_level @property def event_uuid(self): @@ -46076,17 +66587,69 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False + @property + def new_subscription_level(self): + """ + New folder subscription level. + + :rtype: str + """ + if self._new_subscription_level_present: + return self._new_subscription_level_value + else: + raise AttributeError("missing required field 'new_subscription_level'") + + @new_subscription_level.setter + def new_subscription_level(self, val): + val = self._new_subscription_level_validator.validate(val) + self._new_subscription_level_value = val + self._new_subscription_level_present = True + + @new_subscription_level.deleter + def new_subscription_level(self): + self._new_subscription_level_value = None + self._new_subscription_level_present = False + + @property + def previous_subscription_level(self): + """ + Previous folder subscription level. Might be missing due to historical + data gap. + + :rtype: str + """ + if self._previous_subscription_level_present: + return self._previous_subscription_level_value + else: + return None + + @previous_subscription_level.setter + def previous_subscription_level(self, val): + if val is None: + del self.previous_subscription_level + return + val = self._previous_subscription_level_validator.validate(val) + self._previous_subscription_level_value = val + self._previous_subscription_level_present = True + + @previous_subscription_level.deleter + def previous_subscription_level(self): + self._previous_subscription_level_value = None + self._previous_subscription_level_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocFollowedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderChangeSubscriptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocFollowedDetails(event_uuid={!r})'.format( + return 'PaperFolderChangeSubscriptionDetails(event_uuid={!r}, new_subscription_level={!r}, previous_subscription_level={!r})'.format( self._event_uuid_value, + self._new_subscription_level_value, + self._previous_subscription_level_value, ) -PaperDocFollowedDetails_validator = bv.Struct(PaperDocFollowedDetails) +PaperFolderChangeSubscriptionDetails_validator = bv.Struct(PaperFolderChangeSubscriptionDetails) -class PaperDocFollowedType(bb.Struct): +class PaperFolderChangeSubscriptionType(bb.Struct): __slots__ = [ '_description_value', @@ -46124,20 +66687,21 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocFollowedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderChangeSubscriptionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocFollowedType(description={!r})'.format( + return 'PaperFolderChangeSubscriptionType(description={!r})'.format( self._description_value, ) -PaperDocFollowedType_validator = bv.Struct(PaperDocFollowedType) +PaperFolderChangeSubscriptionType_validator = bv.Struct(PaperFolderChangeSubscriptionType) -class PaperDocMentionDetails(bb.Struct): +class PaperFolderDeletedDetails(bb.Struct): """ - Mentioned team member in Paper doc. + Archived Paper folder. - :ivar team_log.PaperDocMentionDetails.event_uuid: Event unique identifier. + :ivar team_log.PaperFolderDeletedDetails.event_uuid: Event unique + identifier. """ __slots__ = [ @@ -46178,16 +66742,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocMentionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderDeletedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocMentionDetails(event_uuid={!r})'.format( + return 'PaperFolderDeletedDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperDocMentionDetails_validator = bv.Struct(PaperDocMentionDetails) +PaperFolderDeletedDetails_validator = bv.Struct(PaperFolderDeletedDetails) -class PaperDocMentionType(bb.Struct): +class PaperFolderDeletedType(bb.Struct): __slots__ = [ '_description_value', @@ -46225,53 +66789,36 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocMentionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderDeletedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocMentionType(description={!r})'.format( + return 'PaperFolderDeletedType(description={!r})'.format( self._description_value, ) -PaperDocMentionType_validator = bv.Struct(PaperDocMentionType) +PaperFolderDeletedType_validator = bv.Struct(PaperFolderDeletedType) -class PaperDocOwnershipChangedDetails(bb.Struct): +class PaperFolderFollowedDetails(bb.Struct): """ - Transferred ownership of Paper doc. + Followed Paper folder. - :ivar team_log.PaperDocOwnershipChangedDetails.event_uuid: Event unique + :ivar team_log.PaperFolderFollowedDetails.event_uuid: Event unique identifier. - :ivar team_log.PaperDocOwnershipChangedDetails.old_owner_user_id: Previous - owner. - :ivar team_log.PaperDocOwnershipChangedDetails.new_owner_user_id: New owner. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_old_owner_user_id_value', - '_old_owner_user_id_present', - '_new_owner_user_id_value', - '_new_owner_user_id_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - new_owner_user_id=None, - old_owner_user_id=None): + event_uuid=None): self._event_uuid_value = None self._event_uuid_present = False - self._old_owner_user_id_value = None - self._old_owner_user_id_present = False - self._new_owner_user_id_value = None - self._new_owner_user_id_present = False if event_uuid is not None: self.event_uuid = event_uuid - if old_owner_user_id is not None: - self.old_owner_user_id = old_owner_user_id - if new_owner_user_id is not None: - self.new_owner_user_id = new_owner_user_id @property def event_uuid(self): @@ -46296,68 +66843,17 @@ def event_uuid(self): self._event_uuid_value = None self._event_uuid_present = False - @property - def old_owner_user_id(self): - """ - Previous owner. - - :rtype: str - """ - if self._old_owner_user_id_present: - return self._old_owner_user_id_value - else: - return None - - @old_owner_user_id.setter - def old_owner_user_id(self, val): - if val is None: - del self.old_owner_user_id - return - val = self._old_owner_user_id_validator.validate(val) - self._old_owner_user_id_value = val - self._old_owner_user_id_present = True - - @old_owner_user_id.deleter - def old_owner_user_id(self): - self._old_owner_user_id_value = None - self._old_owner_user_id_present = False - - @property - def new_owner_user_id(self): - """ - New owner. - - :rtype: str - """ - if self._new_owner_user_id_present: - return self._new_owner_user_id_value - else: - raise AttributeError("missing required field 'new_owner_user_id'") - - @new_owner_user_id.setter - def new_owner_user_id(self, val): - val = self._new_owner_user_id_validator.validate(val) - self._new_owner_user_id_value = val - self._new_owner_user_id_present = True - - @new_owner_user_id.deleter - def new_owner_user_id(self): - self._new_owner_user_id_value = None - self._new_owner_user_id_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocOwnershipChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderFollowedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocOwnershipChangedDetails(event_uuid={!r}, new_owner_user_id={!r}, old_owner_user_id={!r})'.format( + return 'PaperFolderFollowedDetails(event_uuid={!r})'.format( self._event_uuid_value, - self._new_owner_user_id_value, - self._old_owner_user_id_value, ) -PaperDocOwnershipChangedDetails_validator = bv.Struct(PaperDocOwnershipChangedDetails) +PaperFolderFollowedDetails_validator = bv.Struct(PaperFolderFollowedDetails) -class PaperDocOwnershipChangedType(bb.Struct): +class PaperFolderFollowedType(bb.Struct): __slots__ = [ '_description_value', @@ -46389,26 +66885,112 @@ def description(self, val): self._description_value = val self._description_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperFolderFollowedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperFolderFollowedType(description={!r})'.format( + self._description_value, + ) + +PaperFolderFollowedType_validator = bv.Struct(PaperFolderFollowedType) + +class PaperFolderLogInfo(bb.Struct): + """ + Paper folder's logged information. + + :ivar team_log.PaperFolderLogInfo.folder_id: Papers folder Id. + :ivar team_log.PaperFolderLogInfo.folder_name: Paper folder name. + """ + + __slots__ = [ + '_folder_id_value', + '_folder_id_present', + '_folder_name_value', + '_folder_name_present', + ] + + _has_required_fields = True + + def __init__(self, + folder_id=None, + folder_name=None): + self._folder_id_value = None + self._folder_id_present = False + self._folder_name_value = None + self._folder_name_present = False + if folder_id is not None: + self.folder_id = folder_id + if folder_name is not None: + self.folder_name = folder_name + + @property + def folder_id(self): + """ + Papers folder Id. + + :rtype: str + """ + if self._folder_id_present: + return self._folder_id_value + else: + raise AttributeError("missing required field 'folder_id'") + + @folder_id.setter + def folder_id(self, val): + val = self._folder_id_validator.validate(val) + self._folder_id_value = val + self._folder_id_present = True + + @folder_id.deleter + def folder_id(self): + self._folder_id_value = None + self._folder_id_present = False + + @property + def folder_name(self): + """ + Paper folder name. + + :rtype: str + """ + if self._folder_name_present: + return self._folder_name_value + else: + raise AttributeError("missing required field 'folder_name'") + + @folder_name.setter + def folder_name(self, val): + val = self._folder_name_validator.validate(val) + self._folder_name_value = val + self._folder_name_present = True + + @folder_name.deleter + def folder_name(self): + self._folder_name_value = None + self._folder_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocOwnershipChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocOwnershipChangedType(description={!r})'.format( - self._description_value, + return 'PaperFolderLogInfo(folder_id={!r}, folder_name={!r})'.format( + self._folder_id_value, + self._folder_name_value, ) -PaperDocOwnershipChangedType_validator = bv.Struct(PaperDocOwnershipChangedType) +PaperFolderLogInfo_validator = bv.Struct(PaperFolderLogInfo) -class PaperDocRequestAccessDetails(bb.Struct): +class PaperFolderTeamInviteDetails(bb.Struct): """ - Requested access to Paper doc. + Shared Paper folder with users and/or groups. - :ivar team_log.PaperDocRequestAccessDetails.event_uuid: Event unique + :ivar team_log.PaperFolderTeamInviteDetails.event_uuid: Event unique identifier. """ @@ -46450,16 +67032,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocRequestAccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderTeamInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocRequestAccessDetails(event_uuid={!r})'.format( + return 'PaperFolderTeamInviteDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperDocRequestAccessDetails_validator = bv.Struct(PaperDocRequestAccessDetails) +PaperFolderTeamInviteDetails_validator = bv.Struct(PaperFolderTeamInviteDetails) -class PaperDocRequestAccessType(bb.Struct): +class PaperFolderTeamInviteType(bb.Struct): __slots__ = [ '_description_value', @@ -46497,45 +67079,115 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocRequestAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperFolderTeamInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocRequestAccessType(description={!r})'.format( + return 'PaperFolderTeamInviteType(description={!r})'.format( self._description_value, ) -PaperDocRequestAccessType_validator = bv.Struct(PaperDocRequestAccessType) +PaperFolderTeamInviteType_validator = bv.Struct(PaperFolderTeamInviteType) -class PaperDocResolveCommentDetails(bb.Struct): +class PaperMemberPolicy(bb.Union): """ - Resolved Paper doc comment. + Policy for controlling if team members can share Paper documents externally. - :ivar team_log.PaperDocResolveCommentDetails.event_uuid: Event unique - identifier. - :ivar team_log.PaperDocResolveCommentDetails.comment_text: Comment text. - Might be missing due to historical data gap. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + anyone_with_link = None + # Attribute is overwritten below the class definition + only_team = None + # Attribute is overwritten below the class definition + team_and_explicitly_shared = None + # Attribute is overwritten below the class definition + other = None + + def is_anyone_with_link(self): + """ + Check if the union tag is ``anyone_with_link``. + + :rtype: bool + """ + return self._tag == 'anyone_with_link' + + def is_only_team(self): + """ + Check if the union tag is ``only_team``. + + :rtype: bool + """ + return self._tag == 'only_team' + + def is_team_and_explicitly_shared(self): + """ + Check if the union tag is ``team_and_explicitly_shared``. + + :rtype: bool + """ + return self._tag == 'team_and_explicitly_shared' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperMemberPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperMemberPolicy(%r, %r)' % (self._tag, self._value) + +PaperMemberPolicy_validator = bv.Union(PaperMemberPolicy) + +class PaperPublishedLinkChangePermissionDetails(bb.Struct): + """ + Changed permissions for published doc. + + :ivar team_log.PaperPublishedLinkChangePermissionDetails.event_uuid: Event + unique identifier. + :ivar + team_log.PaperPublishedLinkChangePermissionDetails.new_permission_level: + New permission level. + :ivar + team_log.PaperPublishedLinkChangePermissionDetails.previous_permission_level: + Previous permission level. """ __slots__ = [ '_event_uuid_value', '_event_uuid_present', - '_comment_text_value', - '_comment_text_present', + '_new_permission_level_value', + '_new_permission_level_present', + '_previous_permission_level_value', + '_previous_permission_level_present', ] _has_required_fields = True def __init__(self, event_uuid=None, - comment_text=None): + new_permission_level=None, + previous_permission_level=None): self._event_uuid_value = None self._event_uuid_present = False - self._comment_text_value = None - self._comment_text_present = False + self._new_permission_level_value = None + self._new_permission_level_present = False + self._previous_permission_level_value = None + self._previous_permission_level_present = False if event_uuid is not None: self.event_uuid = event_uuid - if comment_text is not None: - self.comment_text = comment_text + if new_permission_level is not None: + self.new_permission_level = new_permission_level + if previous_permission_level is not None: + self.previous_permission_level = previous_permission_level @property def event_uuid(self): @@ -46561,43 +67213,64 @@ def event_uuid(self): self._event_uuid_present = False @property - def comment_text(self): + def new_permission_level(self): """ - Comment text. Might be missing due to historical data gap. + New permission level. :rtype: str """ - if self._comment_text_present: - return self._comment_text_value + if self._new_permission_level_present: + return self._new_permission_level_value else: - return None + raise AttributeError("missing required field 'new_permission_level'") - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + @new_permission_level.setter + def new_permission_level(self, val): + val = self._new_permission_level_validator.validate(val) + self._new_permission_level_value = val + self._new_permission_level_present = True - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + @new_permission_level.deleter + def new_permission_level(self): + self._new_permission_level_value = None + self._new_permission_level_present = False + + @property + def previous_permission_level(self): + """ + Previous permission level. + + :rtype: str + """ + if self._previous_permission_level_present: + return self._previous_permission_level_value + else: + raise AttributeError("missing required field 'previous_permission_level'") + + @previous_permission_level.setter + def previous_permission_level(self, val): + val = self._previous_permission_level_validator.validate(val) + self._previous_permission_level_value = val + self._previous_permission_level_present = True + + @previous_permission_level.deleter + def previous_permission_level(self): + self._previous_permission_level_value = None + self._previous_permission_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocResolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkChangePermissionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocResolveCommentDetails(event_uuid={!r}, comment_text={!r})'.format( + return 'PaperPublishedLinkChangePermissionDetails(event_uuid={!r}, new_permission_level={!r}, previous_permission_level={!r})'.format( self._event_uuid_value, - self._comment_text_value, + self._new_permission_level_value, + self._previous_permission_level_value, ) -PaperDocResolveCommentDetails_validator = bv.Struct(PaperDocResolveCommentDetails) +PaperPublishedLinkChangePermissionDetails_validator = bv.Struct(PaperPublishedLinkChangePermissionDetails) -class PaperDocResolveCommentType(bb.Struct): +class PaperPublishedLinkChangePermissionType(bb.Struct): __slots__ = [ '_description_value', @@ -46635,20 +67308,21 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocResolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkChangePermissionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocResolveCommentType(description={!r})'.format( + return 'PaperPublishedLinkChangePermissionType(description={!r})'.format( self._description_value, ) -PaperDocResolveCommentType_validator = bv.Struct(PaperDocResolveCommentType) +PaperPublishedLinkChangePermissionType_validator = bv.Struct(PaperPublishedLinkChangePermissionType) -class PaperDocRevertDetails(bb.Struct): +class PaperPublishedLinkCreateDetails(bb.Struct): """ - Restored Paper doc to previous version. + Published doc. - :ivar team_log.PaperDocRevertDetails.event_uuid: Event unique identifier. + :ivar team_log.PaperPublishedLinkCreateDetails.event_uuid: Event unique + identifier. """ __slots__ = [ @@ -46689,16 +67363,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocRevertDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocRevertDetails(event_uuid={!r})'.format( + return 'PaperPublishedLinkCreateDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperDocRevertDetails_validator = bv.Struct(PaperDocRevertDetails) +PaperPublishedLinkCreateDetails_validator = bv.Struct(PaperPublishedLinkCreateDetails) -class PaperDocRevertType(bb.Struct): +class PaperPublishedLinkCreateType(bb.Struct): __slots__ = [ '_description_value', @@ -46736,20 +67410,20 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocRevertType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocRevertType(description={!r})'.format( + return 'PaperPublishedLinkCreateType(description={!r})'.format( self._description_value, ) -PaperDocRevertType_validator = bv.Struct(PaperDocRevertType) +PaperPublishedLinkCreateType_validator = bv.Struct(PaperPublishedLinkCreateType) -class PaperDocSlackShareDetails(bb.Struct): +class PaperPublishedLinkDisabledDetails(bb.Struct): """ - Shared Paper doc via Slack. + Unpublished doc. - :ivar team_log.PaperDocSlackShareDetails.event_uuid: Event unique + :ivar team_log.PaperPublishedLinkDisabledDetails.event_uuid: Event unique identifier. """ @@ -46791,16 +67465,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocSlackShareDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkDisabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocSlackShareDetails(event_uuid={!r})'.format( + return 'PaperPublishedLinkDisabledDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperDocSlackShareDetails_validator = bv.Struct(PaperDocSlackShareDetails) +PaperPublishedLinkDisabledDetails_validator = bv.Struct(PaperPublishedLinkDisabledDetails) -class PaperDocSlackShareType(bb.Struct): +class PaperPublishedLinkDisabledType(bb.Struct): __slots__ = [ '_description_value', @@ -46838,20 +67512,20 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocSlackShareType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkDisabledType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocSlackShareType(description={!r})'.format( + return 'PaperPublishedLinkDisabledType(description={!r})'.format( self._description_value, ) -PaperDocSlackShareType_validator = bv.Struct(PaperDocSlackShareType) +PaperPublishedLinkDisabledType_validator = bv.Struct(PaperPublishedLinkDisabledType) -class PaperDocTeamInviteDetails(bb.Struct): +class PaperPublishedLinkViewDetails(bb.Struct): """ - Shared Paper doc with team member. + Viewed published doc. - :ivar team_log.PaperDocTeamInviteDetails.event_uuid: Event unique + :ivar team_log.PaperPublishedLinkViewDetails.event_uuid: Event unique identifier. """ @@ -46893,16 +67567,16 @@ def event_uuid(self): self._event_uuid_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocTeamInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkViewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocTeamInviteDetails(event_uuid={!r})'.format( + return 'PaperPublishedLinkViewDetails(event_uuid={!r})'.format( self._event_uuid_value, ) -PaperDocTeamInviteDetails_validator = bv.Struct(PaperDocTeamInviteDetails) +PaperPublishedLinkViewDetails_validator = bv.Struct(PaperPublishedLinkViewDetails) -class PaperDocTeamInviteType(bb.Struct): +class PaperPublishedLinkViewType(bb.Struct): __slots__ = [ '_description_value', @@ -46940,208 +67614,188 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocTeamInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PaperPublishedLinkViewType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocTeamInviteType(description={!r})'.format( + return 'PaperPublishedLinkViewType(description={!r})'.format( self._description_value, ) -PaperDocTeamInviteType_validator = bv.Struct(PaperDocTeamInviteType) +PaperPublishedLinkViewType_validator = bv.Struct(PaperPublishedLinkViewType) -class PaperDocTrashedDetails(bb.Struct): +class ParticipantLogInfo(bb.Union): """ - Deleted Paper doc. + A user or group - :ivar team_log.PaperDocTrashedDetails.event_uuid: Event unique identifier. - """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. - __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - ] + :ivar UserLogInfo ParticipantLogInfo.user: A user with a Dropbox account. + :ivar GroupLogInfo ParticipantLogInfo.group: Group details. + """ - _has_required_fields = True + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + @classmethod + def user(cls, val): + """ + Create an instance of this class set to the ``user`` tag with value + ``val``. - @property - def event_uuid(self): + :param UserLogInfo val: + :rtype: ParticipantLogInfo """ - Event unique identifier. + return cls('user', val) - :rtype: str + @classmethod + def group(cls, val): """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") + Create an instance of this class set to the ``group`` tag with value + ``val``. - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + :param GroupLogInfo val: + :rtype: ParticipantLogInfo + """ + return cls('group', val) - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + def is_user(self): + """ + Check if the union tag is ``user``. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocTrashedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: bool + """ + return self._tag == 'user' - def __repr__(self): - return 'PaperDocTrashedDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + def is_group(self): + """ + Check if the union tag is ``group``. -PaperDocTrashedDetails_validator = bv.Struct(PaperDocTrashedDetails) + :rtype: bool + """ + return self._tag == 'group' -class PaperDocTrashedType(bb.Struct): + def is_other(self): + """ + Check if the union tag is ``other``. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: bool + """ + return self._tag == 'other' - _has_required_fields = True + def get_user(self): + """ + A user with a Dropbox account. - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + Only call this if :meth:`is_user` is true. - @property - def description(self): + :rtype: UserLogInfo """ - :rtype: str + if not self.is_user(): + raise AttributeError("tag 'user' not set") + return self._value + + def get_group(self): """ - if self._description_present: - return self._description_value - else: - raise AttributeError("missing required field 'description'") + Group details. - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + Only call this if :meth:`is_group` is true. - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + :rtype: GroupLogInfo + """ + if not self.is_group(): + raise AttributeError("tag 'group' not set") + return self._value def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocTrashedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ParticipantLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocTrashedType(description={!r})'.format( - self._description_value, - ) + return 'ParticipantLogInfo(%r, %r)' % (self._tag, self._value) -PaperDocTrashedType_validator = bv.Struct(PaperDocTrashedType) +ParticipantLogInfo_validator = bv.Union(ParticipantLogInfo) -class PaperDocUnresolveCommentDetails(bb.Struct): +class PassPolicy(bb.Union): """ - Unresolved Paper doc comment. - - :ivar team_log.PaperDocUnresolveCommentDetails.event_uuid: Event unique - identifier. - :ivar team_log.PaperDocUnresolveCommentDetails.comment_text: Comment text. - Might be missing due to historical data gap. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - '_comment_text_value', - '_comment_text_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + allow = None + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_enabled(self): + """ + Check if the union tag is ``enabled``. - def __init__(self, - event_uuid=None, - comment_text=None): - self._event_uuid_value = None - self._event_uuid_present = False - self._comment_text_value = None - self._comment_text_present = False - if event_uuid is not None: - self.event_uuid = event_uuid - if comment_text is not None: - self.comment_text = comment_text + :rtype: bool + """ + return self._tag == 'enabled' - @property - def event_uuid(self): + def is_allow(self): """ - Event unique identifier. + Check if the union tag is ``allow``. - :rtype: str + :rtype: bool """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") + return self._tag == 'allow' - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + def is_disabled(self): + """ + Check if the union tag is ``disabled``. - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + :rtype: bool + """ + return self._tag == 'disabled' - @property - def comment_text(self): + def is_other(self): """ - Comment text. Might be missing due to historical data gap. + Check if the union tag is ``other``. - :rtype: str + :rtype: bool """ - if self._comment_text_present: - return self._comment_text_value - else: - return None + return self._tag == 'other' - @comment_text.setter - def comment_text(self, val): - if val is None: - del self.comment_text - return - val = self._comment_text_validator.validate(val) - self._comment_text_value = val - self._comment_text_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PassPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - @comment_text.deleter - def comment_text(self): - self._comment_text_value = None - self._comment_text_present = False + def __repr__(self): + return 'PassPolicy(%r, %r)' % (self._tag, self._value) + +PassPolicy_validator = bv.Union(PassPolicy) + +class PasswordChangeDetails(bb.Struct): + """ + Changed password. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocUnresolveCommentDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordChangeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocUnresolveCommentDetails(event_uuid={!r}, comment_text={!r})'.format( - self._event_uuid_value, - self._comment_text_value, - ) + return 'PasswordChangeDetails()' -PaperDocUnresolveCommentDetails_validator = bv.Struct(PaperDocUnresolveCommentDetails) +PasswordChangeDetails_validator = bv.Struct(PasswordChangeDetails) -class PaperDocUnresolveCommentType(bb.Struct): +class PasswordChangeType(bb.Struct): __slots__ = [ '_description_value', @@ -47179,70 +67833,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocUnresolveCommentType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordChangeType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocUnresolveCommentType(description={!r})'.format( + return 'PasswordChangeType(description={!r})'.format( self._description_value, ) -PaperDocUnresolveCommentType_validator = bv.Struct(PaperDocUnresolveCommentType) - -class PaperDocUntrashedDetails(bb.Struct): - """ - Restored Paper doc. +PasswordChangeType_validator = bv.Struct(PasswordChangeType) - :ivar team_log.PaperDocUntrashedDetails.event_uuid: Event unique identifier. +class PasswordResetAllDetails(bb.Struct): + """ + Reset all team member passwords. """ - __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - ] - - _has_required_fields = True - - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid - - @property - def event_uuid(self): - """ - Event unique identifier. - - :rtype: str - """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") - - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + __slots__ = [ + ] - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + _has_required_fields = False + + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocUntrashedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordResetAllDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocUntrashedDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + return 'PasswordResetAllDetails()' -PaperDocUntrashedDetails_validator = bv.Struct(PaperDocUntrashedDetails) +PasswordResetAllDetails_validator = bv.Struct(PasswordResetAllDetails) -class PaperDocUntrashedType(bb.Struct): +class PasswordResetAllType(bb.Struct): __slots__ = [ '_description_value', @@ -47280,70 +67901,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocUntrashedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordResetAllType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocUntrashedType(description={!r})'.format( + return 'PasswordResetAllType(description={!r})'.format( self._description_value, ) -PaperDocUntrashedType_validator = bv.Struct(PaperDocUntrashedType) +PasswordResetAllType_validator = bv.Struct(PasswordResetAllType) -class PaperDocViewDetails(bb.Struct): +class PasswordResetDetails(bb.Struct): """ - Viewed Paper doc. - - :ivar team_log.PaperDocViewDetails.event_uuid: Event unique identifier. + Reset password. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', ] - _has_required_fields = True - - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid - - @property - def event_uuid(self): - """ - Event unique identifier. - - :rtype: str - """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") - - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + _has_required_fields = False - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocViewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordResetDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocViewDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + return 'PasswordResetDetails()' -PaperDocViewDetails_validator = bv.Struct(PaperDocViewDetails) +PasswordResetDetails_validator = bv.Struct(PasswordResetDetails) -class PaperDocViewType(bb.Struct): +class PasswordResetType(bb.Struct): __slots__ = [ '_description_value', @@ -47381,190 +67969,105 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocViewType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordResetType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocViewType(description={!r})'.format( + return 'PasswordResetType(description={!r})'.format( self._description_value, ) -PaperDocViewType_validator = bv.Struct(PaperDocViewType) +PasswordResetType_validator = bv.Struct(PasswordResetType) -class PaperDocumentLogInfo(bb.Struct): +class PasswordStrengthRequirementsChangePolicyDetails(bb.Struct): """ - Paper document's logged information. + Changed team password strength requirements. - :ivar team_log.PaperDocumentLogInfo.doc_id: Papers document Id. - :ivar team_log.PaperDocumentLogInfo.doc_title: Paper document title. + :ivar + team_log.PasswordStrengthRequirementsChangePolicyDetails.previous_value: + Old password strength policy. + :ivar team_log.PasswordStrengthRequirementsChangePolicyDetails.new_value: + New password strength policy. """ __slots__ = [ - '_doc_id_value', - '_doc_id_present', - '_doc_title_value', - '_doc_title_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', ] _has_required_fields = True def __init__(self, - doc_id=None, - doc_title=None): - self._doc_id_value = None - self._doc_id_present = False - self._doc_title_value = None - self._doc_title_present = False - if doc_id is not None: - self.doc_id = doc_id - if doc_title is not None: - self.doc_title = doc_title + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def doc_id(self): + def previous_value(self): """ - Papers document Id. + Old password strength policy. - :rtype: str + :rtype: team_policies.PasswordStrengthPolicy """ - if self._doc_id_present: - return self._doc_id_value + if self._previous_value_present: + return self._previous_value_value else: - raise AttributeError("missing required field 'doc_id'") + raise AttributeError("missing required field 'previous_value'") - @doc_id.setter - def doc_id(self, val): - val = self._doc_id_validator.validate(val) - self._doc_id_value = val - self._doc_id_present = True + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @doc_id.deleter - def doc_id(self): - self._doc_id_value = None - self._doc_id_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property - def doc_title(self): + def new_value(self): """ - Paper document title. + New password strength policy. - :rtype: str + :rtype: team_policies.PasswordStrengthPolicy """ - if self._doc_title_present: - return self._doc_title_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'doc_title'") + raise AttributeError("missing required field 'new_value'") - @doc_title.setter - def doc_title(self, val): - val = self._doc_title_validator.validate(val) - self._doc_title_value = val - self._doc_title_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @doc_title.deleter - def doc_title(self): - self._doc_title_value = None - self._doc_title_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDocumentLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordStrengthRequirementsChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperDocumentLogInfo(doc_id={!r}, doc_title={!r})'.format( - self._doc_id_value, - self._doc_title_value, + return 'PasswordStrengthRequirementsChangePolicyDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, ) -PaperDocumentLogInfo_validator = bv.Struct(PaperDocumentLogInfo) - -class PaperDownloadFormat(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - docx = None - # Attribute is overwritten below the class definition - html = None - # Attribute is overwritten below the class definition - markdown = None - # Attribute is overwritten below the class definition - pdf = None - # Attribute is overwritten below the class definition - other = None - - def is_docx(self): - """ - Check if the union tag is ``docx``. - - :rtype: bool - """ - return self._tag == 'docx' - - def is_html(self): - """ - Check if the union tag is ``html``. - - :rtype: bool - """ - return self._tag == 'html' - - def is_markdown(self): - """ - Check if the union tag is ``markdown``. - - :rtype: bool - """ - return self._tag == 'markdown' - - def is_pdf(self): - """ - Check if the union tag is ``pdf``. - - :rtype: bool - """ - return self._tag == 'pdf' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperDownloadFormat, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PaperDownloadFormat(%r, %r)' % (self._tag, self._value) - -PaperDownloadFormat_validator = bv.Union(PaperDownloadFormat) - -class PaperEnabledUsersGroupAdditionDetails(bb.Struct): - """ - Added users to Paper-enabled users list. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperEnabledUsersGroupAdditionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PaperEnabledUsersGroupAdditionDetails()' - -PaperEnabledUsersGroupAdditionDetails_validator = bv.Struct(PaperEnabledUsersGroupAdditionDetails) +PasswordStrengthRequirementsChangePolicyDetails_validator = bv.Struct(PasswordStrengthRequirementsChangePolicyDetails) -class PaperEnabledUsersGroupAdditionType(bb.Struct): +class PasswordStrengthRequirementsChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -47602,139 +68105,163 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperEnabledUsersGroupAdditionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PasswordStrengthRequirementsChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperEnabledUsersGroupAdditionType(description={!r})'.format( + return 'PasswordStrengthRequirementsChangePolicyType(description={!r})'.format( self._description_value, ) -PaperEnabledUsersGroupAdditionType_validator = bv.Struct(PaperEnabledUsersGroupAdditionType) +PasswordStrengthRequirementsChangePolicyType_validator = bv.Struct(PasswordStrengthRequirementsChangePolicyType) -class PaperEnabledUsersGroupRemovalDetails(bb.Struct): +class PathLogInfo(bb.Struct): """ - Removed users from Paper-enabled users list. + Path's details. + + :ivar team_log.PathLogInfo.contextual: Fully qualified path relative to + event's context. Might be missing due to historical data gap. + :ivar team_log.PathLogInfo.namespace_relative: Path relative to the + namespace containing the content. """ __slots__ = [ + '_contextual_value', + '_contextual_present', + '_namespace_relative_value', + '_namespace_relative_present', ] - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperEnabledUsersGroupRemovalDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PaperEnabledUsersGroupRemovalDetails()' + _has_required_fields = True -PaperEnabledUsersGroupRemovalDetails_validator = bv.Struct(PaperEnabledUsersGroupRemovalDetails) + def __init__(self, + namespace_relative=None, + contextual=None): + self._contextual_value = None + self._contextual_present = False + self._namespace_relative_value = None + self._namespace_relative_present = False + if contextual is not None: + self.contextual = contextual + if namespace_relative is not None: + self.namespace_relative = namespace_relative -class PaperEnabledUsersGroupRemovalType(bb.Struct): + @property + def contextual(self): + """ + Fully qualified path relative to event's context. Might be missing due + to historical data gap. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: str + """ + if self._contextual_present: + return self._contextual_value + else: + return None - _has_required_fields = True + @contextual.setter + def contextual(self, val): + if val is None: + del self.contextual + return + val = self._contextual_validator.validate(val) + self._contextual_value = val + self._contextual_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @contextual.deleter + def contextual(self): + self._contextual_value = None + self._contextual_present = False @property - def description(self): + def namespace_relative(self): """ - :rtype: str + Path relative to the namespace containing the content. + + :rtype: NamespaceRelativePathLogInfo """ - if self._description_present: - return self._description_value + if self._namespace_relative_present: + return self._namespace_relative_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'namespace_relative'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @namespace_relative.setter + def namespace_relative(self, val): + self._namespace_relative_validator.validate_type_only(val) + self._namespace_relative_value = val + self._namespace_relative_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @namespace_relative.deleter + def namespace_relative(self): + self._namespace_relative_value = None + self._namespace_relative_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperEnabledUsersGroupRemovalType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PathLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperEnabledUsersGroupRemovalType(description={!r})'.format( - self._description_value, + return 'PathLogInfo(namespace_relative={!r}, contextual={!r})'.format( + self._namespace_relative_value, + self._contextual_value, ) -PaperEnabledUsersGroupRemovalType_validator = bv.Struct(PaperEnabledUsersGroupRemovalType) +PathLogInfo_validator = bv.Struct(PathLogInfo) -class PaperExternalViewAllowDetails(bb.Struct): +class PendingSecondaryEmailAddedDetails(bb.Struct): """ - Changed Paper external sharing setting to anyone. + Added pending secondary email. - :ivar team_log.PaperExternalViewAllowDetails.event_uuid: Event unique - identifier. + :ivar team_log.PendingSecondaryEmailAddedDetails.secondary_email: New + pending secondary email. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', + '_secondary_email_value', + '_secondary_email_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + secondary_email=None): + self._secondary_email_value = None + self._secondary_email_present = False + if secondary_email is not None: + self.secondary_email = secondary_email @property - def event_uuid(self): + def secondary_email(self): """ - Event unique identifier. + New pending secondary email. :rtype: str """ - if self._event_uuid_present: - return self._event_uuid_value + if self._secondary_email_present: + return self._secondary_email_value else: - raise AttributeError("missing required field 'event_uuid'") + raise AttributeError("missing required field 'secondary_email'") - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + @secondary_email.setter + def secondary_email(self, val): + val = self._secondary_email_validator.validate(val) + self._secondary_email_value = val + self._secondary_email_present = True - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + @secondary_email.deleter + def secondary_email(self): + self._secondary_email_value = None + self._secondary_email_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperExternalViewAllowDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PendingSecondaryEmailAddedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperExternalViewAllowDetails(event_uuid={!r})'.format( - self._event_uuid_value, + return 'PendingSecondaryEmailAddedDetails(secondary_email={!r})'.format( + self._secondary_email_value, ) -PaperExternalViewAllowDetails_validator = bv.Struct(PaperExternalViewAllowDetails) +PendingSecondaryEmailAddedDetails_validator = bv.Struct(PendingSecondaryEmailAddedDetails) -class PaperExternalViewAllowType(bb.Struct): +class PendingSecondaryEmailAddedType(bb.Struct): __slots__ = [ '_description_value', @@ -47772,71 +68299,109 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperExternalViewAllowType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PendingSecondaryEmailAddedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperExternalViewAllowType(description={!r})'.format( + return 'PendingSecondaryEmailAddedType(description={!r})'.format( self._description_value, ) -PaperExternalViewAllowType_validator = bv.Struct(PaperExternalViewAllowType) +PendingSecondaryEmailAddedType_validator = bv.Struct(PendingSecondaryEmailAddedType) -class PaperExternalViewDefaultTeamDetails(bb.Struct): +class PermanentDeleteChangePolicyDetails(bb.Struct): """ - Changed Paper external sharing setting to default team. + Enabled/disabled ability of team members to permanently delete content. - :ivar team_log.PaperExternalViewDefaultTeamDetails.event_uuid: Event unique - identifier. + :ivar team_log.PermanentDeleteChangePolicyDetails.new_value: New permanent + delete content policy. + :ivar team_log.PermanentDeleteChangePolicyDetails.previous_value: Previous + permanent delete content policy. Might be missing due to historical data + gap. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def event_uuid(self): + def new_value(self): """ - Event unique identifier. + New permanent delete content policy. - :rtype: str + :rtype: ContentPermanentDeletePolicy """ - if self._event_uuid_present: - return self._event_uuid_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'event_uuid'") + raise AttributeError("missing required field 'new_value'") - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous permanent delete content policy. Might be missing due to + historical data gap. + + :rtype: ContentPermanentDeletePolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperExternalViewDefaultTeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PermanentDeleteChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperExternalViewDefaultTeamDetails(event_uuid={!r})'.format( - self._event_uuid_value, + return 'PermanentDeleteChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -PaperExternalViewDefaultTeamDetails_validator = bv.Struct(PaperExternalViewDefaultTeamDetails) +PermanentDeleteChangePolicyDetails_validator = bv.Struct(PermanentDeleteChangePolicyDetails) -class PaperExternalViewDefaultTeamType(bb.Struct): +class PermanentDeleteChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -47874,637 +68439,787 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperExternalViewDefaultTeamType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PermanentDeleteChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperExternalViewDefaultTeamType(description={!r})'.format( + return 'PermanentDeleteChangePolicyType(description={!r})'.format( self._description_value, ) -PaperExternalViewDefaultTeamType_validator = bv.Struct(PaperExternalViewDefaultTeamType) +PermanentDeleteChangePolicyType_validator = bv.Struct(PermanentDeleteChangePolicyType) -class PaperExternalViewForbidDetails(bb.Struct): +class PlacementRestriction(bb.Union): """ - Changed Paper external sharing setting to team-only. - - :ivar team_log.PaperExternalViewForbidDetails.event_uuid: Event unique - identifier. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + australia_only = None + # Attribute is overwritten below the class definition + europe_only = None + # Attribute is overwritten below the class definition + japan_only = None + # Attribute is overwritten below the class definition + none = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_australia_only(self): + """ + Check if the union tag is ``australia_only``. - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + :rtype: bool + """ + return self._tag == 'australia_only' - @property - def event_uuid(self): + def is_europe_only(self): """ - Event unique identifier. + Check if the union tag is ``europe_only``. - :rtype: str + :rtype: bool """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") + return self._tag == 'europe_only' - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + def is_japan_only(self): + """ + Check if the union tag is ``japan_only``. - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + :rtype: bool + """ + return self._tag == 'japan_only' + + def is_none(self): + """ + Check if the union tag is ``none``. + + :rtype: bool + """ + return self._tag == 'none' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperExternalViewForbidDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PlacementRestriction, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperExternalViewForbidDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + return 'PlacementRestriction(%r, %r)' % (self._tag, self._value) -PaperExternalViewForbidDetails_validator = bv.Struct(PaperExternalViewForbidDetails) +PlacementRestriction_validator = bv.Union(PlacementRestriction) -class PaperExternalViewForbidType(bb.Struct): +class PrimaryTeamRequestAcceptedDetails(bb.Struct): + """ + Team merge request acceptance details shown to the primary team + + :ivar team_log.PrimaryTeamRequestAcceptedDetails.secondary_team: The + secondary team name. + :ivar team_log.PrimaryTeamRequestAcceptedDetails.sent_by: The name of the + secondary team admin who sent the request originally. + """ __slots__ = [ - '_description_value', - '_description_present', + '_secondary_team_value', + '_secondary_team_present', + '_sent_by_value', + '_sent_by_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + secondary_team=None, + sent_by=None): + self._secondary_team_value = None + self._secondary_team_present = False + self._sent_by_value = None + self._sent_by_present = False + if secondary_team is not None: + self.secondary_team = secondary_team + if sent_by is not None: + self.sent_by = sent_by @property - def description(self): + def secondary_team(self): """ + The secondary team name. + :rtype: str """ - if self._description_present: - return self._description_value + if self._secondary_team_present: + return self._secondary_team_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'secondary_team'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @secondary_team.setter + def secondary_team(self, val): + val = self._secondary_team_validator.validate(val) + self._secondary_team_value = val + self._secondary_team_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @secondary_team.deleter + def secondary_team(self): + self._secondary_team_value = None + self._secondary_team_present = False + + @property + def sent_by(self): + """ + The name of the secondary team admin who sent the request originally. + + :rtype: str + """ + if self._sent_by_present: + return self._sent_by_value + else: + raise AttributeError("missing required field 'sent_by'") + + @sent_by.setter + def sent_by(self, val): + val = self._sent_by_validator.validate(val) + self._sent_by_value = val + self._sent_by_present = True + + @sent_by.deleter + def sent_by(self): + self._sent_by_value = None + self._sent_by_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperExternalViewForbidType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PrimaryTeamRequestAcceptedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperExternalViewForbidType(description={!r})'.format( - self._description_value, + return 'PrimaryTeamRequestAcceptedDetails(secondary_team={!r}, sent_by={!r})'.format( + self._secondary_team_value, + self._sent_by_value, ) -PaperExternalViewForbidType_validator = bv.Struct(PaperExternalViewForbidType) +PrimaryTeamRequestAcceptedDetails_validator = bv.Struct(PrimaryTeamRequestAcceptedDetails) -class PaperFolderChangeSubscriptionDetails(bb.Struct): +class PrimaryTeamRequestCanceledDetails(bb.Struct): """ - Followed/unfollowed Paper folder. + Team merge request cancellation details shown to the primary team - :ivar team_log.PaperFolderChangeSubscriptionDetails.event_uuid: Event unique - identifier. - :ivar team_log.PaperFolderChangeSubscriptionDetails.new_subscription_level: - New folder subscription level. - :ivar - team_log.PaperFolderChangeSubscriptionDetails.previous_subscription_level: - Previous folder subscription level. Might be missing due to historical - data gap. + :ivar team_log.PrimaryTeamRequestCanceledDetails.secondary_team: The + secondary team name. + :ivar team_log.PrimaryTeamRequestCanceledDetails.sent_by: The name of the + secondary team admin who sent the request originally. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - '_new_subscription_level_value', - '_new_subscription_level_present', - '_previous_subscription_level_value', - '_previous_subscription_level_present', + '_secondary_team_value', + '_secondary_team_present', + '_sent_by_value', + '_sent_by_present', ] _has_required_fields = True def __init__(self, - event_uuid=None, - new_subscription_level=None, - previous_subscription_level=None): - self._event_uuid_value = None - self._event_uuid_present = False - self._new_subscription_level_value = None - self._new_subscription_level_present = False - self._previous_subscription_level_value = None - self._previous_subscription_level_present = False - if event_uuid is not None: - self.event_uuid = event_uuid - if new_subscription_level is not None: - self.new_subscription_level = new_subscription_level - if previous_subscription_level is not None: - self.previous_subscription_level = previous_subscription_level + secondary_team=None, + sent_by=None): + self._secondary_team_value = None + self._secondary_team_present = False + self._sent_by_value = None + self._sent_by_present = False + if secondary_team is not None: + self.secondary_team = secondary_team + if sent_by is not None: + self.sent_by = sent_by @property - def event_uuid(self): + def secondary_team(self): """ - Event unique identifier. + The secondary team name. :rtype: str """ - if self._event_uuid_present: - return self._event_uuid_value + if self._secondary_team_present: + return self._secondary_team_value else: - raise AttributeError("missing required field 'event_uuid'") + raise AttributeError("missing required field 'secondary_team'") - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + @secondary_team.setter + def secondary_team(self, val): + val = self._secondary_team_validator.validate(val) + self._secondary_team_value = val + self._secondary_team_present = True - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + @secondary_team.deleter + def secondary_team(self): + self._secondary_team_value = None + self._secondary_team_present = False @property - def new_subscription_level(self): + def sent_by(self): """ - New folder subscription level. + The name of the secondary team admin who sent the request originally. :rtype: str """ - if self._new_subscription_level_present: - return self._new_subscription_level_value + if self._sent_by_present: + return self._sent_by_value else: - raise AttributeError("missing required field 'new_subscription_level'") + raise AttributeError("missing required field 'sent_by'") - @new_subscription_level.setter - def new_subscription_level(self, val): - val = self._new_subscription_level_validator.validate(val) - self._new_subscription_level_value = val - self._new_subscription_level_present = True + @sent_by.setter + def sent_by(self, val): + val = self._sent_by_validator.validate(val) + self._sent_by_value = val + self._sent_by_present = True - @new_subscription_level.deleter - def new_subscription_level(self): - self._new_subscription_level_value = None - self._new_subscription_level_present = False + @sent_by.deleter + def sent_by(self): + self._sent_by_value = None + self._sent_by_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PrimaryTeamRequestCanceledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PrimaryTeamRequestCanceledDetails(secondary_team={!r}, sent_by={!r})'.format( + self._secondary_team_value, + self._sent_by_value, + ) + +PrimaryTeamRequestCanceledDetails_validator = bv.Struct(PrimaryTeamRequestCanceledDetails) + +class PrimaryTeamRequestExpiredDetails(bb.Struct): + """ + Team merge request expiration details shown to the primary team + + :ivar team_log.PrimaryTeamRequestExpiredDetails.secondary_team: The + secondary team name. + :ivar team_log.PrimaryTeamRequestExpiredDetails.sent_by: The name of the + secondary team admin who sent the request originally. + """ + + __slots__ = [ + '_secondary_team_value', + '_secondary_team_present', + '_sent_by_value', + '_sent_by_present', + ] + + _has_required_fields = True + + def __init__(self, + secondary_team=None, + sent_by=None): + self._secondary_team_value = None + self._secondary_team_present = False + self._sent_by_value = None + self._sent_by_present = False + if secondary_team is not None: + self.secondary_team = secondary_team + if sent_by is not None: + self.sent_by = sent_by @property - def previous_subscription_level(self): + def secondary_team(self): """ - Previous folder subscription level. Might be missing due to historical - data gap. + The secondary team name. :rtype: str """ - if self._previous_subscription_level_present: - return self._previous_subscription_level_value + if self._secondary_team_present: + return self._secondary_team_value else: - return None + raise AttributeError("missing required field 'secondary_team'") - @previous_subscription_level.setter - def previous_subscription_level(self, val): - if val is None: - del self.previous_subscription_level - return - val = self._previous_subscription_level_validator.validate(val) - self._previous_subscription_level_value = val - self._previous_subscription_level_present = True + @secondary_team.setter + def secondary_team(self, val): + val = self._secondary_team_validator.validate(val) + self._secondary_team_value = val + self._secondary_team_present = True - @previous_subscription_level.deleter - def previous_subscription_level(self): - self._previous_subscription_level_value = None - self._previous_subscription_level_present = False + @secondary_team.deleter + def secondary_team(self): + self._secondary_team_value = None + self._secondary_team_present = False + + @property + def sent_by(self): + """ + The name of the secondary team admin who sent the request originally. + + :rtype: str + """ + if self._sent_by_present: + return self._sent_by_value + else: + raise AttributeError("missing required field 'sent_by'") + + @sent_by.setter + def sent_by(self, val): + val = self._sent_by_validator.validate(val) + self._sent_by_value = val + self._sent_by_present = True + + @sent_by.deleter + def sent_by(self): + self._sent_by_value = None + self._sent_by_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderChangeSubscriptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PrimaryTeamRequestExpiredDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperFolderChangeSubscriptionDetails(event_uuid={!r}, new_subscription_level={!r}, previous_subscription_level={!r})'.format( - self._event_uuid_value, - self._new_subscription_level_value, - self._previous_subscription_level_value, + return 'PrimaryTeamRequestExpiredDetails(secondary_team={!r}, sent_by={!r})'.format( + self._secondary_team_value, + self._sent_by_value, ) -PaperFolderChangeSubscriptionDetails_validator = bv.Struct(PaperFolderChangeSubscriptionDetails) +PrimaryTeamRequestExpiredDetails_validator = bv.Struct(PrimaryTeamRequestExpiredDetails) -class PaperFolderChangeSubscriptionType(bb.Struct): +class PrimaryTeamRequestReminderDetails(bb.Struct): + """ + Team merge request reminder details shown to the primary team + + :ivar team_log.PrimaryTeamRequestReminderDetails.secondary_team: The + secondary team name. + :ivar team_log.PrimaryTeamRequestReminderDetails.sent_to: The name of the + primary team admin the request was sent to. + """ __slots__ = [ - '_description_value', - '_description_present', + '_secondary_team_value', + '_secondary_team_present', + '_sent_to_value', + '_sent_to_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + secondary_team=None, + sent_to=None): + self._secondary_team_value = None + self._secondary_team_present = False + self._sent_to_value = None + self._sent_to_present = False + if secondary_team is not None: + self.secondary_team = secondary_team + if sent_to is not None: + self.sent_to = sent_to @property - def description(self): + def secondary_team(self): """ + The secondary team name. + :rtype: str """ - if self._description_present: - return self._description_value + if self._secondary_team_present: + return self._secondary_team_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'secondary_team'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @secondary_team.setter + def secondary_team(self, val): + val = self._secondary_team_validator.validate(val) + self._secondary_team_value = val + self._secondary_team_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @secondary_team.deleter + def secondary_team(self): + self._secondary_team_value = None + self._secondary_team_present = False + + @property + def sent_to(self): + """ + The name of the primary team admin the request was sent to. + + :rtype: str + """ + if self._sent_to_present: + return self._sent_to_value + else: + raise AttributeError("missing required field 'sent_to'") + + @sent_to.setter + def sent_to(self, val): + val = self._sent_to_validator.validate(val) + self._sent_to_value = val + self._sent_to_present = True + + @sent_to.deleter + def sent_to(self): + self._sent_to_value = None + self._sent_to_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderChangeSubscriptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(PrimaryTeamRequestReminderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperFolderChangeSubscriptionType(description={!r})'.format( - self._description_value, + return 'PrimaryTeamRequestReminderDetails(secondary_team={!r}, sent_to={!r})'.format( + self._secondary_team_value, + self._sent_to_value, ) -PaperFolderChangeSubscriptionType_validator = bv.Struct(PaperFolderChangeSubscriptionType) - -class PaperFolderDeletedDetails(bb.Struct): - """ - Archived Paper folder. - - :ivar team_log.PaperFolderDeletedDetails.event_uuid: Event unique - identifier. - """ +PrimaryTeamRequestReminderDetails_validator = bv.Struct(PrimaryTeamRequestReminderDetails) - __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - ] +class QuickActionType(bb.Union): + """ + Quick action type. - _has_required_fields = True + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + _catch_all = 'other' + # Attribute is overwritten below the class definition + delete_shared_link = None + # Attribute is overwritten below the class definition + reset_password = None + # Attribute is overwritten below the class definition + restore_file_or_folder = None + # Attribute is overwritten below the class definition + unlink_app = None + # Attribute is overwritten below the class definition + unlink_device = None + # Attribute is overwritten below the class definition + unlink_session = None + # Attribute is overwritten below the class definition + other = None - @property - def event_uuid(self): + def is_delete_shared_link(self): """ - Event unique identifier. + Check if the union tag is ``delete_shared_link``. - :rtype: str + :rtype: bool """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") - - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + return self._tag == 'delete_shared_link' - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + def is_reset_password(self): + """ + Check if the union tag is ``reset_password``. - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderDeletedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + :rtype: bool + """ + return self._tag == 'reset_password' - def __repr__(self): - return 'PaperFolderDeletedDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + def is_restore_file_or_folder(self): + """ + Check if the union tag is ``restore_file_or_folder``. -PaperFolderDeletedDetails_validator = bv.Struct(PaperFolderDeletedDetails) + :rtype: bool + """ + return self._tag == 'restore_file_or_folder' -class PaperFolderDeletedType(bb.Struct): + def is_unlink_app(self): + """ + Check if the union tag is ``unlink_app``. - __slots__ = [ - '_description_value', - '_description_present', - ] + :rtype: bool + """ + return self._tag == 'unlink_app' - _has_required_fields = True + def is_unlink_device(self): + """ + Check if the union tag is ``unlink_device``. - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + :rtype: bool + """ + return self._tag == 'unlink_device' - @property - def description(self): + def is_unlink_session(self): """ - :rtype: str + Check if the union tag is ``unlink_session``. + + :rtype: bool """ - if self._description_present: - return self._description_value - else: - raise AttributeError("missing required field 'description'") + return self._tag == 'unlink_session' - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + def is_other(self): + """ + Check if the union tag is ``other``. - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + :rtype: bool + """ + return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderDeletedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(QuickActionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperFolderDeletedType(description={!r})'.format( - self._description_value, - ) + return 'QuickActionType(%r, %r)' % (self._tag, self._value) -PaperFolderDeletedType_validator = bv.Struct(PaperFolderDeletedType) +QuickActionType_validator = bv.Union(QuickActionType) -class PaperFolderFollowedDetails(bb.Struct): +class RelocateAssetReferencesLogInfo(bb.Struct): """ - Followed Paper folder. + Provides the indices of the source asset and the destination asset for a + relocate action. - :ivar team_log.PaperFolderFollowedDetails.event_uuid: Event unique - identifier. + :ivar team_log.RelocateAssetReferencesLogInfo.src_asset_index: Source asset + position in the Assets list. + :ivar team_log.RelocateAssetReferencesLogInfo.dest_asset_index: Destination + asset position in the Assets list. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', + '_src_asset_index_value', + '_src_asset_index_present', + '_dest_asset_index_value', + '_dest_asset_index_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + src_asset_index=None, + dest_asset_index=None): + self._src_asset_index_value = None + self._src_asset_index_present = False + self._dest_asset_index_value = None + self._dest_asset_index_present = False + if src_asset_index is not None: + self.src_asset_index = src_asset_index + if dest_asset_index is not None: + self.dest_asset_index = dest_asset_index @property - def event_uuid(self): + def src_asset_index(self): """ - Event unique identifier. + Source asset position in the Assets list. - :rtype: str + :rtype: int """ - if self._event_uuid_present: - return self._event_uuid_value + if self._src_asset_index_present: + return self._src_asset_index_value else: - raise AttributeError("missing required field 'event_uuid'") - - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True - - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderFollowedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PaperFolderFollowedDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) - -PaperFolderFollowedDetails_validator = bv.Struct(PaperFolderFollowedDetails) - -class PaperFolderFollowedType(bb.Struct): - - __slots__ = [ - '_description_value', - '_description_present', - ] + raise AttributeError("missing required field 'src_asset_index'") - _has_required_fields = True + @src_asset_index.setter + def src_asset_index(self, val): + val = self._src_asset_index_validator.validate(val) + self._src_asset_index_value = val + self._src_asset_index_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @src_asset_index.deleter + def src_asset_index(self): + self._src_asset_index_value = None + self._src_asset_index_present = False @property - def description(self): + def dest_asset_index(self): """ - :rtype: str + Destination asset position in the Assets list. + + :rtype: int """ - if self._description_present: - return self._description_value + if self._dest_asset_index_present: + return self._dest_asset_index_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'dest_asset_index'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @dest_asset_index.setter + def dest_asset_index(self, val): + val = self._dest_asset_index_validator.validate(val) + self._dest_asset_index_value = val + self._dest_asset_index_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @dest_asset_index.deleter + def dest_asset_index(self): + self._dest_asset_index_value = None + self._dest_asset_index_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderFollowedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RelocateAssetReferencesLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperFolderFollowedType(description={!r})'.format( - self._description_value, + return 'RelocateAssetReferencesLogInfo(src_asset_index={!r}, dest_asset_index={!r})'.format( + self._src_asset_index_value, + self._dest_asset_index_value, ) -PaperFolderFollowedType_validator = bv.Struct(PaperFolderFollowedType) +RelocateAssetReferencesLogInfo_validator = bv.Struct(RelocateAssetReferencesLogInfo) -class PaperFolderLogInfo(bb.Struct): +class ResellerLogInfo(bb.Struct): """ - Paper folder's logged information. + Reseller information. - :ivar team_log.PaperFolderLogInfo.folder_id: Papers folder Id. - :ivar team_log.PaperFolderLogInfo.folder_name: Paper folder name. + :ivar team_log.ResellerLogInfo.reseller_name: Reseller name. + :ivar team_log.ResellerLogInfo.reseller_email: Reseller email. """ __slots__ = [ - '_folder_id_value', - '_folder_id_present', - '_folder_name_value', - '_folder_name_present', + '_reseller_name_value', + '_reseller_name_present', + '_reseller_email_value', + '_reseller_email_present', ] _has_required_fields = True def __init__(self, - folder_id=None, - folder_name=None): - self._folder_id_value = None - self._folder_id_present = False - self._folder_name_value = None - self._folder_name_present = False - if folder_id is not None: - self.folder_id = folder_id - if folder_name is not None: - self.folder_name = folder_name + reseller_name=None, + reseller_email=None): + self._reseller_name_value = None + self._reseller_name_present = False + self._reseller_email_value = None + self._reseller_email_present = False + if reseller_name is not None: + self.reseller_name = reseller_name + if reseller_email is not None: + self.reseller_email = reseller_email @property - def folder_id(self): + def reseller_name(self): """ - Papers folder Id. + Reseller name. :rtype: str """ - if self._folder_id_present: - return self._folder_id_value + if self._reseller_name_present: + return self._reseller_name_value else: - raise AttributeError("missing required field 'folder_id'") + raise AttributeError("missing required field 'reseller_name'") - @folder_id.setter - def folder_id(self, val): - val = self._folder_id_validator.validate(val) - self._folder_id_value = val - self._folder_id_present = True + @reseller_name.setter + def reseller_name(self, val): + val = self._reseller_name_validator.validate(val) + self._reseller_name_value = val + self._reseller_name_present = True - @folder_id.deleter - def folder_id(self): - self._folder_id_value = None - self._folder_id_present = False + @reseller_name.deleter + def reseller_name(self): + self._reseller_name_value = None + self._reseller_name_present = False @property - def folder_name(self): + def reseller_email(self): """ - Paper folder name. + Reseller email. :rtype: str """ - if self._folder_name_present: - return self._folder_name_value + if self._reseller_email_present: + return self._reseller_email_value else: - raise AttributeError("missing required field 'folder_name'") + raise AttributeError("missing required field 'reseller_email'") - @folder_name.setter - def folder_name(self, val): - val = self._folder_name_validator.validate(val) - self._folder_name_value = val - self._folder_name_present = True + @reseller_email.setter + def reseller_email(self, val): + val = self._reseller_email_validator.validate(val) + self._reseller_email_value = val + self._reseller_email_present = True - @folder_name.deleter - def folder_name(self): - self._folder_name_value = None - self._folder_name_present = False + @reseller_email.deleter + def reseller_email(self): + self._reseller_email_value = None + self._reseller_email_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperFolderLogInfo(folder_id={!r}, folder_name={!r})'.format( - self._folder_id_value, - self._folder_name_value, + return 'ResellerLogInfo(reseller_name={!r}, reseller_email={!r})'.format( + self._reseller_name_value, + self._reseller_email_value, ) -PaperFolderLogInfo_validator = bv.Struct(PaperFolderLogInfo) +ResellerLogInfo_validator = bv.Struct(ResellerLogInfo) -class PaperFolderTeamInviteDetails(bb.Struct): +class ResellerSupportChangePolicyDetails(bb.Struct): """ - Shared Paper folder with member. + Enabled/disabled reseller support. - :ivar team_log.PaperFolderTeamInviteDetails.event_uuid: Event unique - identifier. + :ivar team_log.ResellerSupportChangePolicyDetails.new_value: New Reseller + support policy. + :ivar team_log.ResellerSupportChangePolicyDetails.previous_value: Previous + Reseller support policy. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def event_uuid(self): + def new_value(self): """ - Event unique identifier. + New Reseller support policy. - :rtype: str + :rtype: ResellerSupportPolicy """ - if self._event_uuid_present: - return self._event_uuid_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'event_uuid'") + raise AttributeError("missing required field 'new_value'") - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous Reseller support policy. + + :rtype: ResellerSupportPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderTeamInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerSupportChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperFolderTeamInviteDetails(event_uuid={!r})'.format( - self._event_uuid_value, + return 'ResellerSupportChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -PaperFolderTeamInviteDetails_validator = bv.Struct(PaperFolderTeamInviteDetails) +ResellerSupportChangePolicyDetails_validator = bv.Struct(ResellerSupportChangePolicyDetails) -class PaperFolderTeamInviteType(bb.Struct): +class ResellerSupportChangePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -48542,18 +69257,19 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperFolderTeamInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerSupportChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperFolderTeamInviteType(description={!r})'.format( + return 'ResellerSupportChangePolicyType(description={!r})'.format( self._description_value, ) -PaperFolderTeamInviteType_validator = bv.Struct(PaperFolderTeamInviteType) +ResellerSupportChangePolicyType_validator = bv.Struct(ResellerSupportChangePolicyType) -class PaperMemberPolicy(bb.Union): +class ResellerSupportPolicy(bb.Union): """ - Policy for controlling if team members can share Paper documents externally. + Policy for controlling if reseller can access the admin console as + administrator This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the @@ -48562,37 +69278,27 @@ class PaperMemberPolicy(bb.Union): _catch_all = 'other' # Attribute is overwritten below the class definition - anyone_with_link = None - # Attribute is overwritten below the class definition - only_team = None + disabled = None # Attribute is overwritten below the class definition - team_and_explicitly_shared = None + enabled = None # Attribute is overwritten below the class definition other = None - def is_anyone_with_link(self): - """ - Check if the union tag is ``anyone_with_link``. - - :rtype: bool - """ - return self._tag == 'anyone_with_link' - - def is_only_team(self): + def is_disabled(self): """ - Check if the union tag is ``only_team``. + Check if the union tag is ``disabled``. :rtype: bool """ - return self._tag == 'only_team' + return self._tag == 'disabled' - def is_team_and_explicitly_shared(self): + def is_enabled(self): """ - Check if the union tag is ``team_and_explicitly_shared``. + Check if the union tag is ``enabled``. :rtype: bool """ - return self._tag == 'team_and_explicitly_shared' + return self._tag == 'enabled' def is_other(self): """ @@ -48603,69 +69309,35 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperMemberPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerSupportPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperMemberPolicy(%r, %r)' % (self._tag, self._value) - -PaperMemberPolicy_validator = bv.Union(PaperMemberPolicy) - -class PaperPublishedLinkCreateDetails(bb.Struct): - """ - Published doc. - - :ivar team_log.PaperPublishedLinkCreateDetails.event_uuid: Event unique - identifier. - """ - - __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', - ] - - _has_required_fields = True + return 'ResellerSupportPolicy(%r, %r)' % (self._tag, self._value) - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid +ResellerSupportPolicy_validator = bv.Union(ResellerSupportPolicy) - @property - def event_uuid(self): - """ - Event unique identifier. +class ResellerSupportSessionEndDetails(bb.Struct): + """ + Ended reseller support session. + """ - :rtype: str - """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") + __slots__ = [ + ] - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + _has_required_fields = False - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperPublishedLinkCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerSupportSessionEndDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperPublishedLinkCreateDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + return 'ResellerSupportSessionEndDetails()' -PaperPublishedLinkCreateDetails_validator = bv.Struct(PaperPublishedLinkCreateDetails) +ResellerSupportSessionEndDetails_validator = bv.Struct(ResellerSupportSessionEndDetails) -class PaperPublishedLinkCreateType(bb.Struct): +class ResellerSupportSessionEndType(bb.Struct): __slots__ = [ '_description_value', @@ -48703,71 +69375,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperPublishedLinkCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerSupportSessionEndType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperPublishedLinkCreateType(description={!r})'.format( + return 'ResellerSupportSessionEndType(description={!r})'.format( self._description_value, ) -PaperPublishedLinkCreateType_validator = bv.Struct(PaperPublishedLinkCreateType) +ResellerSupportSessionEndType_validator = bv.Struct(ResellerSupportSessionEndType) -class PaperPublishedLinkDisabledDetails(bb.Struct): +class ResellerSupportSessionStartDetails(bb.Struct): """ - Unpublished doc. - - :ivar team_log.PaperPublishedLinkDisabledDetails.event_uuid: Event unique - identifier. + Started reseller support session. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', ] - _has_required_fields = True - - def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid - - @property - def event_uuid(self): - """ - Event unique identifier. - - :rtype: str - """ - if self._event_uuid_present: - return self._event_uuid_value - else: - raise AttributeError("missing required field 'event_uuid'") - - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + _has_required_fields = False - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperPublishedLinkDisabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerSupportSessionStartDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperPublishedLinkDisabledDetails(event_uuid={!r})'.format( - self._event_uuid_value, - ) + return 'ResellerSupportSessionStartDetails()' -PaperPublishedLinkDisabledDetails_validator = bv.Struct(PaperPublishedLinkDisabledDetails) +ResellerSupportSessionStartDetails_validator = bv.Struct(ResellerSupportSessionStartDetails) -class PaperPublishedLinkDisabledType(bb.Struct): +class ResellerSupportSessionStartType(bb.Struct): __slots__ = [ '_description_value', @@ -48805,71 +69443,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperPublishedLinkDisabledType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ResellerSupportSessionStartType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperPublishedLinkDisabledType(description={!r})'.format( + return 'ResellerSupportSessionStartType(description={!r})'.format( self._description_value, ) -PaperPublishedLinkDisabledType_validator = bv.Struct(PaperPublishedLinkDisabledType) +ResellerSupportSessionStartType_validator = bv.Struct(ResellerSupportSessionStartType) -class PaperPublishedLinkViewDetails(bb.Struct): +class RewindFolderDetails(bb.Struct): """ - Viewed published doc. + Rewound a folder. - :ivar team_log.PaperPublishedLinkViewDetails.event_uuid: Event unique - identifier. + :ivar team_log.RewindFolderDetails.rewind_folder_target_ts_ms: Folder was + Rewound to this date. """ __slots__ = [ - '_event_uuid_value', - '_event_uuid_present', + '_rewind_folder_target_ts_ms_value', + '_rewind_folder_target_ts_ms_present', ] _has_required_fields = True def __init__(self, - event_uuid=None): - self._event_uuid_value = None - self._event_uuid_present = False - if event_uuid is not None: - self.event_uuid = event_uuid + rewind_folder_target_ts_ms=None): + self._rewind_folder_target_ts_ms_value = None + self._rewind_folder_target_ts_ms_present = False + if rewind_folder_target_ts_ms is not None: + self.rewind_folder_target_ts_ms = rewind_folder_target_ts_ms @property - def event_uuid(self): + def rewind_folder_target_ts_ms(self): """ - Event unique identifier. + Folder was Rewound to this date. - :rtype: str + :rtype: datetime.datetime """ - if self._event_uuid_present: - return self._event_uuid_value + if self._rewind_folder_target_ts_ms_present: + return self._rewind_folder_target_ts_ms_value else: - raise AttributeError("missing required field 'event_uuid'") + raise AttributeError("missing required field 'rewind_folder_target_ts_ms'") - @event_uuid.setter - def event_uuid(self, val): - val = self._event_uuid_validator.validate(val) - self._event_uuid_value = val - self._event_uuid_present = True + @rewind_folder_target_ts_ms.setter + def rewind_folder_target_ts_ms(self, val): + val = self._rewind_folder_target_ts_ms_validator.validate(val) + self._rewind_folder_target_ts_ms_value = val + self._rewind_folder_target_ts_ms_present = True - @event_uuid.deleter - def event_uuid(self): - self._event_uuid_value = None - self._event_uuid_present = False + @rewind_folder_target_ts_ms.deleter + def rewind_folder_target_ts_ms(self): + self._rewind_folder_target_ts_ms_value = None + self._rewind_folder_target_ts_ms_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperPublishedLinkViewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RewindFolderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperPublishedLinkViewDetails(event_uuid={!r})'.format( - self._event_uuid_value, + return 'RewindFolderDetails(rewind_folder_target_ts_ms={!r})'.format( + self._rewind_folder_target_ts_ms_value, ) -PaperPublishedLinkViewDetails_validator = bv.Struct(PaperPublishedLinkViewDetails) +RewindFolderDetails_validator = bv.Struct(RewindFolderDetails) -class PaperPublishedLinkViewType(bb.Struct): +class RewindFolderType(bb.Struct): __slots__ = [ '_description_value', @@ -48907,68 +69545,47 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PaperPublishedLinkViewType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RewindFolderType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PaperPublishedLinkViewType(description={!r})'.format( + return 'RewindFolderType(description={!r})'.format( self._description_value, ) -PaperPublishedLinkViewType_validator = bv.Struct(PaperPublishedLinkViewType) +RewindFolderType_validator = bv.Struct(RewindFolderType) -class ParticipantLogInfo(bb.Union): +class RewindPolicy(bb.Union): """ - A user or group + Policy for controlling whether team members can rewind This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the corresponding ``get_*`` method. - - :ivar UserLogInfo ParticipantLogInfo.user: A user with a Dropbox account. - :ivar GroupLogInfo ParticipantLogInfo.group: Group details. """ _catch_all = 'other' # Attribute is overwritten below the class definition + admins_only = None + # Attribute is overwritten below the class definition + everyone = None + # Attribute is overwritten below the class definition other = None - @classmethod - def user(cls, val): - """ - Create an instance of this class set to the ``user`` tag with value - ``val``. - - :param UserLogInfo val: - :rtype: ParticipantLogInfo - """ - return cls('user', val) - - @classmethod - def group(cls, val): - """ - Create an instance of this class set to the ``group`` tag with value - ``val``. - - :param GroupLogInfo val: - :rtype: ParticipantLogInfo - """ - return cls('group', val) - - def is_user(self): + def is_admins_only(self): """ - Check if the union tag is ``user``. + Check if the union tag is ``admins_only``. :rtype: bool """ - return self._tag == 'user' + return self._tag == 'admins_only' - def is_group(self): + def is_everyone(self): """ - Check if the union tag is ``group``. + Check if the union tag is ``everyone``. :rtype: bool """ - return self._tag == 'group' + return self._tag == 'everyone' def is_other(self): """ @@ -48978,117 +69595,103 @@ def is_other(self): """ return self._tag == 'other' - def get_user(self): - """ - A user with a Dropbox account. - - Only call this if :meth:`is_user` is true. - - :rtype: UserLogInfo - """ - if not self.is_user(): - raise AttributeError("tag 'user' not set") - return self._value - - def get_group(self): - """ - Group details. - - Only call this if :meth:`is_group` is true. - - :rtype: GroupLogInfo - """ - if not self.is_group(): - raise AttributeError("tag 'group' not set") - return self._value - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ParticipantLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RewindPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ParticipantLogInfo(%r, %r)' % (self._tag, self._value) + return 'RewindPolicy(%r, %r)' % (self._tag, self._value) -ParticipantLogInfo_validator = bv.Union(ParticipantLogInfo) +RewindPolicy_validator = bv.Union(RewindPolicy) -class PassPolicy(bb.Union): +class RewindPolicyChangedDetails(bb.Struct): """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + Changed Rewind policy for team. + + :ivar team_log.RewindPolicyChangedDetails.new_value: New Dropbox Rewind + policy. + :ivar team_log.RewindPolicyChangedDetails.previous_value: Previous Dropbox + Rewind policy. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - allow = None - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - other = None + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] - def is_enabled(self): - """ - Check if the union tag is ``enabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'enabled' + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value - def is_allow(self): + @property + def new_value(self): """ - Check if the union tag is ``allow``. + New Dropbox Rewind policy. - :rtype: bool + :rtype: RewindPolicy """ - return self._tag == 'allow' + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") - def is_disabled(self): - """ - Check if the union tag is ``disabled``. + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - :rtype: bool - """ - return self._tag == 'disabled' + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False - def is_other(self): + @property + def previous_value(self): """ - Check if the union tag is ``other``. + Previous Dropbox Rewind policy. - :rtype: bool + :rtype: RewindPolicy """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PassPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PassPolicy(%r, %r)' % (self._tag, self._value) - -PassPolicy_validator = bv.Union(PassPolicy) - -class PasswordChangeDetails(bb.Struct): - """ - Changed password. - """ - - __slots__ = [ - ] + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") - _has_required_fields = False + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - def __init__(self): - pass + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PasswordChangeDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RewindPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PasswordChangeDetails()' + return 'RewindPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -PasswordChangeDetails_validator = bv.Struct(PasswordChangeDetails) +RewindPolicyChangedDetails_validator = bv.Struct(RewindPolicyChangedDetails) -class PasswordChangeType(bb.Struct): +class RewindPolicyChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -49126,105 +69729,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PasswordChangeType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(RewindPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PasswordChangeType(description={!r})'.format( + return 'RewindPolicyChangedType(description={!r})'.format( self._description_value, ) -PasswordChangeType_validator = bv.Struct(PasswordChangeType) +RewindPolicyChangedType_validator = bv.Struct(RewindPolicyChangedType) -class PasswordResetAllDetails(bb.Struct): - """ - Reset all team member passwords. +class SecondaryEmailDeletedDetails(bb.Struct): """ + Deleted secondary email. - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PasswordResetAllDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PasswordResetAllDetails()' - -PasswordResetAllDetails_validator = bv.Struct(PasswordResetAllDetails) - -class PasswordResetAllType(bb.Struct): + :ivar team_log.SecondaryEmailDeletedDetails.secondary_email: Deleted + secondary email. + """ __slots__ = [ - '_description_value', - '_description_present', + '_secondary_email_value', + '_secondary_email_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + secondary_email=None): + self._secondary_email_value = None + self._secondary_email_present = False + if secondary_email is not None: + self.secondary_email = secondary_email @property - def description(self): + def secondary_email(self): """ + Deleted secondary email. + :rtype: str """ - if self._description_present: - return self._description_value + if self._secondary_email_present: + return self._secondary_email_value else: - raise AttributeError("missing required field 'description'") + raise AttributeError("missing required field 'secondary_email'") - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @secondary_email.setter + def secondary_email(self, val): + val = self._secondary_email_validator.validate(val) + self._secondary_email_value = val + self._secondary_email_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @secondary_email.deleter + def secondary_email(self): + self._secondary_email_value = None + self._secondary_email_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PasswordResetAllType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryEmailDeletedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PasswordResetAllType(description={!r})'.format( - self._description_value, + return 'SecondaryEmailDeletedDetails(secondary_email={!r})'.format( + self._secondary_email_value, ) -PasswordResetAllType_validator = bv.Struct(PasswordResetAllType) - -class PasswordResetDetails(bb.Struct): - """ - Reset password. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PasswordResetDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PasswordResetDetails()' - -PasswordResetDetails_validator = bv.Struct(PasswordResetDetails) +SecondaryEmailDeletedDetails_validator = bv.Struct(SecondaryEmailDeletedDetails) -class PasswordResetType(bb.Struct): +class SecondaryEmailDeletedType(bb.Struct): __slots__ = [ '_description_value', @@ -49262,201 +69831,71 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PasswordResetType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PasswordResetType(description={!r})'.format( - self._description_value, - ) - -PasswordResetType_validator = bv.Struct(PasswordResetType) - -class PathLogInfo(bb.Struct): - """ - Path's details. - - :ivar team_log.PathLogInfo.contextual: Fully qualified path relative to - event's context. Might be missing due to historical data gap. - :ivar team_log.PathLogInfo.namespace_relative: Path relative to the - namespace containing the content. - """ - - __slots__ = [ - '_contextual_value', - '_contextual_present', - '_namespace_relative_value', - '_namespace_relative_present', - ] - - _has_required_fields = True - - def __init__(self, - namespace_relative=None, - contextual=None): - self._contextual_value = None - self._contextual_present = False - self._namespace_relative_value = None - self._namespace_relative_present = False - if contextual is not None: - self.contextual = contextual - if namespace_relative is not None: - self.namespace_relative = namespace_relative - - @property - def contextual(self): - """ - Fully qualified path relative to event's context. Might be missing due - to historical data gap. - - :rtype: str - """ - if self._contextual_present: - return self._contextual_value - else: - return None - - @contextual.setter - def contextual(self, val): - if val is None: - del self.contextual - return - val = self._contextual_validator.validate(val) - self._contextual_value = val - self._contextual_present = True - - @contextual.deleter - def contextual(self): - self._contextual_value = None - self._contextual_present = False - - @property - def namespace_relative(self): - """ - Path relative to the namespace containing the content. - - :rtype: NamespaceRelativePathLogInfo - """ - if self._namespace_relative_present: - return self._namespace_relative_value - else: - raise AttributeError("missing required field 'namespace_relative'") - - @namespace_relative.setter - def namespace_relative(self, val): - self._namespace_relative_validator.validate_type_only(val) - self._namespace_relative_value = val - self._namespace_relative_present = True - - @namespace_relative.deleter - def namespace_relative(self): - self._namespace_relative_value = None - self._namespace_relative_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PathLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PathLogInfo(namespace_relative={!r}, contextual={!r})'.format( - self._namespace_relative_value, - self._contextual_value, - ) - -PathLogInfo_validator = bv.Struct(PathLogInfo) - -class PermanentDeleteChangePolicyDetails(bb.Struct): - """ - Enabled/disabled ability of team members to permanently delete content. - - :ivar team_log.PermanentDeleteChangePolicyDetails.new_value: New permanent - delete content policy. - :ivar team_log.PermanentDeleteChangePolicyDetails.previous_value: Previous - permanent delete content policy. Might be missing due to historical data - gap. - """ - - __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', - ] - - _has_required_fields = True - - def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + super(SecondaryEmailDeletedType, self)._process_custom_annotations(annotation_type, field_path, processor) - @property - def new_value(self): - """ - New permanent delete content policy. + def __repr__(self): + return 'SecondaryEmailDeletedType(description={!r})'.format( + self._description_value, + ) - :rtype: ContentPermanentDeletePolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") +SecondaryEmailDeletedType_validator = bv.Struct(SecondaryEmailDeletedType) - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True +class SecondaryEmailVerifiedDetails(bb.Struct): + """ + Verified secondary email. - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + :ivar team_log.SecondaryEmailVerifiedDetails.secondary_email: Verified + secondary email. + """ + + __slots__ = [ + '_secondary_email_value', + '_secondary_email_present', + ] + + _has_required_fields = True + + def __init__(self, + secondary_email=None): + self._secondary_email_value = None + self._secondary_email_present = False + if secondary_email is not None: + self.secondary_email = secondary_email @property - def previous_value(self): + def secondary_email(self): """ - Previous permanent delete content policy. Might be missing due to - historical data gap. + Verified secondary email. - :rtype: ContentPermanentDeletePolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._secondary_email_present: + return self._secondary_email_value else: - return None + raise AttributeError("missing required field 'secondary_email'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @secondary_email.setter + def secondary_email(self, val): + val = self._secondary_email_validator.validate(val) + self._secondary_email_value = val + self._secondary_email_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @secondary_email.deleter + def secondary_email(self): + self._secondary_email_value = None + self._secondary_email_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PermanentDeleteChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryEmailVerifiedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PermanentDeleteChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'SecondaryEmailVerifiedDetails(secondary_email={!r})'.format( + self._secondary_email_value, ) -PermanentDeleteChangePolicyDetails_validator = bv.Struct(PermanentDeleteChangePolicyDetails) +SecondaryEmailVerifiedDetails_validator = bv.Struct(SecondaryEmailVerifiedDetails) -class PermanentDeleteChangePolicyType(bb.Struct): +class SecondaryEmailVerifiedType(bb.Struct): __slots__ = [ '_description_value', @@ -49494,16 +69933,16 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PermanentDeleteChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryEmailVerifiedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PermanentDeleteChangePolicyType(description={!r})'.format( + return 'SecondaryEmailVerifiedType(description={!r})'.format( self._description_value, ) -PermanentDeleteChangePolicyType_validator = bv.Struct(PermanentDeleteChangePolicyType) +SecondaryEmailVerifiedType_validator = bv.Struct(SecondaryEmailVerifiedType) -class PlacementRestriction(bb.Union): +class SecondaryMailsPolicy(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will return true. To get the associated value of a tag (if one exists), use the @@ -49512,47 +69951,27 @@ class PlacementRestriction(bb.Union): _catch_all = 'other' # Attribute is overwritten below the class definition - australia_only = None - # Attribute is overwritten below the class definition - europe_only = None - # Attribute is overwritten below the class definition - japan_only = None + disabled = None # Attribute is overwritten below the class definition - none = None + enabled = None # Attribute is overwritten below the class definition other = None - def is_australia_only(self): - """ - Check if the union tag is ``australia_only``. - - :rtype: bool - """ - return self._tag == 'australia_only' - - def is_europe_only(self): - """ - Check if the union tag is ``europe_only``. - - :rtype: bool - """ - return self._tag == 'europe_only' - - def is_japan_only(self): + def is_disabled(self): """ - Check if the union tag is ``japan_only``. + Check if the union tag is ``disabled``. :rtype: bool """ - return self._tag == 'japan_only' + return self._tag == 'disabled' - def is_none(self): + def is_enabled(self): """ - Check if the union tag is ``none``. + Check if the union tag is ``enabled``. :rtype: bool """ - return self._tag == 'none' + return self._tag == 'enabled' def is_other(self): """ @@ -49563,202 +69982,161 @@ def is_other(self): return self._tag == 'other' def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PlacementRestriction, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryMailsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PlacementRestriction(%r, %r)' % (self._tag, self._value) + return 'SecondaryMailsPolicy(%r, %r)' % (self._tag, self._value) -PlacementRestriction_validator = bv.Union(PlacementRestriction) +SecondaryMailsPolicy_validator = bv.Union(SecondaryMailsPolicy) -class PrimaryTeamRequestAcceptedDetails(bb.Struct): +class SecondaryMailsPolicyChangedDetails(bb.Struct): """ - Team merge request acceptance details shown to the primary team + Secondary mails policy changed. - :ivar team_log.PrimaryTeamRequestAcceptedDetails.secondary_team: The - secondary team name. - :ivar team_log.PrimaryTeamRequestAcceptedDetails.sent_by: The name of the - secondary team admin who sent the request originally. + :ivar team_log.SecondaryMailsPolicyChangedDetails.previous_value: Previous + secondary mails policy. + :ivar team_log.SecondaryMailsPolicyChangedDetails.new_value: New secondary + mails policy. """ __slots__ = [ - '_secondary_team_value', - '_secondary_team_present', - '_sent_by_value', - '_sent_by_present', + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', ] _has_required_fields = True def __init__(self, - secondary_team=None, - sent_by=None): - self._secondary_team_value = None - self._secondary_team_present = False - self._sent_by_value = None - self._sent_by_present = False - if secondary_team is not None: - self.secondary_team = secondary_team - if sent_by is not None: - self.sent_by = sent_by + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value @property - def secondary_team(self): + def previous_value(self): """ - The secondary team name. + Previous secondary mails policy. - :rtype: str + :rtype: SecondaryMailsPolicy """ - if self._secondary_team_present: - return self._secondary_team_value + if self._previous_value_present: + return self._previous_value_value else: - raise AttributeError("missing required field 'secondary_team'") + raise AttributeError("missing required field 'previous_value'") - @secondary_team.setter - def secondary_team(self, val): - val = self._secondary_team_validator.validate(val) - self._secondary_team_value = val - self._secondary_team_present = True + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @secondary_team.deleter - def secondary_team(self): - self._secondary_team_value = None - self._secondary_team_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False @property - def sent_by(self): + def new_value(self): """ - The name of the secondary team admin who sent the request originally. + New secondary mails policy. - :rtype: str + :rtype: SecondaryMailsPolicy """ - if self._sent_by_present: - return self._sent_by_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'sent_by'") + raise AttributeError("missing required field 'new_value'") - @sent_by.setter - def sent_by(self, val): - val = self._sent_by_validator.validate(val) - self._sent_by_value = val - self._sent_by_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @sent_by.deleter - def sent_by(self): - self._sent_by_value = None - self._sent_by_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PrimaryTeamRequestAcceptedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryMailsPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PrimaryTeamRequestAcceptedDetails(secondary_team={!r}, sent_by={!r})'.format( - self._secondary_team_value, - self._sent_by_value, + return 'SecondaryMailsPolicyChangedDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, ) -PrimaryTeamRequestAcceptedDetails_validator = bv.Struct(PrimaryTeamRequestAcceptedDetails) - -class PrimaryTeamRequestCanceledDetails(bb.Struct): - """ - Team merge request cancellation details shown to the primary team +SecondaryMailsPolicyChangedDetails_validator = bv.Struct(SecondaryMailsPolicyChangedDetails) - :ivar team_log.PrimaryTeamRequestCanceledDetails.secondary_team: The - secondary team name. - :ivar team_log.PrimaryTeamRequestCanceledDetails.sent_by: The name of the - secondary team admin who sent the request originally. - """ +class SecondaryMailsPolicyChangedType(bb.Struct): __slots__ = [ - '_secondary_team_value', - '_secondary_team_present', - '_sent_by_value', - '_sent_by_present', + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - secondary_team=None, - sent_by=None): - self._secondary_team_value = None - self._secondary_team_present = False - self._sent_by_value = None - self._sent_by_present = False - if secondary_team is not None: - self.secondary_team = secondary_team - if sent_by is not None: - self.sent_by = sent_by - - @property - def secondary_team(self): - """ - The secondary team name. - - :rtype: str - """ - if self._secondary_team_present: - return self._secondary_team_value - else: - raise AttributeError("missing required field 'secondary_team'") - - @secondary_team.setter - def secondary_team(self, val): - val = self._secondary_team_validator.validate(val) - self._secondary_team_value = val - self._secondary_team_present = True - - @secondary_team.deleter - def secondary_team(self): - self._secondary_team_value = None - self._secondary_team_present = False + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def sent_by(self): + def description(self): """ - The name of the secondary team admin who sent the request originally. - :rtype: str """ - if self._sent_by_present: - return self._sent_by_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'sent_by'") + raise AttributeError("missing required field 'description'") - @sent_by.setter - def sent_by(self, val): - val = self._sent_by_validator.validate(val) - self._sent_by_value = val - self._sent_by_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @sent_by.deleter - def sent_by(self): - self._sent_by_value = None - self._sent_by_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PrimaryTeamRequestCanceledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryMailsPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PrimaryTeamRequestCanceledDetails(secondary_team={!r}, sent_by={!r})'.format( - self._secondary_team_value, - self._sent_by_value, + return 'SecondaryMailsPolicyChangedType(description={!r})'.format( + self._description_value, ) -PrimaryTeamRequestCanceledDetails_validator = bv.Struct(PrimaryTeamRequestCanceledDetails) +SecondaryMailsPolicyChangedType_validator = bv.Struct(SecondaryMailsPolicyChangedType) -class PrimaryTeamRequestExpiredDetails(bb.Struct): +class SecondaryTeamRequestAcceptedDetails(bb.Struct): """ - Team merge request expiration details shown to the primary team + Team merge request acceptance details shown to the secondary team - :ivar team_log.PrimaryTeamRequestExpiredDetails.secondary_team: The - secondary team name. - :ivar team_log.PrimaryTeamRequestExpiredDetails.sent_by: The name of the + :ivar team_log.SecondaryTeamRequestAcceptedDetails.primary_team: The primary + team name. + :ivar team_log.SecondaryTeamRequestAcceptedDetails.sent_by: The name of the secondary team admin who sent the request originally. """ __slots__ = [ - '_secondary_team_value', - '_secondary_team_present', + '_primary_team_value', + '_primary_team_present', '_sent_by_value', '_sent_by_present', ] @@ -49766,39 +70144,39 @@ class PrimaryTeamRequestExpiredDetails(bb.Struct): _has_required_fields = True def __init__(self, - secondary_team=None, + primary_team=None, sent_by=None): - self._secondary_team_value = None - self._secondary_team_present = False + self._primary_team_value = None + self._primary_team_present = False self._sent_by_value = None self._sent_by_present = False - if secondary_team is not None: - self.secondary_team = secondary_team + if primary_team is not None: + self.primary_team = primary_team if sent_by is not None: self.sent_by = sent_by @property - def secondary_team(self): + def primary_team(self): """ - The secondary team name. + The primary team name. :rtype: str """ - if self._secondary_team_present: - return self._secondary_team_value + if self._primary_team_present: + return self._primary_team_value else: - raise AttributeError("missing required field 'secondary_team'") + raise AttributeError("missing required field 'primary_team'") - @secondary_team.setter - def secondary_team(self, val): - val = self._secondary_team_validator.validate(val) - self._secondary_team_value = val - self._secondary_team_present = True + @primary_team.setter + def primary_team(self, val): + val = self._primary_team_validator.validate(val) + self._primary_team_value = val + self._primary_team_present = True - @secondary_team.deleter - def secondary_team(self): - self._secondary_team_value = None - self._secondary_team_present = False + @primary_team.deleter + def primary_team(self): + self._primary_team_value = None + self._primary_team_present = False @property def sent_by(self): @@ -49824,74 +70202,51 @@ def sent_by(self): self._sent_by_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PrimaryTeamRequestExpiredDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryTeamRequestAcceptedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'PrimaryTeamRequestExpiredDetails(secondary_team={!r}, sent_by={!r})'.format( - self._secondary_team_value, + return 'SecondaryTeamRequestAcceptedDetails(primary_team={!r}, sent_by={!r})'.format( + self._primary_team_value, self._sent_by_value, ) -PrimaryTeamRequestExpiredDetails_validator = bv.Struct(PrimaryTeamRequestExpiredDetails) +SecondaryTeamRequestAcceptedDetails_validator = bv.Struct(SecondaryTeamRequestAcceptedDetails) -class PrimaryTeamRequestReminderDetails(bb.Struct): +class SecondaryTeamRequestCanceledDetails(bb.Struct): """ - Team merge request reminder details shown to the primary team + Team merge request cancellation details shown to the secondary team - :ivar team_log.PrimaryTeamRequestReminderDetails.secondary_team: The - secondary team name. - :ivar team_log.PrimaryTeamRequestReminderDetails.sent_to: The name of the - primary team admin the request was sent to. + :ivar team_log.SecondaryTeamRequestCanceledDetails.sent_to: The email of the + primary team admin that the request was sent to. + :ivar team_log.SecondaryTeamRequestCanceledDetails.sent_by: The name of the + secondary team admin who sent the request originally. """ __slots__ = [ - '_secondary_team_value', - '_secondary_team_present', '_sent_to_value', '_sent_to_present', + '_sent_by_value', + '_sent_by_present', ] _has_required_fields = True def __init__(self, - secondary_team=None, - sent_to=None): - self._secondary_team_value = None - self._secondary_team_present = False + sent_to=None, + sent_by=None): self._sent_to_value = None self._sent_to_present = False - if secondary_team is not None: - self.secondary_team = secondary_team + self._sent_by_value = None + self._sent_by_present = False if sent_to is not None: self.sent_to = sent_to - - @property - def secondary_team(self): - """ - The secondary team name. - - :rtype: str - """ - if self._secondary_team_present: - return self._secondary_team_value - else: - raise AttributeError("missing required field 'secondary_team'") - - @secondary_team.setter - def secondary_team(self, val): - val = self._secondary_team_validator.validate(val) - self._secondary_team_value = val - self._secondary_team_present = True - - @secondary_team.deleter - def secondary_team(self): - self._secondary_team_value = None - self._secondary_team_present = False + if sent_by is not None: + self.sent_by = sent_by @property def sent_to(self): """ - The name of the primary team admin the request was sent to. + The email of the primary team admin that the request was sent to. :rtype: str """ @@ -49911,360 +70266,307 @@ def sent_to(self): self._sent_to_value = None self._sent_to_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(PrimaryTeamRequestReminderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'PrimaryTeamRequestReminderDetails(secondary_team={!r}, sent_to={!r})'.format( - self._secondary_team_value, - self._sent_to_value, - ) - -PrimaryTeamRequestReminderDetails_validator = bv.Struct(PrimaryTeamRequestReminderDetails) - -class QuickActionType(bb.Union): - """ - Quick action type. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - delete_shared_link = None - # Attribute is overwritten below the class definition - reset_password = None - # Attribute is overwritten below the class definition - restore_file_or_folder = None - # Attribute is overwritten below the class definition - unlink_app = None - # Attribute is overwritten below the class definition - unlink_session = None - # Attribute is overwritten below the class definition - other = None - - def is_delete_shared_link(self): - """ - Check if the union tag is ``delete_shared_link``. - - :rtype: bool - """ - return self._tag == 'delete_shared_link' - - def is_reset_password(self): - """ - Check if the union tag is ``reset_password``. - - :rtype: bool - """ - return self._tag == 'reset_password' - - def is_restore_file_or_folder(self): - """ - Check if the union tag is ``restore_file_or_folder``. - - :rtype: bool - """ - return self._tag == 'restore_file_or_folder' - - def is_unlink_app(self): - """ - Check if the union tag is ``unlink_app``. - - :rtype: bool - """ - return self._tag == 'unlink_app' - - def is_unlink_session(self): + @property + def sent_by(self): """ - Check if the union tag is ``unlink_session``. + The name of the secondary team admin who sent the request originally. - :rtype: bool + :rtype: str """ - return self._tag == 'unlink_session' + if self._sent_by_present: + return self._sent_by_value + else: + raise AttributeError("missing required field 'sent_by'") - def is_other(self): - """ - Check if the union tag is ``other``. + @sent_by.setter + def sent_by(self, val): + val = self._sent_by_validator.validate(val) + self._sent_by_value = val + self._sent_by_present = True - :rtype: bool - """ - return self._tag == 'other' + @sent_by.deleter + def sent_by(self): + self._sent_by_value = None + self._sent_by_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(QuickActionType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryTeamRequestCanceledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'QuickActionType(%r, %r)' % (self._tag, self._value) + return 'SecondaryTeamRequestCanceledDetails(sent_to={!r}, sent_by={!r})'.format( + self._sent_to_value, + self._sent_by_value, + ) -QuickActionType_validator = bv.Union(QuickActionType) +SecondaryTeamRequestCanceledDetails_validator = bv.Struct(SecondaryTeamRequestCanceledDetails) -class RelocateAssetReferencesLogInfo(bb.Struct): +class SecondaryTeamRequestExpiredDetails(bb.Struct): """ - Provides the indices of the source asset and the destination asset for a - relocate action. + Team merge request expiration details shown to the secondary team - :ivar team_log.RelocateAssetReferencesLogInfo.src_asset_index: Source asset - position in the Assets list. - :ivar team_log.RelocateAssetReferencesLogInfo.dest_asset_index: Destination - asset position in the Assets list. + :ivar team_log.SecondaryTeamRequestExpiredDetails.sent_to: The email of the + primary team admin the request was sent to. """ __slots__ = [ - '_src_asset_index_value', - '_src_asset_index_present', - '_dest_asset_index_value', - '_dest_asset_index_present', + '_sent_to_value', + '_sent_to_present', ] _has_required_fields = True def __init__(self, - src_asset_index=None, - dest_asset_index=None): - self._src_asset_index_value = None - self._src_asset_index_present = False - self._dest_asset_index_value = None - self._dest_asset_index_present = False - if src_asset_index is not None: - self.src_asset_index = src_asset_index - if dest_asset_index is not None: - self.dest_asset_index = dest_asset_index - - @property - def src_asset_index(self): - """ - Source asset position in the Assets list. - - :rtype: int - """ - if self._src_asset_index_present: - return self._src_asset_index_value - else: - raise AttributeError("missing required field 'src_asset_index'") - - @src_asset_index.setter - def src_asset_index(self, val): - val = self._src_asset_index_validator.validate(val) - self._src_asset_index_value = val - self._src_asset_index_present = True - - @src_asset_index.deleter - def src_asset_index(self): - self._src_asset_index_value = None - self._src_asset_index_present = False + sent_to=None): + self._sent_to_value = None + self._sent_to_present = False + if sent_to is not None: + self.sent_to = sent_to @property - def dest_asset_index(self): + def sent_to(self): """ - Destination asset position in the Assets list. + The email of the primary team admin the request was sent to. - :rtype: int + :rtype: str """ - if self._dest_asset_index_present: - return self._dest_asset_index_value + if self._sent_to_present: + return self._sent_to_value else: - raise AttributeError("missing required field 'dest_asset_index'") + raise AttributeError("missing required field 'sent_to'") - @dest_asset_index.setter - def dest_asset_index(self, val): - val = self._dest_asset_index_validator.validate(val) - self._dest_asset_index_value = val - self._dest_asset_index_present = True + @sent_to.setter + def sent_to(self, val): + val = self._sent_to_validator.validate(val) + self._sent_to_value = val + self._sent_to_present = True - @dest_asset_index.deleter - def dest_asset_index(self): - self._dest_asset_index_value = None - self._dest_asset_index_present = False + @sent_to.deleter + def sent_to(self): + self._sent_to_value = None + self._sent_to_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(RelocateAssetReferencesLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryTeamRequestExpiredDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'RelocateAssetReferencesLogInfo(src_asset_index={!r}, dest_asset_index={!r})'.format( - self._src_asset_index_value, - self._dest_asset_index_value, + return 'SecondaryTeamRequestExpiredDetails(sent_to={!r})'.format( + self._sent_to_value, ) -RelocateAssetReferencesLogInfo_validator = bv.Struct(RelocateAssetReferencesLogInfo) +SecondaryTeamRequestExpiredDetails_validator = bv.Struct(SecondaryTeamRequestExpiredDetails) -class ResellerLogInfo(bb.Struct): +class SecondaryTeamRequestReminderDetails(bb.Struct): """ - Reseller information. + Team merge request reminder details shown to the secondary team - :ivar team_log.ResellerLogInfo.reseller_name: Reseller name. - :ivar team_log.ResellerLogInfo.reseller_email: Reseller email. + :ivar team_log.SecondaryTeamRequestReminderDetails.sent_to: The email of the + primary team admin the request was sent to. """ __slots__ = [ - '_reseller_name_value', - '_reseller_name_present', - '_reseller_email_value', - '_reseller_email_present', + '_sent_to_value', + '_sent_to_present', ] _has_required_fields = True def __init__(self, - reseller_name=None, - reseller_email=None): - self._reseller_name_value = None - self._reseller_name_present = False - self._reseller_email_value = None - self._reseller_email_present = False - if reseller_name is not None: - self.reseller_name = reseller_name - if reseller_email is not None: - self.reseller_email = reseller_email - - @property - def reseller_name(self): - """ - Reseller name. - - :rtype: str - """ - if self._reseller_name_present: - return self._reseller_name_value - else: - raise AttributeError("missing required field 'reseller_name'") - - @reseller_name.setter - def reseller_name(self, val): - val = self._reseller_name_validator.validate(val) - self._reseller_name_value = val - self._reseller_name_present = True - - @reseller_name.deleter - def reseller_name(self): - self._reseller_name_value = None - self._reseller_name_present = False + sent_to=None): + self._sent_to_value = None + self._sent_to_present = False + if sent_to is not None: + self.sent_to = sent_to @property - def reseller_email(self): + def sent_to(self): """ - Reseller email. + The email of the primary team admin the request was sent to. :rtype: str """ - if self._reseller_email_present: - return self._reseller_email_value + if self._sent_to_present: + return self._sent_to_value else: - raise AttributeError("missing required field 'reseller_email'") + raise AttributeError("missing required field 'sent_to'") - @reseller_email.setter - def reseller_email(self, val): - val = self._reseller_email_validator.validate(val) - self._reseller_email_value = val - self._reseller_email_present = True + @sent_to.setter + def sent_to(self, val): + val = self._sent_to_validator.validate(val) + self._sent_to_value = val + self._sent_to_present = True - @reseller_email.deleter - def reseller_email(self): - self._reseller_email_value = None - self._reseller_email_present = False + @sent_to.deleter + def sent_to(self): + self._sent_to_value = None + self._sent_to_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SecondaryTeamRequestReminderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ResellerLogInfo(reseller_name={!r}, reseller_email={!r})'.format( - self._reseller_name_value, - self._reseller_email_value, + return 'SecondaryTeamRequestReminderDetails(sent_to={!r})'.format( + self._sent_to_value, ) -ResellerLogInfo_validator = bv.Struct(ResellerLogInfo) +SecondaryTeamRequestReminderDetails_validator = bv.Struct(SecondaryTeamRequestReminderDetails) -class ResellerSupportChangePolicyDetails(bb.Struct): +class SfAddGroupDetails(bb.Struct): """ - Enabled/disabled reseller support. + Added team to shared folder. - :ivar team_log.ResellerSupportChangePolicyDetails.new_value: New Reseller - support policy. - :ivar team_log.ResellerSupportChangePolicyDetails.previous_value: Previous - Reseller support policy. + :ivar team_log.SfAddGroupDetails.target_asset_index: Target asset position + in the Assets list. + :ivar team_log.SfAddGroupDetails.original_folder_name: Original shared + folder name. + :ivar team_log.SfAddGroupDetails.sharing_permission: Sharing permission. + Might be missing due to historical data gap. + :ivar team_log.SfAddGroupDetails.team_name: Team name. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_target_asset_index_value', + '_target_asset_index_present', + '_original_folder_name_value', + '_original_folder_name_present', + '_sharing_permission_value', + '_sharing_permission_present', + '_team_name_value', + '_team_name_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + target_asset_index=None, + original_folder_name=None, + team_name=None, + sharing_permission=None): + self._target_asset_index_value = None + self._target_asset_index_present = False + self._original_folder_name_value = None + self._original_folder_name_present = False + self._sharing_permission_value = None + self._sharing_permission_present = False + self._team_name_value = None + self._team_name_present = False + if target_asset_index is not None: + self.target_asset_index = target_asset_index + if original_folder_name is not None: + self.original_folder_name = original_folder_name + if sharing_permission is not None: + self.sharing_permission = sharing_permission + if team_name is not None: + self.team_name = team_name @property - def new_value(self): + def target_asset_index(self): """ - New Reseller support policy. + Target asset position in the Assets list. - :rtype: ResellerSupportPolicy + :rtype: int """ - if self._new_value_present: - return self._new_value_value + if self._target_asset_index_present: + return self._target_asset_index_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'target_asset_index'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @target_asset_index.setter + def target_asset_index(self, val): + val = self._target_asset_index_validator.validate(val) + self._target_asset_index_value = val + self._target_asset_index_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @target_asset_index.deleter + def target_asset_index(self): + self._target_asset_index_value = None + self._target_asset_index_present = False @property - def previous_value(self): + def original_folder_name(self): """ - Previous Reseller support policy. + Original shared folder name. - :rtype: ResellerSupportPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._original_folder_name_present: + return self._original_folder_name_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'original_folder_name'") - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @original_folder_name.setter + def original_folder_name(self, val): + val = self._original_folder_name_validator.validate(val) + self._original_folder_name_value = val + self._original_folder_name_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @original_folder_name.deleter + def original_folder_name(self): + self._original_folder_name_value = None + self._original_folder_name_present = False + + @property + def sharing_permission(self): + """ + Sharing permission. Might be missing due to historical data gap. + + :rtype: str + """ + if self._sharing_permission_present: + return self._sharing_permission_value + else: + return None + + @sharing_permission.setter + def sharing_permission(self, val): + if val is None: + del self.sharing_permission + return + val = self._sharing_permission_validator.validate(val) + self._sharing_permission_value = val + self._sharing_permission_present = True + + @sharing_permission.deleter + def sharing_permission(self): + self._sharing_permission_value = None + self._sharing_permission_present = False + + @property + def team_name(self): + """ + Team name. + + :rtype: str + """ + if self._team_name_present: + return self._team_name_value + else: + raise AttributeError("missing required field 'team_name'") + + @team_name.setter + def team_name(self, val): + val = self._team_name_validator.validate(val) + self._team_name_value = val + self._team_name_present = True + + @team_name.deleter + def team_name(self): + self._team_name_value = None + self._team_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerSupportChangePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfAddGroupDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ResellerSupportChangePolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'SfAddGroupDetails(target_asset_index={!r}, original_folder_name={!r}, team_name={!r}, sharing_permission={!r})'.format( + self._target_asset_index_value, + self._original_folder_name_value, + self._team_name_value, + self._sharing_permission_value, ) -ResellerSupportChangePolicyDetails_validator = bv.Struct(ResellerSupportChangePolicyDetails) +SfAddGroupDetails_validator = bv.Struct(SfAddGroupDetails) -class ResellerSupportChangePolicyType(bb.Struct): +class SfAddGroupType(bb.Struct): __slots__ = [ '_description_value', @@ -50302,155 +70604,141 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerSupportChangePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfAddGroupType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ResellerSupportChangePolicyType(description={!r})'.format( + return 'SfAddGroupType(description={!r})'.format( self._description_value, ) -ResellerSupportChangePolicyType_validator = bv.Struct(ResellerSupportChangePolicyType) - -class ResellerSupportPolicy(bb.Union): - """ - Policy for controlling if reseller can access the admin console as - administrator +SfAddGroupType_validator = bv.Struct(SfAddGroupType) - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. +class SfAllowNonMembersToViewSharedLinksDetails(bb.Struct): """ + Allowed non-collaborators to view links to files in shared folder. - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None - - def is_disabled(self): - """ - Check if the union tag is ``disabled``. - - :rtype: bool - """ - return self._tag == 'disabled' - - def is_enabled(self): - """ - Check if the union tag is ``enabled``. - - :rtype: bool - """ - return self._tag == 'enabled' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerSupportPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ResellerSupportPolicy(%r, %r)' % (self._tag, self._value) - -ResellerSupportPolicy_validator = bv.Union(ResellerSupportPolicy) - -class ResellerSupportSessionEndDetails(bb.Struct): - """ - Ended reseller support session. + :ivar team_log.SfAllowNonMembersToViewSharedLinksDetails.target_asset_index: + Target asset position in the Assets list. + :ivar + team_log.SfAllowNonMembersToViewSharedLinksDetails.original_folder_name: + Original shared folder name. + :ivar team_log.SfAllowNonMembersToViewSharedLinksDetails.shared_folder_type: + Shared folder type. Might be missing due to historical data gap. """ __slots__ = [ + '_target_asset_index_value', + '_target_asset_index_present', + '_original_folder_name_value', + '_original_folder_name_present', + '_shared_folder_type_value', + '_shared_folder_type_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + target_asset_index=None, + original_folder_name=None, + shared_folder_type=None): + self._target_asset_index_value = None + self._target_asset_index_present = False + self._original_folder_name_value = None + self._original_folder_name_present = False + self._shared_folder_type_value = None + self._shared_folder_type_present = False + if target_asset_index is not None: + self.target_asset_index = target_asset_index + if original_folder_name is not None: + self.original_folder_name = original_folder_name + if shared_folder_type is not None: + self.shared_folder_type = shared_folder_type - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerSupportSessionEndDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + @property + def target_asset_index(self): + """ + Target asset position in the Assets list. - def __repr__(self): - return 'ResellerSupportSessionEndDetails()' + :rtype: int + """ + if self._target_asset_index_present: + return self._target_asset_index_value + else: + raise AttributeError("missing required field 'target_asset_index'") -ResellerSupportSessionEndDetails_validator = bv.Struct(ResellerSupportSessionEndDetails) + @target_asset_index.setter + def target_asset_index(self, val): + val = self._target_asset_index_validator.validate(val) + self._target_asset_index_value = val + self._target_asset_index_present = True -class ResellerSupportSessionEndType(bb.Struct): + @target_asset_index.deleter + def target_asset_index(self): + self._target_asset_index_value = None + self._target_asset_index_present = False - __slots__ = [ - '_description_value', - '_description_present', - ] + @property + def original_folder_name(self): + """ + Original shared folder name. - _has_required_fields = True + :rtype: str + """ + if self._original_folder_name_present: + return self._original_folder_name_value + else: + raise AttributeError("missing required field 'original_folder_name'") - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @original_folder_name.setter + def original_folder_name(self, val): + val = self._original_folder_name_validator.validate(val) + self._original_folder_name_value = val + self._original_folder_name_present = True + + @original_folder_name.deleter + def original_folder_name(self): + self._original_folder_name_value = None + self._original_folder_name_present = False @property - def description(self): + def shared_folder_type(self): """ + Shared folder type. Might be missing due to historical data gap. + :rtype: str """ - if self._description_present: - return self._description_value + if self._shared_folder_type_present: + return self._shared_folder_type_value else: - raise AttributeError("missing required field 'description'") + return None - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True + @shared_folder_type.setter + def shared_folder_type(self, val): + if val is None: + del self.shared_folder_type + return + val = self._shared_folder_type_validator.validate(val) + self._shared_folder_type_value = val + self._shared_folder_type_present = True - @description.deleter - def description(self): - self._description_value = None - self._description_present = False + @shared_folder_type.deleter + def shared_folder_type(self): + self._shared_folder_type_value = None + self._shared_folder_type_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerSupportSessionEndType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfAllowNonMembersToViewSharedLinksDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ResellerSupportSessionEndType(description={!r})'.format( - self._description_value, + return 'SfAllowNonMembersToViewSharedLinksDetails(target_asset_index={!r}, original_folder_name={!r}, shared_folder_type={!r})'.format( + self._target_asset_index_value, + self._original_folder_name_value, + self._shared_folder_type_value, ) -ResellerSupportSessionEndType_validator = bv.Struct(ResellerSupportSessionEndType) - -class ResellerSupportSessionStartDetails(bb.Struct): - """ - Started reseller support session. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self): - pass - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerSupportSessionStartDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'ResellerSupportSessionStartDetails()' - -ResellerSupportSessionStartDetails_validator = bv.Struct(ResellerSupportSessionStartDetails) +SfAllowNonMembersToViewSharedLinksDetails_validator = bv.Struct(SfAllowNonMembersToViewSharedLinksDetails) -class ResellerSupportSessionStartType(bb.Struct): +class SfAllowNonMembersToViewSharedLinksType(bb.Struct): __slots__ = [ '_description_value', @@ -50488,151 +70776,178 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ResellerSupportSessionStartType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfAllowNonMembersToViewSharedLinksType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ResellerSupportSessionStartType(description={!r})'.format( + return 'SfAllowNonMembersToViewSharedLinksType(description={!r})'.format( self._description_value, ) -ResellerSupportSessionStartType_validator = bv.Struct(ResellerSupportSessionStartType) +SfAllowNonMembersToViewSharedLinksType_validator = bv.Struct(SfAllowNonMembersToViewSharedLinksType) -class SecondaryMailsPolicy(bb.Union): - """ - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. +class SfExternalInviteWarnDetails(bb.Struct): """ + Set team members to see warning before sharing folders outside team. - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None - - def is_disabled(self): - """ - Check if the union tag is ``disabled``. + :ivar team_log.SfExternalInviteWarnDetails.target_asset_index: Target asset + position in the Assets list. + :ivar team_log.SfExternalInviteWarnDetails.original_folder_name: Original + shared folder name. + :ivar team_log.SfExternalInviteWarnDetails.new_sharing_permission: New + sharing permission. Might be missing due to historical data gap. + :ivar team_log.SfExternalInviteWarnDetails.previous_sharing_permission: + Previous sharing permission. Might be missing due to historical data + gap. + """ - :rtype: bool - """ - return self._tag == 'disabled' + __slots__ = [ + '_target_asset_index_value', + '_target_asset_index_present', + '_original_folder_name_value', + '_original_folder_name_present', + '_new_sharing_permission_value', + '_new_sharing_permission_present', + '_previous_sharing_permission_value', + '_previous_sharing_permission_present', + ] - def is_enabled(self): - """ - Check if the union tag is ``enabled``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'enabled' + def __init__(self, + target_asset_index=None, + original_folder_name=None, + new_sharing_permission=None, + previous_sharing_permission=None): + self._target_asset_index_value = None + self._target_asset_index_present = False + self._original_folder_name_value = None + self._original_folder_name_present = False + self._new_sharing_permission_value = None + self._new_sharing_permission_present = False + self._previous_sharing_permission_value = None + self._previous_sharing_permission_present = False + if target_asset_index is not None: + self.target_asset_index = target_asset_index + if original_folder_name is not None: + self.original_folder_name = original_folder_name + if new_sharing_permission is not None: + self.new_sharing_permission = new_sharing_permission + if previous_sharing_permission is not None: + self.previous_sharing_permission = previous_sharing_permission - def is_other(self): + @property + def target_asset_index(self): """ - Check if the union tag is ``other``. + Target asset position in the Assets list. - :rtype: bool + :rtype: int """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SecondaryMailsPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SecondaryMailsPolicy(%r, %r)' % (self._tag, self._value) + if self._target_asset_index_present: + return self._target_asset_index_value + else: + raise AttributeError("missing required field 'target_asset_index'") -SecondaryMailsPolicy_validator = bv.Union(SecondaryMailsPolicy) + @target_asset_index.setter + def target_asset_index(self, val): + val = self._target_asset_index_validator.validate(val) + self._target_asset_index_value = val + self._target_asset_index_present = True -class SecondaryMailsPolicyChangedDetails(bb.Struct): - """ - Secondary mails policy changed. + @target_asset_index.deleter + def target_asset_index(self): + self._target_asset_index_value = None + self._target_asset_index_present = False - :ivar team_log.SecondaryMailsPolicyChangedDetails.previous_value: Previous - secondary mails policy. - :ivar team_log.SecondaryMailsPolicyChangedDetails.new_value: New secondary - mails policy. - """ + @property + def original_folder_name(self): + """ + Original shared folder name. - __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', - ] + :rtype: str + """ + if self._original_folder_name_present: + return self._original_folder_name_value + else: + raise AttributeError("missing required field 'original_folder_name'") - _has_required_fields = True + @original_folder_name.setter + def original_folder_name(self, val): + val = self._original_folder_name_validator.validate(val) + self._original_folder_name_value = val + self._original_folder_name_present = True - def __init__(self, - previous_value=None, - new_value=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value + @original_folder_name.deleter + def original_folder_name(self): + self._original_folder_name_value = None + self._original_folder_name_present = False @property - def previous_value(self): + def new_sharing_permission(self): """ - Previous secondary mails policy. + New sharing permission. Might be missing due to historical data gap. - :rtype: SecondaryMailsPolicy + :rtype: str """ - if self._previous_value_present: - return self._previous_value_value + if self._new_sharing_permission_present: + return self._new_sharing_permission_value else: - raise AttributeError("missing required field 'previous_value'") + return None - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @new_sharing_permission.setter + def new_sharing_permission(self, val): + if val is None: + del self.new_sharing_permission + return + val = self._new_sharing_permission_validator.validate(val) + self._new_sharing_permission_value = val + self._new_sharing_permission_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @new_sharing_permission.deleter + def new_sharing_permission(self): + self._new_sharing_permission_value = None + self._new_sharing_permission_present = False @property - def new_value(self): + def previous_sharing_permission(self): """ - New secondary mails policy. + Previous sharing permission. Might be missing due to historical data + gap. - :rtype: SecondaryMailsPolicy + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._previous_sharing_permission_present: + return self._previous_sharing_permission_value else: - raise AttributeError("missing required field 'new_value'") + return None - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @previous_sharing_permission.setter + def previous_sharing_permission(self, val): + if val is None: + del self.previous_sharing_permission + return + val = self._previous_sharing_permission_validator.validate(val) + self._previous_sharing_permission_value = val + self._previous_sharing_permission_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @previous_sharing_permission.deleter + def previous_sharing_permission(self): + self._previous_sharing_permission_value = None + self._previous_sharing_permission_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SecondaryMailsPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfExternalInviteWarnDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SecondaryMailsPolicyChangedDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, - self._new_value_value, + return 'SfExternalInviteWarnDetails(target_asset_index={!r}, original_folder_name={!r}, new_sharing_permission={!r}, previous_sharing_permission={!r})'.format( + self._target_asset_index_value, + self._original_folder_name_value, + self._new_sharing_permission_value, + self._previous_sharing_permission_value, ) -SecondaryMailsPolicyChangedDetails_validator = bv.Struct(SecondaryMailsPolicyChangedDetails) +SfExternalInviteWarnDetails_validator = bv.Struct(SfExternalInviteWarnDetails) -class SecondaryMailsPolicyChangedType(bb.Struct): +class SfExternalInviteWarnType(bb.Struct): __slots__ = [ '_description_value', @@ -50670,312 +70985,234 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SecondaryMailsPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfExternalInviteWarnType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SecondaryMailsPolicyChangedType(description={!r})'.format( + return 'SfExternalInviteWarnType(description={!r})'.format( self._description_value, ) -SecondaryMailsPolicyChangedType_validator = bv.Struct(SecondaryMailsPolicyChangedType) - -class SecondaryTeamRequestAcceptedDetails(bb.Struct): - """ - Team merge request acceptance details shown to the secondary team - - :ivar team_log.SecondaryTeamRequestAcceptedDetails.primary_team: The primary - team name. - :ivar team_log.SecondaryTeamRequestAcceptedDetails.sent_by: The name of the - secondary team admin who sent the request originally. - """ - - __slots__ = [ - '_primary_team_value', - '_primary_team_present', - '_sent_by_value', - '_sent_by_present', - ] - - _has_required_fields = True - - def __init__(self, - primary_team=None, - sent_by=None): - self._primary_team_value = None - self._primary_team_present = False - self._sent_by_value = None - self._sent_by_present = False - if primary_team is not None: - self.primary_team = primary_team - if sent_by is not None: - self.sent_by = sent_by - - @property - def primary_team(self): - """ - The primary team name. - - :rtype: str - """ - if self._primary_team_present: - return self._primary_team_value - else: - raise AttributeError("missing required field 'primary_team'") - - @primary_team.setter - def primary_team(self, val): - val = self._primary_team_validator.validate(val) - self._primary_team_value = val - self._primary_team_present = True - - @primary_team.deleter - def primary_team(self): - self._primary_team_value = None - self._primary_team_present = False - - @property - def sent_by(self): - """ - The name of the secondary team admin who sent the request originally. - - :rtype: str - """ - if self._sent_by_present: - return self._sent_by_value - else: - raise AttributeError("missing required field 'sent_by'") - - @sent_by.setter - def sent_by(self, val): - val = self._sent_by_validator.validate(val) - self._sent_by_value = val - self._sent_by_present = True - - @sent_by.deleter - def sent_by(self): - self._sent_by_value = None - self._sent_by_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SecondaryTeamRequestAcceptedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SecondaryTeamRequestAcceptedDetails(primary_team={!r}, sent_by={!r})'.format( - self._primary_team_value, - self._sent_by_value, - ) - -SecondaryTeamRequestAcceptedDetails_validator = bv.Struct(SecondaryTeamRequestAcceptedDetails) +SfExternalInviteWarnType_validator = bv.Struct(SfExternalInviteWarnType) -class SecondaryTeamRequestCanceledDetails(bb.Struct): +class SfFbInviteChangeRoleDetails(bb.Struct): """ - Team merge request cancellation details shown to the secondary team + Changed Facebook user's role in shared folder. - :ivar team_log.SecondaryTeamRequestCanceledDetails.sent_to: The email of the - primary team admin that the request was sent to. - :ivar team_log.SecondaryTeamRequestCanceledDetails.sent_by: The name of the - secondary team admin who sent the request originally. + :ivar team_log.SfFbInviteChangeRoleDetails.target_asset_index: Target asset + position in the Assets list. + :ivar team_log.SfFbInviteChangeRoleDetails.original_folder_name: Original + shared folder name. + :ivar team_log.SfFbInviteChangeRoleDetails.previous_sharing_permission: + Previous sharing permission. Might be missing due to historical data + gap. + :ivar team_log.SfFbInviteChangeRoleDetails.new_sharing_permission: New + sharing permission. Might be missing due to historical data gap. """ __slots__ = [ - '_sent_to_value', - '_sent_to_present', - '_sent_by_value', - '_sent_by_present', + '_target_asset_index_value', + '_target_asset_index_present', + '_original_folder_name_value', + '_original_folder_name_present', + '_previous_sharing_permission_value', + '_previous_sharing_permission_present', + '_new_sharing_permission_value', + '_new_sharing_permission_present', ] _has_required_fields = True def __init__(self, - sent_to=None, - sent_by=None): - self._sent_to_value = None - self._sent_to_present = False - self._sent_by_value = None - self._sent_by_present = False - if sent_to is not None: - self.sent_to = sent_to - if sent_by is not None: - self.sent_by = sent_by + target_asset_index=None, + original_folder_name=None, + previous_sharing_permission=None, + new_sharing_permission=None): + self._target_asset_index_value = None + self._target_asset_index_present = False + self._original_folder_name_value = None + self._original_folder_name_present = False + self._previous_sharing_permission_value = None + self._previous_sharing_permission_present = False + self._new_sharing_permission_value = None + self._new_sharing_permission_present = False + if target_asset_index is not None: + self.target_asset_index = target_asset_index + if original_folder_name is not None: + self.original_folder_name = original_folder_name + if previous_sharing_permission is not None: + self.previous_sharing_permission = previous_sharing_permission + if new_sharing_permission is not None: + self.new_sharing_permission = new_sharing_permission @property - def sent_to(self): + def target_asset_index(self): """ - The email of the primary team admin that the request was sent to. + Target asset position in the Assets list. - :rtype: str + :rtype: int """ - if self._sent_to_present: - return self._sent_to_value + if self._target_asset_index_present: + return self._target_asset_index_value else: - raise AttributeError("missing required field 'sent_to'") + raise AttributeError("missing required field 'target_asset_index'") - @sent_to.setter - def sent_to(self, val): - val = self._sent_to_validator.validate(val) - self._sent_to_value = val - self._sent_to_present = True + @target_asset_index.setter + def target_asset_index(self, val): + val = self._target_asset_index_validator.validate(val) + self._target_asset_index_value = val + self._target_asset_index_present = True - @sent_to.deleter - def sent_to(self): - self._sent_to_value = None - self._sent_to_present = False + @target_asset_index.deleter + def target_asset_index(self): + self._target_asset_index_value = None + self._target_asset_index_present = False @property - def sent_by(self): + def original_folder_name(self): """ - The name of the secondary team admin who sent the request originally. + Original shared folder name. :rtype: str """ - if self._sent_by_present: - return self._sent_by_value + if self._original_folder_name_present: + return self._original_folder_name_value else: - raise AttributeError("missing required field 'sent_by'") - - @sent_by.setter - def sent_by(self, val): - val = self._sent_by_validator.validate(val) - self._sent_by_value = val - self._sent_by_present = True - - @sent_by.deleter - def sent_by(self): - self._sent_by_value = None - self._sent_by_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SecondaryTeamRequestCanceledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SecondaryTeamRequestCanceledDetails(sent_to={!r}, sent_by={!r})'.format( - self._sent_to_value, - self._sent_by_value, - ) + raise AttributeError("missing required field 'original_folder_name'") -SecondaryTeamRequestCanceledDetails_validator = bv.Struct(SecondaryTeamRequestCanceledDetails) + @original_folder_name.setter + def original_folder_name(self, val): + val = self._original_folder_name_validator.validate(val) + self._original_folder_name_value = val + self._original_folder_name_present = True -class SecondaryTeamRequestExpiredDetails(bb.Struct): - """ - Team merge request expiration details shown to the secondary team + @original_folder_name.deleter + def original_folder_name(self): + self._original_folder_name_value = None + self._original_folder_name_present = False - :ivar team_log.SecondaryTeamRequestExpiredDetails.sent_to: The email of the - primary team admin the request was sent to. - """ + @property + def previous_sharing_permission(self): + """ + Previous sharing permission. Might be missing due to historical data + gap. - __slots__ = [ - '_sent_to_value', - '_sent_to_present', - ] + :rtype: str + """ + if self._previous_sharing_permission_present: + return self._previous_sharing_permission_value + else: + return None - _has_required_fields = True + @previous_sharing_permission.setter + def previous_sharing_permission(self, val): + if val is None: + del self.previous_sharing_permission + return + val = self._previous_sharing_permission_validator.validate(val) + self._previous_sharing_permission_value = val + self._previous_sharing_permission_present = True - def __init__(self, - sent_to=None): - self._sent_to_value = None - self._sent_to_present = False - if sent_to is not None: - self.sent_to = sent_to + @previous_sharing_permission.deleter + def previous_sharing_permission(self): + self._previous_sharing_permission_value = None + self._previous_sharing_permission_present = False @property - def sent_to(self): + def new_sharing_permission(self): """ - The email of the primary team admin the request was sent to. + New sharing permission. Might be missing due to historical data gap. :rtype: str """ - if self._sent_to_present: - return self._sent_to_value + if self._new_sharing_permission_present: + return self._new_sharing_permission_value else: - raise AttributeError("missing required field 'sent_to'") + return None - @sent_to.setter - def sent_to(self, val): - val = self._sent_to_validator.validate(val) - self._sent_to_value = val - self._sent_to_present = True + @new_sharing_permission.setter + def new_sharing_permission(self, val): + if val is None: + del self.new_sharing_permission + return + val = self._new_sharing_permission_validator.validate(val) + self._new_sharing_permission_value = val + self._new_sharing_permission_present = True - @sent_to.deleter - def sent_to(self): - self._sent_to_value = None - self._sent_to_present = False + @new_sharing_permission.deleter + def new_sharing_permission(self): + self._new_sharing_permission_value = None + self._new_sharing_permission_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SecondaryTeamRequestExpiredDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfFbInviteChangeRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SecondaryTeamRequestExpiredDetails(sent_to={!r})'.format( - self._sent_to_value, + return 'SfFbInviteChangeRoleDetails(target_asset_index={!r}, original_folder_name={!r}, previous_sharing_permission={!r}, new_sharing_permission={!r})'.format( + self._target_asset_index_value, + self._original_folder_name_value, + self._previous_sharing_permission_value, + self._new_sharing_permission_value, ) -SecondaryTeamRequestExpiredDetails_validator = bv.Struct(SecondaryTeamRequestExpiredDetails) - -class SecondaryTeamRequestReminderDetails(bb.Struct): - """ - Team merge request reminder details shown to the secondary team +SfFbInviteChangeRoleDetails_validator = bv.Struct(SfFbInviteChangeRoleDetails) - :ivar team_log.SecondaryTeamRequestReminderDetails.sent_to: The email of the - primary team admin the request was sent to. - """ +class SfFbInviteChangeRoleType(bb.Struct): __slots__ = [ - '_sent_to_value', - '_sent_to_present', + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - sent_to=None): - self._sent_to_value = None - self._sent_to_present = False - if sent_to is not None: - self.sent_to = sent_to + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def sent_to(self): + def description(self): """ - The email of the primary team admin the request was sent to. - :rtype: str """ - if self._sent_to_present: - return self._sent_to_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'sent_to'") + raise AttributeError("missing required field 'description'") - @sent_to.setter - def sent_to(self, val): - val = self._sent_to_validator.validate(val) - self._sent_to_value = val - self._sent_to_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @sent_to.deleter - def sent_to(self): - self._sent_to_value = None - self._sent_to_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SecondaryTeamRequestReminderDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfFbInviteChangeRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SecondaryTeamRequestReminderDetails(sent_to={!r})'.format( - self._sent_to_value, + return 'SfFbInviteChangeRoleType(description={!r})'.format( + self._description_value, ) -SecondaryTeamRequestReminderDetails_validator = bv.Struct(SecondaryTeamRequestReminderDetails) +SfFbInviteChangeRoleType_validator = bv.Struct(SfFbInviteChangeRoleType) -class SfAddGroupDetails(bb.Struct): +class SfFbInviteDetails(bb.Struct): """ - Added team to shared folder. + Invited Facebook users to shared folder. - :ivar team_log.SfAddGroupDetails.target_asset_index: Target asset position + :ivar team_log.SfFbInviteDetails.target_asset_index: Target asset position in the Assets list. - :ivar team_log.SfAddGroupDetails.original_folder_name: Original shared + :ivar team_log.SfFbInviteDetails.original_folder_name: Original shared folder name. - :ivar team_log.SfAddGroupDetails.sharing_permission: Sharing permission. + :ivar team_log.SfFbInviteDetails.sharing_permission: Sharing permission. Might be missing due to historical data gap. - :ivar team_log.SfAddGroupDetails.team_name: Team name. """ __slots__ = [ @@ -50985,8 +71222,6 @@ class SfAddGroupDetails(bb.Struct): '_original_folder_name_present', '_sharing_permission_value', '_sharing_permission_present', - '_team_name_value', - '_team_name_present', ] _has_required_fields = True @@ -50994,7 +71229,6 @@ class SfAddGroupDetails(bb.Struct): def __init__(self, target_asset_index=None, original_folder_name=None, - team_name=None, sharing_permission=None): self._target_asset_index_value = None self._target_asset_index_present = False @@ -51002,16 +71236,12 @@ def __init__(self, self._original_folder_name_present = False self._sharing_permission_value = None self._sharing_permission_present = False - self._team_name_value = None - self._team_name_present = False if target_asset_index is not None: self.target_asset_index = target_asset_index if original_folder_name is not None: self.original_folder_name = original_folder_name if sharing_permission is not None: self.sharing_permission = sharing_permission - if team_name is not None: - self.team_name = team_name @property def target_asset_index(self): @@ -51085,43 +71315,19 @@ def sharing_permission(self): self._sharing_permission_value = None self._sharing_permission_present = False - @property - def team_name(self): - """ - Team name. - - :rtype: str - """ - if self._team_name_present: - return self._team_name_value - else: - raise AttributeError("missing required field 'team_name'") - - @team_name.setter - def team_name(self, val): - val = self._team_name_validator.validate(val) - self._team_name_value = val - self._team_name_present = True - - @team_name.deleter - def team_name(self): - self._team_name_value = None - self._team_name_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfAddGroupDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfFbInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfAddGroupDetails(target_asset_index={!r}, original_folder_name={!r}, team_name={!r}, sharing_permission={!r})'.format( + return 'SfFbInviteDetails(target_asset_index={!r}, original_folder_name={!r}, sharing_permission={!r})'.format( self._target_asset_index_value, self._original_folder_name_value, - self._team_name_value, self._sharing_permission_value, ) -SfAddGroupDetails_validator = bv.Struct(SfAddGroupDetails) +SfFbInviteDetails_validator = bv.Struct(SfFbInviteDetails) -class SfAddGroupType(bb.Struct): +class SfFbInviteType(bb.Struct): __slots__ = [ '_description_value', @@ -51159,26 +71365,23 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfAddGroupType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfFbInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfAddGroupType(description={!r})'.format( + return 'SfFbInviteType(description={!r})'.format( self._description_value, ) -SfAddGroupType_validator = bv.Struct(SfAddGroupType) +SfFbInviteType_validator = bv.Struct(SfFbInviteType) -class SfAllowNonMembersToViewSharedLinksDetails(bb.Struct): +class SfFbUninviteDetails(bb.Struct): """ - Allowed non-collaborators to view links to files in shared folder. + Uninvited Facebook user from shared folder. - :ivar team_log.SfAllowNonMembersToViewSharedLinksDetails.target_asset_index: - Target asset position in the Assets list. - :ivar - team_log.SfAllowNonMembersToViewSharedLinksDetails.original_folder_name: - Original shared folder name. - :ivar team_log.SfAllowNonMembersToViewSharedLinksDetails.shared_folder_type: - Shared folder type. Might be missing due to historical data gap. + :ivar team_log.SfFbUninviteDetails.target_asset_index: Target asset position + in the Assets list. + :ivar team_log.SfFbUninviteDetails.original_folder_name: Original shared + folder name. """ __slots__ = [ @@ -51186,28 +71389,21 @@ class SfAllowNonMembersToViewSharedLinksDetails(bb.Struct): '_target_asset_index_present', '_original_folder_name_value', '_original_folder_name_present', - '_shared_folder_type_value', - '_shared_folder_type_present', ] _has_required_fields = True def __init__(self, target_asset_index=None, - original_folder_name=None, - shared_folder_type=None): + original_folder_name=None): self._target_asset_index_value = None self._target_asset_index_present = False self._original_folder_name_value = None self._original_folder_name_present = False - self._shared_folder_type_value = None - self._shared_folder_type_present = False if target_asset_index is not None: self.target_asset_index = target_asset_index if original_folder_name is not None: self.original_folder_name = original_folder_name - if shared_folder_type is not None: - self.shared_folder_type = shared_folder_type @property def target_asset_index(self): @@ -51255,45 +71451,120 @@ def original_folder_name(self): self._original_folder_name_value = None self._original_folder_name_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SfFbUninviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SfFbUninviteDetails(target_asset_index={!r}, original_folder_name={!r})'.format( + self._target_asset_index_value, + self._original_folder_name_value, + ) + +SfFbUninviteDetails_validator = bv.Struct(SfFbUninviteDetails) + +class SfFbUninviteType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + @property - def shared_folder_type(self): + def description(self): """ - Shared folder type. Might be missing due to historical data gap. - :rtype: str """ - if self._shared_folder_type_present: - return self._shared_folder_type_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @shared_folder_type.setter - def shared_folder_type(self, val): - if val is None: - del self.shared_folder_type - return - val = self._shared_folder_type_validator.validate(val) - self._shared_folder_type_value = val - self._shared_folder_type_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @shared_folder_type.deleter - def shared_folder_type(self): - self._shared_folder_type_value = None - self._shared_folder_type_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfAllowNonMembersToViewSharedLinksDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfFbUninviteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfAllowNonMembersToViewSharedLinksDetails(target_asset_index={!r}, original_folder_name={!r}, shared_folder_type={!r})'.format( + return 'SfFbUninviteType(description={!r})'.format( + self._description_value, + ) + +SfFbUninviteType_validator = bv.Struct(SfFbUninviteType) + +class SfInviteGroupDetails(bb.Struct): + """ + Invited group to shared folder. + + :ivar team_log.SfInviteGroupDetails.target_asset_index: Target asset + position in the Assets list. + """ + + __slots__ = [ + '_target_asset_index_value', + '_target_asset_index_present', + ] + + _has_required_fields = True + + def __init__(self, + target_asset_index=None): + self._target_asset_index_value = None + self._target_asset_index_present = False + if target_asset_index is not None: + self.target_asset_index = target_asset_index + + @property + def target_asset_index(self): + """ + Target asset position in the Assets list. + + :rtype: int + """ + if self._target_asset_index_present: + return self._target_asset_index_value + else: + raise AttributeError("missing required field 'target_asset_index'") + + @target_asset_index.setter + def target_asset_index(self, val): + val = self._target_asset_index_validator.validate(val) + self._target_asset_index_value = val + self._target_asset_index_present = True + + @target_asset_index.deleter + def target_asset_index(self): + self._target_asset_index_value = None + self._target_asset_index_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SfInviteGroupDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SfInviteGroupDetails(target_asset_index={!r})'.format( self._target_asset_index_value, - self._original_folder_name_value, - self._shared_folder_type_value, ) -SfAllowNonMembersToViewSharedLinksDetails_validator = bv.Struct(SfAllowNonMembersToViewSharedLinksDetails) +SfInviteGroupDetails_validator = bv.Struct(SfInviteGroupDetails) -class SfAllowNonMembersToViewSharedLinksType(bb.Struct): +class SfInviteGroupType(bb.Struct): __slots__ = [ '_description_value', @@ -51331,28 +71602,23 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfAllowNonMembersToViewSharedLinksType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfInviteGroupType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfAllowNonMembersToViewSharedLinksType(description={!r})'.format( + return 'SfInviteGroupType(description={!r})'.format( self._description_value, ) -SfAllowNonMembersToViewSharedLinksType_validator = bv.Struct(SfAllowNonMembersToViewSharedLinksType) +SfInviteGroupType_validator = bv.Struct(SfInviteGroupType) -class SfExternalInviteWarnDetails(bb.Struct): +class SfTeamGrantAccessDetails(bb.Struct): """ - Set team members to see warning before sharing folders outside team. + Granted access to shared folder. - :ivar team_log.SfExternalInviteWarnDetails.target_asset_index: Target asset + :ivar team_log.SfTeamGrantAccessDetails.target_asset_index: Target asset position in the Assets list. - :ivar team_log.SfExternalInviteWarnDetails.original_folder_name: Original + :ivar team_log.SfTeamGrantAccessDetails.original_folder_name: Original shared folder name. - :ivar team_log.SfExternalInviteWarnDetails.new_sharing_permission: New - sharing permission. Might be missing due to historical data gap. - :ivar team_log.SfExternalInviteWarnDetails.previous_sharing_permission: - Previous sharing permission. Might be missing due to historical data - gap. """ __slots__ = [ @@ -51360,35 +71626,21 @@ class SfExternalInviteWarnDetails(bb.Struct): '_target_asset_index_present', '_original_folder_name_value', '_original_folder_name_present', - '_new_sharing_permission_value', - '_new_sharing_permission_present', - '_previous_sharing_permission_value', - '_previous_sharing_permission_present', ] _has_required_fields = True def __init__(self, target_asset_index=None, - original_folder_name=None, - new_sharing_permission=None, - previous_sharing_permission=None): + original_folder_name=None): self._target_asset_index_value = None self._target_asset_index_present = False self._original_folder_name_value = None self._original_folder_name_present = False - self._new_sharing_permission_value = None - self._new_sharing_permission_present = False - self._previous_sharing_permission_value = None - self._previous_sharing_permission_present = False if target_asset_index is not None: self.target_asset_index = target_asset_index if original_folder_name is not None: self.original_folder_name = original_folder_name - if new_sharing_permission is not None: - self.new_sharing_permission = new_sharing_permission - if previous_sharing_permission is not None: - self.previous_sharing_permission = previous_sharing_permission @property def target_asset_index(self): @@ -51436,73 +71688,18 @@ def original_folder_name(self): self._original_folder_name_value = None self._original_folder_name_present = False - @property - def new_sharing_permission(self): - """ - New sharing permission. Might be missing due to historical data gap. - - :rtype: str - """ - if self._new_sharing_permission_present: - return self._new_sharing_permission_value - else: - return None - - @new_sharing_permission.setter - def new_sharing_permission(self, val): - if val is None: - del self.new_sharing_permission - return - val = self._new_sharing_permission_validator.validate(val) - self._new_sharing_permission_value = val - self._new_sharing_permission_present = True - - @new_sharing_permission.deleter - def new_sharing_permission(self): - self._new_sharing_permission_value = None - self._new_sharing_permission_present = False - - @property - def previous_sharing_permission(self): - """ - Previous sharing permission. Might be missing due to historical data - gap. - - :rtype: str - """ - if self._previous_sharing_permission_present: - return self._previous_sharing_permission_value - else: - return None - - @previous_sharing_permission.setter - def previous_sharing_permission(self, val): - if val is None: - del self.previous_sharing_permission - return - val = self._previous_sharing_permission_validator.validate(val) - self._previous_sharing_permission_value = val - self._previous_sharing_permission_present = True - - @previous_sharing_permission.deleter - def previous_sharing_permission(self): - self._previous_sharing_permission_value = None - self._previous_sharing_permission_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfExternalInviteWarnDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamGrantAccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfExternalInviteWarnDetails(target_asset_index={!r}, original_folder_name={!r}, new_sharing_permission={!r}, previous_sharing_permission={!r})'.format( + return 'SfTeamGrantAccessDetails(target_asset_index={!r}, original_folder_name={!r})'.format( self._target_asset_index_value, self._original_folder_name_value, - self._new_sharing_permission_value, - self._previous_sharing_permission_value, ) -SfExternalInviteWarnDetails_validator = bv.Struct(SfExternalInviteWarnDetails) +SfTeamGrantAccessDetails_validator = bv.Struct(SfTeamGrantAccessDetails) -class SfExternalInviteWarnType(bb.Struct): +class SfTeamGrantAccessType(bb.Struct): __slots__ = [ '_description_value', @@ -51540,28 +71737,28 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfExternalInviteWarnType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamGrantAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfExternalInviteWarnType(description={!r})'.format( + return 'SfTeamGrantAccessType(description={!r})'.format( self._description_value, ) -SfExternalInviteWarnType_validator = bv.Struct(SfExternalInviteWarnType) +SfTeamGrantAccessType_validator = bv.Struct(SfTeamGrantAccessType) -class SfFbInviteChangeRoleDetails(bb.Struct): +class SfTeamInviteChangeRoleDetails(bb.Struct): """ - Changed Facebook user's role in shared folder. + Changed team member's role in shared folder. - :ivar team_log.SfFbInviteChangeRoleDetails.target_asset_index: Target asset - position in the Assets list. - :ivar team_log.SfFbInviteChangeRoleDetails.original_folder_name: Original + :ivar team_log.SfTeamInviteChangeRoleDetails.target_asset_index: Target + asset position in the Assets list. + :ivar team_log.SfTeamInviteChangeRoleDetails.original_folder_name: Original shared folder name. - :ivar team_log.SfFbInviteChangeRoleDetails.previous_sharing_permission: + :ivar team_log.SfTeamInviteChangeRoleDetails.new_sharing_permission: New + sharing permission. Might be missing due to historical data gap. + :ivar team_log.SfTeamInviteChangeRoleDetails.previous_sharing_permission: Previous sharing permission. Might be missing due to historical data gap. - :ivar team_log.SfFbInviteChangeRoleDetails.new_sharing_permission: New - sharing permission. Might be missing due to historical data gap. """ __slots__ = [ @@ -51569,10 +71766,10 @@ class SfFbInviteChangeRoleDetails(bb.Struct): '_target_asset_index_present', '_original_folder_name_value', '_original_folder_name_present', - '_previous_sharing_permission_value', - '_previous_sharing_permission_present', '_new_sharing_permission_value', '_new_sharing_permission_present', + '_previous_sharing_permission_value', + '_previous_sharing_permission_present', ] _has_required_fields = True @@ -51580,24 +71777,24 @@ class SfFbInviteChangeRoleDetails(bb.Struct): def __init__(self, target_asset_index=None, original_folder_name=None, - previous_sharing_permission=None, - new_sharing_permission=None): + new_sharing_permission=None, + previous_sharing_permission=None): self._target_asset_index_value = None self._target_asset_index_present = False self._original_folder_name_value = None self._original_folder_name_present = False - self._previous_sharing_permission_value = None - self._previous_sharing_permission_present = False self._new_sharing_permission_value = None self._new_sharing_permission_present = False + self._previous_sharing_permission_value = None + self._previous_sharing_permission_present = False if target_asset_index is not None: self.target_asset_index = target_asset_index if original_folder_name is not None: self.original_folder_name = original_folder_name - if previous_sharing_permission is not None: - self.previous_sharing_permission = previous_sharing_permission if new_sharing_permission is not None: self.new_sharing_permission = new_sharing_permission + if previous_sharing_permission is not None: + self.previous_sharing_permission = previous_sharing_permission @property def target_asset_index(self): @@ -51645,6 +71842,32 @@ def original_folder_name(self): self._original_folder_name_value = None self._original_folder_name_present = False + @property + def new_sharing_permission(self): + """ + New sharing permission. Might be missing due to historical data gap. + + :rtype: str + """ + if self._new_sharing_permission_present: + return self._new_sharing_permission_value + else: + return None + + @new_sharing_permission.setter + def new_sharing_permission(self, val): + if val is None: + del self.new_sharing_permission + return + val = self._new_sharing_permission_validator.validate(val) + self._new_sharing_permission_value = val + self._new_sharing_permission_present = True + + @new_sharing_permission.deleter + def new_sharing_permission(self): + self._new_sharing_permission_value = None + self._new_sharing_permission_present = False + @property def previous_sharing_permission(self): """ @@ -51672,46 +71895,20 @@ def previous_sharing_permission(self): self._previous_sharing_permission_value = None self._previous_sharing_permission_present = False - @property - def new_sharing_permission(self): - """ - New sharing permission. Might be missing due to historical data gap. - - :rtype: str - """ - if self._new_sharing_permission_present: - return self._new_sharing_permission_value - else: - return None - - @new_sharing_permission.setter - def new_sharing_permission(self, val): - if val is None: - del self.new_sharing_permission - return - val = self._new_sharing_permission_validator.validate(val) - self._new_sharing_permission_value = val - self._new_sharing_permission_present = True - - @new_sharing_permission.deleter - def new_sharing_permission(self): - self._new_sharing_permission_value = None - self._new_sharing_permission_present = False - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfFbInviteChangeRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamInviteChangeRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfFbInviteChangeRoleDetails(target_asset_index={!r}, original_folder_name={!r}, previous_sharing_permission={!r}, new_sharing_permission={!r})'.format( + return 'SfTeamInviteChangeRoleDetails(target_asset_index={!r}, original_folder_name={!r}, new_sharing_permission={!r}, previous_sharing_permission={!r})'.format( self._target_asset_index_value, self._original_folder_name_value, - self._previous_sharing_permission_value, self._new_sharing_permission_value, + self._previous_sharing_permission_value, ) -SfFbInviteChangeRoleDetails_validator = bv.Struct(SfFbInviteChangeRoleDetails) +SfTeamInviteChangeRoleDetails_validator = bv.Struct(SfTeamInviteChangeRoleDetails) -class SfFbInviteChangeRoleType(bb.Struct): +class SfTeamInviteChangeRoleType(bb.Struct): __slots__ = [ '_description_value', @@ -51749,24 +71946,24 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfFbInviteChangeRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamInviteChangeRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfFbInviteChangeRoleType(description={!r})'.format( + return 'SfTeamInviteChangeRoleType(description={!r})'.format( self._description_value, ) -SfFbInviteChangeRoleType_validator = bv.Struct(SfFbInviteChangeRoleType) +SfTeamInviteChangeRoleType_validator = bv.Struct(SfTeamInviteChangeRoleType) -class SfFbInviteDetails(bb.Struct): +class SfTeamInviteDetails(bb.Struct): """ - Invited Facebook users to shared folder. + Invited team members to shared folder. - :ivar team_log.SfFbInviteDetails.target_asset_index: Target asset position + :ivar team_log.SfTeamInviteDetails.target_asset_index: Target asset position in the Assets list. - :ivar team_log.SfFbInviteDetails.original_folder_name: Original shared + :ivar team_log.SfTeamInviteDetails.original_folder_name: Original shared folder name. - :ivar team_log.SfFbInviteDetails.sharing_permission: Sharing permission. + :ivar team_log.SfTeamInviteDetails.sharing_permission: Sharing permission. Might be missing due to historical data gap. """ @@ -51871,18 +72068,18 @@ def sharing_permission(self): self._sharing_permission_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfFbInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfFbInviteDetails(target_asset_index={!r}, original_folder_name={!r}, sharing_permission={!r})'.format( + return 'SfTeamInviteDetails(target_asset_index={!r}, original_folder_name={!r}, sharing_permission={!r})'.format( self._target_asset_index_value, self._original_folder_name_value, self._sharing_permission_value, ) -SfFbInviteDetails_validator = bv.Struct(SfFbInviteDetails) +SfTeamInviteDetails_validator = bv.Struct(SfTeamInviteDetails) -class SfFbInviteType(bb.Struct): +class SfTeamInviteType(bb.Struct): __slots__ = [ '_description_value', @@ -51920,22 +72117,22 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfFbInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfFbInviteType(description={!r})'.format( + return 'SfTeamInviteType(description={!r})'.format( self._description_value, ) -SfFbInviteType_validator = bv.Struct(SfFbInviteType) +SfTeamInviteType_validator = bv.Struct(SfTeamInviteType) -class SfFbUninviteDetails(bb.Struct): +class SfTeamJoinDetails(bb.Struct): """ - Uninvited Facebook user from shared folder. + Joined team member's shared folder. - :ivar team_log.SfFbUninviteDetails.target_asset_index: Target asset position + :ivar team_log.SfTeamJoinDetails.target_asset_index: Target asset position in the Assets list. - :ivar team_log.SfFbUninviteDetails.original_folder_name: Original shared + :ivar team_log.SfTeamJoinDetails.original_folder_name: Original shared folder name. """ @@ -52007,84 +72204,64 @@ def original_folder_name(self): self._original_folder_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfFbUninviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamJoinDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfFbUninviteDetails(target_asset_index={!r}, original_folder_name={!r})'.format( + return 'SfTeamJoinDetails(target_asset_index={!r}, original_folder_name={!r})'.format( self._target_asset_index_value, self._original_folder_name_value, ) -SfFbUninviteDetails_validator = bv.Struct(SfFbUninviteDetails) - -class SfFbUninviteType(bb.Struct): - - __slots__ = [ - '_description_value', - '_description_present', - ] - - _has_required_fields = True - - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description - - @property - def description(self): - """ - :rtype: str - """ - if self._description_present: - return self._description_value - else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfFbUninviteType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SfFbUninviteType(description={!r})'.format( - self._description_value, - ) - -SfFbUninviteType_validator = bv.Struct(SfFbUninviteType) +SfTeamJoinDetails_validator = bv.Struct(SfTeamJoinDetails) -class SfInviteGroupDetails(bb.Struct): +class SfTeamJoinFromOobLinkDetails(bb.Struct): """ - Invited group to shared folder. + Joined team member's shared folder from link. - :ivar team_log.SfInviteGroupDetails.target_asset_index: Target asset + :ivar team_log.SfTeamJoinFromOobLinkDetails.target_asset_index: Target asset position in the Assets list. + :ivar team_log.SfTeamJoinFromOobLinkDetails.original_folder_name: Original + shared folder name. + :ivar team_log.SfTeamJoinFromOobLinkDetails.token_key: Shared link token + key. + :ivar team_log.SfTeamJoinFromOobLinkDetails.sharing_permission: Sharing + permission. Might be missing due to historical data gap. """ __slots__ = [ '_target_asset_index_value', '_target_asset_index_present', + '_original_folder_name_value', + '_original_folder_name_present', + '_token_key_value', + '_token_key_present', + '_sharing_permission_value', + '_sharing_permission_present', ] _has_required_fields = True def __init__(self, - target_asset_index=None): + target_asset_index=None, + original_folder_name=None, + token_key=None, + sharing_permission=None): self._target_asset_index_value = None self._target_asset_index_present = False + self._original_folder_name_value = None + self._original_folder_name_present = False + self._token_key_value = None + self._token_key_present = False + self._sharing_permission_value = None + self._sharing_permission_present = False if target_asset_index is not None: self.target_asset_index = target_asset_index + if original_folder_name is not None: + self.original_folder_name = original_folder_name + if token_key is not None: + self.token_key = token_key + if sharing_permission is not None: + self.sharing_permission = sharing_permission @property def target_asset_index(self): @@ -52109,17 +72286,95 @@ def target_asset_index(self): self._target_asset_index_value = None self._target_asset_index_present = False + @property + def original_folder_name(self): + """ + Original shared folder name. + + :rtype: str + """ + if self._original_folder_name_present: + return self._original_folder_name_value + else: + raise AttributeError("missing required field 'original_folder_name'") + + @original_folder_name.setter + def original_folder_name(self, val): + val = self._original_folder_name_validator.validate(val) + self._original_folder_name_value = val + self._original_folder_name_present = True + + @original_folder_name.deleter + def original_folder_name(self): + self._original_folder_name_value = None + self._original_folder_name_present = False + + @property + def token_key(self): + """ + Shared link token key. + + :rtype: str + """ + if self._token_key_present: + return self._token_key_value + else: + return None + + @token_key.setter + def token_key(self, val): + if val is None: + del self.token_key + return + val = self._token_key_validator.validate(val) + self._token_key_value = val + self._token_key_present = True + + @token_key.deleter + def token_key(self): + self._token_key_value = None + self._token_key_present = False + + @property + def sharing_permission(self): + """ + Sharing permission. Might be missing due to historical data gap. + + :rtype: str + """ + if self._sharing_permission_present: + return self._sharing_permission_value + else: + return None + + @sharing_permission.setter + def sharing_permission(self, val): + if val is None: + del self.sharing_permission + return + val = self._sharing_permission_validator.validate(val) + self._sharing_permission_value = val + self._sharing_permission_present = True + + @sharing_permission.deleter + def sharing_permission(self): + self._sharing_permission_value = None + self._sharing_permission_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfInviteGroupDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamJoinFromOobLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfInviteGroupDetails(target_asset_index={!r})'.format( + return 'SfTeamJoinFromOobLinkDetails(target_asset_index={!r}, original_folder_name={!r}, token_key={!r}, sharing_permission={!r})'.format( self._target_asset_index_value, + self._original_folder_name_value, + self._token_key_value, + self._sharing_permission_value, ) -SfInviteGroupDetails_validator = bv.Struct(SfInviteGroupDetails) +SfTeamJoinFromOobLinkDetails_validator = bv.Struct(SfTeamJoinFromOobLinkDetails) -class SfInviteGroupType(bb.Struct): +class SfTeamJoinFromOobLinkType(bb.Struct): __slots__ = [ '_description_value', @@ -52157,23 +72412,70 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfInviteGroupType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamJoinFromOobLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfInviteGroupType(description={!r})'.format( + return 'SfTeamJoinFromOobLinkType(description={!r})'.format( self._description_value, ) -SfInviteGroupType_validator = bv.Struct(SfInviteGroupType) +SfTeamJoinFromOobLinkType_validator = bv.Struct(SfTeamJoinFromOobLinkType) -class SfTeamGrantAccessDetails(bb.Struct): +class SfTeamJoinType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SfTeamJoinType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SfTeamJoinType(description={!r})'.format( + self._description_value, + ) + +SfTeamJoinType_validator = bv.Struct(SfTeamJoinType) + +class SfTeamUninviteDetails(bb.Struct): """ - Granted access to shared folder. + Unshared folder with team member. - :ivar team_log.SfTeamGrantAccessDetails.target_asset_index: Target asset + :ivar team_log.SfTeamUninviteDetails.target_asset_index: Target asset position in the Assets list. - :ivar team_log.SfTeamGrantAccessDetails.original_folder_name: Original - shared folder name. + :ivar team_log.SfTeamUninviteDetails.original_folder_name: Original shared + folder name. """ __slots__ = [ @@ -52244,17 +72546,17 @@ def original_folder_name(self): self._original_folder_name_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamGrantAccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamUninviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamGrantAccessDetails(target_asset_index={!r}, original_folder_name={!r})'.format( + return 'SfTeamUninviteDetails(target_asset_index={!r}, original_folder_name={!r})'.format( self._target_asset_index_value, self._original_folder_name_value, ) -SfTeamGrantAccessDetails_validator = bv.Struct(SfTeamGrantAccessDetails) +SfTeamUninviteDetails_validator = bv.Struct(SfTeamUninviteDetails) -class SfTeamGrantAccessType(bb.Struct): +class SfTeamUninviteType(bb.Struct): __slots__ = [ '_description_value', @@ -52292,178 +72594,210 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamGrantAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SfTeamUninviteType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamGrantAccessType(description={!r})'.format( + return 'SfTeamUninviteType(description={!r})'.format( self._description_value, ) -SfTeamGrantAccessType_validator = bv.Struct(SfTeamGrantAccessType) +SfTeamUninviteType_validator = bv.Struct(SfTeamUninviteType) -class SfTeamInviteChangeRoleDetails(bb.Struct): +class SharedContentAddInviteesDetails(bb.Struct): """ - Changed team member's role in shared folder. + Invited user to Dropbox and added them to shared file/folder. - :ivar team_log.SfTeamInviteChangeRoleDetails.target_asset_index: Target - asset position in the Assets list. - :ivar team_log.SfTeamInviteChangeRoleDetails.original_folder_name: Original - shared folder name. - :ivar team_log.SfTeamInviteChangeRoleDetails.new_sharing_permission: New - sharing permission. Might be missing due to historical data gap. - :ivar team_log.SfTeamInviteChangeRoleDetails.previous_sharing_permission: - Previous sharing permission. Might be missing due to historical data - gap. + :ivar team_log.SharedContentAddInviteesDetails.shared_content_access_level: + Shared content access level. + :ivar team_log.SharedContentAddInviteesDetails.invitees: A list of invitees. """ __slots__ = [ - '_target_asset_index_value', - '_target_asset_index_present', - '_original_folder_name_value', - '_original_folder_name_present', - '_new_sharing_permission_value', - '_new_sharing_permission_present', - '_previous_sharing_permission_value', - '_previous_sharing_permission_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_invitees_value', + '_invitees_present', ] _has_required_fields = True def __init__(self, - target_asset_index=None, - original_folder_name=None, - new_sharing_permission=None, - previous_sharing_permission=None): - self._target_asset_index_value = None - self._target_asset_index_present = False - self._original_folder_name_value = None - self._original_folder_name_present = False - self._new_sharing_permission_value = None - self._new_sharing_permission_present = False - self._previous_sharing_permission_value = None - self._previous_sharing_permission_present = False - if target_asset_index is not None: - self.target_asset_index = target_asset_index - if original_folder_name is not None: - self.original_folder_name = original_folder_name - if new_sharing_permission is not None: - self.new_sharing_permission = new_sharing_permission - if previous_sharing_permission is not None: - self.previous_sharing_permission = previous_sharing_permission + shared_content_access_level=None, + invitees=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._invitees_value = None + self._invitees_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if invitees is not None: + self.invitees = invitees @property - def target_asset_index(self): + def shared_content_access_level(self): """ - Target asset position in the Assets list. + Shared content access level. - :rtype: int + :rtype: sharing.AccessLevel """ - if self._target_asset_index_present: - return self._target_asset_index_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - raise AttributeError("missing required field 'target_asset_index'") + raise AttributeError("missing required field 'shared_content_access_level'") - @target_asset_index.setter - def target_asset_index(self, val): - val = self._target_asset_index_validator.validate(val) - self._target_asset_index_value = val - self._target_asset_index_present = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - @target_asset_index.deleter - def target_asset_index(self): - self._target_asset_index_value = None - self._target_asset_index_present = False + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False @property - def original_folder_name(self): + def invitees(self): """ - Original shared folder name. + A list of invitees. - :rtype: str + :rtype: list of [str] """ - if self._original_folder_name_present: - return self._original_folder_name_value + if self._invitees_present: + return self._invitees_value else: - raise AttributeError("missing required field 'original_folder_name'") + raise AttributeError("missing required field 'invitees'") - @original_folder_name.setter - def original_folder_name(self, val): - val = self._original_folder_name_validator.validate(val) - self._original_folder_name_value = val - self._original_folder_name_present = True + @invitees.setter + def invitees(self, val): + val = self._invitees_validator.validate(val) + self._invitees_value = val + self._invitees_present = True - @original_folder_name.deleter - def original_folder_name(self): - self._original_folder_name_value = None - self._original_folder_name_present = False + @invitees.deleter + def invitees(self): + self._invitees_value = None + self._invitees_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentAddInviteesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentAddInviteesDetails(shared_content_access_level={!r}, invitees={!r})'.format( + self._shared_content_access_level_value, + self._invitees_value, + ) + +SharedContentAddInviteesDetails_validator = bv.Struct(SharedContentAddInviteesDetails) + +class SharedContentAddInviteesType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def new_sharing_permission(self): + def description(self): """ - New sharing permission. Might be missing due to historical data gap. + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentAddInviteesType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentAddInviteesType(description={!r})'.format( + self._description_value, + ) + +SharedContentAddInviteesType_validator = bv.Struct(SharedContentAddInviteesType) + +class SharedContentAddLinkExpiryDetails(bb.Struct): + """ + Added expiration date to link for shared file/folder. + + :ivar team_log.SharedContentAddLinkExpiryDetails.new_value: New shared + content link expiration date. Might be missing due to historical data + gap. + """ - :rtype: str - """ - if self._new_sharing_permission_present: - return self._new_sharing_permission_value - else: - return None + __slots__ = [ + '_new_value_value', + '_new_value_present', + ] - @new_sharing_permission.setter - def new_sharing_permission(self, val): - if val is None: - del self.new_sharing_permission - return - val = self._new_sharing_permission_validator.validate(val) - self._new_sharing_permission_value = val - self._new_sharing_permission_present = True + _has_required_fields = False - @new_sharing_permission.deleter - def new_sharing_permission(self): - self._new_sharing_permission_value = None - self._new_sharing_permission_present = False + def __init__(self, + new_value=None): + self._new_value_value = None + self._new_value_present = False + if new_value is not None: + self.new_value = new_value @property - def previous_sharing_permission(self): + def new_value(self): """ - Previous sharing permission. Might be missing due to historical data - gap. + New shared content link expiration date. Might be missing due to + historical data gap. - :rtype: str + :rtype: datetime.datetime """ - if self._previous_sharing_permission_present: - return self._previous_sharing_permission_value + if self._new_value_present: + return self._new_value_value else: return None - @previous_sharing_permission.setter - def previous_sharing_permission(self, val): + @new_value.setter + def new_value(self, val): if val is None: - del self.previous_sharing_permission + del self.new_value return - val = self._previous_sharing_permission_validator.validate(val) - self._previous_sharing_permission_value = val - self._previous_sharing_permission_present = True + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @previous_sharing_permission.deleter - def previous_sharing_permission(self): - self._previous_sharing_permission_value = None - self._previous_sharing_permission_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamInviteChangeRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentAddLinkExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamInviteChangeRoleDetails(target_asset_index={!r}, original_folder_name={!r}, new_sharing_permission={!r}, previous_sharing_permission={!r})'.format( - self._target_asset_index_value, - self._original_folder_name_value, - self._new_sharing_permission_value, - self._previous_sharing_permission_value, + return 'SharedContentAddLinkExpiryDetails(new_value={!r})'.format( + self._new_value_value, ) -SfTeamInviteChangeRoleDetails_validator = bv.Struct(SfTeamInviteChangeRoleDetails) +SharedContentAddLinkExpiryDetails_validator = bv.Struct(SharedContentAddLinkExpiryDetails) -class SfTeamInviteChangeRoleType(bb.Struct): +class SharedContentAddLinkExpiryType(bb.Struct): __slots__ = [ '_description_value', @@ -52501,140 +72835,139 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamInviteChangeRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentAddLinkExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamInviteChangeRoleType(description={!r})'.format( + return 'SharedContentAddLinkExpiryType(description={!r})'.format( self._description_value, ) -SfTeamInviteChangeRoleType_validator = bv.Struct(SfTeamInviteChangeRoleType) +SharedContentAddLinkExpiryType_validator = bv.Struct(SharedContentAddLinkExpiryType) -class SfTeamInviteDetails(bb.Struct): +class SharedContentAddLinkPasswordDetails(bb.Struct): """ - Invited team members to shared folder. - - :ivar team_log.SfTeamInviteDetails.target_asset_index: Target asset position - in the Assets list. - :ivar team_log.SfTeamInviteDetails.original_folder_name: Original shared - folder name. - :ivar team_log.SfTeamInviteDetails.sharing_permission: Sharing permission. - Might be missing due to historical data gap. + Added password to link for shared file/folder. """ __slots__ = [ - '_target_asset_index_value', - '_target_asset_index_present', - '_original_folder_name_value', - '_original_folder_name_present', - '_sharing_permission_value', - '_sharing_permission_present', + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentAddLinkPasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentAddLinkPasswordDetails()' + +SharedContentAddLinkPasswordDetails_validator = bv.Struct(SharedContentAddLinkPasswordDetails) + +class SharedContentAddLinkPasswordType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - target_asset_index=None, - original_folder_name=None, - sharing_permission=None): - self._target_asset_index_value = None - self._target_asset_index_present = False - self._original_folder_name_value = None - self._original_folder_name_present = False - self._sharing_permission_value = None - self._sharing_permission_present = False - if target_asset_index is not None: - self.target_asset_index = target_asset_index - if original_folder_name is not None: - self.original_folder_name = original_folder_name - if sharing_permission is not None: - self.sharing_permission = sharing_permission + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def target_asset_index(self): + def description(self): """ - Target asset position in the Assets list. - - :rtype: int + :rtype: str """ - if self._target_asset_index_present: - return self._target_asset_index_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'target_asset_index'") + raise AttributeError("missing required field 'description'") - @target_asset_index.setter - def target_asset_index(self, val): - val = self._target_asset_index_validator.validate(val) - self._target_asset_index_value = val - self._target_asset_index_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @target_asset_index.deleter - def target_asset_index(self): - self._target_asset_index_value = None - self._target_asset_index_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False - @property - def original_folder_name(self): - """ - Original shared folder name. + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentAddLinkPasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) - :rtype: str - """ - if self._original_folder_name_present: - return self._original_folder_name_value - else: - raise AttributeError("missing required field 'original_folder_name'") + def __repr__(self): + return 'SharedContentAddLinkPasswordType(description={!r})'.format( + self._description_value, + ) - @original_folder_name.setter - def original_folder_name(self, val): - val = self._original_folder_name_validator.validate(val) - self._original_folder_name_value = val - self._original_folder_name_present = True +SharedContentAddLinkPasswordType_validator = bv.Struct(SharedContentAddLinkPasswordType) - @original_folder_name.deleter - def original_folder_name(self): - self._original_folder_name_value = None - self._original_folder_name_present = False +class SharedContentAddMemberDetails(bb.Struct): + """ + Added users and/or groups to shared file/folder. + + :ivar team_log.SharedContentAddMemberDetails.shared_content_access_level: + Shared content access level. + """ + + __slots__ = [ + '_shared_content_access_level_value', + '_shared_content_access_level_present', + ] + + _has_required_fields = True + + def __init__(self, + shared_content_access_level=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level @property - def sharing_permission(self): + def shared_content_access_level(self): """ - Sharing permission. Might be missing due to historical data gap. + Shared content access level. - :rtype: str + :rtype: sharing.AccessLevel """ - if self._sharing_permission_present: - return self._sharing_permission_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - return None + raise AttributeError("missing required field 'shared_content_access_level'") - @sharing_permission.setter - def sharing_permission(self, val): - if val is None: - del self.sharing_permission - return - val = self._sharing_permission_validator.validate(val) - self._sharing_permission_value = val - self._sharing_permission_present = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - @sharing_permission.deleter - def sharing_permission(self): - self._sharing_permission_value = None - self._sharing_permission_present = False + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentAddMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamInviteDetails(target_asset_index={!r}, original_folder_name={!r}, sharing_permission={!r})'.format( - self._target_asset_index_value, - self._original_folder_name_value, - self._sharing_permission_value, + return 'SharedContentAddMemberDetails(shared_content_access_level={!r})'.format( + self._shared_content_access_level_value, ) -SfTeamInviteDetails_validator = bv.Struct(SfTeamInviteDetails) +SharedContentAddMemberDetails_validator = bv.Struct(SharedContentAddMemberDetails) -class SfTeamInviteType(bb.Struct): +class SharedContentAddMemberType(bb.Struct): __slots__ = [ '_description_value', @@ -52672,264 +73005,279 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamInviteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentAddMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamInviteType(description={!r})'.format( + return 'SharedContentAddMemberType(description={!r})'.format( self._description_value, ) -SfTeamInviteType_validator = bv.Struct(SfTeamInviteType) +SharedContentAddMemberType_validator = bv.Struct(SharedContentAddMemberType) -class SfTeamJoinDetails(bb.Struct): +class SharedContentChangeDownloadsPolicyDetails(bb.Struct): """ - Joined team member's shared folder. + Changed whether members can download shared file/folder. - :ivar team_log.SfTeamJoinDetails.target_asset_index: Target asset position - in the Assets list. - :ivar team_log.SfTeamJoinDetails.original_folder_name: Original shared - folder name. + :ivar team_log.SharedContentChangeDownloadsPolicyDetails.new_value: New + downloads policy. + :ivar team_log.SharedContentChangeDownloadsPolicyDetails.previous_value: + Previous downloads policy. Might be missing due to historical data gap. """ __slots__ = [ - '_target_asset_index_value', - '_target_asset_index_present', - '_original_folder_name_value', - '_original_folder_name_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - target_asset_index=None, - original_folder_name=None): - self._target_asset_index_value = None - self._target_asset_index_present = False - self._original_folder_name_value = None - self._original_folder_name_present = False - if target_asset_index is not None: - self.target_asset_index = target_asset_index - if original_folder_name is not None: - self.original_folder_name = original_folder_name + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def target_asset_index(self): + def new_value(self): """ - Target asset position in the Assets list. + New downloads policy. - :rtype: int + :rtype: DownloadPolicyType """ - if self._target_asset_index_present: - return self._target_asset_index_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'target_asset_index'") + raise AttributeError("missing required field 'new_value'") - @target_asset_index.setter - def target_asset_index(self, val): - val = self._target_asset_index_validator.validate(val) - self._target_asset_index_value = val - self._target_asset_index_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @target_asset_index.deleter - def target_asset_index(self): - self._target_asset_index_value = None - self._target_asset_index_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False @property - def original_folder_name(self): + def previous_value(self): """ - Original shared folder name. + Previous downloads policy. Might be missing due to historical data gap. - :rtype: str + :rtype: DownloadPolicyType """ - if self._original_folder_name_present: - return self._original_folder_name_value + if self._previous_value_present: + return self._previous_value_value else: - raise AttributeError("missing required field 'original_folder_name'") + return None - @original_folder_name.setter - def original_folder_name(self, val): - val = self._original_folder_name_validator.validate(val) - self._original_folder_name_value = val - self._original_folder_name_present = True + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @original_folder_name.deleter - def original_folder_name(self): - self._original_folder_name_value = None - self._original_folder_name_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamJoinDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeDownloadsPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamJoinDetails(target_asset_index={!r}, original_folder_name={!r})'.format( - self._target_asset_index_value, - self._original_folder_name_value, + return 'SharedContentChangeDownloadsPolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -SfTeamJoinDetails_validator = bv.Struct(SfTeamJoinDetails) - -class SfTeamJoinFromOobLinkDetails(bb.Struct): - """ - Joined team member's shared folder from link. +SharedContentChangeDownloadsPolicyDetails_validator = bv.Struct(SharedContentChangeDownloadsPolicyDetails) - :ivar team_log.SfTeamJoinFromOobLinkDetails.target_asset_index: Target asset - position in the Assets list. - :ivar team_log.SfTeamJoinFromOobLinkDetails.original_folder_name: Original - shared folder name. - :ivar team_log.SfTeamJoinFromOobLinkDetails.token_key: Shared link token - key. - :ivar team_log.SfTeamJoinFromOobLinkDetails.sharing_permission: Sharing - permission. Might be missing due to historical data gap. - """ +class SharedContentChangeDownloadsPolicyType(bb.Struct): __slots__ = [ - '_target_asset_index_value', - '_target_asset_index_present', - '_original_folder_name_value', - '_original_folder_name_present', - '_token_key_value', - '_token_key_present', - '_sharing_permission_value', - '_sharing_permission_present', + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - target_asset_index=None, - original_folder_name=None, - token_key=None, - sharing_permission=None): - self._target_asset_index_value = None - self._target_asset_index_present = False - self._original_folder_name_value = None - self._original_folder_name_present = False - self._token_key_value = None - self._token_key_present = False - self._sharing_permission_value = None - self._sharing_permission_present = False - if target_asset_index is not None: - self.target_asset_index = target_asset_index - if original_folder_name is not None: - self.original_folder_name = original_folder_name - if token_key is not None: - self.token_key = token_key - if sharing_permission is not None: - self.sharing_permission = sharing_permission + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def target_asset_index(self): + def description(self): """ - Target asset position in the Assets list. - - :rtype: int + :rtype: str """ - if self._target_asset_index_present: - return self._target_asset_index_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'target_asset_index'") + raise AttributeError("missing required field 'description'") - @target_asset_index.setter - def target_asset_index(self, val): - val = self._target_asset_index_validator.validate(val) - self._target_asset_index_value = val - self._target_asset_index_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @target_asset_index.deleter - def target_asset_index(self): - self._target_asset_index_value = None - self._target_asset_index_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentChangeDownloadsPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentChangeDownloadsPolicyType(description={!r})'.format( + self._description_value, + ) + +SharedContentChangeDownloadsPolicyType_validator = bv.Struct(SharedContentChangeDownloadsPolicyType) + +class SharedContentChangeInviteeRoleDetails(bb.Struct): + """ + Changed access type of invitee to shared file/folder before invite was + accepted. + + :ivar team_log.SharedContentChangeInviteeRoleDetails.previous_access_level: + Previous access level. Might be missing due to historical data gap. + :ivar team_log.SharedContentChangeInviteeRoleDetails.new_access_level: New + access level. + :ivar team_log.SharedContentChangeInviteeRoleDetails.invitee: The invitee + whose role was changed. + """ + + __slots__ = [ + '_previous_access_level_value', + '_previous_access_level_present', + '_new_access_level_value', + '_new_access_level_present', + '_invitee_value', + '_invitee_present', + ] + + _has_required_fields = True + + def __init__(self, + new_access_level=None, + invitee=None, + previous_access_level=None): + self._previous_access_level_value = None + self._previous_access_level_present = False + self._new_access_level_value = None + self._new_access_level_present = False + self._invitee_value = None + self._invitee_present = False + if previous_access_level is not None: + self.previous_access_level = previous_access_level + if new_access_level is not None: + self.new_access_level = new_access_level + if invitee is not None: + self.invitee = invitee @property - def original_folder_name(self): + def previous_access_level(self): """ - Original shared folder name. + Previous access level. Might be missing due to historical data gap. - :rtype: str + :rtype: sharing.AccessLevel """ - if self._original_folder_name_present: - return self._original_folder_name_value + if self._previous_access_level_present: + return self._previous_access_level_value else: - raise AttributeError("missing required field 'original_folder_name'") + return None - @original_folder_name.setter - def original_folder_name(self, val): - val = self._original_folder_name_validator.validate(val) - self._original_folder_name_value = val - self._original_folder_name_present = True + @previous_access_level.setter + def previous_access_level(self, val): + if val is None: + del self.previous_access_level + return + self._previous_access_level_validator.validate_type_only(val) + self._previous_access_level_value = val + self._previous_access_level_present = True - @original_folder_name.deleter - def original_folder_name(self): - self._original_folder_name_value = None - self._original_folder_name_present = False + @previous_access_level.deleter + def previous_access_level(self): + self._previous_access_level_value = None + self._previous_access_level_present = False @property - def token_key(self): + def new_access_level(self): """ - Shared link token key. + New access level. - :rtype: str + :rtype: sharing.AccessLevel """ - if self._token_key_present: - return self._token_key_value + if self._new_access_level_present: + return self._new_access_level_value else: - return None + raise AttributeError("missing required field 'new_access_level'") - @token_key.setter - def token_key(self, val): - if val is None: - del self.token_key - return - val = self._token_key_validator.validate(val) - self._token_key_value = val - self._token_key_present = True + @new_access_level.setter + def new_access_level(self, val): + self._new_access_level_validator.validate_type_only(val) + self._new_access_level_value = val + self._new_access_level_present = True - @token_key.deleter - def token_key(self): - self._token_key_value = None - self._token_key_present = False + @new_access_level.deleter + def new_access_level(self): + self._new_access_level_value = None + self._new_access_level_present = False @property - def sharing_permission(self): + def invitee(self): """ - Sharing permission. Might be missing due to historical data gap. + The invitee whose role was changed. :rtype: str """ - if self._sharing_permission_present: - return self._sharing_permission_value + if self._invitee_present: + return self._invitee_value else: - return None + raise AttributeError("missing required field 'invitee'") - @sharing_permission.setter - def sharing_permission(self, val): - if val is None: - del self.sharing_permission - return - val = self._sharing_permission_validator.validate(val) - self._sharing_permission_value = val - self._sharing_permission_present = True + @invitee.setter + def invitee(self, val): + val = self._invitee_validator.validate(val) + self._invitee_value = val + self._invitee_present = True - @sharing_permission.deleter - def sharing_permission(self): - self._sharing_permission_value = None - self._sharing_permission_present = False + @invitee.deleter + def invitee(self): + self._invitee_value = None + self._invitee_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamJoinFromOobLinkDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeInviteeRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamJoinFromOobLinkDetails(target_asset_index={!r}, original_folder_name={!r}, token_key={!r}, sharing_permission={!r})'.format( - self._target_asset_index_value, - self._original_folder_name_value, - self._token_key_value, - self._sharing_permission_value, + return 'SharedContentChangeInviteeRoleDetails(new_access_level={!r}, invitee={!r}, previous_access_level={!r})'.format( + self._new_access_level_value, + self._invitee_value, + self._previous_access_level_value, ) -SfTeamJoinFromOobLinkDetails_validator = bv.Struct(SfTeamJoinFromOobLinkDetails) +SharedContentChangeInviteeRoleDetails_validator = bv.Struct(SharedContentChangeInviteeRoleDetails) -class SfTeamJoinFromOobLinkType(bb.Struct): +class SharedContentChangeInviteeRoleType(bb.Struct): __slots__ = [ '_description_value', @@ -52967,16 +73315,107 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamJoinFromOobLinkType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeInviteeRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamJoinFromOobLinkType(description={!r})'.format( + return 'SharedContentChangeInviteeRoleType(description={!r})'.format( self._description_value, ) -SfTeamJoinFromOobLinkType_validator = bv.Struct(SfTeamJoinFromOobLinkType) +SharedContentChangeInviteeRoleType_validator = bv.Struct(SharedContentChangeInviteeRoleType) -class SfTeamJoinType(bb.Struct): +class SharedContentChangeLinkAudienceDetails(bb.Struct): + """ + Changed link audience of shared file/folder. + + :ivar team_log.SharedContentChangeLinkAudienceDetails.new_value: New link + audience value. + :ivar team_log.SharedContentChangeLinkAudienceDetails.previous_value: + Previous link audience value. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New link audience value. + + :rtype: sharing.LinkAudience + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous link audience value. + + :rtype: sharing.LinkAudience + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentChangeLinkAudienceDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentChangeLinkAudienceDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) + +SharedContentChangeLinkAudienceDetails_validator = bv.Struct(SharedContentChangeLinkAudienceDetails) + +class SharedContentChangeLinkAudienceType(bb.Struct): __slots__ = [ '_description_value', @@ -53014,104 +73453,182 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamJoinType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeLinkAudienceType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamJoinType(description={!r})'.format( + return 'SharedContentChangeLinkAudienceType(description={!r})'.format( self._description_value, ) -SfTeamJoinType_validator = bv.Struct(SfTeamJoinType) +SharedContentChangeLinkAudienceType_validator = bv.Struct(SharedContentChangeLinkAudienceType) -class SfTeamUninviteDetails(bb.Struct): +class SharedContentChangeLinkExpiryDetails(bb.Struct): """ - Unshared folder with team member. + Changed link expiration of shared file/folder. - :ivar team_log.SfTeamUninviteDetails.target_asset_index: Target asset - position in the Assets list. - :ivar team_log.SfTeamUninviteDetails.original_folder_name: Original shared - folder name. + :ivar team_log.SharedContentChangeLinkExpiryDetails.new_value: New shared + content link expiration date. Might be missing due to historical data + gap. + :ivar team_log.SharedContentChangeLinkExpiryDetails.previous_value: Previous + shared content link expiration date. Might be missing due to historical + data gap. """ __slots__ = [ - '_target_asset_index_value', - '_target_asset_index_present', - '_original_folder_name_value', - '_original_folder_name_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - target_asset_index=None, - original_folder_name=None): - self._target_asset_index_value = None - self._target_asset_index_present = False - self._original_folder_name_value = None - self._original_folder_name_present = False - if target_asset_index is not None: - self.target_asset_index = target_asset_index - if original_folder_name is not None: - self.original_folder_name = original_folder_name + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def target_asset_index(self): + def new_value(self): """ - Target asset position in the Assets list. + New shared content link expiration date. Might be missing due to + historical data gap. - :rtype: int + :rtype: datetime.datetime """ - if self._target_asset_index_present: - return self._target_asset_index_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'target_asset_index'") + return None - @target_asset_index.setter - def target_asset_index(self, val): - val = self._target_asset_index_validator.validate(val) - self._target_asset_index_value = val - self._target_asset_index_present = True + @new_value.setter + def new_value(self, val): + if val is None: + del self.new_value + return + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @target_asset_index.deleter - def target_asset_index(self): - self._target_asset_index_value = None - self._target_asset_index_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False @property - def original_folder_name(self): + def previous_value(self): """ - Original shared folder name. + Previous shared content link expiration date. Might be missing due to + historical data gap. + + :rtype: datetime.datetime + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentChangeLinkExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentChangeLinkExpiryDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) + +SharedContentChangeLinkExpiryDetails_validator = bv.Struct(SharedContentChangeLinkExpiryDetails) + +class SharedContentChangeLinkExpiryType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ :rtype: str """ - if self._original_folder_name_present: - return self._original_folder_name_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'original_folder_name'") + raise AttributeError("missing required field 'description'") - @original_folder_name.setter - def original_folder_name(self, val): - val = self._original_folder_name_validator.validate(val) - self._original_folder_name_value = val - self._original_folder_name_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @original_folder_name.deleter - def original_folder_name(self): - self._original_folder_name_value = None - self._original_folder_name_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamUninviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeLinkExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamUninviteDetails(target_asset_index={!r}, original_folder_name={!r})'.format( - self._target_asset_index_value, - self._original_folder_name_value, + return 'SharedContentChangeLinkExpiryType(description={!r})'.format( + self._description_value, ) -SfTeamUninviteDetails_validator = bv.Struct(SfTeamUninviteDetails) +SharedContentChangeLinkExpiryType_validator = bv.Struct(SharedContentChangeLinkExpiryType) -class SfTeamUninviteType(bb.Struct): +class SharedContentChangeLinkPasswordDetails(bb.Struct): + """ + Changed link password of shared file/folder. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentChangeLinkPasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentChangeLinkPasswordDetails()' + +SharedContentChangeLinkPasswordDetails_validator = bv.Struct(SharedContentChangeLinkPasswordDetails) + +class SharedContentChangeLinkPasswordType(bb.Struct): __slots__ = [ '_description_value', @@ -53149,103 +73666,107 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SfTeamUninviteType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeLinkPasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SfTeamUninviteType(description={!r})'.format( + return 'SharedContentChangeLinkPasswordType(description={!r})'.format( self._description_value, ) -SfTeamUninviteType_validator = bv.Struct(SfTeamUninviteType) +SharedContentChangeLinkPasswordType_validator = bv.Struct(SharedContentChangeLinkPasswordType) -class SharedContentAddInviteesDetails(bb.Struct): +class SharedContentChangeMemberRoleDetails(bb.Struct): """ - Invited user to Dropbox and added them to shared file/folder. + Changed access type of shared file/folder member. - :ivar team_log.SharedContentAddInviteesDetails.shared_content_access_level: - Shared content access level. - :ivar team_log.SharedContentAddInviteesDetails.invitees: A list of invitees. + :ivar team_log.SharedContentChangeMemberRoleDetails.previous_access_level: + Previous access level. Might be missing due to historical data gap. + :ivar team_log.SharedContentChangeMemberRoleDetails.new_access_level: New + access level. """ __slots__ = [ - '_shared_content_access_level_value', - '_shared_content_access_level_present', - '_invitees_value', - '_invitees_present', + '_previous_access_level_value', + '_previous_access_level_present', + '_new_access_level_value', + '_new_access_level_present', ] _has_required_fields = True def __init__(self, - shared_content_access_level=None, - invitees=None): - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False - self._invitees_value = None - self._invitees_present = False - if shared_content_access_level is not None: - self.shared_content_access_level = shared_content_access_level - if invitees is not None: - self.invitees = invitees + new_access_level=None, + previous_access_level=None): + self._previous_access_level_value = None + self._previous_access_level_present = False + self._new_access_level_value = None + self._new_access_level_present = False + if previous_access_level is not None: + self.previous_access_level = previous_access_level + if new_access_level is not None: + self.new_access_level = new_access_level @property - def shared_content_access_level(self): + def previous_access_level(self): """ - Shared content access level. + Previous access level. Might be missing due to historical data gap. :rtype: sharing.AccessLevel """ - if self._shared_content_access_level_present: - return self._shared_content_access_level_value + if self._previous_access_level_present: + return self._previous_access_level_value else: - raise AttributeError("missing required field 'shared_content_access_level'") + return None - @shared_content_access_level.setter - def shared_content_access_level(self, val): - self._shared_content_access_level_validator.validate_type_only(val) - self._shared_content_access_level_value = val - self._shared_content_access_level_present = True + @previous_access_level.setter + def previous_access_level(self, val): + if val is None: + del self.previous_access_level + return + self._previous_access_level_validator.validate_type_only(val) + self._previous_access_level_value = val + self._previous_access_level_present = True - @shared_content_access_level.deleter - def shared_content_access_level(self): - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False + @previous_access_level.deleter + def previous_access_level(self): + self._previous_access_level_value = None + self._previous_access_level_present = False @property - def invitees(self): + def new_access_level(self): """ - A list of invitees. + New access level. - :rtype: list of [str] + :rtype: sharing.AccessLevel """ - if self._invitees_present: - return self._invitees_value + if self._new_access_level_present: + return self._new_access_level_value else: - raise AttributeError("missing required field 'invitees'") + raise AttributeError("missing required field 'new_access_level'") - @invitees.setter - def invitees(self, val): - val = self._invitees_validator.validate(val) - self._invitees_value = val - self._invitees_present = True + @new_access_level.setter + def new_access_level(self, val): + self._new_access_level_validator.validate_type_only(val) + self._new_access_level_value = val + self._new_access_level_present = True - @invitees.deleter - def invitees(self): - self._invitees_value = None - self._invitees_present = False + @new_access_level.deleter + def new_access_level(self): + self._new_access_level_value = None + self._new_access_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddInviteesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeMemberRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddInviteesDetails(shared_content_access_level={!r}, invitees={!r})'.format( - self._shared_content_access_level_value, - self._invitees_value, + return 'SharedContentChangeMemberRoleDetails(new_access_level={!r}, previous_access_level={!r})'.format( + self._new_access_level_value, + self._previous_access_level_value, ) -SharedContentAddInviteesDetails_validator = bv.Struct(SharedContentAddInviteesDetails) +SharedContentChangeMemberRoleDetails_validator = bv.Struct(SharedContentChangeMemberRoleDetails) -class SharedContentAddInviteesType(bb.Struct): +class SharedContentChangeMemberRoleType(bb.Struct): __slots__ = [ '_description_value', @@ -53283,57 +73804,61 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddInviteesType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeMemberRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddInviteesType(description={!r})'.format( + return 'SharedContentChangeMemberRoleType(description={!r})'.format( self._description_value, ) -SharedContentAddInviteesType_validator = bv.Struct(SharedContentAddInviteesType) +SharedContentChangeMemberRoleType_validator = bv.Struct(SharedContentChangeMemberRoleType) -class SharedContentAddLinkExpiryDetails(bb.Struct): +class SharedContentChangeViewerInfoPolicyDetails(bb.Struct): """ - Added expiration date to link for shared file/folder. + Changed whether members can see who viewed shared file/folder. - :ivar team_log.SharedContentAddLinkExpiryDetails.new_value: New shared - content link expiration date. Might be missing due to historical data - gap. + :ivar team_log.SharedContentChangeViewerInfoPolicyDetails.new_value: New + viewer info policy. + :ivar team_log.SharedContentChangeViewerInfoPolicyDetails.previous_value: + Previous view info policy. Might be missing due to historical data gap. """ __slots__ = [ '_new_value_value', '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - new_value=None): + new_value=None, + previous_value=None): self._new_value_value = None self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False if new_value is not None: self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property def new_value(self): """ - New shared content link expiration date. Might be missing due to - historical data gap. + New viewer info policy. - :rtype: datetime.datetime + :rtype: sharing.ViewerInfoPolicy """ if self._new_value_present: return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") @new_value.setter def new_value(self, val): - if val is None: - del self.new_value - return - val = self._new_value_validator.validate(val) + self._new_value_validator.validate_type_only(val) self._new_value_value = val self._new_value_present = True @@ -53342,17 +73867,44 @@ def new_value(self): self._new_value_value = None self._new_value_present = False + @property + def previous_value(self): + """ + Previous view info policy. Might be missing due to historical data gap. + + :rtype: sharing.ViewerInfoPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddLinkExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeViewerInfoPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddLinkExpiryDetails(new_value={!r})'.format( + return 'SharedContentChangeViewerInfoPolicyDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, + self._previous_value_value, ) -SharedContentAddLinkExpiryDetails_validator = bv.Struct(SharedContentAddLinkExpiryDetails) +SharedContentChangeViewerInfoPolicyDetails_validator = bv.Struct(SharedContentChangeViewerInfoPolicyDetails) -class SharedContentAddLinkExpiryType(bb.Struct): +class SharedContentChangeViewerInfoPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -53390,37 +73942,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddLinkExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentChangeViewerInfoPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddLinkExpiryType(description={!r})'.format( + return 'SharedContentChangeViewerInfoPolicyType(description={!r})'.format( self._description_value, ) -SharedContentAddLinkExpiryType_validator = bv.Struct(SharedContentAddLinkExpiryType) +SharedContentChangeViewerInfoPolicyType_validator = bv.Struct(SharedContentChangeViewerInfoPolicyType) -class SharedContentAddLinkPasswordDetails(bb.Struct): +class SharedContentClaimInvitationDetails(bb.Struct): """ - Added password to link for shared file/folder. + Acquired membership of shared file/folder by accepting invite. + + :ivar team_log.SharedContentClaimInvitationDetails.shared_content_link: + Shared content link. """ __slots__ = [ + '_shared_content_link_value', + '_shared_content_link_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + shared_content_link=None): + self._shared_content_link_value = None + self._shared_content_link_present = False + if shared_content_link is not None: + self.shared_content_link = shared_content_link + + @property + def shared_content_link(self): + """ + Shared content link. + + :rtype: str + """ + if self._shared_content_link_present: + return self._shared_content_link_value + else: + return None + + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True + + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddLinkPasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentClaimInvitationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddLinkPasswordDetails()' + return 'SharedContentClaimInvitationDetails(shared_content_link={!r})'.format( + self._shared_content_link_value, + ) -SharedContentAddLinkPasswordDetails_validator = bv.Struct(SharedContentAddLinkPasswordDetails) +SharedContentClaimInvitationDetails_validator = bv.Struct(SharedContentClaimInvitationDetails) -class SharedContentAddLinkPasswordType(bb.Struct): +class SharedContentClaimInvitationType(bb.Struct): __slots__ = [ '_description_value', @@ -53458,36 +74047,112 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddLinkPasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentClaimInvitationType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddLinkPasswordType(description={!r})'.format( + return 'SharedContentClaimInvitationType(description={!r})'.format( self._description_value, ) -SharedContentAddLinkPasswordType_validator = bv.Struct(SharedContentAddLinkPasswordType) +SharedContentClaimInvitationType_validator = bv.Struct(SharedContentClaimInvitationType) -class SharedContentAddMemberDetails(bb.Struct): +class SharedContentCopyDetails(bb.Struct): """ - Added users and/or groups to shared file/folder. + Copied shared file/folder to own Dropbox. - :ivar team_log.SharedContentAddMemberDetails.shared_content_access_level: - Shared content access level. + :ivar team_log.SharedContentCopyDetails.shared_content_link: Shared content + link. + :ivar team_log.SharedContentCopyDetails.shared_content_owner: The shared + content owner. + :ivar team_log.SharedContentCopyDetails.shared_content_access_level: Shared + content access level. + :ivar team_log.SharedContentCopyDetails.destination_path: The path where the + member saved the content. """ __slots__ = [ + '_shared_content_link_value', + '_shared_content_link_present', + '_shared_content_owner_value', + '_shared_content_owner_present', '_shared_content_access_level_value', '_shared_content_access_level_present', + '_destination_path_value', + '_destination_path_present', ] _has_required_fields = True def __init__(self, - shared_content_access_level=None): + shared_content_link=None, + shared_content_access_level=None, + destination_path=None, + shared_content_owner=None): + self._shared_content_link_value = None + self._shared_content_link_present = False + self._shared_content_owner_value = None + self._shared_content_owner_present = False self._shared_content_access_level_value = None self._shared_content_access_level_present = False + self._destination_path_value = None + self._destination_path_present = False + if shared_content_link is not None: + self.shared_content_link = shared_content_link + if shared_content_owner is not None: + self.shared_content_owner = shared_content_owner if shared_content_access_level is not None: self.shared_content_access_level = shared_content_access_level + if destination_path is not None: + self.destination_path = destination_path + + @property + def shared_content_link(self): + """ + Shared content link. + + :rtype: str + """ + if self._shared_content_link_present: + return self._shared_content_link_value + else: + raise AttributeError("missing required field 'shared_content_link'") + + @shared_content_link.setter + def shared_content_link(self, val): + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True + + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False + + @property + def shared_content_owner(self): + """ + The shared content owner. + + :rtype: UserLogInfo + """ + if self._shared_content_owner_present: + return self._shared_content_owner_value + else: + return None + + @shared_content_owner.setter + def shared_content_owner(self, val): + if val is None: + del self.shared_content_owner + return + self._shared_content_owner_validator.validate_type_only(val) + self._shared_content_owner_value = val + self._shared_content_owner_present = True + + @shared_content_owner.deleter + def shared_content_owner(self): + self._shared_content_owner_value = None + self._shared_content_owner_present = False @property def shared_content_access_level(self): @@ -53512,17 +74177,43 @@ def shared_content_access_level(self): self._shared_content_access_level_value = None self._shared_content_access_level_present = False + @property + def destination_path(self): + """ + The path where the member saved the content. + + :rtype: str + """ + if self._destination_path_present: + return self._destination_path_value + else: + raise AttributeError("missing required field 'destination_path'") + + @destination_path.setter + def destination_path(self, val): + val = self._destination_path_validator.validate(val) + self._destination_path_value = val + self._destination_path_present = True + + @destination_path.deleter + def destination_path(self): + self._destination_path_value = None + self._destination_path_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentCopyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddMemberDetails(shared_content_access_level={!r})'.format( + return 'SharedContentCopyDetails(shared_content_link={!r}, shared_content_access_level={!r}, destination_path={!r}, shared_content_owner={!r})'.format( + self._shared_content_link_value, self._shared_content_access_level_value, + self._destination_path_value, + self._shared_content_owner_value, ) -SharedContentAddMemberDetails_validator = bv.Struct(SharedContentAddMemberDetails) +SharedContentCopyDetails_validator = bv.Struct(SharedContentCopyDetails) -class SharedContentAddMemberType(bb.Struct): +class SharedContentCopyType(bb.Struct): __slots__ = [ '_description_value', @@ -53560,107 +74251,140 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentAddMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentCopyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentAddMemberType(description={!r})'.format( + return 'SharedContentCopyType(description={!r})'.format( self._description_value, ) -SharedContentAddMemberType_validator = bv.Struct(SharedContentAddMemberType) +SharedContentCopyType_validator = bv.Struct(SharedContentCopyType) -class SharedContentChangeDownloadsPolicyDetails(bb.Struct): +class SharedContentDownloadDetails(bb.Struct): """ - Changed whether members can download shared file/folder. + Downloaded shared file/folder. - :ivar team_log.SharedContentChangeDownloadsPolicyDetails.new_value: New - downloads policy. - :ivar team_log.SharedContentChangeDownloadsPolicyDetails.previous_value: - Previous downloads policy. Might be missing due to historical data gap. + :ivar team_log.SharedContentDownloadDetails.shared_content_link: Shared + content link. + :ivar team_log.SharedContentDownloadDetails.shared_content_owner: The shared + content owner. + :ivar team_log.SharedContentDownloadDetails.shared_content_access_level: + Shared content access level. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_shared_content_link_value', + '_shared_content_link_present', + '_shared_content_owner_value', + '_shared_content_owner_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + shared_content_link=None, + shared_content_access_level=None, + shared_content_owner=None): + self._shared_content_link_value = None + self._shared_content_link_present = False + self._shared_content_owner_value = None + self._shared_content_owner_present = False + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + if shared_content_link is not None: + self.shared_content_link = shared_content_link + if shared_content_owner is not None: + self.shared_content_owner = shared_content_owner + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level @property - def new_value(self): + def shared_content_link(self): """ - New downloads policy. + Shared content link. - :rtype: DownloadPolicyType + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._shared_content_link_present: + return self._shared_content_link_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'shared_content_link'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @shared_content_link.setter + def shared_content_link(self, val): + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False @property - def previous_value(self): + def shared_content_owner(self): """ - Previous downloads policy. Might be missing due to historical data gap. + The shared content owner. - :rtype: DownloadPolicyType + :rtype: UserLogInfo """ - if self._previous_value_present: - return self._previous_value_value + if self._shared_content_owner_present: + return self._shared_content_owner_value else: return None - @previous_value.setter - def previous_value(self, val): + @shared_content_owner.setter + def shared_content_owner(self, val): if val is None: - del self.previous_value + del self.shared_content_owner return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + self._shared_content_owner_validator.validate_type_only(val) + self._shared_content_owner_value = val + self._shared_content_owner_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @shared_content_owner.deleter + def shared_content_owner(self): + self._shared_content_owner_value = None + self._shared_content_owner_present = False + + @property + def shared_content_access_level(self): + """ + Shared content access level. + + :rtype: sharing.AccessLevel + """ + if self._shared_content_access_level_present: + return self._shared_content_access_level_value + else: + raise AttributeError("missing required field 'shared_content_access_level'") + + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True + + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeDownloadsPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeDownloadsPolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'SharedContentDownloadDetails(shared_content_link={!r}, shared_content_access_level={!r}, shared_content_owner={!r})'.format( + self._shared_content_link_value, + self._shared_content_access_level_value, + self._shared_content_owner_value, ) -SharedContentChangeDownloadsPolicyDetails_validator = bv.Struct(SharedContentChangeDownloadsPolicyDetails) +SharedContentDownloadDetails_validator = bv.Struct(SharedContentDownloadDetails) -class SharedContentChangeDownloadsPolicyType(bb.Struct): +class SharedContentDownloadType(bb.Struct): __slots__ = [ '_description_value', @@ -53698,141 +74422,139 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeDownloadsPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeDownloadsPolicyType(description={!r})'.format( + return 'SharedContentDownloadType(description={!r})'.format( self._description_value, ) -SharedContentChangeDownloadsPolicyType_validator = bv.Struct(SharedContentChangeDownloadsPolicyType) +SharedContentDownloadType_validator = bv.Struct(SharedContentDownloadType) -class SharedContentChangeInviteeRoleDetails(bb.Struct): +class SharedContentRelinquishMembershipDetails(bb.Struct): """ - Changed access type of invitee to shared file/folder before invite was - accepted. - - :ivar team_log.SharedContentChangeInviteeRoleDetails.previous_access_level: - Previous access level. Might be missing due to historical data gap. - :ivar team_log.SharedContentChangeInviteeRoleDetails.new_access_level: New - access level. - :ivar team_log.SharedContentChangeInviteeRoleDetails.invitee: The invitee - whose role was changed. + Left shared file/folder. """ __slots__ = [ - '_previous_access_level_value', - '_previous_access_level_present', - '_new_access_level_value', - '_new_access_level_present', - '_invitee_value', - '_invitee_present', + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentRelinquishMembershipDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentRelinquishMembershipDetails()' + +SharedContentRelinquishMembershipDetails_validator = bv.Struct(SharedContentRelinquishMembershipDetails) + +class SharedContentRelinquishMembershipType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', ] _has_required_fields = True def __init__(self, - new_access_level=None, - invitee=None, - previous_access_level=None): - self._previous_access_level_value = None - self._previous_access_level_present = False - self._new_access_level_value = None - self._new_access_level_present = False - self._invitee_value = None - self._invitee_present = False - if previous_access_level is not None: - self.previous_access_level = previous_access_level - if new_access_level is not None: - self.new_access_level = new_access_level - if invitee is not None: - self.invitee = invitee + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def previous_access_level(self): + def description(self): """ - Previous access level. Might be missing due to historical data gap. - - :rtype: sharing.AccessLevel + :rtype: str """ - if self._previous_access_level_present: - return self._previous_access_level_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentRelinquishMembershipType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentRelinquishMembershipType(description={!r})'.format( + self._description_value, + ) - @previous_access_level.setter - def previous_access_level(self, val): - if val is None: - del self.previous_access_level - return - self._previous_access_level_validator.validate_type_only(val) - self._previous_access_level_value = val - self._previous_access_level_present = True +SharedContentRelinquishMembershipType_validator = bv.Struct(SharedContentRelinquishMembershipType) - @previous_access_level.deleter - def previous_access_level(self): - self._previous_access_level_value = None - self._previous_access_level_present = False +class SharedContentRemoveInviteesDetails(bb.Struct): + """ + Removed invitee from shared file/folder before invite was accepted. - @property - def new_access_level(self): - """ - New access level. + :ivar team_log.SharedContentRemoveInviteesDetails.invitees: A list of + invitees. + """ - :rtype: sharing.AccessLevel - """ - if self._new_access_level_present: - return self._new_access_level_value - else: - raise AttributeError("missing required field 'new_access_level'") + __slots__ = [ + '_invitees_value', + '_invitees_present', + ] - @new_access_level.setter - def new_access_level(self, val): - self._new_access_level_validator.validate_type_only(val) - self._new_access_level_value = val - self._new_access_level_present = True + _has_required_fields = True - @new_access_level.deleter - def new_access_level(self): - self._new_access_level_value = None - self._new_access_level_present = False + def __init__(self, + invitees=None): + self._invitees_value = None + self._invitees_present = False + if invitees is not None: + self.invitees = invitees @property - def invitee(self): + def invitees(self): """ - The invitee whose role was changed. + A list of invitees. - :rtype: str + :rtype: list of [str] """ - if self._invitee_present: - return self._invitee_value + if self._invitees_present: + return self._invitees_value else: - raise AttributeError("missing required field 'invitee'") + raise AttributeError("missing required field 'invitees'") - @invitee.setter - def invitee(self, val): - val = self._invitee_validator.validate(val) - self._invitee_value = val - self._invitee_present = True + @invitees.setter + def invitees(self, val): + val = self._invitees_validator.validate(val) + self._invitees_value = val + self._invitees_present = True - @invitee.deleter - def invitee(self): - self._invitee_value = None - self._invitee_present = False + @invitees.deleter + def invitees(self): + self._invitees_value = None + self._invitees_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeInviteeRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRemoveInviteesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeInviteeRoleDetails(new_access_level={!r}, invitee={!r}, previous_access_level={!r})'.format( - self._new_access_level_value, - self._invitee_value, - self._previous_access_level_value, + return 'SharedContentRemoveInviteesDetails(invitees={!r})'.format( + self._invitees_value, ) -SharedContentChangeInviteeRoleDetails_validator = bv.Struct(SharedContentChangeInviteeRoleDetails) +SharedContentRemoveInviteesDetails_validator = bv.Struct(SharedContentRemoveInviteesDetails) -class SharedContentChangeInviteeRoleType(bb.Struct): +class SharedContentRemoveInviteesType(bb.Struct): __slots__ = [ '_description_value', @@ -53870,75 +74592,45 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeInviteeRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRemoveInviteesType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeInviteeRoleType(description={!r})'.format( + return 'SharedContentRemoveInviteesType(description={!r})'.format( self._description_value, ) -SharedContentChangeInviteeRoleType_validator = bv.Struct(SharedContentChangeInviteeRoleType) +SharedContentRemoveInviteesType_validator = bv.Struct(SharedContentRemoveInviteesType) -class SharedContentChangeLinkAudienceDetails(bb.Struct): +class SharedContentRemoveLinkExpiryDetails(bb.Struct): """ - Changed link audience of shared file/folder. + Removed link expiration date of shared file/folder. - :ivar team_log.SharedContentChangeLinkAudienceDetails.new_value: New link - audience value. - :ivar team_log.SharedContentChangeLinkAudienceDetails.previous_value: - Previous link audience value. + :ivar team_log.SharedContentRemoveLinkExpiryDetails.previous_value: Previous + shared content link expiration date. Might be missing due to historical + data gap. """ __slots__ = [ - '_new_value_value', - '_new_value_present', '_previous_value_value', '_previous_value_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - new_value=None, previous_value=None): - self._new_value_value = None - self._new_value_present = False self._previous_value_value = None self._previous_value_present = False - if new_value is not None: - self.new_value = new_value if previous_value is not None: self.previous_value = previous_value - @property - def new_value(self): - """ - New link audience value. - - :rtype: sharing.LinkAudience - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False - @property def previous_value(self): """ - Previous link audience value. + Previous shared content link expiration date. Might be missing due to + historical data gap. - :rtype: sharing.LinkAudience + :rtype: datetime.datetime """ if self._previous_value_present: return self._previous_value_value @@ -53950,7 +74642,7 @@ def previous_value(self, val): if val is None: del self.previous_value return - self._previous_value_validator.validate_type_only(val) + val = self._previous_value_validator.validate(val) self._previous_value_value = val self._previous_value_present = True @@ -53960,17 +74652,16 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeLinkAudienceDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRemoveLinkExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeLinkAudienceDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, + return 'SharedContentRemoveLinkExpiryDetails(previous_value={!r})'.format( self._previous_value_value, ) -SharedContentChangeLinkAudienceDetails_validator = bv.Struct(SharedContentChangeLinkAudienceDetails) +SharedContentRemoveLinkExpiryDetails_validator = bv.Struct(SharedContentRemoveLinkExpiryDetails) -class SharedContentChangeLinkAudienceType(bb.Struct): +class SharedContentRemoveLinkExpiryType(bb.Struct): __slots__ = [ '_description_value', @@ -54008,114 +74699,142 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeLinkAudienceType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRemoveLinkExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeLinkAudienceType(description={!r})'.format( + return 'SharedContentRemoveLinkExpiryType(description={!r})'.format( self._description_value, ) -SharedContentChangeLinkAudienceType_validator = bv.Struct(SharedContentChangeLinkAudienceType) +SharedContentRemoveLinkExpiryType_validator = bv.Struct(SharedContentRemoveLinkExpiryType) -class SharedContentChangeLinkExpiryDetails(bb.Struct): +class SharedContentRemoveLinkPasswordDetails(bb.Struct): """ - Changed link expiration of shared file/folder. - - :ivar team_log.SharedContentChangeLinkExpiryDetails.new_value: New shared - content link expiration date. Might be missing due to historical data - gap. - :ivar team_log.SharedContentChangeLinkExpiryDetails.previous_value: Previous - shared content link expiration date. Might be missing due to historical - data gap. + Removed link password of shared file/folder. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', ] _has_required_fields = False + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentRemoveLinkPasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentRemoveLinkPasswordDetails()' + +SharedContentRemoveLinkPasswordDetails_validator = bv.Struct(SharedContentRemoveLinkPasswordDetails) + +class SharedContentRemoveLinkPasswordType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description @property - def new_value(self): + def description(self): """ - New shared content link expiration date. Might be missing due to - historical data gap. - - :rtype: datetime.datetime + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._description_present: + return self._description_value else: - return None + raise AttributeError("missing required field 'description'") - @new_value.setter - def new_value(self, val): - if val is None: - del self.new_value - return - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentRemoveLinkPasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentRemoveLinkPasswordType(description={!r})'.format( + self._description_value, + ) + +SharedContentRemoveLinkPasswordType_validator = bv.Struct(SharedContentRemoveLinkPasswordType) + +class SharedContentRemoveMemberDetails(bb.Struct): + """ + Removed user/group from shared file/folder. + + :ivar team_log.SharedContentRemoveMemberDetails.shared_content_access_level: + Shared content access level. + """ + + __slots__ = [ + '_shared_content_access_level_value', + '_shared_content_access_level_present', + ] + + _has_required_fields = False + + def __init__(self, + shared_content_access_level=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level @property - def previous_value(self): + def shared_content_access_level(self): """ - Previous shared content link expiration date. Might be missing due to - historical data gap. + Shared content access level. - :rtype: datetime.datetime + :rtype: sharing.AccessLevel """ - if self._previous_value_present: - return self._previous_value_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: return None - @previous_value.setter - def previous_value(self, val): + @shared_content_access_level.setter + def shared_content_access_level(self, val): if val is None: - del self.previous_value + del self.shared_content_access_level return - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeLinkExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRemoveMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeLinkExpiryDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'SharedContentRemoveMemberDetails(shared_content_access_level={!r})'.format( + self._shared_content_access_level_value, ) -SharedContentChangeLinkExpiryDetails_validator = bv.Struct(SharedContentChangeLinkExpiryDetails) +SharedContentRemoveMemberDetails_validator = bv.Struct(SharedContentRemoveMemberDetails) -class SharedContentChangeLinkExpiryType(bb.Struct): +class SharedContentRemoveMemberType(bb.Struct): __slots__ = [ '_description_value', @@ -54153,37 +74872,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeLinkExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRemoveMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeLinkExpiryType(description={!r})'.format( + return 'SharedContentRemoveMemberType(description={!r})'.format( self._description_value, ) -SharedContentChangeLinkExpiryType_validator = bv.Struct(SharedContentChangeLinkExpiryType) +SharedContentRemoveMemberType_validator = bv.Struct(SharedContentRemoveMemberType) -class SharedContentChangeLinkPasswordDetails(bb.Struct): +class SharedContentRequestAccessDetails(bb.Struct): """ - Changed link password of shared file/folder. + Requested access to shared file/folder. + + :ivar team_log.SharedContentRequestAccessDetails.shared_content_link: Shared + content link. """ __slots__ = [ + '_shared_content_link_value', + '_shared_content_link_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + shared_content_link=None): + self._shared_content_link_value = None + self._shared_content_link_present = False + if shared_content_link is not None: + self.shared_content_link = shared_content_link + + @property + def shared_content_link(self): + """ + Shared content link. + + :rtype: str + """ + if self._shared_content_link_present: + return self._shared_content_link_value + else: + return None + + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True + + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeLinkPasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRequestAccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeLinkPasswordDetails()' + return 'SharedContentRequestAccessDetails(shared_content_link={!r})'.format( + self._shared_content_link_value, + ) -SharedContentChangeLinkPasswordDetails_validator = bv.Struct(SharedContentChangeLinkPasswordDetails) +SharedContentRequestAccessDetails_validator = bv.Struct(SharedContentRequestAccessDetails) -class SharedContentChangeLinkPasswordType(bb.Struct): +class SharedContentRequestAccessType(bb.Struct): __slots__ = [ '_description_value', @@ -54221,107 +74977,105 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeLinkPasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRequestAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeLinkPasswordType(description={!r})'.format( + return 'SharedContentRequestAccessType(description={!r})'.format( self._description_value, ) -SharedContentChangeLinkPasswordType_validator = bv.Struct(SharedContentChangeLinkPasswordType) +SharedContentRequestAccessType_validator = bv.Struct(SharedContentRequestAccessType) -class SharedContentChangeMemberRoleDetails(bb.Struct): +class SharedContentRestoreInviteesDetails(bb.Struct): """ - Changed access type of shared file/folder member. + Restored shared file/folder invitees. - :ivar team_log.SharedContentChangeMemberRoleDetails.previous_access_level: - Previous access level. Might be missing due to historical data gap. - :ivar team_log.SharedContentChangeMemberRoleDetails.new_access_level: New - access level. + :ivar + team_log.SharedContentRestoreInviteesDetails.shared_content_access_level: + Shared content access level. + :ivar team_log.SharedContentRestoreInviteesDetails.invitees: A list of + invitees. """ __slots__ = [ - '_previous_access_level_value', - '_previous_access_level_present', - '_new_access_level_value', - '_new_access_level_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_invitees_value', + '_invitees_present', ] _has_required_fields = True def __init__(self, - new_access_level=None, - previous_access_level=None): - self._previous_access_level_value = None - self._previous_access_level_present = False - self._new_access_level_value = None - self._new_access_level_present = False - if previous_access_level is not None: - self.previous_access_level = previous_access_level - if new_access_level is not None: - self.new_access_level = new_access_level + shared_content_access_level=None, + invitees=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._invitees_value = None + self._invitees_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if invitees is not None: + self.invitees = invitees @property - def previous_access_level(self): + def shared_content_access_level(self): """ - Previous access level. Might be missing due to historical data gap. + Shared content access level. :rtype: sharing.AccessLevel """ - if self._previous_access_level_present: - return self._previous_access_level_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - return None + raise AttributeError("missing required field 'shared_content_access_level'") - @previous_access_level.setter - def previous_access_level(self, val): - if val is None: - del self.previous_access_level - return - self._previous_access_level_validator.validate_type_only(val) - self._previous_access_level_value = val - self._previous_access_level_present = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - @previous_access_level.deleter - def previous_access_level(self): - self._previous_access_level_value = None - self._previous_access_level_present = False + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False @property - def new_access_level(self): + def invitees(self): """ - New access level. + A list of invitees. - :rtype: sharing.AccessLevel + :rtype: list of [str] """ - if self._new_access_level_present: - return self._new_access_level_value + if self._invitees_present: + return self._invitees_value else: - raise AttributeError("missing required field 'new_access_level'") + raise AttributeError("missing required field 'invitees'") - @new_access_level.setter - def new_access_level(self, val): - self._new_access_level_validator.validate_type_only(val) - self._new_access_level_value = val - self._new_access_level_present = True + @invitees.setter + def invitees(self, val): + val = self._invitees_validator.validate(val) + self._invitees_value = val + self._invitees_present = True - @new_access_level.deleter - def new_access_level(self): - self._new_access_level_value = None - self._new_access_level_present = False + @invitees.deleter + def invitees(self): + self._invitees_value = None + self._invitees_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeMemberRoleDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRestoreInviteesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeMemberRoleDetails(new_access_level={!r}, previous_access_level={!r})'.format( - self._new_access_level_value, - self._previous_access_level_value, + return 'SharedContentRestoreInviteesDetails(shared_content_access_level={!r}, invitees={!r})'.format( + self._shared_content_access_level_value, + self._invitees_value, ) -SharedContentChangeMemberRoleDetails_validator = bv.Struct(SharedContentChangeMemberRoleDetails) +SharedContentRestoreInviteesDetails_validator = bv.Struct(SharedContentRestoreInviteesDetails) -class SharedContentChangeMemberRoleType(bb.Struct): +class SharedContentRestoreInviteesType(bb.Struct): __slots__ = [ '_description_value', @@ -54359,107 +75113,72 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeMemberRoleType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRestoreInviteesType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeMemberRoleType(description={!r})'.format( + return 'SharedContentRestoreInviteesType(description={!r})'.format( self._description_value, ) -SharedContentChangeMemberRoleType_validator = bv.Struct(SharedContentChangeMemberRoleType) +SharedContentRestoreInviteesType_validator = bv.Struct(SharedContentRestoreInviteesType) -class SharedContentChangeViewerInfoPolicyDetails(bb.Struct): +class SharedContentRestoreMemberDetails(bb.Struct): """ - Changed whether members can see who viewed shared file/folder. + Restored users and/or groups to membership of shared file/folder. - :ivar team_log.SharedContentChangeViewerInfoPolicyDetails.new_value: New - viewer info policy. - :ivar team_log.SharedContentChangeViewerInfoPolicyDetails.previous_value: - Previous view info policy. Might be missing due to historical data gap. + :ivar + team_log.SharedContentRestoreMemberDetails.shared_content_access_level: + Shared content access level. """ - - __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + + __slots__ = [ + '_shared_content_access_level_value', + '_shared_content_access_level_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New viewer info policy. - - :rtype: sharing.ViewerInfoPolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + shared_content_access_level=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level @property - def previous_value(self): + def shared_content_access_level(self): """ - Previous view info policy. Might be missing due to historical data gap. + Shared content access level. - :rtype: sharing.ViewerInfoPolicy + :rtype: sharing.AccessLevel """ - if self._previous_value_present: - return self._previous_value_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - return None + raise AttributeError("missing required field 'shared_content_access_level'") - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeViewerInfoPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRestoreMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeViewerInfoPolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'SharedContentRestoreMemberDetails(shared_content_access_level={!r})'.format( + self._shared_content_access_level_value, ) -SharedContentChangeViewerInfoPolicyDetails_validator = bv.Struct(SharedContentChangeViewerInfoPolicyDetails) +SharedContentRestoreMemberDetails_validator = bv.Struct(SharedContentRestoreMemberDetails) -class SharedContentChangeViewerInfoPolicyType(bb.Struct): +class SharedContentRestoreMemberType(bb.Struct): __slots__ = [ '_description_value', @@ -54497,74 +75216,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentChangeViewerInfoPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentRestoreMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentChangeViewerInfoPolicyType(description={!r})'.format( + return 'SharedContentRestoreMemberType(description={!r})'.format( self._description_value, ) -SharedContentChangeViewerInfoPolicyType_validator = bv.Struct(SharedContentChangeViewerInfoPolicyType) +SharedContentRestoreMemberType_validator = bv.Struct(SharedContentRestoreMemberType) -class SharedContentClaimInvitationDetails(bb.Struct): +class SharedContentUnshareDetails(bb.Struct): """ - Acquired membership of shared file/folder by accepting invite. - - :ivar team_log.SharedContentClaimInvitationDetails.shared_content_link: - Shared content link. + Unshared file/folder by clearing membership. """ __slots__ = [ - '_shared_content_link_value', - '_shared_content_link_present', ] _has_required_fields = False - def __init__(self, - shared_content_link=None): - self._shared_content_link_value = None - self._shared_content_link_present = False - if shared_content_link is not None: - self.shared_content_link = shared_content_link - - @property - def shared_content_link(self): - """ - Shared content link. - - :rtype: str - """ - if self._shared_content_link_present: - return self._shared_content_link_value - else: - return None - - @shared_content_link.setter - def shared_content_link(self, val): - if val is None: - del self.shared_content_link - return - val = self._shared_content_link_validator.validate(val) - self._shared_content_link_value = val - self._shared_content_link_present = True - - @shared_content_link.deleter - def shared_content_link(self): - self._shared_content_link_value = None - self._shared_content_link_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentClaimInvitationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentUnshareDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentClaimInvitationDetails(shared_content_link={!r})'.format( - self._shared_content_link_value, - ) + return 'SharedContentUnshareDetails()' -SharedContentClaimInvitationDetails_validator = bv.Struct(SharedContentClaimInvitationDetails) +SharedContentUnshareDetails_validator = bv.Struct(SharedContentUnshareDetails) -class SharedContentClaimInvitationType(bb.Struct): +class SharedContentUnshareType(bb.Struct): __slots__ = [ '_description_value', @@ -54602,27 +75284,25 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentClaimInvitationType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedContentUnshareType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentClaimInvitationType(description={!r})'.format( + return 'SharedContentUnshareType(description={!r})'.format( self._description_value, ) -SharedContentClaimInvitationType_validator = bv.Struct(SharedContentClaimInvitationType) +SharedContentUnshareType_validator = bv.Struct(SharedContentUnshareType) -class SharedContentCopyDetails(bb.Struct): +class SharedContentViewDetails(bb.Struct): """ - Copied shared file/folder to own Dropbox. + Previewed shared file/folder. - :ivar team_log.SharedContentCopyDetails.shared_content_link: Shared content + :ivar team_log.SharedContentViewDetails.shared_content_link: Shared content link. - :ivar team_log.SharedContentCopyDetails.shared_content_owner: The shared + :ivar team_log.SharedContentViewDetails.shared_content_owner: The shared content owner. - :ivar team_log.SharedContentCopyDetails.shared_content_access_level: Shared + :ivar team_log.SharedContentViewDetails.shared_content_access_level: Shared content access level. - :ivar team_log.SharedContentCopyDetails.destination_path: The path where the - member saved the content. """ __slots__ = [ @@ -54632,8 +75312,6 @@ class SharedContentCopyDetails(bb.Struct): '_shared_content_owner_present', '_shared_content_access_level_value', '_shared_content_access_level_present', - '_destination_path_value', - '_destination_path_present', ] _has_required_fields = True @@ -54641,7 +75319,6 @@ class SharedContentCopyDetails(bb.Struct): def __init__(self, shared_content_link=None, shared_content_access_level=None, - destination_path=None, shared_content_owner=None): self._shared_content_link_value = None self._shared_content_link_present = False @@ -54649,16 +75326,12 @@ def __init__(self, self._shared_content_owner_present = False self._shared_content_access_level_value = None self._shared_content_access_level_present = False - self._destination_path_value = None - self._destination_path_present = False if shared_content_link is not None: self.shared_content_link = shared_content_link if shared_content_owner is not None: self.shared_content_owner = shared_content_owner if shared_content_access_level is not None: self.shared_content_access_level = shared_content_access_level - if destination_path is not None: - self.destination_path = destination_path @property def shared_content_link(self): @@ -54732,43 +75405,299 @@ def shared_content_access_level(self): self._shared_content_access_level_value = None self._shared_content_access_level_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentViewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentViewDetails(shared_content_link={!r}, shared_content_access_level={!r}, shared_content_owner={!r})'.format( + self._shared_content_link_value, + self._shared_content_access_level_value, + self._shared_content_owner_value, + ) + +SharedContentViewDetails_validator = bv.Struct(SharedContentViewDetails) + +class SharedContentViewType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + @property - def destination_path(self): + def description(self): """ - The path where the member saved the content. + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedContentViewType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedContentViewType(description={!r})'.format( + self._description_value, + ) + +SharedContentViewType_validator = bv.Struct(SharedContentViewType) + +class SharedFolderChangeLinkPolicyDetails(bb.Struct): + """ + Changed who can access shared folder via link. + + :ivar team_log.SharedFolderChangeLinkPolicyDetails.new_value: New shared + folder link policy. + :ivar team_log.SharedFolderChangeLinkPolicyDetails.previous_value: Previous + shared folder link policy. Might be missing due to historical data gap. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New shared folder link policy. + :rtype: sharing.SharedLinkPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous shared folder link policy. Might be missing due to historical + data gap. + + :rtype: sharing.SharedLinkPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedFolderChangeLinkPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedFolderChangeLinkPolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) + +SharedFolderChangeLinkPolicyDetails_validator = bv.Struct(SharedFolderChangeLinkPolicyDetails) + +class SharedFolderChangeLinkPolicyType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ :rtype: str """ - if self._destination_path_present: - return self._destination_path_value + if self._description_present: + return self._description_value else: - raise AttributeError("missing required field 'destination_path'") + raise AttributeError("missing required field 'description'") - @destination_path.setter - def destination_path(self, val): - val = self._destination_path_validator.validate(val) - self._destination_path_value = val - self._destination_path_present = True + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True - @destination_path.deleter - def destination_path(self): - self._destination_path_value = None - self._destination_path_present = False + @description.deleter + def description(self): + self._description_value = None + self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentCopyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderChangeLinkPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentCopyDetails(shared_content_link={!r}, shared_content_access_level={!r}, destination_path={!r}, shared_content_owner={!r})'.format( - self._shared_content_link_value, - self._shared_content_access_level_value, - self._destination_path_value, - self._shared_content_owner_value, + return 'SharedFolderChangeLinkPolicyType(description={!r})'.format( + self._description_value, ) -SharedContentCopyDetails_validator = bv.Struct(SharedContentCopyDetails) +SharedFolderChangeLinkPolicyType_validator = bv.Struct(SharedFolderChangeLinkPolicyType) -class SharedContentCopyType(bb.Struct): +class SharedFolderChangeMembersInheritancePolicyDetails(bb.Struct): + """ + Changed whether shared folder inherits members from parent folder. + + :ivar team_log.SharedFolderChangeMembersInheritancePolicyDetails.new_value: + New member inheritance policy. + :ivar + team_log.SharedFolderChangeMembersInheritancePolicyDetails.previous_value: + Previous member inheritance policy. Might be missing due to historical + data gap. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New member inheritance policy. + + :rtype: SharedFolderMembersInheritancePolicy + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous member inheritance policy. Might be missing due to historical + data gap. + + :rtype: SharedFolderMembersInheritancePolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedFolderChangeMembersInheritancePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedFolderChangeMembersInheritancePolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) + +SharedFolderChangeMembersInheritancePolicyDetails_validator = bv.Struct(SharedFolderChangeMembersInheritancePolicyDetails) + +class SharedFolderChangeMembersInheritancePolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -54806,140 +75735,110 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentCopyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderChangeMembersInheritancePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentCopyType(description={!r})'.format( + return 'SharedFolderChangeMembersInheritancePolicyType(description={!r})'.format( self._description_value, ) -SharedContentCopyType_validator = bv.Struct(SharedContentCopyType) +SharedFolderChangeMembersInheritancePolicyType_validator = bv.Struct(SharedFolderChangeMembersInheritancePolicyType) -class SharedContentDownloadDetails(bb.Struct): +class SharedFolderChangeMembersManagementPolicyDetails(bb.Struct): """ - Downloaded shared file/folder. + Changed who can add/remove members of shared folder. - :ivar team_log.SharedContentDownloadDetails.shared_content_link: Shared - content link. - :ivar team_log.SharedContentDownloadDetails.shared_content_owner: The shared - content owner. - :ivar team_log.SharedContentDownloadDetails.shared_content_access_level: - Shared content access level. + :ivar team_log.SharedFolderChangeMembersManagementPolicyDetails.new_value: + New members management policy. + :ivar + team_log.SharedFolderChangeMembersManagementPolicyDetails.previous_value: + Previous members management policy. Might be missing due to historical + data gap. """ __slots__ = [ - '_shared_content_link_value', - '_shared_content_link_present', - '_shared_content_owner_value', - '_shared_content_owner_present', - '_shared_content_access_level_value', - '_shared_content_access_level_present', + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] _has_required_fields = True def __init__(self, - shared_content_link=None, - shared_content_access_level=None, - shared_content_owner=None): - self._shared_content_link_value = None - self._shared_content_link_present = False - self._shared_content_owner_value = None - self._shared_content_owner_present = False - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False - if shared_content_link is not None: - self.shared_content_link = shared_content_link - if shared_content_owner is not None: - self.shared_content_owner = shared_content_owner - if shared_content_access_level is not None: - self.shared_content_access_level = shared_content_access_level + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value @property - def shared_content_link(self): + def new_value(self): """ - Shared content link. + New members management policy. - :rtype: str + :rtype: sharing.AclUpdatePolicy """ - if self._shared_content_link_present: - return self._shared_content_link_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'shared_content_link'") + raise AttributeError("missing required field 'new_value'") - @shared_content_link.setter - def shared_content_link(self, val): - val = self._shared_content_link_validator.validate(val) - self._shared_content_link_value = val - self._shared_content_link_present = True + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True - @shared_content_link.deleter - def shared_content_link(self): - self._shared_content_link_value = None - self._shared_content_link_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False @property - def shared_content_owner(self): + def previous_value(self): """ - The shared content owner. + Previous members management policy. Might be missing due to historical + data gap. - :rtype: UserLogInfo + :rtype: sharing.AclUpdatePolicy """ - if self._shared_content_owner_present: - return self._shared_content_owner_value + if self._previous_value_present: + return self._previous_value_value else: return None - @shared_content_owner.setter - def shared_content_owner(self, val): + @previous_value.setter + def previous_value(self, val): if val is None: - del self.shared_content_owner + del self.previous_value return - self._shared_content_owner_validator.validate_type_only(val) - self._shared_content_owner_value = val - self._shared_content_owner_present = True - - @shared_content_owner.deleter - def shared_content_owner(self): - self._shared_content_owner_value = None - self._shared_content_owner_present = False - - @property - def shared_content_access_level(self): - """ - Shared content access level. - - :rtype: sharing.AccessLevel - """ - if self._shared_content_access_level_present: - return self._shared_content_access_level_value - else: - raise AttributeError("missing required field 'shared_content_access_level'") - - @shared_content_access_level.setter - def shared_content_access_level(self, val): - self._shared_content_access_level_validator.validate_type_only(val) - self._shared_content_access_level_value = val - self._shared_content_access_level_present = True + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True - @shared_content_access_level.deleter - def shared_content_access_level(self): - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderChangeMembersManagementPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentDownloadDetails(shared_content_link={!r}, shared_content_access_level={!r}, shared_content_owner={!r})'.format( - self._shared_content_link_value, - self._shared_content_access_level_value, - self._shared_content_owner_value, + return 'SharedFolderChangeMembersManagementPolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, ) -SharedContentDownloadDetails_validator = bv.Struct(SharedContentDownloadDetails) +SharedFolderChangeMembersManagementPolicyDetails_validator = bv.Struct(SharedFolderChangeMembersManagementPolicyDetails) -class SharedContentDownloadType(bb.Struct): +class SharedFolderChangeMembersManagementPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -54977,37 +75876,109 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderChangeMembersManagementPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentDownloadType(description={!r})'.format( + return 'SharedFolderChangeMembersManagementPolicyType(description={!r})'.format( self._description_value, ) -SharedContentDownloadType_validator = bv.Struct(SharedContentDownloadType) +SharedFolderChangeMembersManagementPolicyType_validator = bv.Struct(SharedFolderChangeMembersManagementPolicyType) -class SharedContentRelinquishMembershipDetails(bb.Struct): +class SharedFolderChangeMembersPolicyDetails(bb.Struct): """ - Left shared file/folder. + Changed who can become member of shared folder. + + :ivar team_log.SharedFolderChangeMembersPolicyDetails.new_value: New + external invite policy. + :ivar team_log.SharedFolderChangeMembersPolicyDetails.previous_value: + Previous external invite policy. Might be missing due to historical data + gap. """ __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New external invite policy. + + :rtype: sharing.MemberPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous external invite policy. Might be missing due to historical data + gap. + + :rtype: sharing.MemberPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + return None + + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRelinquishMembershipDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderChangeMembersPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRelinquishMembershipDetails()' + return 'SharedFolderChangeMembersPolicyDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) -SharedContentRelinquishMembershipDetails_validator = bv.Struct(SharedContentRelinquishMembershipDetails) +SharedFolderChangeMembersPolicyDetails_validator = bv.Struct(SharedFolderChangeMembersPolicyDetails) -class SharedContentRelinquishMembershipType(bb.Struct): +class SharedFolderChangeMembersPolicyType(bb.Struct): __slots__ = [ '_description_value', @@ -55045,71 +76016,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRelinquishMembershipType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderChangeMembersPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRelinquishMembershipType(description={!r})'.format( + return 'SharedFolderChangeMembersPolicyType(description={!r})'.format( self._description_value, ) -SharedContentRelinquishMembershipType_validator = bv.Struct(SharedContentRelinquishMembershipType) +SharedFolderChangeMembersPolicyType_validator = bv.Struct(SharedFolderChangeMembersPolicyType) -class SharedContentRemoveInviteesDetails(bb.Struct): +class SharedFolderCreateDetails(bb.Struct): """ - Removed invitee from shared file/folder before invite was accepted. + Created shared folder. - :ivar team_log.SharedContentRemoveInviteesDetails.invitees: A list of - invitees. + :ivar team_log.SharedFolderCreateDetails.target_ns_id: Target namespace ID. + Might be missing due to historical data gap. """ __slots__ = [ - '_invitees_value', - '_invitees_present', + '_target_ns_id_value', + '_target_ns_id_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - invitees=None): - self._invitees_value = None - self._invitees_present = False - if invitees is not None: - self.invitees = invitees + target_ns_id=None): + self._target_ns_id_value = None + self._target_ns_id_present = False + if target_ns_id is not None: + self.target_ns_id = target_ns_id @property - def invitees(self): + def target_ns_id(self): """ - A list of invitees. + Target namespace ID. Might be missing due to historical data gap. - :rtype: list of [str] + :rtype: str """ - if self._invitees_present: - return self._invitees_value + if self._target_ns_id_present: + return self._target_ns_id_value else: - raise AttributeError("missing required field 'invitees'") + return None - @invitees.setter - def invitees(self, val): - val = self._invitees_validator.validate(val) - self._invitees_value = val - self._invitees_present = True + @target_ns_id.setter + def target_ns_id(self, val): + if val is None: + del self.target_ns_id + return + val = self._target_ns_id_validator.validate(val) + self._target_ns_id_value = val + self._target_ns_id_present = True - @invitees.deleter - def invitees(self): - self._invitees_value = None - self._invitees_present = False + @target_ns_id.deleter + def target_ns_id(self): + self._target_ns_id_value = None + self._target_ns_id_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveInviteesDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveInviteesDetails(invitees={!r})'.format( - self._invitees_value, + return 'SharedFolderCreateDetails(target_ns_id={!r})'.format( + self._target_ns_id_value, ) -SharedContentRemoveInviteesDetails_validator = bv.Struct(SharedContentRemoveInviteesDetails) +SharedFolderCreateDetails_validator = bv.Struct(SharedFolderCreateDetails) -class SharedContentRemoveInviteesType(bb.Struct): +class SharedFolderCreateType(bb.Struct): __slots__ = [ '_description_value', @@ -55147,76 +76121,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveInviteesType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveInviteesType(description={!r})'.format( + return 'SharedFolderCreateType(description={!r})'.format( self._description_value, ) -SharedContentRemoveInviteesType_validator = bv.Struct(SharedContentRemoveInviteesType) +SharedFolderCreateType_validator = bv.Struct(SharedFolderCreateType) -class SharedContentRemoveLinkExpiryDetails(bb.Struct): +class SharedFolderDeclineInvitationDetails(bb.Struct): """ - Removed link expiration date of shared file/folder. - - :ivar team_log.SharedContentRemoveLinkExpiryDetails.previous_value: Previous - shared content link expiration date. Might be missing due to historical - data gap. + Declined team member's invite to shared folder. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', ] _has_required_fields = False - def __init__(self, - previous_value=None): - self._previous_value_value = None - self._previous_value_present = False - if previous_value is not None: - self.previous_value = previous_value - - @property - def previous_value(self): - """ - Previous shared content link expiration date. Might be missing due to - historical data gap. - - :rtype: datetime.datetime - """ - if self._previous_value_present: - return self._previous_value_value - else: - return None - - @previous_value.setter - def previous_value(self, val): - if val is None: - del self.previous_value - return - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True - - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveLinkExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderDeclineInvitationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveLinkExpiryDetails(previous_value={!r})'.format( - self._previous_value_value, - ) + return 'SharedFolderDeclineInvitationDetails()' -SharedContentRemoveLinkExpiryDetails_validator = bv.Struct(SharedContentRemoveLinkExpiryDetails) +SharedFolderDeclineInvitationDetails_validator = bv.Struct(SharedFolderDeclineInvitationDetails) -class SharedContentRemoveLinkExpiryType(bb.Struct): +class SharedFolderDeclineInvitationType(bb.Struct): __slots__ = [ '_description_value', @@ -55254,18 +76189,67 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveLinkExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderDeclineInvitationType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveLinkExpiryType(description={!r})'.format( + return 'SharedFolderDeclineInvitationType(description={!r})'.format( self._description_value, ) -SharedContentRemoveLinkExpiryType_validator = bv.Struct(SharedContentRemoveLinkExpiryType) +SharedFolderDeclineInvitationType_validator = bv.Struct(SharedFolderDeclineInvitationType) -class SharedContentRemoveLinkPasswordDetails(bb.Struct): +class SharedFolderMembersInheritancePolicy(bb.Union): """ - Removed link password of shared file/folder. + Specifies if a shared folder inherits its members from the parent folder. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + inherit_members = None + # Attribute is overwritten below the class definition + dont_inherit_members = None + # Attribute is overwritten below the class definition + other = None + + def is_inherit_members(self): + """ + Check if the union tag is ``inherit_members``. + + :rtype: bool + """ + return self._tag == 'inherit_members' + + def is_dont_inherit_members(self): + """ + Check if the union tag is ``dont_inherit_members``. + + :rtype: bool + """ + return self._tag == 'dont_inherit_members' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedFolderMembersInheritancePolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SharedFolderMembersInheritancePolicy(%r, %r)' % (self._tag, self._value) + +SharedFolderMembersInheritancePolicy_validator = bv.Union(SharedFolderMembersInheritancePolicy) + +class SharedFolderMountDetails(bb.Struct): + """ + Added shared folder to own Dropbox. """ __slots__ = [ @@ -55277,14 +76261,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveLinkPasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderMountDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveLinkPasswordDetails()' + return 'SharedFolderMountDetails()' -SharedContentRemoveLinkPasswordDetails_validator = bv.Struct(SharedContentRemoveLinkPasswordDetails) +SharedFolderMountDetails_validator = bv.Struct(SharedFolderMountDetails) -class SharedContentRemoveLinkPasswordType(bb.Struct): +class SharedFolderMountType(bb.Struct): __slots__ = [ '_description_value', @@ -55322,74 +76306,183 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveLinkPasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderMountType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveLinkPasswordType(description={!r})'.format( + return 'SharedFolderMountType(description={!r})'.format( self._description_value, ) -SharedContentRemoveLinkPasswordType_validator = bv.Struct(SharedContentRemoveLinkPasswordType) +SharedFolderMountType_validator = bv.Struct(SharedFolderMountType) -class SharedContentRemoveMemberDetails(bb.Struct): +class SharedFolderNestDetails(bb.Struct): """ - Removed user/group from shared file/folder. + Changed parent of shared folder. - :ivar team_log.SharedContentRemoveMemberDetails.shared_content_access_level: - Shared content access level. + :ivar team_log.SharedFolderNestDetails.previous_parent_ns_id: Previous + parent namespace ID. Might be missing due to historical data gap. + :ivar team_log.SharedFolderNestDetails.new_parent_ns_id: New parent + namespace ID. Might be missing due to historical data gap. + :ivar team_log.SharedFolderNestDetails.previous_ns_path: Previous namespace + path. Might be missing due to historical data gap. + :ivar team_log.SharedFolderNestDetails.new_ns_path: New namespace path. + Might be missing due to historical data gap. """ - __slots__ = [ - '_shared_content_access_level_value', - '_shared_content_access_level_present', - ] + __slots__ = [ + '_previous_parent_ns_id_value', + '_previous_parent_ns_id_present', + '_new_parent_ns_id_value', + '_new_parent_ns_id_present', + '_previous_ns_path_value', + '_previous_ns_path_present', + '_new_ns_path_value', + '_new_ns_path_present', + ] + + _has_required_fields = False + + def __init__(self, + previous_parent_ns_id=None, + new_parent_ns_id=None, + previous_ns_path=None, + new_ns_path=None): + self._previous_parent_ns_id_value = None + self._previous_parent_ns_id_present = False + self._new_parent_ns_id_value = None + self._new_parent_ns_id_present = False + self._previous_ns_path_value = None + self._previous_ns_path_present = False + self._new_ns_path_value = None + self._new_ns_path_present = False + if previous_parent_ns_id is not None: + self.previous_parent_ns_id = previous_parent_ns_id + if new_parent_ns_id is not None: + self.new_parent_ns_id = new_parent_ns_id + if previous_ns_path is not None: + self.previous_ns_path = previous_ns_path + if new_ns_path is not None: + self.new_ns_path = new_ns_path + + @property + def previous_parent_ns_id(self): + """ + Previous parent namespace ID. Might be missing due to historical data + gap. + + :rtype: str + """ + if self._previous_parent_ns_id_present: + return self._previous_parent_ns_id_value + else: + return None + + @previous_parent_ns_id.setter + def previous_parent_ns_id(self, val): + if val is None: + del self.previous_parent_ns_id + return + val = self._previous_parent_ns_id_validator.validate(val) + self._previous_parent_ns_id_value = val + self._previous_parent_ns_id_present = True + + @previous_parent_ns_id.deleter + def previous_parent_ns_id(self): + self._previous_parent_ns_id_value = None + self._previous_parent_ns_id_present = False + + @property + def new_parent_ns_id(self): + """ + New parent namespace ID. Might be missing due to historical data gap. + + :rtype: str + """ + if self._new_parent_ns_id_present: + return self._new_parent_ns_id_value + else: + return None + + @new_parent_ns_id.setter + def new_parent_ns_id(self, val): + if val is None: + del self.new_parent_ns_id + return + val = self._new_parent_ns_id_validator.validate(val) + self._new_parent_ns_id_value = val + self._new_parent_ns_id_present = True + + @new_parent_ns_id.deleter + def new_parent_ns_id(self): + self._new_parent_ns_id_value = None + self._new_parent_ns_id_present = False + + @property + def previous_ns_path(self): + """ + Previous namespace path. Might be missing due to historical data gap. + + :rtype: str + """ + if self._previous_ns_path_present: + return self._previous_ns_path_value + else: + return None - _has_required_fields = False + @previous_ns_path.setter + def previous_ns_path(self, val): + if val is None: + del self.previous_ns_path + return + val = self._previous_ns_path_validator.validate(val) + self._previous_ns_path_value = val + self._previous_ns_path_present = True - def __init__(self, - shared_content_access_level=None): - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False - if shared_content_access_level is not None: - self.shared_content_access_level = shared_content_access_level + @previous_ns_path.deleter + def previous_ns_path(self): + self._previous_ns_path_value = None + self._previous_ns_path_present = False @property - def shared_content_access_level(self): + def new_ns_path(self): """ - Shared content access level. + New namespace path. Might be missing due to historical data gap. - :rtype: sharing.AccessLevel + :rtype: str """ - if self._shared_content_access_level_present: - return self._shared_content_access_level_value + if self._new_ns_path_present: + return self._new_ns_path_value else: return None - @shared_content_access_level.setter - def shared_content_access_level(self, val): + @new_ns_path.setter + def new_ns_path(self, val): if val is None: - del self.shared_content_access_level + del self.new_ns_path return - self._shared_content_access_level_validator.validate_type_only(val) - self._shared_content_access_level_value = val - self._shared_content_access_level_present = True + val = self._new_ns_path_validator.validate(val) + self._new_ns_path_value = val + self._new_ns_path_present = True - @shared_content_access_level.deleter - def shared_content_access_level(self): - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False + @new_ns_path.deleter + def new_ns_path(self): + self._new_ns_path_value = None + self._new_ns_path_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveMemberDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderNestDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveMemberDetails(shared_content_access_level={!r})'.format( - self._shared_content_access_level_value, + return 'SharedFolderNestDetails(previous_parent_ns_id={!r}, new_parent_ns_id={!r}, previous_ns_path={!r}, new_ns_path={!r})'.format( + self._previous_parent_ns_id_value, + self._new_parent_ns_id_value, + self._previous_ns_path_value, + self._new_ns_path_value, ) -SharedContentRemoveMemberDetails_validator = bv.Struct(SharedContentRemoveMemberDetails) +SharedFolderNestDetails_validator = bv.Struct(SharedFolderNestDetails) -class SharedContentRemoveMemberType(bb.Struct): +class SharedFolderNestType(bb.Struct): __slots__ = [ '_description_value', @@ -55427,74 +76520,107 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRemoveMemberType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderNestType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRemoveMemberType(description={!r})'.format( + return 'SharedFolderNestType(description={!r})'.format( self._description_value, ) -SharedContentRemoveMemberType_validator = bv.Struct(SharedContentRemoveMemberType) +SharedFolderNestType_validator = bv.Struct(SharedFolderNestType) -class SharedContentRequestAccessDetails(bb.Struct): +class SharedFolderTransferOwnershipDetails(bb.Struct): """ - Requested access to shared file/folder. + Transferred ownership of shared folder to another member. - :ivar team_log.SharedContentRequestAccessDetails.shared_content_link: Shared - content link. + :ivar team_log.SharedFolderTransferOwnershipDetails.previous_owner_email: + The email address of the previous shared folder owner. + :ivar team_log.SharedFolderTransferOwnershipDetails.new_owner_email: The + email address of the new shared folder owner. """ __slots__ = [ - '_shared_content_link_value', - '_shared_content_link_present', + '_previous_owner_email_value', + '_previous_owner_email_present', + '_new_owner_email_value', + '_new_owner_email_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - shared_content_link=None): - self._shared_content_link_value = None - self._shared_content_link_present = False - if shared_content_link is not None: - self.shared_content_link = shared_content_link + new_owner_email=None, + previous_owner_email=None): + self._previous_owner_email_value = None + self._previous_owner_email_present = False + self._new_owner_email_value = None + self._new_owner_email_present = False + if previous_owner_email is not None: + self.previous_owner_email = previous_owner_email + if new_owner_email is not None: + self.new_owner_email = new_owner_email @property - def shared_content_link(self): + def previous_owner_email(self): """ - Shared content link. + The email address of the previous shared folder owner. :rtype: str """ - if self._shared_content_link_present: - return self._shared_content_link_value + if self._previous_owner_email_present: + return self._previous_owner_email_value else: return None - @shared_content_link.setter - def shared_content_link(self, val): + @previous_owner_email.setter + def previous_owner_email(self, val): if val is None: - del self.shared_content_link + del self.previous_owner_email return - val = self._shared_content_link_validator.validate(val) - self._shared_content_link_value = val - self._shared_content_link_present = True + val = self._previous_owner_email_validator.validate(val) + self._previous_owner_email_value = val + self._previous_owner_email_present = True - @shared_content_link.deleter - def shared_content_link(self): - self._shared_content_link_value = None - self._shared_content_link_present = False + @previous_owner_email.deleter + def previous_owner_email(self): + self._previous_owner_email_value = None + self._previous_owner_email_present = False + + @property + def new_owner_email(self): + """ + The email address of the new shared folder owner. + + :rtype: str + """ + if self._new_owner_email_present: + return self._new_owner_email_value + else: + raise AttributeError("missing required field 'new_owner_email'") + + @new_owner_email.setter + def new_owner_email(self, val): + val = self._new_owner_email_validator.validate(val) + self._new_owner_email_value = val + self._new_owner_email_present = True + + @new_owner_email.deleter + def new_owner_email(self): + self._new_owner_email_value = None + self._new_owner_email_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRequestAccessDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderTransferOwnershipDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRequestAccessDetails(shared_content_link={!r})'.format( - self._shared_content_link_value, + return 'SharedFolderTransferOwnershipDetails(new_owner_email={!r}, previous_owner_email={!r})'.format( + self._new_owner_email_value, + self._previous_owner_email_value, ) -SharedContentRequestAccessDetails_validator = bv.Struct(SharedContentRequestAccessDetails) +SharedFolderTransferOwnershipDetails_validator = bv.Struct(SharedFolderTransferOwnershipDetails) -class SharedContentRequestAccessType(bb.Struct): +class SharedFolderTransferOwnershipType(bb.Struct): __slots__ = [ '_description_value', @@ -55532,18 +76658,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentRequestAccessType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderTransferOwnershipType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentRequestAccessType(description={!r})'.format( + return 'SharedFolderTransferOwnershipType(description={!r})'.format( self._description_value, ) -SharedContentRequestAccessType_validator = bv.Struct(SharedContentRequestAccessType) +SharedFolderTransferOwnershipType_validator = bv.Struct(SharedFolderTransferOwnershipType) -class SharedContentUnshareDetails(bb.Struct): +class SharedFolderUnmountDetails(bb.Struct): """ - Unshared file/folder by clearing membership and turning off link. + Deleted shared folder from Dropbox. """ __slots__ = [ @@ -55555,14 +76681,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentUnshareDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderUnmountDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentUnshareDetails()' + return 'SharedFolderUnmountDetails()' -SharedContentUnshareDetails_validator = bv.Struct(SharedContentUnshareDetails) +SharedFolderUnmountDetails_validator = bv.Struct(SharedFolderUnmountDetails) -class SharedContentUnshareType(bb.Struct): +class SharedFolderUnmountType(bb.Struct): __slots__ = [ '_description_value', @@ -55600,140 +76726,130 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentUnshareType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedFolderUnmountType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentUnshareType(description={!r})'.format( + return 'SharedFolderUnmountType(description={!r})'.format( self._description_value, ) -SharedContentUnshareType_validator = bv.Struct(SharedContentUnshareType) +SharedFolderUnmountType_validator = bv.Struct(SharedFolderUnmountType) -class SharedContentViewDetails(bb.Struct): +class SharedLinkAccessLevel(bb.Union): """ - Previewed shared file/folder. + Shared link access level. - :ivar team_log.SharedContentViewDetails.shared_content_link: Shared content - link. - :ivar team_log.SharedContentViewDetails.shared_content_owner: The shared - content owner. - :ivar team_log.SharedContentViewDetails.shared_content_access_level: Shared - content access level. + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. """ - __slots__ = [ - '_shared_content_link_value', - '_shared_content_link_present', - '_shared_content_owner_value', - '_shared_content_owner_present', - '_shared_content_access_level_value', - '_shared_content_access_level_present', - ] + _catch_all = 'other' + # Attribute is overwritten below the class definition + none = None + # Attribute is overwritten below the class definition + reader = None + # Attribute is overwritten below the class definition + writer = None + # Attribute is overwritten below the class definition + other = None - _has_required_fields = True + def is_none(self): + """ + Check if the union tag is ``none``. - def __init__(self, - shared_content_link=None, - shared_content_access_level=None, - shared_content_owner=None): - self._shared_content_link_value = None - self._shared_content_link_present = False - self._shared_content_owner_value = None - self._shared_content_owner_present = False - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False - if shared_content_link is not None: - self.shared_content_link = shared_content_link - if shared_content_owner is not None: - self.shared_content_owner = shared_content_owner - if shared_content_access_level is not None: - self.shared_content_access_level = shared_content_access_level + :rtype: bool + """ + return self._tag == 'none' - @property - def shared_content_link(self): + def is_reader(self): """ - Shared content link. + Check if the union tag is ``reader``. - :rtype: str + :rtype: bool """ - if self._shared_content_link_present: - return self._shared_content_link_value - else: - raise AttributeError("missing required field 'shared_content_link'") + return self._tag == 'reader' - @shared_content_link.setter - def shared_content_link(self, val): - val = self._shared_content_link_validator.validate(val) - self._shared_content_link_value = val - self._shared_content_link_present = True + def is_writer(self): + """ + Check if the union tag is ``writer``. - @shared_content_link.deleter - def shared_content_link(self): - self._shared_content_link_value = None - self._shared_content_link_present = False + :rtype: bool + """ + return self._tag == 'writer' - @property - def shared_content_owner(self): + def is_other(self): """ - The shared content owner. + Check if the union tag is ``other``. - :rtype: UserLogInfo + :rtype: bool """ - if self._shared_content_owner_present: - return self._shared_content_owner_value - else: - return None + return self._tag == 'other' - @shared_content_owner.setter - def shared_content_owner(self, val): - if val is None: - del self.shared_content_owner - return - self._shared_content_owner_validator.validate_type_only(val) - self._shared_content_owner_value = val - self._shared_content_owner_present = True + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SharedLinkAccessLevel, self)._process_custom_annotations(annotation_type, field_path, processor) - @shared_content_owner.deleter - def shared_content_owner(self): - self._shared_content_owner_value = None - self._shared_content_owner_present = False + def __repr__(self): + return 'SharedLinkAccessLevel(%r, %r)' % (self._tag, self._value) + +SharedLinkAccessLevel_validator = bv.Union(SharedLinkAccessLevel) + +class SharedLinkAddExpiryDetails(bb.Struct): + """ + Added shared link expiration date. + + :ivar team_log.SharedLinkAddExpiryDetails.new_value: New shared link + expiration date. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None): + self._new_value_value = None + self._new_value_present = False + if new_value is not None: + self.new_value = new_value @property - def shared_content_access_level(self): + def new_value(self): """ - Shared content access level. + New shared link expiration date. - :rtype: sharing.AccessLevel + :rtype: datetime.datetime """ - if self._shared_content_access_level_present: - return self._shared_content_access_level_value + if self._new_value_present: + return self._new_value_value else: - raise AttributeError("missing required field 'shared_content_access_level'") + raise AttributeError("missing required field 'new_value'") - @shared_content_access_level.setter - def shared_content_access_level(self, val): - self._shared_content_access_level_validator.validate_type_only(val) - self._shared_content_access_level_value = val - self._shared_content_access_level_present = True + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @shared_content_access_level.deleter - def shared_content_access_level(self): - self._shared_content_access_level_value = None - self._shared_content_access_level_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentViewDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkAddExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentViewDetails(shared_content_link={!r}, shared_content_access_level={!r}, shared_content_owner={!r})'.format( - self._shared_content_link_value, - self._shared_content_access_level_value, - self._shared_content_owner_value, + return 'SharedLinkAddExpiryDetails(new_value={!r})'.format( + self._new_value_value, ) -SharedContentViewDetails_validator = bv.Struct(SharedContentViewDetails) +SharedLinkAddExpiryDetails_validator = bv.Struct(SharedLinkAddExpiryDetails) -class SharedContentViewType(bb.Struct): +class SharedLinkAddExpiryType(bb.Struct): __slots__ = [ '_description_value', @@ -55771,23 +76887,23 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedContentViewType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkAddExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedContentViewType(description={!r})'.format( + return 'SharedLinkAddExpiryType(description={!r})'.format( self._description_value, ) -SharedContentViewType_validator = bv.Struct(SharedContentViewType) +SharedLinkAddExpiryType_validator = bv.Struct(SharedLinkAddExpiryType) -class SharedFolderChangeLinkPolicyDetails(bb.Struct): +class SharedLinkChangeExpiryDetails(bb.Struct): """ - Changed who can access shared folder via link. + Changed shared link expiration date. - :ivar team_log.SharedFolderChangeLinkPolicyDetails.new_value: New shared - folder link policy. - :ivar team_log.SharedFolderChangeLinkPolicyDetails.previous_value: Previous - shared folder link policy. Might be missing due to historical data gap. + :ivar team_log.SharedLinkChangeExpiryDetails.new_value: New shared link + expiration date. Might be missing due to historical data gap. + :ivar team_log.SharedLinkChangeExpiryDetails.previous_value: Previous shared + link expiration date. Might be missing due to historical data gap. """ __slots__ = [ @@ -55797,7 +76913,7 @@ class SharedFolderChangeLinkPolicyDetails(bb.Struct): '_previous_value_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, new_value=None, @@ -55814,18 +76930,22 @@ def __init__(self, @property def new_value(self): """ - New shared folder link policy. + New shared link expiration date. Might be missing due to historical data + gap. - :rtype: sharing.SharedLinkPolicy + :rtype: datetime.datetime """ if self._new_value_present: return self._new_value_value else: - raise AttributeError("missing required field 'new_value'") + return None @new_value.setter def new_value(self, val): - self._new_value_validator.validate_type_only(val) + if val is None: + del self.new_value + return + val = self._new_value_validator.validate(val) self._new_value_value = val self._new_value_present = True @@ -55837,10 +76957,10 @@ def new_value(self): @property def previous_value(self): """ - Previous shared folder link policy. Might be missing due to historical + Previous shared link expiration date. Might be missing due to historical data gap. - :rtype: sharing.SharedLinkPolicy + :rtype: datetime.datetime """ if self._previous_value_present: return self._previous_value_value @@ -55852,7 +76972,7 @@ def previous_value(self, val): if val is None: del self.previous_value return - self._previous_value_validator.validate_type_only(val) + val = self._previous_value_validator.validate(val) self._previous_value_value = val self._previous_value_present = True @@ -55862,17 +76982,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeLinkPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkChangeExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeLinkPolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'SharedLinkChangeExpiryDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -SharedFolderChangeLinkPolicyDetails_validator = bv.Struct(SharedFolderChangeLinkPolicyDetails) +SharedLinkChangeExpiryDetails_validator = bv.Struct(SharedLinkChangeExpiryDetails) -class SharedFolderChangeLinkPolicyType(bb.Struct): +class SharedLinkChangeExpiryType(bb.Struct): __slots__ = [ '_description_value', @@ -55910,25 +77030,23 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeLinkPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkChangeExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeLinkPolicyType(description={!r})'.format( + return 'SharedLinkChangeExpiryType(description={!r})'.format( self._description_value, ) -SharedFolderChangeLinkPolicyType_validator = bv.Struct(SharedFolderChangeLinkPolicyType) +SharedLinkChangeExpiryType_validator = bv.Struct(SharedLinkChangeExpiryType) -class SharedFolderChangeMembersInheritancePolicyDetails(bb.Struct): +class SharedLinkChangeVisibilityDetails(bb.Struct): """ - Changed whether shared folder inherits members from parent folder. + Changed visibility of shared link. - :ivar team_log.SharedFolderChangeMembersInheritancePolicyDetails.new_value: - New member inheritance policy. - :ivar - team_log.SharedFolderChangeMembersInheritancePolicyDetails.previous_value: - Previous member inheritance policy. Might be missing due to historical - data gap. + :ivar team_log.SharedLinkChangeVisibilityDetails.new_value: New shared link + visibility. + :ivar team_log.SharedLinkChangeVisibilityDetails.previous_value: Previous + shared link visibility. Might be missing due to historical data gap. """ __slots__ = [ @@ -55955,9 +77073,9 @@ def __init__(self, @property def new_value(self): """ - New member inheritance policy. + New shared link visibility. - :rtype: SharedFolderMembersInheritancePolicy + :rtype: SharedLinkVisibility """ if self._new_value_present: return self._new_value_value @@ -55978,10 +77096,10 @@ def new_value(self): @property def previous_value(self): """ - Previous member inheritance policy. Might be missing due to historical - data gap. + Previous shared link visibility. Might be missing due to historical data + gap. - :rtype: SharedFolderMembersInheritancePolicy + :rtype: SharedLinkVisibility """ if self._previous_value_present: return self._previous_value_value @@ -56003,17 +77121,17 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeMembersInheritancePolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkChangeVisibilityDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeMembersInheritancePolicyDetails(new_value={!r}, previous_value={!r})'.format( + return 'SharedLinkChangeVisibilityDetails(new_value={!r}, previous_value={!r})'.format( self._new_value_value, self._previous_value_value, ) -SharedFolderChangeMembersInheritancePolicyDetails_validator = bv.Struct(SharedFolderChangeMembersInheritancePolicyDetails) +SharedLinkChangeVisibilityDetails_validator = bv.Struct(SharedLinkChangeVisibilityDetails) -class SharedFolderChangeMembersInheritancePolicyType(bb.Struct): +class SharedLinkChangeVisibilityType(bb.Struct): __slots__ = [ '_description_value', @@ -56051,110 +77169,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeMembersInheritancePolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkChangeVisibilityType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeMembersInheritancePolicyType(description={!r})'.format( + return 'SharedLinkChangeVisibilityType(description={!r})'.format( self._description_value, ) -SharedFolderChangeMembersInheritancePolicyType_validator = bv.Struct(SharedFolderChangeMembersInheritancePolicyType) +SharedLinkChangeVisibilityType_validator = bv.Struct(SharedLinkChangeVisibilityType) -class SharedFolderChangeMembersManagementPolicyDetails(bb.Struct): +class SharedLinkCopyDetails(bb.Struct): """ - Changed who can add/remove members of shared folder. + Added file/folder to Dropbox from shared link. - :ivar team_log.SharedFolderChangeMembersManagementPolicyDetails.new_value: - New members management policy. - :ivar - team_log.SharedFolderChangeMembersManagementPolicyDetails.previous_value: - Previous members management policy. Might be missing due to historical - data gap. + :ivar team_log.SharedLinkCopyDetails.shared_link_owner: Shared link owner + details. Might be missing due to historical data gap. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_shared_link_owner_value', + '_shared_link_owner_present', ] - _has_required_fields = True - - def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New members management policy. - - :rtype: sharing.AclUpdatePolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + _has_required_fields = False + + def __init__(self, + shared_link_owner=None): + self._shared_link_owner_value = None + self._shared_link_owner_present = False + if shared_link_owner is not None: + self.shared_link_owner = shared_link_owner @property - def previous_value(self): + def shared_link_owner(self): """ - Previous members management policy. Might be missing due to historical - data gap. + Shared link owner details. Might be missing due to historical data gap. - :rtype: sharing.AclUpdatePolicy + :rtype: UserLogInfo """ - if self._previous_value_present: - return self._previous_value_value + if self._shared_link_owner_present: + return self._shared_link_owner_value else: return None - @previous_value.setter - def previous_value(self, val): + @shared_link_owner.setter + def shared_link_owner(self, val): if val is None: - del self.previous_value + del self.shared_link_owner return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + self._shared_link_owner_validator.validate_type_only(val) + self._shared_link_owner_value = val + self._shared_link_owner_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @shared_link_owner.deleter + def shared_link_owner(self): + self._shared_link_owner_value = None + self._shared_link_owner_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeMembersManagementPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkCopyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeMembersManagementPolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'SharedLinkCopyDetails(shared_link_owner={!r})'.format( + self._shared_link_owner_value, ) -SharedFolderChangeMembersManagementPolicyDetails_validator = bv.Struct(SharedFolderChangeMembersManagementPolicyDetails) +SharedLinkCopyDetails_validator = bv.Struct(SharedLinkCopyDetails) -class SharedFolderChangeMembersManagementPolicyType(bb.Struct): +class SharedLinkCopyType(bb.Struct): __slots__ = [ '_description_value', @@ -56192,109 +77274,75 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeMembersManagementPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkCopyType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeMembersManagementPolicyType(description={!r})'.format( + return 'SharedLinkCopyType(description={!r})'.format( self._description_value, ) -SharedFolderChangeMembersManagementPolicyType_validator = bv.Struct(SharedFolderChangeMembersManagementPolicyType) +SharedLinkCopyType_validator = bv.Struct(SharedLinkCopyType) -class SharedFolderChangeMembersPolicyDetails(bb.Struct): +class SharedLinkCreateDetails(bb.Struct): """ - Changed who can become member of shared folder. + Created shared link. - :ivar team_log.SharedFolderChangeMembersPolicyDetails.new_value: New - external invite policy. - :ivar team_log.SharedFolderChangeMembersPolicyDetails.previous_value: - Previous external invite policy. Might be missing due to historical data - gap. + :ivar team_log.SharedLinkCreateDetails.shared_link_access_level: Defines who + can access the shared link. Might be missing due to historical data gap. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_shared_link_access_level_value', + '_shared_link_access_level_present', ] - _has_required_fields = True + _has_required_fields = False def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value - - @property - def new_value(self): - """ - New external invite policy. - - :rtype: sharing.MemberPolicy - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True - - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + shared_link_access_level=None): + self._shared_link_access_level_value = None + self._shared_link_access_level_present = False + if shared_link_access_level is not None: + self.shared_link_access_level = shared_link_access_level @property - def previous_value(self): + def shared_link_access_level(self): """ - Previous external invite policy. Might be missing due to historical data - gap. + Defines who can access the shared link. Might be missing due to + historical data gap. - :rtype: sharing.MemberPolicy + :rtype: SharedLinkAccessLevel """ - if self._previous_value_present: - return self._previous_value_value + if self._shared_link_access_level_present: + return self._shared_link_access_level_value else: return None - @previous_value.setter - def previous_value(self, val): + @shared_link_access_level.setter + def shared_link_access_level(self, val): if val is None: - del self.previous_value + del self.shared_link_access_level return - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + self._shared_link_access_level_validator.validate_type_only(val) + self._shared_link_access_level_value = val + self._shared_link_access_level_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @shared_link_access_level.deleter + def shared_link_access_level(self): + self._shared_link_access_level_value = None + self._shared_link_access_level_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeMembersPolicyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeMembersPolicyDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'SharedLinkCreateDetails(shared_link_access_level={!r})'.format( + self._shared_link_access_level_value, ) -SharedFolderChangeMembersPolicyDetails_validator = bv.Struct(SharedFolderChangeMembersPolicyDetails) +SharedLinkCreateDetails_validator = bv.Struct(SharedLinkCreateDetails) -class SharedFolderChangeMembersPolicyType(bb.Struct): +class SharedLinkCreateType(bb.Struct): __slots__ = [ '_description_value', @@ -56332,74 +77380,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderChangeMembersPolicyType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderChangeMembersPolicyType(description={!r})'.format( + return 'SharedLinkCreateType(description={!r})'.format( self._description_value, ) -SharedFolderChangeMembersPolicyType_validator = bv.Struct(SharedFolderChangeMembersPolicyType) +SharedLinkCreateType_validator = bv.Struct(SharedLinkCreateType) -class SharedFolderCreateDetails(bb.Struct): +class SharedLinkDisableDetails(bb.Struct): """ - Created shared folder. + Removed shared link. - :ivar team_log.SharedFolderCreateDetails.target_ns_id: Target namespace ID. - Might be missing due to historical data gap. + :ivar team_log.SharedLinkDisableDetails.shared_link_owner: Shared link owner + details. Might be missing due to historical data gap. """ __slots__ = [ - '_target_ns_id_value', - '_target_ns_id_present', + '_shared_link_owner_value', + '_shared_link_owner_present', ] _has_required_fields = False def __init__(self, - target_ns_id=None): - self._target_ns_id_value = None - self._target_ns_id_present = False - if target_ns_id is not None: - self.target_ns_id = target_ns_id + shared_link_owner=None): + self._shared_link_owner_value = None + self._shared_link_owner_present = False + if shared_link_owner is not None: + self.shared_link_owner = shared_link_owner @property - def target_ns_id(self): + def shared_link_owner(self): """ - Target namespace ID. Might be missing due to historical data gap. + Shared link owner details. Might be missing due to historical data gap. - :rtype: str + :rtype: UserLogInfo """ - if self._target_ns_id_present: - return self._target_ns_id_value + if self._shared_link_owner_present: + return self._shared_link_owner_value else: return None - @target_ns_id.setter - def target_ns_id(self, val): + @shared_link_owner.setter + def shared_link_owner(self, val): if val is None: - del self.target_ns_id + del self.shared_link_owner return - val = self._target_ns_id_validator.validate(val) - self._target_ns_id_value = val - self._target_ns_id_present = True + self._shared_link_owner_validator.validate_type_only(val) + self._shared_link_owner_value = val + self._shared_link_owner_present = True - @target_ns_id.deleter - def target_ns_id(self): - self._target_ns_id_value = None - self._target_ns_id_present = False + @shared_link_owner.deleter + def shared_link_owner(self): + self._shared_link_owner_value = None + self._shared_link_owner_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkDisableDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderCreateDetails(target_ns_id={!r})'.format( - self._target_ns_id_value, + return 'SharedLinkDisableDetails(shared_link_owner={!r})'.format( + self._shared_link_owner_value, ) -SharedFolderCreateDetails_validator = bv.Struct(SharedFolderCreateDetails) +SharedLinkDisableDetails_validator = bv.Struct(SharedLinkDisableDetails) -class SharedFolderCreateType(bb.Struct): +class SharedLinkDisableType(bb.Struct): __slots__ = [ '_description_value', @@ -56437,37 +77485,74 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkDisableType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderCreateType(description={!r})'.format( + return 'SharedLinkDisableType(description={!r})'.format( self._description_value, ) -SharedFolderCreateType_validator = bv.Struct(SharedFolderCreateType) +SharedLinkDisableType_validator = bv.Struct(SharedLinkDisableType) -class SharedFolderDeclineInvitationDetails(bb.Struct): +class SharedLinkDownloadDetails(bb.Struct): """ - Declined team member's invite to shared folder. + Downloaded file/folder from shared link. + + :ivar team_log.SharedLinkDownloadDetails.shared_link_owner: Shared link + owner details. Might be missing due to historical data gap. """ __slots__ = [ + '_shared_link_owner_value', + '_shared_link_owner_present', ] _has_required_fields = False - def __init__(self): - pass + def __init__(self, + shared_link_owner=None): + self._shared_link_owner_value = None + self._shared_link_owner_present = False + if shared_link_owner is not None: + self.shared_link_owner = shared_link_owner + + @property + def shared_link_owner(self): + """ + Shared link owner details. Might be missing due to historical data gap. + + :rtype: UserLogInfo + """ + if self._shared_link_owner_present: + return self._shared_link_owner_value + else: + return None + + @shared_link_owner.setter + def shared_link_owner(self, val): + if val is None: + del self.shared_link_owner + return + self._shared_link_owner_validator.validate_type_only(val) + self._shared_link_owner_value = val + self._shared_link_owner_present = True + + @shared_link_owner.deleter + def shared_link_owner(self): + self._shared_link_owner_value = None + self._shared_link_owner_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderDeclineInvitationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderDeclineInvitationDetails()' + return 'SharedLinkDownloadDetails(shared_link_owner={!r})'.format( + self._shared_link_owner_value, + ) -SharedFolderDeclineInvitationDetails_validator = bv.Struct(SharedFolderDeclineInvitationDetails) +SharedLinkDownloadDetails_validator = bv.Struct(SharedLinkDownloadDetails) -class SharedFolderDeclineInvitationType(bb.Struct): +class SharedLinkDownloadType(bb.Struct): __slots__ = [ '_description_value', @@ -56505,86 +77590,75 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderDeclineInvitationType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderDeclineInvitationType(description={!r})'.format( + return 'SharedLinkDownloadType(description={!r})'.format( self._description_value, ) -SharedFolderDeclineInvitationType_validator = bv.Struct(SharedFolderDeclineInvitationType) +SharedLinkDownloadType_validator = bv.Struct(SharedLinkDownloadType) -class SharedFolderMembersInheritancePolicy(bb.Union): +class SharedLinkRemoveExpiryDetails(bb.Struct): """ - Specifies if a shared folder inherits its members from the parent folder. + Removed shared link expiration date. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar team_log.SharedLinkRemoveExpiryDetails.previous_value: Previous shared + link expiration date. Might be missing due to historical data gap. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - inherit_members = None - # Attribute is overwritten below the class definition - dont_inherit_members = None - # Attribute is overwritten below the class definition - other = None - - def is_inherit_members(self): - """ - Check if the union tag is ``inherit_members``. - - :rtype: bool - """ - return self._tag == 'inherit_members' + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + ] - def is_dont_inherit_members(self): - """ - Check if the union tag is ``dont_inherit_members``. + _has_required_fields = False - :rtype: bool - """ - return self._tag == 'dont_inherit_members' + def __init__(self, + previous_value=None): + self._previous_value_value = None + self._previous_value_present = False + if previous_value is not None: + self.previous_value = previous_value - def is_other(self): + @property + def previous_value(self): """ - Check if the union tag is ``other``. + Previous shared link expiration date. Might be missing due to historical + data gap. - :rtype: bool + :rtype: datetime.datetime """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderMembersInheritancePolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SharedFolderMembersInheritancePolicy(%r, %r)' % (self._tag, self._value) - -SharedFolderMembersInheritancePolicy_validator = bv.Union(SharedFolderMembersInheritancePolicy) - -class SharedFolderMountDetails(bb.Struct): - """ - Added shared folder to own Dropbox. - """ - - __slots__ = [ - ] + if self._previous_value_present: + return self._previous_value_value + else: + return None - _has_required_fields = False + @previous_value.setter + def previous_value(self, val): + if val is None: + del self.previous_value + return + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - def __init__(self): - pass + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderMountDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkRemoveExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderMountDetails()' + return 'SharedLinkRemoveExpiryDetails(previous_value={!r})'.format( + self._previous_value_value, + ) -SharedFolderMountDetails_validator = bv.Struct(SharedFolderMountDetails) +SharedLinkRemoveExpiryDetails_validator = bv.Struct(SharedLinkRemoveExpiryDetails) -class SharedFolderMountType(bb.Struct): +class SharedLinkRemoveExpiryType(bb.Struct): __slots__ = [ '_description_value', @@ -56622,183 +77696,146 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderMountType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkRemoveExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderMountType(description={!r})'.format( + return 'SharedLinkRemoveExpiryType(description={!r})'.format( self._description_value, ) -SharedFolderMountType_validator = bv.Struct(SharedFolderMountType) +SharedLinkRemoveExpiryType_validator = bv.Struct(SharedLinkRemoveExpiryType) -class SharedFolderNestDetails(bb.Struct): +class SharedLinkSettingsAddExpirationDetails(bb.Struct): """ - Changed parent of shared folder. + Added an expiration date to the shared link. - :ivar team_log.SharedFolderNestDetails.previous_parent_ns_id: Previous - parent namespace ID. Might be missing due to historical data gap. - :ivar team_log.SharedFolderNestDetails.new_parent_ns_id: New parent - namespace ID. Might be missing due to historical data gap. - :ivar team_log.SharedFolderNestDetails.previous_ns_path: Previous namespace - path. Might be missing due to historical data gap. - :ivar team_log.SharedFolderNestDetails.new_ns_path: New namespace path. - Might be missing due to historical data gap. + :ivar + team_log.SharedLinkSettingsAddExpirationDetails.shared_content_access_level: + Shared content access level. + :ivar team_log.SharedLinkSettingsAddExpirationDetails.shared_content_link: + Shared content link. + :ivar team_log.SharedLinkSettingsAddExpirationDetails.new_value: New shared + content link expiration date. Might be missing due to historical data + gap. """ __slots__ = [ - '_previous_parent_ns_id_value', - '_previous_parent_ns_id_present', - '_new_parent_ns_id_value', - '_new_parent_ns_id_present', - '_previous_ns_path_value', - '_previous_ns_path_present', - '_new_ns_path_value', - '_new_ns_path_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', + '_new_value_value', + '_new_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - previous_parent_ns_id=None, - new_parent_ns_id=None, - previous_ns_path=None, - new_ns_path=None): - self._previous_parent_ns_id_value = None - self._previous_parent_ns_id_present = False - self._new_parent_ns_id_value = None - self._new_parent_ns_id_present = False - self._previous_ns_path_value = None - self._previous_ns_path_present = False - self._new_ns_path_value = None - self._new_ns_path_present = False - if previous_parent_ns_id is not None: - self.previous_parent_ns_id = previous_parent_ns_id - if new_parent_ns_id is not None: - self.new_parent_ns_id = new_parent_ns_id - if previous_ns_path is not None: - self.previous_ns_path = previous_ns_path - if new_ns_path is not None: - self.new_ns_path = new_ns_path - - @property - def previous_parent_ns_id(self): - """ - Previous parent namespace ID. Might be missing due to historical data - gap. - - :rtype: str - """ - if self._previous_parent_ns_id_present: - return self._previous_parent_ns_id_value - else: - return None - - @previous_parent_ns_id.setter - def previous_parent_ns_id(self, val): - if val is None: - del self.previous_parent_ns_id - return - val = self._previous_parent_ns_id_validator.validate(val) - self._previous_parent_ns_id_value = val - self._previous_parent_ns_id_present = True - - @previous_parent_ns_id.deleter - def previous_parent_ns_id(self): - self._previous_parent_ns_id_value = None - self._previous_parent_ns_id_present = False + shared_content_access_level=None, + shared_content_link=None, + new_value=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False + self._new_value_value = None + self._new_value_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link + if new_value is not None: + self.new_value = new_value @property - def new_parent_ns_id(self): + def shared_content_access_level(self): """ - New parent namespace ID. Might be missing due to historical data gap. + Shared content access level. - :rtype: str + :rtype: sharing.AccessLevel """ - if self._new_parent_ns_id_present: - return self._new_parent_ns_id_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - return None + raise AttributeError("missing required field 'shared_content_access_level'") - @new_parent_ns_id.setter - def new_parent_ns_id(self, val): - if val is None: - del self.new_parent_ns_id - return - val = self._new_parent_ns_id_validator.validate(val) - self._new_parent_ns_id_value = val - self._new_parent_ns_id_present = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - @new_parent_ns_id.deleter - def new_parent_ns_id(self): - self._new_parent_ns_id_value = None - self._new_parent_ns_id_present = False + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False @property - def previous_ns_path(self): + def shared_content_link(self): """ - Previous namespace path. Might be missing due to historical data gap. + Shared content link. :rtype: str """ - if self._previous_ns_path_present: - return self._previous_ns_path_value + if self._shared_content_link_present: + return self._shared_content_link_value else: return None - @previous_ns_path.setter - def previous_ns_path(self, val): + @shared_content_link.setter + def shared_content_link(self, val): if val is None: - del self.previous_ns_path + del self.shared_content_link return - val = self._previous_ns_path_validator.validate(val) - self._previous_ns_path_value = val - self._previous_ns_path_present = True + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True - @previous_ns_path.deleter - def previous_ns_path(self): - self._previous_ns_path_value = None - self._previous_ns_path_present = False + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False @property - def new_ns_path(self): + def new_value(self): """ - New namespace path. Might be missing due to historical data gap. + New shared content link expiration date. Might be missing due to + historical data gap. - :rtype: str + :rtype: datetime.datetime """ - if self._new_ns_path_present: - return self._new_ns_path_value + if self._new_value_present: + return self._new_value_value else: return None - @new_ns_path.setter - def new_ns_path(self, val): + @new_value.setter + def new_value(self, val): if val is None: - del self.new_ns_path + del self.new_value return - val = self._new_ns_path_validator.validate(val) - self._new_ns_path_value = val - self._new_ns_path_present = True + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True - @new_ns_path.deleter - def new_ns_path(self): - self._new_ns_path_value = None - self._new_ns_path_present = False + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderNestDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAddExpirationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderNestDetails(previous_parent_ns_id={!r}, new_parent_ns_id={!r}, previous_ns_path={!r}, new_ns_path={!r})'.format( - self._previous_parent_ns_id_value, - self._new_parent_ns_id_value, - self._previous_ns_path_value, - self._new_ns_path_value, + return 'SharedLinkSettingsAddExpirationDetails(shared_content_access_level={!r}, shared_content_link={!r}, new_value={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, + self._new_value_value, ) -SharedFolderNestDetails_validator = bv.Struct(SharedFolderNestDetails) +SharedLinkSettingsAddExpirationDetails_validator = bv.Struct(SharedLinkSettingsAddExpirationDetails) -class SharedFolderNestType(bb.Struct): +class SharedLinkSettingsAddExpirationType(bb.Struct): __slots__ = [ '_description_value', @@ -56836,107 +77873,108 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderNestType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAddExpirationType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderNestType(description={!r})'.format( + return 'SharedLinkSettingsAddExpirationType(description={!r})'.format( self._description_value, ) -SharedFolderNestType_validator = bv.Struct(SharedFolderNestType) +SharedLinkSettingsAddExpirationType_validator = bv.Struct(SharedLinkSettingsAddExpirationType) -class SharedFolderTransferOwnershipDetails(bb.Struct): +class SharedLinkSettingsAddPasswordDetails(bb.Struct): """ - Transferred ownership of shared folder to another member. + Added a password to the shared link. - :ivar team_log.SharedFolderTransferOwnershipDetails.previous_owner_email: - The email address of the previous shared folder owner. - :ivar team_log.SharedFolderTransferOwnershipDetails.new_owner_email: The - email address of the new shared folder owner. + :ivar + team_log.SharedLinkSettingsAddPasswordDetails.shared_content_access_level: + Shared content access level. + :ivar team_log.SharedLinkSettingsAddPasswordDetails.shared_content_link: + Shared content link. """ __slots__ = [ - '_previous_owner_email_value', - '_previous_owner_email_present', - '_new_owner_email_value', - '_new_owner_email_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', ] _has_required_fields = True def __init__(self, - new_owner_email=None, - previous_owner_email=None): - self._previous_owner_email_value = None - self._previous_owner_email_present = False - self._new_owner_email_value = None - self._new_owner_email_present = False - if previous_owner_email is not None: - self.previous_owner_email = previous_owner_email - if new_owner_email is not None: - self.new_owner_email = new_owner_email + shared_content_access_level=None, + shared_content_link=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link @property - def previous_owner_email(self): + def shared_content_access_level(self): """ - The email address of the previous shared folder owner. + Shared content access level. - :rtype: str + :rtype: sharing.AccessLevel """ - if self._previous_owner_email_present: - return self._previous_owner_email_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - return None + raise AttributeError("missing required field 'shared_content_access_level'") - @previous_owner_email.setter - def previous_owner_email(self, val): - if val is None: - del self.previous_owner_email - return - val = self._previous_owner_email_validator.validate(val) - self._previous_owner_email_value = val - self._previous_owner_email_present = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - @previous_owner_email.deleter - def previous_owner_email(self): - self._previous_owner_email_value = None - self._previous_owner_email_present = False + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False @property - def new_owner_email(self): + def shared_content_link(self): """ - The email address of the new shared folder owner. + Shared content link. :rtype: str """ - if self._new_owner_email_present: - return self._new_owner_email_value + if self._shared_content_link_present: + return self._shared_content_link_value else: - raise AttributeError("missing required field 'new_owner_email'") + return None - @new_owner_email.setter - def new_owner_email(self, val): - val = self._new_owner_email_validator.validate(val) - self._new_owner_email_value = val - self._new_owner_email_present = True + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True - @new_owner_email.deleter - def new_owner_email(self): - self._new_owner_email_value = None - self._new_owner_email_present = False + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderTransferOwnershipDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAddPasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderTransferOwnershipDetails(new_owner_email={!r}, previous_owner_email={!r})'.format( - self._new_owner_email_value, - self._previous_owner_email_value, + return 'SharedLinkSettingsAddPasswordDetails(shared_content_access_level={!r}, shared_content_link={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, ) -SharedFolderTransferOwnershipDetails_validator = bv.Struct(SharedFolderTransferOwnershipDetails) +SharedLinkSettingsAddPasswordDetails_validator = bv.Struct(SharedLinkSettingsAddPasswordDetails) -class SharedFolderTransferOwnershipType(bb.Struct): +class SharedLinkSettingsAddPasswordType(bb.Struct): __slots__ = [ '_description_value', @@ -56974,37 +78012,109 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderTransferOwnershipType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAddPasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderTransferOwnershipType(description={!r})'.format( + return 'SharedLinkSettingsAddPasswordType(description={!r})'.format( self._description_value, ) -SharedFolderTransferOwnershipType_validator = bv.Struct(SharedFolderTransferOwnershipType) +SharedLinkSettingsAddPasswordType_validator = bv.Struct(SharedLinkSettingsAddPasswordType) -class SharedFolderUnmountDetails(bb.Struct): +class SharedLinkSettingsAllowDownloadDisabledDetails(bb.Struct): """ - Deleted shared folder from Dropbox. + Disabled downloads. + + :ivar + team_log.SharedLinkSettingsAllowDownloadDisabledDetails.shared_content_access_level: + Shared content access level. + :ivar + team_log.SharedLinkSettingsAllowDownloadDisabledDetails.shared_content_link: + Shared content link. """ __slots__ = [ + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + shared_content_access_level=None, + shared_content_link=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link + + @property + def shared_content_access_level(self): + """ + Shared content access level. + + :rtype: sharing.AccessLevel + """ + if self._shared_content_access_level_present: + return self._shared_content_access_level_value + else: + raise AttributeError("missing required field 'shared_content_access_level'") + + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True + + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + + @property + def shared_content_link(self): + """ + Shared content link. + + :rtype: str + """ + if self._shared_content_link_present: + return self._shared_content_link_value + else: + return None + + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True + + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderUnmountDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAllowDownloadDisabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderUnmountDetails()' + return 'SharedLinkSettingsAllowDownloadDisabledDetails(shared_content_access_level={!r}, shared_content_link={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, + ) -SharedFolderUnmountDetails_validator = bv.Struct(SharedFolderUnmountDetails) +SharedLinkSettingsAllowDownloadDisabledDetails_validator = bv.Struct(SharedLinkSettingsAllowDownloadDisabledDetails) -class SharedFolderUnmountType(bb.Struct): +class SharedLinkSettingsAllowDownloadDisabledType(bb.Struct): __slots__ = [ '_description_value', @@ -57042,130 +78152,109 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedFolderUnmountType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAllowDownloadDisabledType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedFolderUnmountType(description={!r})'.format( + return 'SharedLinkSettingsAllowDownloadDisabledType(description={!r})'.format( self._description_value, ) -SharedFolderUnmountType_validator = bv.Struct(SharedFolderUnmountType) +SharedLinkSettingsAllowDownloadDisabledType_validator = bv.Struct(SharedLinkSettingsAllowDownloadDisabledType) -class SharedLinkAccessLevel(bb.Union): +class SharedLinkSettingsAllowDownloadEnabledDetails(bb.Struct): """ - Shared link access level. + Enabled downloads. - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. + :ivar + team_log.SharedLinkSettingsAllowDownloadEnabledDetails.shared_content_access_level: + Shared content access level. + :ivar + team_log.SharedLinkSettingsAllowDownloadEnabledDetails.shared_content_link: + Shared content link. """ - _catch_all = 'other' - # Attribute is overwritten below the class definition - none = None - # Attribute is overwritten below the class definition - reader = None - # Attribute is overwritten below the class definition - writer = None - # Attribute is overwritten below the class definition - other = None - - def is_none(self): - """ - Check if the union tag is ``none``. - - :rtype: bool - """ - return self._tag == 'none' - - def is_reader(self): - """ - Check if the union tag is ``reader``. - - :rtype: bool - """ - return self._tag == 'reader' + __slots__ = [ + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', + ] - def is_writer(self): - """ - Check if the union tag is ``writer``. + _has_required_fields = True - :rtype: bool - """ - return self._tag == 'writer' + def __init__(self, + shared_content_access_level=None, + shared_content_link=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link - def is_other(self): + @property + def shared_content_access_level(self): """ - Check if the union tag is ``other``. + Shared content access level. - :rtype: bool + :rtype: sharing.AccessLevel """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkAccessLevel, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SharedLinkAccessLevel(%r, %r)' % (self._tag, self._value) - -SharedLinkAccessLevel_validator = bv.Union(SharedLinkAccessLevel) - -class SharedLinkAddExpiryDetails(bb.Struct): - """ - Added shared link expiration date. - - :ivar team_log.SharedLinkAddExpiryDetails.new_value: New shared link - expiration date. - """ - - __slots__ = [ - '_new_value_value', - '_new_value_present', - ] + if self._shared_content_access_level_present: + return self._shared_content_access_level_value + else: + raise AttributeError("missing required field 'shared_content_access_level'") - _has_required_fields = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - def __init__(self, - new_value=None): - self._new_value_value = None - self._new_value_present = False - if new_value is not None: - self.new_value = new_value + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False @property - def new_value(self): + def shared_content_link(self): """ - New shared link expiration date. + Shared content link. - :rtype: datetime.datetime + :rtype: str """ - if self._new_value_present: - return self._new_value_value + if self._shared_content_link_present: + return self._shared_content_link_value else: - raise AttributeError("missing required field 'new_value'") + return None - @new_value.setter - def new_value(self, val): - val = self._new_value_validator.validate(val) - self._new_value_value = val - self._new_value_present = True + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkAddExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAllowDownloadEnabledDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkAddExpiryDetails(new_value={!r})'.format( - self._new_value_value, + return 'SharedLinkSettingsAllowDownloadEnabledDetails(shared_content_access_level={!r}, shared_content_link={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, ) -SharedLinkAddExpiryDetails_validator = bv.Struct(SharedLinkAddExpiryDetails) +SharedLinkSettingsAllowDownloadEnabledDetails_validator = bv.Struct(SharedLinkSettingsAllowDownloadEnabledDetails) -class SharedLinkAddExpiryType(bb.Struct): +class SharedLinkSettingsAllowDownloadEnabledType(bb.Struct): __slots__ = [ '_description_value', @@ -57203,65 +78292,129 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkAddExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsAllowDownloadEnabledType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkAddExpiryType(description={!r})'.format( + return 'SharedLinkSettingsAllowDownloadEnabledType(description={!r})'.format( self._description_value, ) -SharedLinkAddExpiryType_validator = bv.Struct(SharedLinkAddExpiryType) +SharedLinkSettingsAllowDownloadEnabledType_validator = bv.Struct(SharedLinkSettingsAllowDownloadEnabledType) -class SharedLinkChangeExpiryDetails(bb.Struct): +class SharedLinkSettingsChangeAudienceDetails(bb.Struct): """ - Changed shared link expiration date. + Changed the audience of the shared link. - :ivar team_log.SharedLinkChangeExpiryDetails.new_value: New shared link - expiration date. Might be missing due to historical data gap. - :ivar team_log.SharedLinkChangeExpiryDetails.previous_value: Previous shared - link expiration date. Might be missing due to historical data gap. + :ivar + team_log.SharedLinkSettingsChangeAudienceDetails.shared_content_access_level: + Shared content access level. + :ivar team_log.SharedLinkSettingsChangeAudienceDetails.shared_content_link: + Shared content link. + :ivar team_log.SharedLinkSettingsChangeAudienceDetails.new_value: New link + audience value. + :ivar team_log.SharedLinkSettingsChangeAudienceDetails.previous_value: + Previous link audience value. """ __slots__ = [ + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', '_new_value_value', '_new_value_present', '_previous_value_value', '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, + shared_content_access_level=None, new_value=None, + shared_content_link=None, previous_value=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False self._new_value_value = None self._new_value_present = False self._previous_value_value = None self._previous_value_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link if new_value is not None: self.new_value = new_value if previous_value is not None: self.previous_value = previous_value + @property + def shared_content_access_level(self): + """ + Shared content access level. + + :rtype: sharing.AccessLevel + """ + if self._shared_content_access_level_present: + return self._shared_content_access_level_value + else: + raise AttributeError("missing required field 'shared_content_access_level'") + + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True + + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + + @property + def shared_content_link(self): + """ + Shared content link. + + :rtype: str + """ + if self._shared_content_link_present: + return self._shared_content_link_value + else: + return None + + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True + + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False + @property def new_value(self): """ - New shared link expiration date. Might be missing due to historical data - gap. + New link audience value. - :rtype: datetime.datetime + :rtype: sharing.LinkAudience """ if self._new_value_present: return self._new_value_value else: - return None + raise AttributeError("missing required field 'new_value'") @new_value.setter def new_value(self, val): - if val is None: - del self.new_value - return - val = self._new_value_validator.validate(val) + self._new_value_validator.validate_type_only(val) self._new_value_value = val self._new_value_present = True @@ -57273,10 +78426,9 @@ def new_value(self): @property def previous_value(self): """ - Previous shared link expiration date. Might be missing due to historical - data gap. + Previous link audience value. - :rtype: datetime.datetime + :rtype: sharing.LinkAudience """ if self._previous_value_present: return self._previous_value_value @@ -57288,7 +78440,7 @@ def previous_value(self, val): if val is None: del self.previous_value return - val = self._previous_value_validator.validate(val) + self._previous_value_validator.validate_type_only(val) self._previous_value_value = val self._previous_value_present = True @@ -57298,17 +78450,19 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkChangeExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsChangeAudienceDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkChangeExpiryDetails(new_value={!r}, previous_value={!r})'.format( + return 'SharedLinkSettingsChangeAudienceDetails(shared_content_access_level={!r}, new_value={!r}, shared_content_link={!r}, previous_value={!r})'.format( + self._shared_content_access_level_value, self._new_value_value, + self._shared_content_link_value, self._previous_value_value, ) -SharedLinkChangeExpiryDetails_validator = bv.Struct(SharedLinkChangeExpiryDetails) +SharedLinkSettingsChangeAudienceDetails_validator = bv.Struct(SharedLinkSettingsChangeAudienceDetails) -class SharedLinkChangeExpiryType(bb.Struct): +class SharedLinkSettingsChangeAudienceType(bb.Struct): __slots__ = [ '_description_value', @@ -57346,26 +78500,38 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkChangeExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsChangeAudienceType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkChangeExpiryType(description={!r})'.format( + return 'SharedLinkSettingsChangeAudienceType(description={!r})'.format( self._description_value, ) -SharedLinkChangeExpiryType_validator = bv.Struct(SharedLinkChangeExpiryType) +SharedLinkSettingsChangeAudienceType_validator = bv.Struct(SharedLinkSettingsChangeAudienceType) -class SharedLinkChangeVisibilityDetails(bb.Struct): +class SharedLinkSettingsChangeExpirationDetails(bb.Struct): """ - Changed visibility of shared link. + Changed the expiration date of the shared link. - :ivar team_log.SharedLinkChangeVisibilityDetails.new_value: New shared link - visibility. - :ivar team_log.SharedLinkChangeVisibilityDetails.previous_value: Previous - shared link visibility. Might be missing due to historical data gap. + :ivar + team_log.SharedLinkSettingsChangeExpirationDetails.shared_content_access_level: + Shared content access level. + :ivar + team_log.SharedLinkSettingsChangeExpirationDetails.shared_content_link: + Shared content link. + :ivar team_log.SharedLinkSettingsChangeExpirationDetails.new_value: New + shared content link expiration date. Might be missing due to historical + data gap. + :ivar team_log.SharedLinkSettingsChangeExpirationDetails.previous_value: + Previous shared content link expiration date. Might be missing due to + historical data gap. """ __slots__ = [ + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', '_new_value_value', '_new_value_present', '_previous_value_value', @@ -57375,32 +78541,95 @@ class SharedLinkChangeVisibilityDetails(bb.Struct): _has_required_fields = True def __init__(self, + shared_content_access_level=None, + shared_content_link=None, new_value=None, previous_value=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False self._new_value_value = None self._new_value_present = False self._previous_value_value = None self._previous_value_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link if new_value is not None: self.new_value = new_value if previous_value is not None: self.previous_value = previous_value + @property + def shared_content_access_level(self): + """ + Shared content access level. + + :rtype: sharing.AccessLevel + """ + if self._shared_content_access_level_present: + return self._shared_content_access_level_value + else: + raise AttributeError("missing required field 'shared_content_access_level'") + + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True + + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + + @property + def shared_content_link(self): + """ + Shared content link. + + :rtype: str + """ + if self._shared_content_link_present: + return self._shared_content_link_value + else: + return None + + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True + + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False + @property def new_value(self): """ - New shared link visibility. + New shared content link expiration date. Might be missing due to + historical data gap. - :rtype: SharedLinkVisibility + :rtype: datetime.datetime """ if self._new_value_present: return self._new_value_value else: - raise AttributeError("missing required field 'new_value'") + return None @new_value.setter def new_value(self, val): - self._new_value_validator.validate_type_only(val) + if val is None: + del self.new_value + return + val = self._new_value_validator.validate(val) self._new_value_value = val self._new_value_present = True @@ -57412,10 +78641,10 @@ def new_value(self): @property def previous_value(self): """ - Previous shared link visibility. Might be missing due to historical data - gap. + Previous shared content link expiration date. Might be missing due to + historical data gap. - :rtype: SharedLinkVisibility + :rtype: datetime.datetime """ if self._previous_value_present: return self._previous_value_value @@ -57427,7 +78656,7 @@ def previous_value(self, val): if val is None: del self.previous_value return - self._previous_value_validator.validate_type_only(val) + val = self._previous_value_validator.validate(val) self._previous_value_value = val self._previous_value_present = True @@ -57437,17 +78666,19 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkChangeVisibilityDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsChangeExpirationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkChangeVisibilityDetails(new_value={!r}, previous_value={!r})'.format( + return 'SharedLinkSettingsChangeExpirationDetails(shared_content_access_level={!r}, shared_content_link={!r}, new_value={!r}, previous_value={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, self._new_value_value, self._previous_value_value, ) -SharedLinkChangeVisibilityDetails_validator = bv.Struct(SharedLinkChangeVisibilityDetails) +SharedLinkSettingsChangeExpirationDetails_validator = bv.Struct(SharedLinkSettingsChangeExpirationDetails) -class SharedLinkChangeVisibilityType(bb.Struct): +class SharedLinkSettingsChangeExpirationType(bb.Struct): __slots__ = [ '_description_value', @@ -57485,180 +78716,108 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkChangeVisibilityType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsChangeExpirationType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkChangeVisibilityType(description={!r})'.format( + return 'SharedLinkSettingsChangeExpirationType(description={!r})'.format( self._description_value, ) -SharedLinkChangeVisibilityType_validator = bv.Struct(SharedLinkChangeVisibilityType) +SharedLinkSettingsChangeExpirationType_validator = bv.Struct(SharedLinkSettingsChangeExpirationType) -class SharedLinkCopyDetails(bb.Struct): +class SharedLinkSettingsChangePasswordDetails(bb.Struct): """ - Added file/folder to Dropbox from shared link. + Changed the password of the shared link. - :ivar team_log.SharedLinkCopyDetails.shared_link_owner: Shared link owner - details. Might be missing due to historical data gap. + :ivar + team_log.SharedLinkSettingsChangePasswordDetails.shared_content_access_level: + Shared content access level. + :ivar team_log.SharedLinkSettingsChangePasswordDetails.shared_content_link: + Shared content link. """ __slots__ = [ - '_shared_link_owner_value', - '_shared_link_owner_present', - ] - - _has_required_fields = False - - def __init__(self, - shared_link_owner=None): - self._shared_link_owner_value = None - self._shared_link_owner_present = False - if shared_link_owner is not None: - self.shared_link_owner = shared_link_owner - - @property - def shared_link_owner(self): - """ - Shared link owner details. Might be missing due to historical data gap. - - :rtype: UserLogInfo - """ - if self._shared_link_owner_present: - return self._shared_link_owner_value - else: - return None - - @shared_link_owner.setter - def shared_link_owner(self, val): - if val is None: - del self.shared_link_owner - return - self._shared_link_owner_validator.validate_type_only(val) - self._shared_link_owner_value = val - self._shared_link_owner_present = True - - @shared_link_owner.deleter - def shared_link_owner(self): - self._shared_link_owner_value = None - self._shared_link_owner_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkCopyDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SharedLinkCopyDetails(shared_link_owner={!r})'.format( - self._shared_link_owner_value, - ) - -SharedLinkCopyDetails_validator = bv.Struct(SharedLinkCopyDetails) - -class SharedLinkCopyType(bb.Struct): - - __slots__ = [ - '_description_value', - '_description_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', ] _has_required_fields = True def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + shared_content_access_level=None, + shared_content_link=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link @property - def description(self): + def shared_content_access_level(self): """ - :rtype: str + Shared content access level. + + :rtype: sharing.AccessLevel """ - if self._description_present: - return self._description_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkCopyType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SharedLinkCopyType(description={!r})'.format( - self._description_value, - ) - -SharedLinkCopyType_validator = bv.Struct(SharedLinkCopyType) - -class SharedLinkCreateDetails(bb.Struct): - """ - Created shared link. - - :ivar team_log.SharedLinkCreateDetails.shared_link_access_level: Defines who - can access the shared link. Might be missing due to historical data gap. - """ - - __slots__ = [ - '_shared_link_access_level_value', - '_shared_link_access_level_present', - ] + raise AttributeError("missing required field 'shared_content_access_level'") - _has_required_fields = False + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - def __init__(self, - shared_link_access_level=None): - self._shared_link_access_level_value = None - self._shared_link_access_level_present = False - if shared_link_access_level is not None: - self.shared_link_access_level = shared_link_access_level + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False @property - def shared_link_access_level(self): + def shared_content_link(self): """ - Defines who can access the shared link. Might be missing due to - historical data gap. + Shared content link. - :rtype: SharedLinkAccessLevel + :rtype: str """ - if self._shared_link_access_level_present: - return self._shared_link_access_level_value + if self._shared_content_link_present: + return self._shared_content_link_value else: return None - @shared_link_access_level.setter - def shared_link_access_level(self, val): + @shared_content_link.setter + def shared_content_link(self, val): if val is None: - del self.shared_link_access_level + del self.shared_content_link return - self._shared_link_access_level_validator.validate_type_only(val) - self._shared_link_access_level_value = val - self._shared_link_access_level_present = True + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True - @shared_link_access_level.deleter - def shared_link_access_level(self): - self._shared_link_access_level_value = None - self._shared_link_access_level_present = False + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkCreateDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsChangePasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkCreateDetails(shared_link_access_level={!r})'.format( - self._shared_link_access_level_value, + return 'SharedLinkSettingsChangePasswordDetails(shared_content_access_level={!r}, shared_content_link={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, ) -SharedLinkCreateDetails_validator = bv.Struct(SharedLinkCreateDetails) +SharedLinkSettingsChangePasswordDetails_validator = bv.Struct(SharedLinkSettingsChangePasswordDetails) -class SharedLinkCreateType(bb.Struct): +class SharedLinkSettingsChangePasswordType(bb.Struct): __slots__ = [ '_description_value', @@ -57696,179 +78855,147 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkCreateType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsChangePasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkCreateType(description={!r})'.format( + return 'SharedLinkSettingsChangePasswordType(description={!r})'.format( self._description_value, ) -SharedLinkCreateType_validator = bv.Struct(SharedLinkCreateType) +SharedLinkSettingsChangePasswordType_validator = bv.Struct(SharedLinkSettingsChangePasswordType) -class SharedLinkDisableDetails(bb.Struct): +class SharedLinkSettingsRemoveExpirationDetails(bb.Struct): """ - Removed shared link. + Removed the expiration date from the shared link. - :ivar team_log.SharedLinkDisableDetails.shared_link_owner: Shared link owner - details. Might be missing due to historical data gap. + :ivar + team_log.SharedLinkSettingsRemoveExpirationDetails.shared_content_access_level: + Shared content access level. + :ivar + team_log.SharedLinkSettingsRemoveExpirationDetails.shared_content_link: + Shared content link. + :ivar team_log.SharedLinkSettingsRemoveExpirationDetails.previous_value: + Previous shared link expiration date. Might be missing due to historical + data gap. """ __slots__ = [ - '_shared_link_owner_value', - '_shared_link_owner_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - shared_link_owner=None): - self._shared_link_owner_value = None - self._shared_link_owner_present = False - if shared_link_owner is not None: - self.shared_link_owner = shared_link_owner + shared_content_access_level=None, + shared_content_link=None, + previous_value=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False + self._previous_value_value = None + self._previous_value_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link + if previous_value is not None: + self.previous_value = previous_value @property - def shared_link_owner(self): + def shared_content_access_level(self): """ - Shared link owner details. Might be missing due to historical data gap. + Shared content access level. - :rtype: UserLogInfo + :rtype: sharing.AccessLevel """ - if self._shared_link_owner_present: - return self._shared_link_owner_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value else: - return None - - @shared_link_owner.setter - def shared_link_owner(self, val): - if val is None: - del self.shared_link_owner - return - self._shared_link_owner_validator.validate_type_only(val) - self._shared_link_owner_value = val - self._shared_link_owner_present = True - - @shared_link_owner.deleter - def shared_link_owner(self): - self._shared_link_owner_value = None - self._shared_link_owner_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkDisableDetails, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SharedLinkDisableDetails(shared_link_owner={!r})'.format( - self._shared_link_owner_value, - ) - -SharedLinkDisableDetails_validator = bv.Struct(SharedLinkDisableDetails) - -class SharedLinkDisableType(bb.Struct): - - __slots__ = [ - '_description_value', - '_description_present', - ] + raise AttributeError("missing required field 'shared_content_access_level'") - _has_required_fields = True + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True - def __init__(self, - description=None): - self._description_value = None - self._description_present = False - if description is not None: - self.description = description + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False @property - def description(self): + def shared_content_link(self): """ + Shared content link. + :rtype: str """ - if self._description_present: - return self._description_value + if self._shared_content_link_present: + return self._shared_content_link_value else: - raise AttributeError("missing required field 'description'") - - @description.setter - def description(self, val): - val = self._description_validator.validate(val) - self._description_value = val - self._description_present = True - - @description.deleter - def description(self): - self._description_value = None - self._description_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkDisableType, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'SharedLinkDisableType(description={!r})'.format( - self._description_value, - ) - -SharedLinkDisableType_validator = bv.Struct(SharedLinkDisableType) - -class SharedLinkDownloadDetails(bb.Struct): - """ - Downloaded file/folder from shared link. - - :ivar team_log.SharedLinkDownloadDetails.shared_link_owner: Shared link - owner details. Might be missing due to historical data gap. - """ - - __slots__ = [ - '_shared_link_owner_value', - '_shared_link_owner_present', - ] + return None - _has_required_fields = False + @shared_content_link.setter + def shared_content_link(self, val): + if val is None: + del self.shared_content_link + return + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True - def __init__(self, - shared_link_owner=None): - self._shared_link_owner_value = None - self._shared_link_owner_present = False - if shared_link_owner is not None: - self.shared_link_owner = shared_link_owner + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False @property - def shared_link_owner(self): + def previous_value(self): """ - Shared link owner details. Might be missing due to historical data gap. + Previous shared link expiration date. Might be missing due to historical + data gap. - :rtype: UserLogInfo + :rtype: datetime.datetime """ - if self._shared_link_owner_present: - return self._shared_link_owner_value + if self._previous_value_present: + return self._previous_value_value else: return None - @shared_link_owner.setter - def shared_link_owner(self, val): + @previous_value.setter + def previous_value(self, val): if val is None: - del self.shared_link_owner + del self.previous_value return - self._shared_link_owner_validator.validate_type_only(val) - self._shared_link_owner_value = val - self._shared_link_owner_present = True + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True - @shared_link_owner.deleter - def shared_link_owner(self): - self._shared_link_owner_value = None - self._shared_link_owner_present = False + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkDownloadDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsRemoveExpirationDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkDownloadDetails(shared_link_owner={!r})'.format( - self._shared_link_owner_value, + return 'SharedLinkSettingsRemoveExpirationDetails(shared_content_access_level={!r}, shared_content_link={!r}, previous_value={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, + self._previous_value_value, ) -SharedLinkDownloadDetails_validator = bv.Struct(SharedLinkDownloadDetails) +SharedLinkSettingsRemoveExpirationDetails_validator = bv.Struct(SharedLinkSettingsRemoveExpirationDetails) -class SharedLinkDownloadType(bb.Struct): +class SharedLinkSettingsRemoveExpirationType(bb.Struct): __slots__ = [ '_description_value', @@ -57906,75 +79033,108 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkDownloadType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsRemoveExpirationType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkDownloadType(description={!r})'.format( + return 'SharedLinkSettingsRemoveExpirationType(description={!r})'.format( self._description_value, ) -SharedLinkDownloadType_validator = bv.Struct(SharedLinkDownloadType) +SharedLinkSettingsRemoveExpirationType_validator = bv.Struct(SharedLinkSettingsRemoveExpirationType) -class SharedLinkRemoveExpiryDetails(bb.Struct): +class SharedLinkSettingsRemovePasswordDetails(bb.Struct): """ - Removed shared link expiration date. + Removed the password from the shared link. - :ivar team_log.SharedLinkRemoveExpiryDetails.previous_value: Previous shared - link expiration date. Might be missing due to historical data gap. + :ivar + team_log.SharedLinkSettingsRemovePasswordDetails.shared_content_access_level: + Shared content access level. + :ivar team_log.SharedLinkSettingsRemovePasswordDetails.shared_content_link: + Shared content link. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', + '_shared_content_access_level_value', + '_shared_content_access_level_present', + '_shared_content_link_value', + '_shared_content_link_present', ] - _has_required_fields = False + _has_required_fields = True def __init__(self, - previous_value=None): - self._previous_value_value = None - self._previous_value_present = False - if previous_value is not None: - self.previous_value = previous_value + shared_content_access_level=None, + shared_content_link=None): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + self._shared_content_link_value = None + self._shared_content_link_present = False + if shared_content_access_level is not None: + self.shared_content_access_level = shared_content_access_level + if shared_content_link is not None: + self.shared_content_link = shared_content_link @property - def previous_value(self): + def shared_content_access_level(self): """ - Previous shared link expiration date. Might be missing due to historical - data gap. + Shared content access level. - :rtype: datetime.datetime + :rtype: sharing.AccessLevel """ - if self._previous_value_present: - return self._previous_value_value + if self._shared_content_access_level_present: + return self._shared_content_access_level_value + else: + raise AttributeError("missing required field 'shared_content_access_level'") + + @shared_content_access_level.setter + def shared_content_access_level(self, val): + self._shared_content_access_level_validator.validate_type_only(val) + self._shared_content_access_level_value = val + self._shared_content_access_level_present = True + + @shared_content_access_level.deleter + def shared_content_access_level(self): + self._shared_content_access_level_value = None + self._shared_content_access_level_present = False + + @property + def shared_content_link(self): + """ + Shared content link. + + :rtype: str + """ + if self._shared_content_link_present: + return self._shared_content_link_value else: return None - @previous_value.setter - def previous_value(self, val): + @shared_content_link.setter + def shared_content_link(self, val): if val is None: - del self.previous_value + del self.shared_content_link return - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + val = self._shared_content_link_validator.validate(val) + self._shared_content_link_value = val + self._shared_content_link_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @shared_content_link.deleter + def shared_content_link(self): + self._shared_content_link_value = None + self._shared_content_link_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkRemoveExpiryDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsRemovePasswordDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkRemoveExpiryDetails(previous_value={!r})'.format( - self._previous_value_value, + return 'SharedLinkSettingsRemovePasswordDetails(shared_content_access_level={!r}, shared_content_link={!r})'.format( + self._shared_content_access_level_value, + self._shared_content_link_value, ) -SharedLinkRemoveExpiryDetails_validator = bv.Struct(SharedLinkRemoveExpiryDetails) +SharedLinkSettingsRemovePasswordDetails_validator = bv.Struct(SharedLinkSettingsRemovePasswordDetails) -class SharedLinkRemoveExpiryType(bb.Struct): +class SharedLinkSettingsRemovePasswordType(bb.Struct): __slots__ = [ '_description_value', @@ -58012,14 +79172,14 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SharedLinkRemoveExpiryType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SharedLinkSettingsRemovePasswordType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SharedLinkRemoveExpiryType(description={!r})'.format( + return 'SharedLinkSettingsRemovePasswordType(description={!r})'.format( self._description_value, ) -SharedLinkRemoveExpiryType_validator = bv.Struct(SharedLinkRemoveExpiryType) +SharedLinkSettingsRemovePasswordType_validator = bv.Struct(SharedLinkSettingsRemovePasswordType) class SharedLinkShareDetails(bb.Struct): """ @@ -58937,6 +80097,8 @@ class SharingMemberPolicy(bb.Union): # Attribute is overwritten below the class definition forbid = None # Attribute is overwritten below the class definition + forbid_with_exclusions = None + # Attribute is overwritten below the class definition other = None def is_allow(self): @@ -58955,6 +80117,14 @@ def is_forbid(self): """ return self._tag == 'forbid' + def is_forbid_with_exclusions(self): + """ + Check if the union tag is ``forbid_with_exclusions``. + + :rtype: bool + """ + return self._tag == 'forbid_with_exclusions' + def is_other(self): """ Check if the union tag is ``other``. @@ -62986,6 +84156,141 @@ def __repr__(self): SmartSyncOptOutType_validator = bv.Struct(SmartSyncOptOutType) +class SmarterSmartSyncPolicyChangedDetails(bb.Struct): + """ + Changed automatic Smart Sync setting for team. + + :ivar team_log.SmarterSmartSyncPolicyChangedDetails.previous_value: Previous + automatic Smart Sync setting. + :ivar team_log.SmarterSmartSyncPolicyChangedDetails.new_value: New automatic + Smart Sync setting. + """ + + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] + + _has_required_fields = True + + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value + + @property + def previous_value(self): + """ + Previous automatic Smart Sync setting. + + :rtype: team_policies.SmarterSmartSyncPolicyState + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + @property + def new_value(self): + """ + New automatic Smart Sync setting. + + :rtype: team_policies.SmarterSmartSyncPolicyState + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SmarterSmartSyncPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SmarterSmartSyncPolicyChangedDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, + ) + +SmarterSmartSyncPolicyChangedDetails_validator = bv.Struct(SmarterSmartSyncPolicyChangedDetails) + +class SmarterSmartSyncPolicyChangedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SmarterSmartSyncPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SmarterSmartSyncPolicyChangedType(description={!r})'.format( + self._description_value, + ) + +SmarterSmartSyncPolicyChangedType_validator = bv.Struct(SmarterSmartSyncPolicyChangedType) + class SpaceCapsType(bb.Union): """ Space limit alert policy @@ -64194,37 +85499,139 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SsoErrorType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SsoErrorType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SsoErrorType(description={!r})'.format( + self._description_value, + ) + +SsoErrorType_validator = bv.Struct(SsoErrorType) + +class SsoRemoveCertDetails(bb.Struct): + """ + Removed X.509 certificate for SSO. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SsoRemoveCertDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SsoRemoveCertDetails()' + +SsoRemoveCertDetails_validator = bv.Struct(SsoRemoveCertDetails) + +class SsoRemoveCertType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SsoRemoveCertType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SsoErrorType(description={!r})'.format( + return 'SsoRemoveCertType(description={!r})'.format( self._description_value, ) -SsoErrorType_validator = bv.Struct(SsoErrorType) +SsoRemoveCertType_validator = bv.Struct(SsoRemoveCertType) -class SsoRemoveCertDetails(bb.Struct): +class SsoRemoveLoginUrlDetails(bb.Struct): """ - Removed X.509 certificate for SSO. + Removed sign-in URL for SSO. + + :ivar team_log.SsoRemoveLoginUrlDetails.previous_value: Previous single + sign-on login URL. """ __slots__ = [ + '_previous_value_value', + '_previous_value_present', ] - _has_required_fields = False + _has_required_fields = True - def __init__(self): - pass + def __init__(self, + previous_value=None): + self._previous_value_value = None + self._previous_value_present = False + if previous_value is not None: + self.previous_value = previous_value + + @property + def previous_value(self): + """ + Previous single sign-on login URL. + + :rtype: str + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SsoRemoveCertDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SsoRemoveLoginUrlDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SsoRemoveCertDetails()' + return 'SsoRemoveLoginUrlDetails(previous_value={!r})'.format( + self._previous_value_value, + ) -SsoRemoveCertDetails_validator = bv.Struct(SsoRemoveCertDetails) +SsoRemoveLoginUrlDetails_validator = bv.Struct(SsoRemoveLoginUrlDetails) -class SsoRemoveCertType(bb.Struct): +class SsoRemoveLoginUrlType(bb.Struct): __slots__ = [ '_description_value', @@ -64262,21 +85669,21 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SsoRemoveCertType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SsoRemoveLoginUrlType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SsoRemoveCertType(description={!r})'.format( + return 'SsoRemoveLoginUrlType(description={!r})'.format( self._description_value, ) -SsoRemoveCertType_validator = bv.Struct(SsoRemoveCertType) +SsoRemoveLoginUrlType_validator = bv.Struct(SsoRemoveLoginUrlType) -class SsoRemoveLoginUrlDetails(bb.Struct): +class SsoRemoveLogoutUrlDetails(bb.Struct): """ - Removed sign-in URL for SSO. + Removed sign-out URL for SSO. - :ivar team_log.SsoRemoveLoginUrlDetails.previous_value: Previous single - sign-on login URL. + :ivar team_log.SsoRemoveLogoutUrlDetails.previous_value: Previous single + sign-on logout URL. """ __slots__ = [ @@ -64296,7 +85703,7 @@ def __init__(self, @property def previous_value(self): """ - Previous single sign-on login URL. + Previous single sign-on logout URL. :rtype: str """ @@ -64317,16 +85724,16 @@ def previous_value(self): self._previous_value_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SsoRemoveLoginUrlDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SsoRemoveLogoutUrlDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SsoRemoveLoginUrlDetails(previous_value={!r})'.format( + return 'SsoRemoveLogoutUrlDetails(previous_value={!r})'.format( self._previous_value_value, ) -SsoRemoveLoginUrlDetails_validator = bv.Struct(SsoRemoveLoginUrlDetails) +SsoRemoveLogoutUrlDetails_validator = bv.Struct(SsoRemoveLogoutUrlDetails) -class SsoRemoveLoginUrlType(bb.Struct): +class SsoRemoveLogoutUrlType(bb.Struct): __slots__ = [ '_description_value', @@ -64364,71 +85771,72 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SsoRemoveLoginUrlType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(SsoRemoveLogoutUrlType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SsoRemoveLoginUrlType(description={!r})'.format( + return 'SsoRemoveLogoutUrlType(description={!r})'.format( self._description_value, ) -SsoRemoveLoginUrlType_validator = bv.Struct(SsoRemoveLoginUrlType) +SsoRemoveLogoutUrlType_validator = bv.Struct(SsoRemoveLogoutUrlType) -class SsoRemoveLogoutUrlDetails(bb.Struct): +class StartedEnterpriseAdminSessionDetails(bb.Struct): """ - Removed sign-out URL for SSO. + Started enterprise admin session. - :ivar team_log.SsoRemoveLogoutUrlDetails.previous_value: Previous single - sign-on logout URL. + :ivar + team_log.StartedEnterpriseAdminSessionDetails.federation_extra_details: + More information about the organization or team. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', + '_federation_extra_details_value', + '_federation_extra_details_present', ] _has_required_fields = True def __init__(self, - previous_value=None): - self._previous_value_value = None - self._previous_value_present = False - if previous_value is not None: - self.previous_value = previous_value + federation_extra_details=None): + self._federation_extra_details_value = None + self._federation_extra_details_present = False + if federation_extra_details is not None: + self.federation_extra_details = federation_extra_details @property - def previous_value(self): + def federation_extra_details(self): """ - Previous single sign-on logout URL. + More information about the organization or team. - :rtype: str + :rtype: FedExtraDetails """ - if self._previous_value_present: - return self._previous_value_value + if self._federation_extra_details_present: + return self._federation_extra_details_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'federation_extra_details'") - @previous_value.setter - def previous_value(self, val): - val = self._previous_value_validator.validate(val) - self._previous_value_value = val - self._previous_value_present = True + @federation_extra_details.setter + def federation_extra_details(self, val): + self._federation_extra_details_validator.validate_type_only(val) + self._federation_extra_details_value = val + self._federation_extra_details_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @federation_extra_details.deleter + def federation_extra_details(self): + self._federation_extra_details_value = None + self._federation_extra_details_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SsoRemoveLogoutUrlDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(StartedEnterpriseAdminSessionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SsoRemoveLogoutUrlDetails(previous_value={!r})'.format( - self._previous_value_value, + return 'StartedEnterpriseAdminSessionDetails(federation_extra_details={!r})'.format( + self._federation_extra_details_value, ) -SsoRemoveLogoutUrlDetails_validator = bv.Struct(SsoRemoveLogoutUrlDetails) +StartedEnterpriseAdminSessionDetails_validator = bv.Struct(StartedEnterpriseAdminSessionDetails) -class SsoRemoveLogoutUrlType(bb.Struct): +class StartedEnterpriseAdminSessionType(bb.Struct): __slots__ = [ '_description_value', @@ -64466,14 +85874,14 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(SsoRemoveLogoutUrlType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(StartedEnterpriseAdminSessionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'SsoRemoveLogoutUrlType(description={!r})'.format( + return 'StartedEnterpriseAdminSessionType(description={!r})'.format( self._description_value, ) -SsoRemoveLogoutUrlType_validator = bv.Struct(SsoRemoveLogoutUrlType) +StartedEnterpriseAdminSessionType_validator = bv.Struct(StartedEnterpriseAdminSessionType) class TeamActivityCreateReportDetails(bb.Struct): """ @@ -64711,6 +86119,60 @@ def __repr__(self): TeamActivityCreateReportType_validator = bv.Struct(TeamActivityCreateReportType) +class TeamDetails(bb.Struct): + """ + More details about the team. + + :ivar team_log.TeamDetails.team: The name of the team. + """ + + __slots__ = [ + '_team_value', + '_team_present', + ] + + _has_required_fields = True + + def __init__(self, + team=None): + self._team_value = None + self._team_present = False + if team is not None: + self.team = team + + @property + def team(self): + """ + The name of the team. + + :rtype: str + """ + if self._team_present: + return self._team_value + else: + raise AttributeError("missing required field 'team'") + + @team.setter + def team(self, val): + val = self._team_validator.validate(val) + self._team_value = val + self._team_present = True + + @team.deleter + def team(self): + self._team_value = None + self._team_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamDetails(team={!r})'.format( + self._team_value, + ) + +TeamDetails_validator = bv.Struct(TeamDetails) + class TeamEvent(bb.Struct): """ An audit log event. @@ -65792,6 +87254,61 @@ def __repr__(self): TeamFolderRenameType_validator = bv.Struct(TeamFolderRenameType) +class TeamInviteDetails(bb.Struct): + """ + Details about team invites + + :ivar team_log.TeamInviteDetails.invite_method: How the user was invited to + the team. + """ + + __slots__ = [ + '_invite_method_value', + '_invite_method_present', + ] + + _has_required_fields = True + + def __init__(self, + invite_method=None): + self._invite_method_value = None + self._invite_method_present = False + if invite_method is not None: + self.invite_method = invite_method + + @property + def invite_method(self): + """ + How the user was invited to the team. + + :rtype: InviteMethod + """ + if self._invite_method_present: + return self._invite_method_value + else: + raise AttributeError("missing required field 'invite_method'") + + @invite_method.setter + def invite_method(self, val): + self._invite_method_validator.validate_type_only(val) + self._invite_method_value = val + self._invite_method_present = True + + @invite_method.deleter + def invite_method(self): + self._invite_method_value = None + self._invite_method_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamInviteDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamInviteDetails(invite_method={!r})'.format( + self._invite_method_value, + ) + +TeamInviteDetails_validator = bv.Struct(TeamInviteDetails) + class TeamLinkedAppLogInfo(AppLogInfo): """ Team linked app @@ -65819,6 +87336,60 @@ def __repr__(self): TeamLinkedAppLogInfo_validator = bv.Struct(TeamLinkedAppLogInfo) +class TeamLogInfo(bb.Struct): + """ + Team's logged information. + + :ivar team_log.TeamLogInfo.display_name: Team display name. + """ + + __slots__ = [ + '_display_name_value', + '_display_name_present', + ] + + _has_required_fields = True + + def __init__(self, + display_name=None): + self._display_name_value = None + self._display_name_present = False + if display_name is not None: + self.display_name = display_name + + @property + def display_name(self): + """ + Team display name. + + :rtype: str + """ + if self._display_name_present: + return self._display_name_value + else: + raise AttributeError("missing required field 'display_name'") + + @display_name.setter + def display_name(self, val): + val = self._display_name_validator.validate(val) + self._display_name_value = val + self._display_name_present = True + + @display_name.deleter + def display_name(self): + self._display_name_value = None + self._display_name_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamLogInfo(display_name={!r})'.format( + self._display_name_value, + ) + +TeamLogInfo_validator = bv.Struct(TeamLogInfo) + class TeamMemberLogInfo(UserLogInfo): """ Team member's logged information. @@ -65827,6 +87398,8 @@ class TeamMemberLogInfo(UserLogInfo): missing due to historical data gap. :ivar team_log.TeamMemberLogInfo.member_external_id: Team member external ID. + :ivar team_log.TeamMemberLogInfo.team: Details about this user’s team + for enterprise event. """ __slots__ = [ @@ -65834,6 +87407,8 @@ class TeamMemberLogInfo(UserLogInfo): '_team_member_id_present', '_member_external_id_value', '_member_external_id_present', + '_team_value', + '_team_present', ] _has_required_fields = False @@ -65843,7 +87418,8 @@ def __init__(self, display_name=None, email=None, team_member_id=None, - member_external_id=None): + member_external_id=None, + team=None): super(TeamMemberLogInfo, self).__init__(account_id, display_name, email) @@ -65851,10 +87427,14 @@ def __init__(self, self._team_member_id_present = False self._member_external_id_value = None self._member_external_id_present = False + self._team_value = None + self._team_present = False if team_member_id is not None: self.team_member_id = team_member_id if member_external_id is not None: self.member_external_id = member_external_id + if team is not None: + self.team = team @property def team_member_id(self): @@ -65908,16 +87488,43 @@ def member_external_id(self): self._member_external_id_value = None self._member_external_id_present = False + @property + def team(self): + """ + Details about this user’s team for enterprise event. + + :rtype: TeamLogInfo + """ + if self._team_present: + return self._team_value + else: + return None + + @team.setter + def team(self, val): + if val is None: + del self.team + return + self._team_validator.validate_type_only(val) + self._team_value = val + self._team_present = True + + @team.deleter + def team(self): + self._team_value = None + self._team_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): super(TeamMemberLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamMemberLogInfo(account_id={!r}, display_name={!r}, email={!r}, team_member_id={!r}, member_external_id={!r})'.format( + return 'TeamMemberLogInfo(account_id={!r}, display_name={!r}, email={!r}, team_member_id={!r}, member_external_id={!r}, team={!r})'.format( self._account_id_value, self._display_name_value, self._email_value, self._team_member_id_value, self._member_external_id_value, + self._team_value, ) TeamMemberLogInfo_validator = bv.Struct(TeamMemberLogInfo) @@ -65931,27 +87538,27 @@ class TeamMembershipType(bb.Union): _catch_all = 'other' # Attribute is overwritten below the class definition - free = None - # Attribute is overwritten below the class definition full = None # Attribute is overwritten below the class definition + free = None + # Attribute is overwritten below the class definition other = None - def is_free(self): + def is_full(self): """ - Check if the union tag is ``free``. + Check if the union tag is ``full``. :rtype: bool """ - return self._tag == 'free' + return self._tag == 'full' - def is_full(self): + def is_free(self): """ - Check if the union tag is ``full``. + Check if the union tag is ``free``. :rtype: bool """ - return self._tag == 'full' + return self._tag == 'free' def is_other(self): """ @@ -69227,153 +90834,424 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamProfileRemoveLogoType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamProfileRemoveLogoType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamProfileRemoveLogoType(description={!r})'.format( + self._description_value, + ) + +TeamProfileRemoveLogoType_validator = bv.Struct(TeamProfileRemoveLogoType) + +class TeamSelectiveSyncPolicy(bb.Union): + """ + Policy for controlling whether team selective sync is enabled for team. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamSelectiveSyncPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamSelectiveSyncPolicy(%r, %r)' % (self._tag, self._value) + +TeamSelectiveSyncPolicy_validator = bv.Union(TeamSelectiveSyncPolicy) + +class TeamSelectiveSyncPolicyChangedDetails(bb.Struct): + """ + Enabled/disabled Team Selective Sync for team. + + :ivar team_log.TeamSelectiveSyncPolicyChangedDetails.new_value: New Team + Selective Sync policy. + :ivar team_log.TeamSelectiveSyncPolicyChangedDetails.previous_value: + Previous Team Selective Sync policy. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New Team Selective Sync policy. + + :rtype: TeamSelectiveSyncPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous Team Selective Sync policy. + + :rtype: TeamSelectiveSyncPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamSelectiveSyncPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamSelectiveSyncPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) + +TeamSelectiveSyncPolicyChangedDetails_validator = bv.Struct(TeamSelectiveSyncPolicyChangedDetails) + +class TeamSelectiveSyncPolicyChangedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamSelectiveSyncPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamSelectiveSyncPolicyChangedType(description={!r})'.format( + self._description_value, + ) + +TeamSelectiveSyncPolicyChangedType_validator = bv.Struct(TeamSelectiveSyncPolicyChangedType) + +class TeamSelectiveSyncSettingsChangedDetails(bb.Struct): + """ + Changed sync default. + + :ivar team_log.TeamSelectiveSyncSettingsChangedDetails.previous_value: + Previous value. + :ivar team_log.TeamSelectiveSyncSettingsChangedDetails.new_value: New value. + """ + + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] + + _has_required_fields = True + + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value + + @property + def previous_value(self): + """ + Previous value. + + :rtype: files.SyncSetting + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + @property + def new_value(self): + """ + New value. + + :rtype: files.SyncSetting + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamSelectiveSyncSettingsChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TeamSelectiveSyncSettingsChangedDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, + ) + +TeamSelectiveSyncSettingsChangedDetails_validator = bv.Struct(TeamSelectiveSyncSettingsChangedDetails) + +class TeamSelectiveSyncSettingsChangedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TeamSelectiveSyncSettingsChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamProfileRemoveLogoType(description={!r})'.format( + return 'TeamSelectiveSyncSettingsChangedType(description={!r})'.format( self._description_value, ) -TeamProfileRemoveLogoType_validator = bv.Struct(TeamProfileRemoveLogoType) - -class TeamSelectiveSyncPolicy(bb.Union): - """ - Policy for controlling whether team selective sync is enabled for team. - - This class acts as a tagged union. Only one of the ``is_*`` methods will - return true. To get the associated value of a tag (if one exists), use the - corresponding ``get_*`` method. - """ - - _catch_all = 'other' - # Attribute is overwritten below the class definition - disabled = None - # Attribute is overwritten below the class definition - enabled = None - # Attribute is overwritten below the class definition - other = None - - def is_disabled(self): - """ - Check if the union tag is ``disabled``. - - :rtype: bool - """ - return self._tag == 'disabled' - - def is_enabled(self): - """ - Check if the union tag is ``enabled``. - - :rtype: bool - """ - return self._tag == 'enabled' - - def is_other(self): - """ - Check if the union tag is ``other``. - - :rtype: bool - """ - return self._tag == 'other' - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamSelectiveSyncPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'TeamSelectiveSyncPolicy(%r, %r)' % (self._tag, self._value) - -TeamSelectiveSyncPolicy_validator = bv.Union(TeamSelectiveSyncPolicy) +TeamSelectiveSyncSettingsChangedType_validator = bv.Struct(TeamSelectiveSyncSettingsChangedType) -class TeamSelectiveSyncPolicyChangedDetails(bb.Struct): +class TeamSharingWhitelistSubjectsChangedDetails(bb.Struct): """ - Enabled/disabled Team Selective Sync for team. + Edited the approved list for sharing externally. - :ivar team_log.TeamSelectiveSyncPolicyChangedDetails.new_value: New Team - Selective Sync policy. - :ivar team_log.TeamSelectiveSyncPolicyChangedDetails.previous_value: - Previous Team Selective Sync policy. + :ivar + team_log.TeamSharingWhitelistSubjectsChangedDetails.added_whitelist_subjects: + Domains or emails added to the approved list for sharing externally. + :ivar + team_log.TeamSharingWhitelistSubjectsChangedDetails.removed_whitelist_subjects: + Domains or emails removed from the approved list for sharing externally. """ __slots__ = [ - '_new_value_value', - '_new_value_present', - '_previous_value_value', - '_previous_value_present', + '_added_whitelist_subjects_value', + '_added_whitelist_subjects_present', + '_removed_whitelist_subjects_value', + '_removed_whitelist_subjects_present', ] _has_required_fields = True def __init__(self, - new_value=None, - previous_value=None): - self._new_value_value = None - self._new_value_present = False - self._previous_value_value = None - self._previous_value_present = False - if new_value is not None: - self.new_value = new_value - if previous_value is not None: - self.previous_value = previous_value + added_whitelist_subjects=None, + removed_whitelist_subjects=None): + self._added_whitelist_subjects_value = None + self._added_whitelist_subjects_present = False + self._removed_whitelist_subjects_value = None + self._removed_whitelist_subjects_present = False + if added_whitelist_subjects is not None: + self.added_whitelist_subjects = added_whitelist_subjects + if removed_whitelist_subjects is not None: + self.removed_whitelist_subjects = removed_whitelist_subjects @property - def new_value(self): + def added_whitelist_subjects(self): """ - New Team Selective Sync policy. + Domains or emails added to the approved list for sharing externally. - :rtype: TeamSelectiveSyncPolicy + :rtype: list of [str] """ - if self._new_value_present: - return self._new_value_value + if self._added_whitelist_subjects_present: + return self._added_whitelist_subjects_value else: - raise AttributeError("missing required field 'new_value'") + raise AttributeError("missing required field 'added_whitelist_subjects'") - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + @added_whitelist_subjects.setter + def added_whitelist_subjects(self, val): + val = self._added_whitelist_subjects_validator.validate(val) + self._added_whitelist_subjects_value = val + self._added_whitelist_subjects_present = True - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + @added_whitelist_subjects.deleter + def added_whitelist_subjects(self): + self._added_whitelist_subjects_value = None + self._added_whitelist_subjects_present = False @property - def previous_value(self): + def removed_whitelist_subjects(self): """ - Previous Team Selective Sync policy. + Domains or emails removed from the approved list for sharing externally. - :rtype: TeamSelectiveSyncPolicy + :rtype: list of [str] """ - if self._previous_value_present: - return self._previous_value_value + if self._removed_whitelist_subjects_present: + return self._removed_whitelist_subjects_value else: - raise AttributeError("missing required field 'previous_value'") + raise AttributeError("missing required field 'removed_whitelist_subjects'") - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True + @removed_whitelist_subjects.setter + def removed_whitelist_subjects(self, val): + val = self._removed_whitelist_subjects_validator.validate(val) + self._removed_whitelist_subjects_value = val + self._removed_whitelist_subjects_present = True - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False + @removed_whitelist_subjects.deleter + def removed_whitelist_subjects(self): + self._removed_whitelist_subjects_value = None + self._removed_whitelist_subjects_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamSelectiveSyncPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamSharingWhitelistSubjectsChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamSelectiveSyncPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( - self._new_value_value, - self._previous_value_value, + return 'TeamSharingWhitelistSubjectsChangedDetails(added_whitelist_subjects={!r}, removed_whitelist_subjects={!r})'.format( + self._added_whitelist_subjects_value, + self._removed_whitelist_subjects_value, ) -TeamSelectiveSyncPolicyChangedDetails_validator = bv.Struct(TeamSelectiveSyncPolicyChangedDetails) +TeamSharingWhitelistSubjectsChangedDetails_validator = bv.Struct(TeamSharingWhitelistSubjectsChangedDetails) -class TeamSelectiveSyncPolicyChangedType(bb.Struct): +class TeamSharingWhitelistSubjectsChangedType(bb.Struct): __slots__ = [ '_description_value', @@ -69411,103 +91289,37 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamSelectiveSyncPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TeamSharingWhitelistSubjectsChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamSelectiveSyncPolicyChangedType(description={!r})'.format( + return 'TeamSharingWhitelistSubjectsChangedType(description={!r})'.format( self._description_value, ) -TeamSelectiveSyncPolicyChangedType_validator = bv.Struct(TeamSelectiveSyncPolicyChangedType) +TeamSharingWhitelistSubjectsChangedType_validator = bv.Struct(TeamSharingWhitelistSubjectsChangedType) -class TeamSelectiveSyncSettingsChangedDetails(bb.Struct): +class TfaAddBackupPhoneDetails(bb.Struct): """ - Changed sync default. - - :ivar team_log.TeamSelectiveSyncSettingsChangedDetails.previous_value: - Previous value. - :ivar team_log.TeamSelectiveSyncSettingsChangedDetails.new_value: New value. + Added backup phone for two-step verification. """ __slots__ = [ - '_previous_value_value', - '_previous_value_present', - '_new_value_value', - '_new_value_present', ] - _has_required_fields = True - - def __init__(self, - previous_value=None, - new_value=None): - self._previous_value_value = None - self._previous_value_present = False - self._new_value_value = None - self._new_value_present = False - if previous_value is not None: - self.previous_value = previous_value - if new_value is not None: - self.new_value = new_value - - @property - def previous_value(self): - """ - Previous value. - - :rtype: files.SyncSetting - """ - if self._previous_value_present: - return self._previous_value_value - else: - raise AttributeError("missing required field 'previous_value'") - - @previous_value.setter - def previous_value(self, val): - self._previous_value_validator.validate_type_only(val) - self._previous_value_value = val - self._previous_value_present = True - - @previous_value.deleter - def previous_value(self): - self._previous_value_value = None - self._previous_value_present = False - - @property - def new_value(self): - """ - New value. - - :rtype: files.SyncSetting - """ - if self._new_value_present: - return self._new_value_value - else: - raise AttributeError("missing required field 'new_value'") - - @new_value.setter - def new_value(self, val): - self._new_value_validator.validate_type_only(val) - self._new_value_value = val - self._new_value_present = True + _has_required_fields = False - @new_value.deleter - def new_value(self): - self._new_value_value = None - self._new_value_present = False + def __init__(self): + pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamSelectiveSyncSettingsChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TfaAddBackupPhoneDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamSelectiveSyncSettingsChangedDetails(previous_value={!r}, new_value={!r})'.format( - self._previous_value_value, - self._new_value_value, - ) + return 'TfaAddBackupPhoneDetails()' -TeamSelectiveSyncSettingsChangedDetails_validator = bv.Struct(TeamSelectiveSyncSettingsChangedDetails) +TfaAddBackupPhoneDetails_validator = bv.Struct(TfaAddBackupPhoneDetails) -class TeamSelectiveSyncSettingsChangedType(bb.Struct): +class TfaAddBackupPhoneType(bb.Struct): __slots__ = [ '_description_value', @@ -69545,18 +91357,18 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TeamSelectiveSyncSettingsChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TfaAddBackupPhoneType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamSelectiveSyncSettingsChangedType(description={!r})'.format( + return 'TfaAddBackupPhoneType(description={!r})'.format( self._description_value, ) -TeamSelectiveSyncSettingsChangedType_validator = bv.Struct(TeamSelectiveSyncSettingsChangedType) +TfaAddBackupPhoneType_validator = bv.Struct(TfaAddBackupPhoneType) -class TfaAddBackupPhoneDetails(bb.Struct): +class TfaAddExceptionDetails(bb.Struct): """ - Added backup phone for two-step verification. + Added members to two factor authentication exception list. """ __slots__ = [ @@ -69568,14 +91380,14 @@ def __init__(self): pass def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TfaAddBackupPhoneDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TfaAddExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TfaAddBackupPhoneDetails()' + return 'TfaAddExceptionDetails()' -TfaAddBackupPhoneDetails_validator = bv.Struct(TfaAddBackupPhoneDetails) +TfaAddExceptionDetails_validator = bv.Struct(TfaAddExceptionDetails) -class TfaAddBackupPhoneType(bb.Struct): +class TfaAddExceptionType(bb.Struct): __slots__ = [ '_description_value', @@ -69613,14 +91425,14 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(TfaAddBackupPhoneType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(TfaAddExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TfaAddBackupPhoneType(description={!r})'.format( + return 'TfaAddExceptionType(description={!r})'.format( self._description_value, ) -TfaAddBackupPhoneType_validator = bv.Struct(TfaAddBackupPhoneType) +TfaAddExceptionType_validator = bv.Struct(TfaAddExceptionType) class TfaAddSecurityKeyDetails(bb.Struct): """ @@ -70211,6 +92023,74 @@ def __repr__(self): TfaRemoveBackupPhoneType_validator = bv.Struct(TfaRemoveBackupPhoneType) +class TfaRemoveExceptionDetails(bb.Struct): + """ + Removed members from two factor authentication exception list. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self): + pass + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TfaRemoveExceptionDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TfaRemoveExceptionDetails()' + +TfaRemoveExceptionDetails_validator = bv.Struct(TfaRemoveExceptionDetails) + +class TfaRemoveExceptionType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(TfaRemoveExceptionType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'TfaRemoveExceptionType(description={!r})'.format( + self._description_value, + ) + +TfaRemoveExceptionType_validator = bv.Struct(TfaRemoveExceptionType) + class TfaRemoveSecurityKeyDetails(bb.Struct): """ Removed security key for two-step verification. @@ -70459,12 +92339,16 @@ class TrustedNonTeamMemberLogInfo(UserLogInfo): User that is not a member of the team but considered trusted. :ivar team_log.TrustedNonTeamMemberLogInfo.trusted_non_team_member_type: - Indicates the type of the trusted non team member user. + Indicates the type of the member of a trusted team. + :ivar team_log.TrustedNonTeamMemberLogInfo.team: Details about this + useru2019s trusted team. """ __slots__ = [ '_trusted_non_team_member_type_value', '_trusted_non_team_member_type_present', + '_team_value', + '_team_present', ] _has_required_fields = True @@ -70473,19 +92357,24 @@ def __init__(self, trusted_non_team_member_type=None, account_id=None, display_name=None, - email=None): + email=None, + team=None): super(TrustedNonTeamMemberLogInfo, self).__init__(account_id, display_name, email) self._trusted_non_team_member_type_value = None self._trusted_non_team_member_type_present = False + self._team_value = None + self._team_present = False if trusted_non_team_member_type is not None: self.trusted_non_team_member_type = trusted_non_team_member_type + if team is not None: + self.team = team @property def trusted_non_team_member_type(self): """ - Indicates the type of the trusted non team member user. + Indicates the type of the member of a trusted team. :rtype: TrustedNonTeamMemberType """ @@ -70505,15 +92394,42 @@ def trusted_non_team_member_type(self): self._trusted_non_team_member_type_value = None self._trusted_non_team_member_type_present = False + @property + def team(self): + """ + Details about this useru2019s trusted team. + + :rtype: TeamLogInfo + """ + if self._team_present: + return self._team_value + else: + return None + + @team.setter + def team(self, val): + if val is None: + del self.team + return + self._team_validator.validate_type_only(val) + self._team_value = val + self._team_present = True + + @team.deleter + def team(self): + self._team_value = None + self._team_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): super(TrustedNonTeamMemberLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TrustedNonTeamMemberLogInfo(trusted_non_team_member_type={!r}, account_id={!r}, display_name={!r}, email={!r})'.format( + return 'TrustedNonTeamMemberLogInfo(trusted_non_team_member_type={!r}, account_id={!r}, display_name={!r}, email={!r}, team={!r})'.format( self._trusted_non_team_member_type_value, self._account_id_value, self._display_name_value, self._email_value, + self._team_value, ) TrustedNonTeamMemberLogInfo_validator = bv.Struct(TrustedNonTeamMemberLogInfo) @@ -70529,6 +92445,8 @@ class TrustedNonTeamMemberType(bb.Union): # Attribute is overwritten below the class definition multi_instance_admin = None # Attribute is overwritten below the class definition + enterprise_admin = None + # Attribute is overwritten below the class definition other = None def is_multi_instance_admin(self): @@ -70539,6 +92457,14 @@ def is_multi_instance_admin(self): """ return self._tag == 'multi_instance_admin' + def is_enterprise_admin(self): + """ + Check if the union tag is ``enterprise_admin``. + + :rtype: bool + """ + return self._tag == 'enterprise_admin' + def is_other(self): """ Check if the union tag is ``other``. @@ -71181,204 +93107,523 @@ def description(self): self._description_present = False def _process_custom_annotations(self, annotation_type, field_path, processor): - super(ViewerInfoPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + super(ViewerInfoPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'ViewerInfoPolicyChangedType(description={!r})'.format( + self._description_value, + ) + +ViewerInfoPolicyChangedType_validator = bv.Struct(ViewerInfoPolicyChangedType) + +class WatermarkingPolicy(bb.Union): + """ + Policy for controlling team access to watermarking feature + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(WatermarkingPolicy, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'WatermarkingPolicy(%r, %r)' % (self._tag, self._value) + +WatermarkingPolicy_validator = bv.Union(WatermarkingPolicy) + +class WatermarkingPolicyChangedDetails(bb.Struct): + """ + Changed watermarking policy for team. + + :ivar team_log.WatermarkingPolicyChangedDetails.new_value: New watermarking + policy. + :ivar team_log.WatermarkingPolicyChangedDetails.previous_value: Previous + watermarking policy. + """ + + __slots__ = [ + '_new_value_value', + '_new_value_present', + '_previous_value_value', + '_previous_value_present', + ] + + _has_required_fields = True + + def __init__(self, + new_value=None, + previous_value=None): + self._new_value_value = None + self._new_value_present = False + self._previous_value_value = None + self._previous_value_present = False + if new_value is not None: + self.new_value = new_value + if previous_value is not None: + self.previous_value = previous_value + + @property + def new_value(self): + """ + New watermarking policy. + + :rtype: WatermarkingPolicy + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + self._new_value_validator.validate_type_only(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + @property + def previous_value(self): + """ + Previous watermarking policy. + + :rtype: WatermarkingPolicy + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + self._previous_value_validator.validate_type_only(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(WatermarkingPolicyChangedDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'WatermarkingPolicyChangedDetails(new_value={!r}, previous_value={!r})'.format( + self._new_value_value, + self._previous_value_value, + ) + +WatermarkingPolicyChangedDetails_validator = bv.Struct(WatermarkingPolicyChangedDetails) + +class WatermarkingPolicyChangedType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(WatermarkingPolicyChangedType, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'WatermarkingPolicyChangedType(description={!r})'.format( + self._description_value, + ) + +WatermarkingPolicyChangedType_validator = bv.Struct(WatermarkingPolicyChangedType) + +class WebDeviceSessionLogInfo(DeviceSessionLogInfo): + """ + Information on active web sessions + + :ivar team_log.WebDeviceSessionLogInfo.session_info: Web session unique id. + Might be missing due to historical data gap. + :ivar team_log.WebDeviceSessionLogInfo.user_agent: Information on the + hosting device. + :ivar team_log.WebDeviceSessionLogInfo.os: Information on the hosting + operating system. + :ivar team_log.WebDeviceSessionLogInfo.browser: Information on the browser + used for this web session. + """ + + __slots__ = [ + '_session_info_value', + '_session_info_present', + '_user_agent_value', + '_user_agent_present', + '_os_value', + '_os_present', + '_browser_value', + '_browser_present', + ] + + _has_required_fields = True + + def __init__(self, + user_agent=None, + os=None, + browser=None, + ip_address=None, + created=None, + updated=None, + session_info=None): + super(WebDeviceSessionLogInfo, self).__init__(ip_address, + created, + updated) + self._session_info_value = None + self._session_info_present = False + self._user_agent_value = None + self._user_agent_present = False + self._os_value = None + self._os_present = False + self._browser_value = None + self._browser_present = False + if session_info is not None: + self.session_info = session_info + if user_agent is not None: + self.user_agent = user_agent + if os is not None: + self.os = os + if browser is not None: + self.browser = browser + + @property + def session_info(self): + """ + Web session unique id. Might be missing due to historical data gap. + + :rtype: WebSessionLogInfo + """ + if self._session_info_present: + return self._session_info_value + else: + return None + + @session_info.setter + def session_info(self, val): + if val is None: + del self.session_info + return + self._session_info_validator.validate_type_only(val) + self._session_info_value = val + self._session_info_present = True + + @session_info.deleter + def session_info(self): + self._session_info_value = None + self._session_info_present = False + + @property + def user_agent(self): + """ + Information on the hosting device. + + :rtype: str + """ + if self._user_agent_present: + return self._user_agent_value + else: + raise AttributeError("missing required field 'user_agent'") + + @user_agent.setter + def user_agent(self, val): + val = self._user_agent_validator.validate(val) + self._user_agent_value = val + self._user_agent_present = True + + @user_agent.deleter + def user_agent(self): + self._user_agent_value = None + self._user_agent_present = False + + @property + def os(self): + """ + Information on the hosting operating system. + + :rtype: str + """ + if self._os_present: + return self._os_value + else: + raise AttributeError("missing required field 'os'") + + @os.setter + def os(self, val): + val = self._os_validator.validate(val) + self._os_value = val + self._os_present = True + + @os.deleter + def os(self): + self._os_value = None + self._os_present = False + + @property + def browser(self): + """ + Information on the browser used for this web session. + + :rtype: str + """ + if self._browser_present: + return self._browser_value + else: + raise AttributeError("missing required field 'browser'") + + @browser.setter + def browser(self, val): + val = self._browser_validator.validate(val) + self._browser_value = val + self._browser_present = True + + @browser.deleter + def browser(self): + self._browser_value = None + self._browser_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(WebDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'WebDeviceSessionLogInfo(user_agent={!r}, os={!r}, browser={!r}, ip_address={!r}, created={!r}, updated={!r}, session_info={!r})'.format( + self._user_agent_value, + self._os_value, + self._browser_value, + self._ip_address_value, + self._created_value, + self._updated_value, + self._session_info_value, + ) + +WebDeviceSessionLogInfo_validator = bv.Struct(WebDeviceSessionLogInfo) + +class WebSessionLogInfo(SessionLogInfo): + """ + Web session. + """ + + __slots__ = [ + ] + + _has_required_fields = False + + def __init__(self, + session_id=None): + super(WebSessionLogInfo, self).__init__(session_id) + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(WebSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'WebSessionLogInfo(session_id={!r})'.format( + self._session_id_value, + ) + +WebSessionLogInfo_validator = bv.Struct(WebSessionLogInfo) + +class WebSessionsChangeActiveSessionLimitDetails(bb.Struct): + """ + Changed limit on active sessions per member. + + :ivar team_log.WebSessionsChangeActiveSessionLimitDetails.previous_value: + Previous max number of concurrent active sessions policy. + :ivar team_log.WebSessionsChangeActiveSessionLimitDetails.new_value: New max + number of concurrent active sessions policy. + """ + + __slots__ = [ + '_previous_value_value', + '_previous_value_present', + '_new_value_value', + '_new_value_present', + ] + + _has_required_fields = True + + def __init__(self, + previous_value=None, + new_value=None): + self._previous_value_value = None + self._previous_value_present = False + self._new_value_value = None + self._new_value_present = False + if previous_value is not None: + self.previous_value = previous_value + if new_value is not None: + self.new_value = new_value + + @property + def previous_value(self): + """ + Previous max number of concurrent active sessions policy. + + :rtype: str + """ + if self._previous_value_present: + return self._previous_value_value + else: + raise AttributeError("missing required field 'previous_value'") + + @previous_value.setter + def previous_value(self, val): + val = self._previous_value_validator.validate(val) + self._previous_value_value = val + self._previous_value_present = True + + @previous_value.deleter + def previous_value(self): + self._previous_value_value = None + self._previous_value_present = False + + @property + def new_value(self): + """ + New max number of concurrent active sessions policy. + + :rtype: str + """ + if self._new_value_present: + return self._new_value_value + else: + raise AttributeError("missing required field 'new_value'") + + @new_value.setter + def new_value(self, val): + val = self._new_value_validator.validate(val) + self._new_value_value = val + self._new_value_present = True + + @new_value.deleter + def new_value(self): + self._new_value_value = None + self._new_value_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(WebSessionsChangeActiveSessionLimitDetails, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'WebSessionsChangeActiveSessionLimitDetails(previous_value={!r}, new_value={!r})'.format( + self._previous_value_value, + self._new_value_value, + ) + +WebSessionsChangeActiveSessionLimitDetails_validator = bv.Struct(WebSessionsChangeActiveSessionLimitDetails) + +class WebSessionsChangeActiveSessionLimitType(bb.Struct): + + __slots__ = [ + '_description_value', + '_description_present', + ] + + _has_required_fields = True + + def __init__(self, + description=None): + self._description_value = None + self._description_present = False + if description is not None: + self.description = description + + @property + def description(self): + """ + :rtype: str + """ + if self._description_present: + return self._description_value + else: + raise AttributeError("missing required field 'description'") + + @description.setter + def description(self, val): + val = self._description_validator.validate(val) + self._description_value = val + self._description_present = True + + @description.deleter + def description(self): + self._description_value = None + self._description_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(WebSessionsChangeActiveSessionLimitType, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'ViewerInfoPolicyChangedType(description={!r})'.format( + return 'WebSessionsChangeActiveSessionLimitType(description={!r})'.format( self._description_value, ) -ViewerInfoPolicyChangedType_validator = bv.Struct(ViewerInfoPolicyChangedType) - -class WebDeviceSessionLogInfo(DeviceSessionLogInfo): - """ - Information on active web sessions - - :ivar team_log.WebDeviceSessionLogInfo.session_info: Web session unique id. - Might be missing due to historical data gap. - :ivar team_log.WebDeviceSessionLogInfo.user_agent: Information on the - hosting device. - :ivar team_log.WebDeviceSessionLogInfo.os: Information on the hosting - operating system. - :ivar team_log.WebDeviceSessionLogInfo.browser: Information on the browser - used for this web session. - """ - - __slots__ = [ - '_session_info_value', - '_session_info_present', - '_user_agent_value', - '_user_agent_present', - '_os_value', - '_os_present', - '_browser_value', - '_browser_present', - ] - - _has_required_fields = True - - def __init__(self, - user_agent=None, - os=None, - browser=None, - ip_address=None, - created=None, - updated=None, - session_info=None): - super(WebDeviceSessionLogInfo, self).__init__(ip_address, - created, - updated) - self._session_info_value = None - self._session_info_present = False - self._user_agent_value = None - self._user_agent_present = False - self._os_value = None - self._os_present = False - self._browser_value = None - self._browser_present = False - if session_info is not None: - self.session_info = session_info - if user_agent is not None: - self.user_agent = user_agent - if os is not None: - self.os = os - if browser is not None: - self.browser = browser - - @property - def session_info(self): - """ - Web session unique id. Might be missing due to historical data gap. - - :rtype: WebSessionLogInfo - """ - if self._session_info_present: - return self._session_info_value - else: - return None - - @session_info.setter - def session_info(self, val): - if val is None: - del self.session_info - return - self._session_info_validator.validate_type_only(val) - self._session_info_value = val - self._session_info_present = True - - @session_info.deleter - def session_info(self): - self._session_info_value = None - self._session_info_present = False - - @property - def user_agent(self): - """ - Information on the hosting device. - - :rtype: str - """ - if self._user_agent_present: - return self._user_agent_value - else: - raise AttributeError("missing required field 'user_agent'") - - @user_agent.setter - def user_agent(self, val): - val = self._user_agent_validator.validate(val) - self._user_agent_value = val - self._user_agent_present = True - - @user_agent.deleter - def user_agent(self): - self._user_agent_value = None - self._user_agent_present = False - - @property - def os(self): - """ - Information on the hosting operating system. - - :rtype: str - """ - if self._os_present: - return self._os_value - else: - raise AttributeError("missing required field 'os'") - - @os.setter - def os(self, val): - val = self._os_validator.validate(val) - self._os_value = val - self._os_present = True - - @os.deleter - def os(self): - self._os_value = None - self._os_present = False - - @property - def browser(self): - """ - Information on the browser used for this web session. - - :rtype: str - """ - if self._browser_present: - return self._browser_value - else: - raise AttributeError("missing required field 'browser'") - - @browser.setter - def browser(self, val): - val = self._browser_validator.validate(val) - self._browser_value = val - self._browser_present = True - - @browser.deleter - def browser(self): - self._browser_value = None - self._browser_present = False - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(WebDeviceSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'WebDeviceSessionLogInfo(user_agent={!r}, os={!r}, browser={!r}, ip_address={!r}, created={!r}, updated={!r}, session_info={!r})'.format( - self._user_agent_value, - self._os_value, - self._browser_value, - self._ip_address_value, - self._created_value, - self._updated_value, - self._session_info_value, - ) - -WebDeviceSessionLogInfo_validator = bv.Struct(WebDeviceSessionLogInfo) - -class WebSessionLogInfo(SessionLogInfo): - """ - Web session. - """ - - __slots__ = [ - ] - - _has_required_fields = False - - def __init__(self, - session_id=None): - super(WebSessionLogInfo, self).__init__(session_id) - - def _process_custom_annotations(self, annotation_type, field_path, processor): - super(WebSessionLogInfo, self)._process_custom_annotations(annotation_type, field_path, processor) - - def __repr__(self): - return 'WebSessionLogInfo(session_id={!r})'.format( - self._session_id_value, - ) - -WebSessionLogInfo_validator = bv.Struct(WebSessionLogInfo) +WebSessionsChangeActiveSessionLimitType_validator = bv.Struct(WebSessionsChangeActiveSessionLimitType) class WebSessionsChangeFixedLengthPolicyDetails(bb.Struct): """ @@ -71827,6 +94072,7 @@ def __repr__(self): AccessMethodLogInfo._sign_in_as_validator = WebSessionLogInfo_validator AccessMethodLogInfo._content_manager_validator = WebSessionLogInfo_validator AccessMethodLogInfo._admin_console_validator = WebSessionLogInfo_validator +AccessMethodLogInfo._enterprise_console_validator = WebSessionLogInfo_validator AccessMethodLogInfo._api_validator = ApiSessionLogInfo_validator AccessMethodLogInfo._other_validator = bv.Void() AccessMethodLogInfo._tagmap = { @@ -71834,6 +94080,7 @@ def __repr__(self): 'sign_in_as': AccessMethodLogInfo._sign_in_as_validator, 'content_manager': AccessMethodLogInfo._content_manager_validator, 'admin_console': AccessMethodLogInfo._admin_console_validator, + 'enterprise_console': AccessMethodLogInfo._enterprise_console_validator, 'api': AccessMethodLogInfo._api_validator, 'other': AccessMethodLogInfo._other_validator, } @@ -71892,13 +94139,33 @@ def __repr__(self): AccountCaptureMigrateAccountType._all_fields_ = [('description', AccountCaptureMigrateAccountType._description_validator)] AccountCaptureNotificationEmailsSentDetails._domain_name_validator = bv.String() -AccountCaptureNotificationEmailsSentDetails._all_field_names_ = set(['domain_name']) -AccountCaptureNotificationEmailsSentDetails._all_fields_ = [('domain_name', AccountCaptureNotificationEmailsSentDetails._domain_name_validator)] +AccountCaptureNotificationEmailsSentDetails._notification_type_validator = bv.Nullable(AccountCaptureNotificationType_validator) +AccountCaptureNotificationEmailsSentDetails._all_field_names_ = set([ + 'domain_name', + 'notification_type', +]) +AccountCaptureNotificationEmailsSentDetails._all_fields_ = [ + ('domain_name', AccountCaptureNotificationEmailsSentDetails._domain_name_validator), + ('notification_type', AccountCaptureNotificationEmailsSentDetails._notification_type_validator), +] AccountCaptureNotificationEmailsSentType._description_validator = bv.String() AccountCaptureNotificationEmailsSentType._all_field_names_ = set(['description']) AccountCaptureNotificationEmailsSentType._all_fields_ = [('description', AccountCaptureNotificationEmailsSentType._description_validator)] +AccountCaptureNotificationType._proactive_warning_notification_validator = bv.Void() +AccountCaptureNotificationType._actionable_notification_validator = bv.Void() +AccountCaptureNotificationType._other_validator = bv.Void() +AccountCaptureNotificationType._tagmap = { + 'proactive_warning_notification': AccountCaptureNotificationType._proactive_warning_notification_validator, + 'actionable_notification': AccountCaptureNotificationType._actionable_notification_validator, + 'other': AccountCaptureNotificationType._other_validator, +} + +AccountCaptureNotificationType.proactive_warning_notification = AccountCaptureNotificationType('proactive_warning_notification') +AccountCaptureNotificationType.actionable_notification = AccountCaptureNotificationType('actionable_notification') +AccountCaptureNotificationType.other = AccountCaptureNotificationType('other') + AccountCapturePolicy._disabled_validator = bv.Void() AccountCapturePolicy._invited_users_validator = bv.Void() AccountCapturePolicy._all_users_validator = bv.Void() @@ -71923,12 +94190,42 @@ def __repr__(self): AccountCaptureRelinquishAccountType._all_field_names_ = set(['description']) AccountCaptureRelinquishAccountType._all_fields_ = [('description', AccountCaptureRelinquishAccountType._description_validator)] +AccountLockOrUnlockedDetails._previous_value_validator = AccountState_validator +AccountLockOrUnlockedDetails._new_value_validator = AccountState_validator +AccountLockOrUnlockedDetails._all_field_names_ = set([ + 'previous_value', + 'new_value', +]) +AccountLockOrUnlockedDetails._all_fields_ = [ + ('previous_value', AccountLockOrUnlockedDetails._previous_value_validator), + ('new_value', AccountLockOrUnlockedDetails._new_value_validator), +] + +AccountLockOrUnlockedType._description_validator = bv.String() +AccountLockOrUnlockedType._all_field_names_ = set(['description']) +AccountLockOrUnlockedType._all_fields_ = [('description', AccountLockOrUnlockedType._description_validator)] + +AccountState._locked_validator = bv.Void() +AccountState._unlocked_validator = bv.Void() +AccountState._other_validator = bv.Void() +AccountState._tagmap = { + 'locked': AccountState._locked_validator, + 'unlocked': AccountState._unlocked_validator, + 'other': AccountState._other_validator, +} + +AccountState.locked = AccountState('locked') +AccountState.unlocked = AccountState('unlocked') +AccountState.other = AccountState('other') + ActionDetails._team_join_details_validator = JoinTeamDetails_validator ActionDetails._remove_action_validator = MemberRemoveActionType_validator +ActionDetails._team_invite_details_validator = TeamInviteDetails_validator ActionDetails._other_validator = bv.Void() ActionDetails._tagmap = { 'team_join_details': ActionDetails._team_join_details_validator, 'remove_action': ActionDetails._remove_action_validator, + 'team_invite_details': ActionDetails._team_invite_details_validator, 'other': ActionDetails._other_validator, } @@ -72069,6 +94366,156 @@ def __repr__(self): AssetLogInfo.other = AssetLogInfo('other') +BinderAddPageDetails._event_uuid_validator = bv.String() +BinderAddPageDetails._doc_title_validator = bv.String() +BinderAddPageDetails._binder_item_name_validator = bv.String() +BinderAddPageDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', +]) +BinderAddPageDetails._all_fields_ = [ + ('event_uuid', BinderAddPageDetails._event_uuid_validator), + ('doc_title', BinderAddPageDetails._doc_title_validator), + ('binder_item_name', BinderAddPageDetails._binder_item_name_validator), +] + +BinderAddPageType._description_validator = bv.String() +BinderAddPageType._all_field_names_ = set(['description']) +BinderAddPageType._all_fields_ = [('description', BinderAddPageType._description_validator)] + +BinderAddSectionDetails._event_uuid_validator = bv.String() +BinderAddSectionDetails._doc_title_validator = bv.String() +BinderAddSectionDetails._binder_item_name_validator = bv.String() +BinderAddSectionDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', +]) +BinderAddSectionDetails._all_fields_ = [ + ('event_uuid', BinderAddSectionDetails._event_uuid_validator), + ('doc_title', BinderAddSectionDetails._doc_title_validator), + ('binder_item_name', BinderAddSectionDetails._binder_item_name_validator), +] + +BinderAddSectionType._description_validator = bv.String() +BinderAddSectionType._all_field_names_ = set(['description']) +BinderAddSectionType._all_fields_ = [('description', BinderAddSectionType._description_validator)] + +BinderRemovePageDetails._event_uuid_validator = bv.String() +BinderRemovePageDetails._doc_title_validator = bv.String() +BinderRemovePageDetails._binder_item_name_validator = bv.String() +BinderRemovePageDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', +]) +BinderRemovePageDetails._all_fields_ = [ + ('event_uuid', BinderRemovePageDetails._event_uuid_validator), + ('doc_title', BinderRemovePageDetails._doc_title_validator), + ('binder_item_name', BinderRemovePageDetails._binder_item_name_validator), +] + +BinderRemovePageType._description_validator = bv.String() +BinderRemovePageType._all_field_names_ = set(['description']) +BinderRemovePageType._all_fields_ = [('description', BinderRemovePageType._description_validator)] + +BinderRemoveSectionDetails._event_uuid_validator = bv.String() +BinderRemoveSectionDetails._doc_title_validator = bv.String() +BinderRemoveSectionDetails._binder_item_name_validator = bv.String() +BinderRemoveSectionDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', +]) +BinderRemoveSectionDetails._all_fields_ = [ + ('event_uuid', BinderRemoveSectionDetails._event_uuid_validator), + ('doc_title', BinderRemoveSectionDetails._doc_title_validator), + ('binder_item_name', BinderRemoveSectionDetails._binder_item_name_validator), +] + +BinderRemoveSectionType._description_validator = bv.String() +BinderRemoveSectionType._all_field_names_ = set(['description']) +BinderRemoveSectionType._all_fields_ = [('description', BinderRemoveSectionType._description_validator)] + +BinderRenamePageDetails._event_uuid_validator = bv.String() +BinderRenamePageDetails._doc_title_validator = bv.String() +BinderRenamePageDetails._binder_item_name_validator = bv.String() +BinderRenamePageDetails._previous_binder_item_name_validator = bv.Nullable(bv.String()) +BinderRenamePageDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', + 'previous_binder_item_name', +]) +BinderRenamePageDetails._all_fields_ = [ + ('event_uuid', BinderRenamePageDetails._event_uuid_validator), + ('doc_title', BinderRenamePageDetails._doc_title_validator), + ('binder_item_name', BinderRenamePageDetails._binder_item_name_validator), + ('previous_binder_item_name', BinderRenamePageDetails._previous_binder_item_name_validator), +] + +BinderRenamePageType._description_validator = bv.String() +BinderRenamePageType._all_field_names_ = set(['description']) +BinderRenamePageType._all_fields_ = [('description', BinderRenamePageType._description_validator)] + +BinderRenameSectionDetails._event_uuid_validator = bv.String() +BinderRenameSectionDetails._doc_title_validator = bv.String() +BinderRenameSectionDetails._binder_item_name_validator = bv.String() +BinderRenameSectionDetails._previous_binder_item_name_validator = bv.Nullable(bv.String()) +BinderRenameSectionDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', + 'previous_binder_item_name', +]) +BinderRenameSectionDetails._all_fields_ = [ + ('event_uuid', BinderRenameSectionDetails._event_uuid_validator), + ('doc_title', BinderRenameSectionDetails._doc_title_validator), + ('binder_item_name', BinderRenameSectionDetails._binder_item_name_validator), + ('previous_binder_item_name', BinderRenameSectionDetails._previous_binder_item_name_validator), +] + +BinderRenameSectionType._description_validator = bv.String() +BinderRenameSectionType._all_field_names_ = set(['description']) +BinderRenameSectionType._all_fields_ = [('description', BinderRenameSectionType._description_validator)] + +BinderReorderPageDetails._event_uuid_validator = bv.String() +BinderReorderPageDetails._doc_title_validator = bv.String() +BinderReorderPageDetails._binder_item_name_validator = bv.String() +BinderReorderPageDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', +]) +BinderReorderPageDetails._all_fields_ = [ + ('event_uuid', BinderReorderPageDetails._event_uuid_validator), + ('doc_title', BinderReorderPageDetails._doc_title_validator), + ('binder_item_name', BinderReorderPageDetails._binder_item_name_validator), +] + +BinderReorderPageType._description_validator = bv.String() +BinderReorderPageType._all_field_names_ = set(['description']) +BinderReorderPageType._all_fields_ = [('description', BinderReorderPageType._description_validator)] + +BinderReorderSectionDetails._event_uuid_validator = bv.String() +BinderReorderSectionDetails._doc_title_validator = bv.String() +BinderReorderSectionDetails._binder_item_name_validator = bv.String() +BinderReorderSectionDetails._all_field_names_ = set([ + 'event_uuid', + 'doc_title', + 'binder_item_name', +]) +BinderReorderSectionDetails._all_fields_ = [ + ('event_uuid', BinderReorderSectionDetails._event_uuid_validator), + ('doc_title', BinderReorderSectionDetails._doc_title_validator), + ('binder_item_name', BinderReorderSectionDetails._binder_item_name_validator), +] + +BinderReorderSectionType._description_validator = bv.String() +BinderReorderSectionType._all_field_names_ = set(['description']) +BinderReorderSectionType._all_fields_ = [('description', BinderReorderSectionType._description_validator)] + CameraUploadsPolicy._disabled_validator = bv.Void() CameraUploadsPolicy._enabled_validator = bv.Void() CameraUploadsPolicy._other_validator = bv.Void() @@ -72123,6 +94570,45 @@ def __repr__(self): ('common_name', Certificate._common_name_validator), ] +ChangedEnterpriseAdminRoleDetails._previous_value_validator = FedAdminRole_validator +ChangedEnterpriseAdminRoleDetails._new_value_validator = FedAdminRole_validator +ChangedEnterpriseAdminRoleDetails._team_name_validator = bv.String() +ChangedEnterpriseAdminRoleDetails._all_field_names_ = set([ + 'previous_value', + 'new_value', + 'team_name', +]) +ChangedEnterpriseAdminRoleDetails._all_fields_ = [ + ('previous_value', ChangedEnterpriseAdminRoleDetails._previous_value_validator), + ('new_value', ChangedEnterpriseAdminRoleDetails._new_value_validator), + ('team_name', ChangedEnterpriseAdminRoleDetails._team_name_validator), +] + +ChangedEnterpriseAdminRoleType._description_validator = bv.String() +ChangedEnterpriseAdminRoleType._all_field_names_ = set(['description']) +ChangedEnterpriseAdminRoleType._all_fields_ = [('description', ChangedEnterpriseAdminRoleType._description_validator)] + +ChangedEnterpriseConnectedTeamStatusDetails._action_validator = FedHandshakeAction_validator +ChangedEnterpriseConnectedTeamStatusDetails._additional_info_validator = FederationStatusChangeAdditionalInfo_validator +ChangedEnterpriseConnectedTeamStatusDetails._previous_value_validator = TrustedTeamsRequestState_validator +ChangedEnterpriseConnectedTeamStatusDetails._new_value_validator = TrustedTeamsRequestState_validator +ChangedEnterpriseConnectedTeamStatusDetails._all_field_names_ = set([ + 'action', + 'additional_info', + 'previous_value', + 'new_value', +]) +ChangedEnterpriseConnectedTeamStatusDetails._all_fields_ = [ + ('action', ChangedEnterpriseConnectedTeamStatusDetails._action_validator), + ('additional_info', ChangedEnterpriseConnectedTeamStatusDetails._additional_info_validator), + ('previous_value', ChangedEnterpriseConnectedTeamStatusDetails._previous_value_validator), + ('new_value', ChangedEnterpriseConnectedTeamStatusDetails._new_value_validator), +] + +ChangedEnterpriseConnectedTeamStatusType._description_validator = bv.String() +ChangedEnterpriseConnectedTeamStatusType._all_field_names_ = set(['description']) +ChangedEnterpriseConnectedTeamStatusType._all_fields_ = [('description', ChangedEnterpriseConnectedTeamStatusType._description_validator)] + CollectionShareDetails._album_name_validator = bv.String() CollectionShareDetails._all_field_names_ = set(['album_name']) CollectionShareDetails._all_fields_ = [('album_name', CollectionShareDetails._album_name_validator)] @@ -72131,6 +94617,10 @@ def __repr__(self): CollectionShareType._all_field_names_ = set(['description']) CollectionShareType._all_fields_ = [('description', CollectionShareType._description_validator)] +ConnectedTeamName._team_validator = bv.String() +ConnectedTeamName._all_field_names_ = set(['team']) +ConnectedTeamName._all_fields_ = [('team', ConnectedTeamName._team_validator)] + ContentPermanentDeletePolicy._disabled_validator = bv.Void() ContentPermanentDeletePolicy._enabled_validator = bv.Void() ContentPermanentDeletePolicy._other_validator = bv.Void() @@ -72148,6 +94638,7 @@ def __repr__(self): ContextLogInfo._non_team_member_validator = NonTeamMemberLogInfo_validator ContextLogInfo._anonymous_validator = bv.Void() ContextLogInfo._team_validator = bv.Void() +ContextLogInfo._organization_team_validator = TeamLogInfo_validator ContextLogInfo._trusted_non_team_member_validator = TrustedNonTeamMemberLogInfo_validator ContextLogInfo._other_validator = bv.Void() ContextLogInfo._tagmap = { @@ -72155,6 +94646,7 @@ def __repr__(self): 'non_team_member': ContextLogInfo._non_team_member_validator, 'anonymous': ContextLogInfo._anonymous_validator, 'team': ContextLogInfo._team_validator, + 'organization_team': ContextLogInfo._organization_team_validator, 'trusted_non_team_member': ContextLogInfo._trusted_non_team_member_validator, 'other': ContextLogInfo._other_validator, } @@ -72170,6 +94662,21 @@ def __repr__(self): CreateFolderType._all_field_names_ = set(['description']) CreateFolderType._all_fields_ = [('description', CreateFolderType._description_validator)] +CreateTeamInviteLinkDetails._link_url_validator = bv.String() +CreateTeamInviteLinkDetails._expiry_date_validator = bv.String() +CreateTeamInviteLinkDetails._all_field_names_ = set([ + 'link_url', + 'expiry_date', +]) +CreateTeamInviteLinkDetails._all_fields_ = [ + ('link_url', CreateTeamInviteLinkDetails._link_url_validator), + ('expiry_date', CreateTeamInviteLinkDetails._expiry_date_validator), +] + +CreateTeamInviteLinkType._description_validator = bv.String() +CreateTeamInviteLinkType._all_field_names_ = set(['description']) +CreateTeamInviteLinkType._all_fields_ = [('description', CreateTeamInviteLinkType._description_validator)] + DataPlacementRestrictionChangePolicyDetails._previous_value_validator = PlacementRestriction_validator DataPlacementRestrictionChangePolicyDetails._new_value_validator = PlacementRestriction_validator DataPlacementRestrictionChangePolicyDetails._all_field_names_ = set([ @@ -72193,6 +94700,14 @@ def __repr__(self): DataPlacementRestrictionSatisfyPolicyType._all_field_names_ = set(['description']) DataPlacementRestrictionSatisfyPolicyType._all_fields_ = [('description', DataPlacementRestrictionSatisfyPolicyType._description_validator)] +DeleteTeamInviteLinkDetails._link_url_validator = bv.String() +DeleteTeamInviteLinkDetails._all_field_names_ = set(['link_url']) +DeleteTeamInviteLinkDetails._all_fields_ = [('link_url', DeleteTeamInviteLinkDetails._link_url_validator)] + +DeleteTeamInviteLinkType._description_validator = bv.String() +DeleteTeamInviteLinkType._all_field_names_ = set(['description']) +DeleteTeamInviteLinkType._all_fields_ = [('description', DeleteTeamInviteLinkType._description_validator)] + DeviceSessionLogInfo._ip_address_validator = bv.Nullable(IpAddress_validator) DeviceSessionLogInfo._created_validator = bv.Nullable(common.DropboxTimestamp_validator) DeviceSessionLogInfo._updated_validator = bv.Nullable(common.DropboxTimestamp_validator) @@ -72271,6 +94786,13 @@ def __repr__(self): DesktopSessionLogInfo._fields_ = [] DesktopSessionLogInfo._all_fields_ = SessionLogInfo._all_fields_ + DesktopSessionLogInfo._fields_ +DeviceApprovalsAddExceptionDetails._all_field_names_ = set([]) +DeviceApprovalsAddExceptionDetails._all_fields_ = [] + +DeviceApprovalsAddExceptionType._description_validator = bv.String() +DeviceApprovalsAddExceptionType._all_field_names_ = set(['description']) +DeviceApprovalsAddExceptionType._all_fields_ = [('description', DeviceApprovalsAddExceptionType._description_validator)] + DeviceApprovalsChangeDesktopPolicyDetails._new_value_validator = bv.Nullable(DeviceApprovalsPolicy_validator) DeviceApprovalsChangeDesktopPolicyDetails._previous_value_validator = bv.Nullable(DeviceApprovalsPolicy_validator) DeviceApprovalsChangeDesktopPolicyDetails._all_field_names_ = set([ @@ -72344,6 +94866,13 @@ def __repr__(self): DeviceApprovalsPolicy.limited = DeviceApprovalsPolicy('limited') DeviceApprovalsPolicy.other = DeviceApprovalsPolicy('other') +DeviceApprovalsRemoveExceptionDetails._all_field_names_ = set([]) +DeviceApprovalsRemoveExceptionDetails._all_fields_ = [] + +DeviceApprovalsRemoveExceptionType._description_validator = bv.String() +DeviceApprovalsRemoveExceptionType._all_field_names_ = set(['description']) +DeviceApprovalsRemoveExceptionType._all_fields_ = [('description', DeviceApprovalsRemoveExceptionType._description_validator)] + DeviceChangeIpDesktopDetails._device_session_info_validator = DeviceSessionLogInfo_validator DeviceChangeIpDesktopDetails._all_field_names_ = set(['device_session_info']) DeviceChangeIpDesktopDetails._all_fields_ = [('device_session_info', DeviceChangeIpDesktopDetails._device_session_info_validator)] @@ -72680,6 +95209,42 @@ def __repr__(self): EnabledDomainInvitesType._all_field_names_ = set(['description']) EnabledDomainInvitesType._all_fields_ = [('description', EnabledDomainInvitesType._description_validator)] +EndedEnterpriseAdminSessionDeprecatedDetails._federation_extra_details_validator = FedExtraDetails_validator +EndedEnterpriseAdminSessionDeprecatedDetails._all_field_names_ = set(['federation_extra_details']) +EndedEnterpriseAdminSessionDeprecatedDetails._all_fields_ = [('federation_extra_details', EndedEnterpriseAdminSessionDeprecatedDetails._federation_extra_details_validator)] + +EndedEnterpriseAdminSessionDeprecatedType._description_validator = bv.String() +EndedEnterpriseAdminSessionDeprecatedType._all_field_names_ = set(['description']) +EndedEnterpriseAdminSessionDeprecatedType._all_fields_ = [('description', EndedEnterpriseAdminSessionDeprecatedType._description_validator)] + +EndedEnterpriseAdminSessionDetails._all_field_names_ = set([]) +EndedEnterpriseAdminSessionDetails._all_fields_ = [] + +EndedEnterpriseAdminSessionType._description_validator = bv.String() +EndedEnterpriseAdminSessionType._all_field_names_ = set(['description']) +EndedEnterpriseAdminSessionType._all_fields_ = [('description', EndedEnterpriseAdminSessionType._description_validator)] + +EnterpriseSettingsLockingDetails._team_name_validator = bv.String() +EnterpriseSettingsLockingDetails._settings_page_name_validator = bv.String() +EnterpriseSettingsLockingDetails._previous_settings_page_locking_state_validator = bv.String() +EnterpriseSettingsLockingDetails._new_settings_page_locking_state_validator = bv.String() +EnterpriseSettingsLockingDetails._all_field_names_ = set([ + 'team_name', + 'settings_page_name', + 'previous_settings_page_locking_state', + 'new_settings_page_locking_state', +]) +EnterpriseSettingsLockingDetails._all_fields_ = [ + ('team_name', EnterpriseSettingsLockingDetails._team_name_validator), + ('settings_page_name', EnterpriseSettingsLockingDetails._settings_page_name_validator), + ('previous_settings_page_locking_state', EnterpriseSettingsLockingDetails._previous_settings_page_locking_state_validator), + ('new_settings_page_locking_state', EnterpriseSettingsLockingDetails._new_settings_page_locking_state_validator), +] + +EnterpriseSettingsLockingType._description_validator = bv.String() +EnterpriseSettingsLockingType._all_field_names_ = set(['description']) +EnterpriseSettingsLockingType._all_fields_ = [('description', EnterpriseSettingsLockingType._description_validator)] + EventCategory._apps_validator = bv.Void() EventCategory._comments_validator = bv.Void() EventCategory._devices_validator = bv.Void() @@ -72687,6 +95252,7 @@ def __repr__(self): EventCategory._file_operations_validator = bv.Void() EventCategory._file_requests_validator = bv.Void() EventCategory._groups_validator = bv.Void() +EventCategory._legal_holds_validator = bv.Void() EventCategory._logins_validator = bv.Void() EventCategory._members_validator = bv.Void() EventCategory._paper_validator = bv.Void() @@ -72709,6 +95275,7 @@ def __repr__(self): 'file_operations': EventCategory._file_operations_validator, 'file_requests': EventCategory._file_requests_validator, 'groups': EventCategory._groups_validator, + 'legal_holds': EventCategory._legal_holds_validator, 'logins': EventCategory._logins_validator, 'members': EventCategory._members_validator, 'paper': EventCategory._paper_validator, @@ -72732,6 +95299,7 @@ def __repr__(self): EventCategory.file_operations = EventCategory('file_operations') EventCategory.file_requests = EventCategory('file_requests') EventCategory.groups = EventCategory('groups') +EventCategory.legal_holds = EventCategory('legal_holds') EventCategory.logins = EventCategory('logins') EventCategory.members = EventCategory('members') EventCategory.paper = EventCategory('paper') @@ -72794,6 +95362,7 @@ def __repr__(self): EventDetails._file_download_details_validator = FileDownloadDetails_validator EventDetails._file_edit_details_validator = FileEditDetails_validator EventDetails._file_get_copy_reference_details_validator = FileGetCopyReferenceDetails_validator +EventDetails._file_locking_lock_status_changed_details_validator = FileLockingLockStatusChangedDetails_validator EventDetails._file_move_details_validator = FileMoveDetails_validator EventDetails._file_permanently_delete_details_validator = FilePermanentlyDeleteDetails_validator EventDetails._file_preview_details_validator = FilePreviewDetails_validator @@ -72802,6 +95371,10 @@ def __repr__(self): EventDetails._file_revert_details_validator = FileRevertDetails_validator EventDetails._file_rollback_changes_details_validator = FileRollbackChangesDetails_validator EventDetails._file_save_copy_reference_details_validator = FileSaveCopyReferenceDetails_validator +EventDetails._folder_overview_description_changed_details_validator = FolderOverviewDescriptionChangedDetails_validator +EventDetails._folder_overview_item_pinned_details_validator = FolderOverviewItemPinnedDetails_validator +EventDetails._folder_overview_item_unpinned_details_validator = FolderOverviewItemUnpinnedDetails_validator +EventDetails._rewind_folder_details_validator = RewindFolderDetails_validator EventDetails._file_request_change_details_validator = FileRequestChangeDetails_validator EventDetails._file_request_close_details_validator = FileRequestCloseDetails_validator EventDetails._file_request_create_details_validator = FileRequestCreateDetails_validator @@ -72820,6 +95393,18 @@ def __repr__(self): EventDetails._group_remove_external_id_details_validator = GroupRemoveExternalIdDetails_validator EventDetails._group_remove_member_details_validator = GroupRemoveMemberDetails_validator EventDetails._group_rename_details_validator = GroupRenameDetails_validator +EventDetails._legal_holds_activate_a_hold_details_validator = LegalHoldsActivateAHoldDetails_validator +EventDetails._legal_holds_add_members_details_validator = LegalHoldsAddMembersDetails_validator +EventDetails._legal_holds_change_hold_details_details_validator = LegalHoldsChangeHoldDetailsDetails_validator +EventDetails._legal_holds_change_hold_name_details_validator = LegalHoldsChangeHoldNameDetails_validator +EventDetails._legal_holds_export_a_hold_details_validator = LegalHoldsExportAHoldDetails_validator +EventDetails._legal_holds_export_cancelled_details_validator = LegalHoldsExportCancelledDetails_validator +EventDetails._legal_holds_export_downloaded_details_validator = LegalHoldsExportDownloadedDetails_validator +EventDetails._legal_holds_export_removed_details_validator = LegalHoldsExportRemovedDetails_validator +EventDetails._legal_holds_release_a_hold_details_validator = LegalHoldsReleaseAHoldDetails_validator +EventDetails._legal_holds_remove_members_details_validator = LegalHoldsRemoveMembersDetails_validator +EventDetails._legal_holds_report_a_hold_details_validator = LegalHoldsReportAHoldDetails_validator +EventDetails._account_lock_or_unlocked_details_validator = AccountLockOrUnlockedDetails_validator EventDetails._emm_error_details_validator = EmmErrorDetails_validator EventDetails._guest_admin_signed_in_via_trusted_teams_details_validator = GuestAdminSignedInViaTrustedTeamsDetails_validator EventDetails._guest_admin_signed_out_via_trusted_teams_details_validator = GuestAdminSignedOutViaTrustedTeamsDetails_validator @@ -72831,6 +95416,8 @@ def __repr__(self): EventDetails._sign_in_as_session_end_details_validator = SignInAsSessionEndDetails_validator EventDetails._sign_in_as_session_start_details_validator = SignInAsSessionStartDetails_validator EventDetails._sso_error_details_validator = SsoErrorDetails_validator +EventDetails._create_team_invite_link_details_validator = CreateTeamInviteLinkDetails_validator +EventDetails._delete_team_invite_link_details_validator = DeleteTeamInviteLinkDetails_validator EventDetails._member_add_external_id_details_validator = MemberAddExternalIdDetails_validator EventDetails._member_add_name_details_validator = MemberAddNameDetails_validator EventDetails._member_change_admin_role_details_validator = MemberChangeAdminRoleDetails_validator @@ -72840,15 +95427,28 @@ def __repr__(self): EventDetails._member_change_name_details_validator = MemberChangeNameDetails_validator EventDetails._member_change_status_details_validator = MemberChangeStatusDetails_validator EventDetails._member_delete_manual_contacts_details_validator = MemberDeleteManualContactsDetails_validator +EventDetails._member_delete_profile_photo_details_validator = MemberDeleteProfilePhotoDetails_validator EventDetails._member_permanently_delete_account_contents_details_validator = MemberPermanentlyDeleteAccountContentsDetails_validator EventDetails._member_remove_external_id_details_validator = MemberRemoveExternalIdDetails_validator +EventDetails._member_set_profile_photo_details_validator = MemberSetProfilePhotoDetails_validator EventDetails._member_space_limits_add_custom_quota_details_validator = MemberSpaceLimitsAddCustomQuotaDetails_validator EventDetails._member_space_limits_change_custom_quota_details_validator = MemberSpaceLimitsChangeCustomQuotaDetails_validator EventDetails._member_space_limits_change_status_details_validator = MemberSpaceLimitsChangeStatusDetails_validator EventDetails._member_space_limits_remove_custom_quota_details_validator = MemberSpaceLimitsRemoveCustomQuotaDetails_validator EventDetails._member_suggest_details_validator = MemberSuggestDetails_validator EventDetails._member_transfer_account_contents_details_validator = MemberTransferAccountContentsDetails_validator +EventDetails._pending_secondary_email_added_details_validator = PendingSecondaryEmailAddedDetails_validator +EventDetails._secondary_email_deleted_details_validator = SecondaryEmailDeletedDetails_validator +EventDetails._secondary_email_verified_details_validator = SecondaryEmailVerifiedDetails_validator EventDetails._secondary_mails_policy_changed_details_validator = SecondaryMailsPolicyChangedDetails_validator +EventDetails._binder_add_page_details_validator = BinderAddPageDetails_validator +EventDetails._binder_add_section_details_validator = BinderAddSectionDetails_validator +EventDetails._binder_remove_page_details_validator = BinderRemovePageDetails_validator +EventDetails._binder_remove_section_details_validator = BinderRemoveSectionDetails_validator +EventDetails._binder_rename_page_details_validator = BinderRenamePageDetails_validator +EventDetails._binder_rename_section_details_validator = BinderRenameSectionDetails_validator +EventDetails._binder_reorder_page_details_validator = BinderReorderPageDetails_validator +EventDetails._binder_reorder_section_details_validator = BinderReorderSectionDetails_validator EventDetails._paper_content_add_member_details_validator = PaperContentAddMemberDetails_validator EventDetails._paper_content_add_to_folder_details_validator = PaperContentAddToFolderDetails_validator EventDetails._paper_content_archive_details_validator = PaperContentArchiveDetails_validator @@ -72886,6 +95486,7 @@ def __repr__(self): EventDetails._paper_folder_deleted_details_validator = PaperFolderDeletedDetails_validator EventDetails._paper_folder_followed_details_validator = PaperFolderFollowedDetails_validator EventDetails._paper_folder_team_invite_details_validator = PaperFolderTeamInviteDetails_validator +EventDetails._paper_published_link_change_permission_details_validator = PaperPublishedLinkChangePermissionDetails_validator EventDetails._paper_published_link_create_details_validator = PaperPublishedLinkCreateDetails_validator EventDetails._paper_published_link_disabled_details_validator = PaperPublishedLinkDisabledDetails_validator EventDetails._paper_published_link_view_details_validator = PaperPublishedLinkViewDetails_validator @@ -72895,11 +95496,25 @@ def __repr__(self): EventDetails._emm_create_exceptions_report_details_validator = EmmCreateExceptionsReportDetails_validator EventDetails._emm_create_usage_report_details_validator = EmmCreateUsageReportDetails_validator EventDetails._export_members_report_details_validator = ExportMembersReportDetails_validator +EventDetails._export_members_report_fail_details_validator = ExportMembersReportFailDetails_validator +EventDetails._no_expiration_link_gen_create_report_details_validator = NoExpirationLinkGenCreateReportDetails_validator +EventDetails._no_expiration_link_gen_report_failed_details_validator = NoExpirationLinkGenReportFailedDetails_validator +EventDetails._no_password_link_gen_create_report_details_validator = NoPasswordLinkGenCreateReportDetails_validator +EventDetails._no_password_link_gen_report_failed_details_validator = NoPasswordLinkGenReportFailedDetails_validator +EventDetails._no_password_link_view_create_report_details_validator = NoPasswordLinkViewCreateReportDetails_validator +EventDetails._no_password_link_view_report_failed_details_validator = NoPasswordLinkViewReportFailedDetails_validator +EventDetails._outdated_link_view_create_report_details_validator = OutdatedLinkViewCreateReportDetails_validator +EventDetails._outdated_link_view_report_failed_details_validator = OutdatedLinkViewReportFailedDetails_validator EventDetails._paper_admin_export_start_details_validator = PaperAdminExportStartDetails_validator EventDetails._smart_sync_create_admin_privilege_report_details_validator = SmartSyncCreateAdminPrivilegeReportDetails_validator EventDetails._team_activity_create_report_details_validator = TeamActivityCreateReportDetails_validator EventDetails._team_activity_create_report_fail_details_validator = TeamActivityCreateReportFailDetails_validator EventDetails._collection_share_details_validator = CollectionShareDetails_validator +EventDetails._file_transfers_file_add_details_validator = FileTransfersFileAddDetails_validator +EventDetails._file_transfers_transfer_delete_details_validator = FileTransfersTransferDeleteDetails_validator +EventDetails._file_transfers_transfer_download_details_validator = FileTransfersTransferDownloadDetails_validator +EventDetails._file_transfers_transfer_send_details_validator = FileTransfersTransferSendDetails_validator +EventDetails._file_transfers_transfer_view_details_validator = FileTransfersTransferViewDetails_validator EventDetails._note_acl_invite_only_details_validator = NoteAclInviteOnlyDetails_validator EventDetails._note_acl_link_details_validator = NoteAclLinkDetails_validator EventDetails._note_acl_team_link_details_validator = NoteAclTeamLinkDetails_validator @@ -72939,6 +95554,8 @@ def __repr__(self): EventDetails._shared_content_remove_link_password_details_validator = SharedContentRemoveLinkPasswordDetails_validator EventDetails._shared_content_remove_member_details_validator = SharedContentRemoveMemberDetails_validator EventDetails._shared_content_request_access_details_validator = SharedContentRequestAccessDetails_validator +EventDetails._shared_content_restore_invitees_details_validator = SharedContentRestoreInviteesDetails_validator +EventDetails._shared_content_restore_member_details_validator = SharedContentRestoreMemberDetails_validator EventDetails._shared_content_unshare_details_validator = SharedContentUnshareDetails_validator EventDetails._shared_content_view_details_validator = SharedContentViewDetails_validator EventDetails._shared_folder_change_link_policy_details_validator = SharedFolderChangeLinkPolicyDetails_validator @@ -72959,6 +95576,15 @@ def __repr__(self): EventDetails._shared_link_disable_details_validator = SharedLinkDisableDetails_validator EventDetails._shared_link_download_details_validator = SharedLinkDownloadDetails_validator EventDetails._shared_link_remove_expiry_details_validator = SharedLinkRemoveExpiryDetails_validator +EventDetails._shared_link_settings_add_expiration_details_validator = SharedLinkSettingsAddExpirationDetails_validator +EventDetails._shared_link_settings_add_password_details_validator = SharedLinkSettingsAddPasswordDetails_validator +EventDetails._shared_link_settings_allow_download_disabled_details_validator = SharedLinkSettingsAllowDownloadDisabledDetails_validator +EventDetails._shared_link_settings_allow_download_enabled_details_validator = SharedLinkSettingsAllowDownloadEnabledDetails_validator +EventDetails._shared_link_settings_change_audience_details_validator = SharedLinkSettingsChangeAudienceDetails_validator +EventDetails._shared_link_settings_change_expiration_details_validator = SharedLinkSettingsChangeExpirationDetails_validator +EventDetails._shared_link_settings_change_password_details_validator = SharedLinkSettingsChangePasswordDetails_validator +EventDetails._shared_link_settings_remove_expiration_details_validator = SharedLinkSettingsRemoveExpirationDetails_validator +EventDetails._shared_link_settings_remove_password_details_validator = SharedLinkSettingsRemovePasswordDetails_validator EventDetails._shared_link_share_details_validator = SharedLinkShareDetails_validator EventDetails._shared_link_view_details_validator = SharedLinkViewDetails_validator EventDetails._shared_note_opened_details_validator = SharedNoteOpenedDetails_validator @@ -73009,10 +95635,12 @@ def __repr__(self): EventDetails._camera_uploads_policy_changed_details_validator = CameraUploadsPolicyChangedDetails_validator EventDetails._data_placement_restriction_change_policy_details_validator = DataPlacementRestrictionChangePolicyDetails_validator EventDetails._data_placement_restriction_satisfy_policy_details_validator = DataPlacementRestrictionSatisfyPolicyDetails_validator +EventDetails._device_approvals_add_exception_details_validator = DeviceApprovalsAddExceptionDetails_validator EventDetails._device_approvals_change_desktop_policy_details_validator = DeviceApprovalsChangeDesktopPolicyDetails_validator EventDetails._device_approvals_change_mobile_policy_details_validator = DeviceApprovalsChangeMobilePolicyDetails_validator EventDetails._device_approvals_change_overage_action_details_validator = DeviceApprovalsChangeOverageActionDetails_validator EventDetails._device_approvals_change_unlink_action_details_validator = DeviceApprovalsChangeUnlinkActionDetails_validator +EventDetails._device_approvals_remove_exception_details_validator = DeviceApprovalsRemoveExceptionDetails_validator EventDetails._directory_restrictions_add_members_details_validator = DirectoryRestrictionsAddMembersDetails_validator EventDetails._directory_restrictions_remove_members_details_validator = DirectoryRestrictionsRemoveMembersDetails_validator EventDetails._emm_add_exception_details_validator = EmmAddExceptionDetails_validator @@ -73020,13 +95648,16 @@ def __repr__(self): EventDetails._emm_remove_exception_details_validator = EmmRemoveExceptionDetails_validator EventDetails._extended_version_history_change_policy_details_validator = ExtendedVersionHistoryChangePolicyDetails_validator EventDetails._file_comments_change_policy_details_validator = FileCommentsChangePolicyDetails_validator +EventDetails._file_locking_policy_changed_details_validator = FileLockingPolicyChangedDetails_validator EventDetails._file_requests_change_policy_details_validator = FileRequestsChangePolicyDetails_validator EventDetails._file_requests_emails_enabled_details_validator = FileRequestsEmailsEnabledDetails_validator EventDetails._file_requests_emails_restricted_to_team_only_details_validator = FileRequestsEmailsRestrictedToTeamOnlyDetails_validator +EventDetails._file_transfers_policy_changed_details_validator = FileTransfersPolicyChangedDetails_validator EventDetails._google_sso_change_policy_details_validator = GoogleSsoChangePolicyDetails_validator EventDetails._group_user_management_change_policy_details_validator = GroupUserManagementChangePolicyDetails_validator EventDetails._integration_policy_changed_details_validator = IntegrationPolicyChangedDetails_validator EventDetails._member_requests_change_policy_details_validator = MemberRequestsChangePolicyDetails_validator +EventDetails._member_send_invite_policy_changed_details_validator = MemberSendInvitePolicyChangedDetails_validator EventDetails._member_space_limits_add_exception_details_validator = MemberSpaceLimitsAddExceptionDetails_validator EventDetails._member_space_limits_change_caps_type_policy_details_validator = MemberSpaceLimitsChangeCapsTypePolicyDetails_validator EventDetails._member_space_limits_change_policy_details_validator = MemberSpaceLimitsChangePolicyDetails_validator @@ -73042,23 +95673,31 @@ def __repr__(self): EventDetails._paper_desktop_policy_changed_details_validator = PaperDesktopPolicyChangedDetails_validator EventDetails._paper_enabled_users_group_addition_details_validator = PaperEnabledUsersGroupAdditionDetails_validator EventDetails._paper_enabled_users_group_removal_details_validator = PaperEnabledUsersGroupRemovalDetails_validator +EventDetails._password_strength_requirements_change_policy_details_validator = PasswordStrengthRequirementsChangePolicyDetails_validator EventDetails._permanent_delete_change_policy_details_validator = PermanentDeleteChangePolicyDetails_validator EventDetails._reseller_support_change_policy_details_validator = ResellerSupportChangePolicyDetails_validator +EventDetails._rewind_policy_changed_details_validator = RewindPolicyChangedDetails_validator EventDetails._sharing_change_folder_join_policy_details_validator = SharingChangeFolderJoinPolicyDetails_validator EventDetails._sharing_change_link_policy_details_validator = SharingChangeLinkPolicyDetails_validator EventDetails._sharing_change_member_policy_details_validator = SharingChangeMemberPolicyDetails_validator EventDetails._showcase_change_download_policy_details_validator = ShowcaseChangeDownloadPolicyDetails_validator EventDetails._showcase_change_enabled_policy_details_validator = ShowcaseChangeEnabledPolicyDetails_validator EventDetails._showcase_change_external_sharing_policy_details_validator = ShowcaseChangeExternalSharingPolicyDetails_validator +EventDetails._smarter_smart_sync_policy_changed_details_validator = SmarterSmartSyncPolicyChangedDetails_validator EventDetails._smart_sync_change_policy_details_validator = SmartSyncChangePolicyDetails_validator EventDetails._smart_sync_not_opt_out_details_validator = SmartSyncNotOptOutDetails_validator EventDetails._smart_sync_opt_out_details_validator = SmartSyncOptOutDetails_validator EventDetails._sso_change_policy_details_validator = SsoChangePolicyDetails_validator EventDetails._team_extensions_policy_changed_details_validator = TeamExtensionsPolicyChangedDetails_validator EventDetails._team_selective_sync_policy_changed_details_validator = TeamSelectiveSyncPolicyChangedDetails_validator +EventDetails._team_sharing_whitelist_subjects_changed_details_validator = TeamSharingWhitelistSubjectsChangedDetails_validator +EventDetails._tfa_add_exception_details_validator = TfaAddExceptionDetails_validator EventDetails._tfa_change_policy_details_validator = TfaChangePolicyDetails_validator +EventDetails._tfa_remove_exception_details_validator = TfaRemoveExceptionDetails_validator EventDetails._two_account_change_policy_details_validator = TwoAccountChangePolicyDetails_validator EventDetails._viewer_info_policy_changed_details_validator = ViewerInfoPolicyChangedDetails_validator +EventDetails._watermarking_policy_changed_details_validator = WatermarkingPolicyChangedDetails_validator +EventDetails._web_sessions_change_active_session_limit_details_validator = WebSessionsChangeActiveSessionLimitDetails_validator EventDetails._web_sessions_change_fixed_length_policy_details_validator = WebSessionsChangeFixedLengthPolicyDetails_validator EventDetails._web_sessions_change_idle_length_policy_details_validator = WebSessionsChangeIdleLengthPolicyDetails_validator EventDetails._team_merge_from_details_validator = TeamMergeFromDetails_validator @@ -73075,7 +95714,13 @@ def __repr__(self): EventDetails._tfa_remove_backup_phone_details_validator = TfaRemoveBackupPhoneDetails_validator EventDetails._tfa_remove_security_key_details_validator = TfaRemoveSecurityKeyDetails_validator EventDetails._tfa_reset_details_validator = TfaResetDetails_validator +EventDetails._changed_enterprise_admin_role_details_validator = ChangedEnterpriseAdminRoleDetails_validator +EventDetails._changed_enterprise_connected_team_status_details_validator = ChangedEnterpriseConnectedTeamStatusDetails_validator +EventDetails._ended_enterprise_admin_session_details_validator = EndedEnterpriseAdminSessionDetails_validator +EventDetails._ended_enterprise_admin_session_deprecated_details_validator = EndedEnterpriseAdminSessionDeprecatedDetails_validator +EventDetails._enterprise_settings_locking_details_validator = EnterpriseSettingsLockingDetails_validator EventDetails._guest_admin_change_status_details_validator = GuestAdminChangeStatusDetails_validator +EventDetails._started_enterprise_admin_session_details_validator = StartedEnterpriseAdminSessionDetails_validator EventDetails._team_merge_request_accepted_details_validator = TeamMergeRequestAcceptedDetails_validator EventDetails._team_merge_request_accepted_shown_to_primary_team_details_validator = TeamMergeRequestAcceptedShownToPrimaryTeamDetails_validator EventDetails._team_merge_request_accepted_shown_to_secondary_team_details_validator = TeamMergeRequestAcceptedShownToSecondaryTeamDetails_validator @@ -73144,6 +95789,7 @@ def __repr__(self): 'file_download_details': EventDetails._file_download_details_validator, 'file_edit_details': EventDetails._file_edit_details_validator, 'file_get_copy_reference_details': EventDetails._file_get_copy_reference_details_validator, + 'file_locking_lock_status_changed_details': EventDetails._file_locking_lock_status_changed_details_validator, 'file_move_details': EventDetails._file_move_details_validator, 'file_permanently_delete_details': EventDetails._file_permanently_delete_details_validator, 'file_preview_details': EventDetails._file_preview_details_validator, @@ -73152,6 +95798,10 @@ def __repr__(self): 'file_revert_details': EventDetails._file_revert_details_validator, 'file_rollback_changes_details': EventDetails._file_rollback_changes_details_validator, 'file_save_copy_reference_details': EventDetails._file_save_copy_reference_details_validator, + 'folder_overview_description_changed_details': EventDetails._folder_overview_description_changed_details_validator, + 'folder_overview_item_pinned_details': EventDetails._folder_overview_item_pinned_details_validator, + 'folder_overview_item_unpinned_details': EventDetails._folder_overview_item_unpinned_details_validator, + 'rewind_folder_details': EventDetails._rewind_folder_details_validator, 'file_request_change_details': EventDetails._file_request_change_details_validator, 'file_request_close_details': EventDetails._file_request_close_details_validator, 'file_request_create_details': EventDetails._file_request_create_details_validator, @@ -73170,6 +95820,18 @@ def __repr__(self): 'group_remove_external_id_details': EventDetails._group_remove_external_id_details_validator, 'group_remove_member_details': EventDetails._group_remove_member_details_validator, 'group_rename_details': EventDetails._group_rename_details_validator, + 'legal_holds_activate_a_hold_details': EventDetails._legal_holds_activate_a_hold_details_validator, + 'legal_holds_add_members_details': EventDetails._legal_holds_add_members_details_validator, + 'legal_holds_change_hold_details_details': EventDetails._legal_holds_change_hold_details_details_validator, + 'legal_holds_change_hold_name_details': EventDetails._legal_holds_change_hold_name_details_validator, + 'legal_holds_export_a_hold_details': EventDetails._legal_holds_export_a_hold_details_validator, + 'legal_holds_export_cancelled_details': EventDetails._legal_holds_export_cancelled_details_validator, + 'legal_holds_export_downloaded_details': EventDetails._legal_holds_export_downloaded_details_validator, + 'legal_holds_export_removed_details': EventDetails._legal_holds_export_removed_details_validator, + 'legal_holds_release_a_hold_details': EventDetails._legal_holds_release_a_hold_details_validator, + 'legal_holds_remove_members_details': EventDetails._legal_holds_remove_members_details_validator, + 'legal_holds_report_a_hold_details': EventDetails._legal_holds_report_a_hold_details_validator, + 'account_lock_or_unlocked_details': EventDetails._account_lock_or_unlocked_details_validator, 'emm_error_details': EventDetails._emm_error_details_validator, 'guest_admin_signed_in_via_trusted_teams_details': EventDetails._guest_admin_signed_in_via_trusted_teams_details_validator, 'guest_admin_signed_out_via_trusted_teams_details': EventDetails._guest_admin_signed_out_via_trusted_teams_details_validator, @@ -73181,6 +95843,8 @@ def __repr__(self): 'sign_in_as_session_end_details': EventDetails._sign_in_as_session_end_details_validator, 'sign_in_as_session_start_details': EventDetails._sign_in_as_session_start_details_validator, 'sso_error_details': EventDetails._sso_error_details_validator, + 'create_team_invite_link_details': EventDetails._create_team_invite_link_details_validator, + 'delete_team_invite_link_details': EventDetails._delete_team_invite_link_details_validator, 'member_add_external_id_details': EventDetails._member_add_external_id_details_validator, 'member_add_name_details': EventDetails._member_add_name_details_validator, 'member_change_admin_role_details': EventDetails._member_change_admin_role_details_validator, @@ -73190,15 +95854,28 @@ def __repr__(self): 'member_change_name_details': EventDetails._member_change_name_details_validator, 'member_change_status_details': EventDetails._member_change_status_details_validator, 'member_delete_manual_contacts_details': EventDetails._member_delete_manual_contacts_details_validator, + 'member_delete_profile_photo_details': EventDetails._member_delete_profile_photo_details_validator, 'member_permanently_delete_account_contents_details': EventDetails._member_permanently_delete_account_contents_details_validator, 'member_remove_external_id_details': EventDetails._member_remove_external_id_details_validator, + 'member_set_profile_photo_details': EventDetails._member_set_profile_photo_details_validator, 'member_space_limits_add_custom_quota_details': EventDetails._member_space_limits_add_custom_quota_details_validator, 'member_space_limits_change_custom_quota_details': EventDetails._member_space_limits_change_custom_quota_details_validator, 'member_space_limits_change_status_details': EventDetails._member_space_limits_change_status_details_validator, 'member_space_limits_remove_custom_quota_details': EventDetails._member_space_limits_remove_custom_quota_details_validator, 'member_suggest_details': EventDetails._member_suggest_details_validator, 'member_transfer_account_contents_details': EventDetails._member_transfer_account_contents_details_validator, + 'pending_secondary_email_added_details': EventDetails._pending_secondary_email_added_details_validator, + 'secondary_email_deleted_details': EventDetails._secondary_email_deleted_details_validator, + 'secondary_email_verified_details': EventDetails._secondary_email_verified_details_validator, 'secondary_mails_policy_changed_details': EventDetails._secondary_mails_policy_changed_details_validator, + 'binder_add_page_details': EventDetails._binder_add_page_details_validator, + 'binder_add_section_details': EventDetails._binder_add_section_details_validator, + 'binder_remove_page_details': EventDetails._binder_remove_page_details_validator, + 'binder_remove_section_details': EventDetails._binder_remove_section_details_validator, + 'binder_rename_page_details': EventDetails._binder_rename_page_details_validator, + 'binder_rename_section_details': EventDetails._binder_rename_section_details_validator, + 'binder_reorder_page_details': EventDetails._binder_reorder_page_details_validator, + 'binder_reorder_section_details': EventDetails._binder_reorder_section_details_validator, 'paper_content_add_member_details': EventDetails._paper_content_add_member_details_validator, 'paper_content_add_to_folder_details': EventDetails._paper_content_add_to_folder_details_validator, 'paper_content_archive_details': EventDetails._paper_content_archive_details_validator, @@ -73236,6 +95913,7 @@ def __repr__(self): 'paper_folder_deleted_details': EventDetails._paper_folder_deleted_details_validator, 'paper_folder_followed_details': EventDetails._paper_folder_followed_details_validator, 'paper_folder_team_invite_details': EventDetails._paper_folder_team_invite_details_validator, + 'paper_published_link_change_permission_details': EventDetails._paper_published_link_change_permission_details_validator, 'paper_published_link_create_details': EventDetails._paper_published_link_create_details_validator, 'paper_published_link_disabled_details': EventDetails._paper_published_link_disabled_details_validator, 'paper_published_link_view_details': EventDetails._paper_published_link_view_details_validator, @@ -73245,11 +95923,25 @@ def __repr__(self): 'emm_create_exceptions_report_details': EventDetails._emm_create_exceptions_report_details_validator, 'emm_create_usage_report_details': EventDetails._emm_create_usage_report_details_validator, 'export_members_report_details': EventDetails._export_members_report_details_validator, + 'export_members_report_fail_details': EventDetails._export_members_report_fail_details_validator, + 'no_expiration_link_gen_create_report_details': EventDetails._no_expiration_link_gen_create_report_details_validator, + 'no_expiration_link_gen_report_failed_details': EventDetails._no_expiration_link_gen_report_failed_details_validator, + 'no_password_link_gen_create_report_details': EventDetails._no_password_link_gen_create_report_details_validator, + 'no_password_link_gen_report_failed_details': EventDetails._no_password_link_gen_report_failed_details_validator, + 'no_password_link_view_create_report_details': EventDetails._no_password_link_view_create_report_details_validator, + 'no_password_link_view_report_failed_details': EventDetails._no_password_link_view_report_failed_details_validator, + 'outdated_link_view_create_report_details': EventDetails._outdated_link_view_create_report_details_validator, + 'outdated_link_view_report_failed_details': EventDetails._outdated_link_view_report_failed_details_validator, 'paper_admin_export_start_details': EventDetails._paper_admin_export_start_details_validator, 'smart_sync_create_admin_privilege_report_details': EventDetails._smart_sync_create_admin_privilege_report_details_validator, 'team_activity_create_report_details': EventDetails._team_activity_create_report_details_validator, 'team_activity_create_report_fail_details': EventDetails._team_activity_create_report_fail_details_validator, 'collection_share_details': EventDetails._collection_share_details_validator, + 'file_transfers_file_add_details': EventDetails._file_transfers_file_add_details_validator, + 'file_transfers_transfer_delete_details': EventDetails._file_transfers_transfer_delete_details_validator, + 'file_transfers_transfer_download_details': EventDetails._file_transfers_transfer_download_details_validator, + 'file_transfers_transfer_send_details': EventDetails._file_transfers_transfer_send_details_validator, + 'file_transfers_transfer_view_details': EventDetails._file_transfers_transfer_view_details_validator, 'note_acl_invite_only_details': EventDetails._note_acl_invite_only_details_validator, 'note_acl_link_details': EventDetails._note_acl_link_details_validator, 'note_acl_team_link_details': EventDetails._note_acl_team_link_details_validator, @@ -73289,6 +95981,8 @@ def __repr__(self): 'shared_content_remove_link_password_details': EventDetails._shared_content_remove_link_password_details_validator, 'shared_content_remove_member_details': EventDetails._shared_content_remove_member_details_validator, 'shared_content_request_access_details': EventDetails._shared_content_request_access_details_validator, + 'shared_content_restore_invitees_details': EventDetails._shared_content_restore_invitees_details_validator, + 'shared_content_restore_member_details': EventDetails._shared_content_restore_member_details_validator, 'shared_content_unshare_details': EventDetails._shared_content_unshare_details_validator, 'shared_content_view_details': EventDetails._shared_content_view_details_validator, 'shared_folder_change_link_policy_details': EventDetails._shared_folder_change_link_policy_details_validator, @@ -73309,6 +96003,15 @@ def __repr__(self): 'shared_link_disable_details': EventDetails._shared_link_disable_details_validator, 'shared_link_download_details': EventDetails._shared_link_download_details_validator, 'shared_link_remove_expiry_details': EventDetails._shared_link_remove_expiry_details_validator, + 'shared_link_settings_add_expiration_details': EventDetails._shared_link_settings_add_expiration_details_validator, + 'shared_link_settings_add_password_details': EventDetails._shared_link_settings_add_password_details_validator, + 'shared_link_settings_allow_download_disabled_details': EventDetails._shared_link_settings_allow_download_disabled_details_validator, + 'shared_link_settings_allow_download_enabled_details': EventDetails._shared_link_settings_allow_download_enabled_details_validator, + 'shared_link_settings_change_audience_details': EventDetails._shared_link_settings_change_audience_details_validator, + 'shared_link_settings_change_expiration_details': EventDetails._shared_link_settings_change_expiration_details_validator, + 'shared_link_settings_change_password_details': EventDetails._shared_link_settings_change_password_details_validator, + 'shared_link_settings_remove_expiration_details': EventDetails._shared_link_settings_remove_expiration_details_validator, + 'shared_link_settings_remove_password_details': EventDetails._shared_link_settings_remove_password_details_validator, 'shared_link_share_details': EventDetails._shared_link_share_details_validator, 'shared_link_view_details': EventDetails._shared_link_view_details_validator, 'shared_note_opened_details': EventDetails._shared_note_opened_details_validator, @@ -73359,10 +96062,12 @@ def __repr__(self): 'camera_uploads_policy_changed_details': EventDetails._camera_uploads_policy_changed_details_validator, 'data_placement_restriction_change_policy_details': EventDetails._data_placement_restriction_change_policy_details_validator, 'data_placement_restriction_satisfy_policy_details': EventDetails._data_placement_restriction_satisfy_policy_details_validator, + 'device_approvals_add_exception_details': EventDetails._device_approvals_add_exception_details_validator, 'device_approvals_change_desktop_policy_details': EventDetails._device_approvals_change_desktop_policy_details_validator, 'device_approvals_change_mobile_policy_details': EventDetails._device_approvals_change_mobile_policy_details_validator, 'device_approvals_change_overage_action_details': EventDetails._device_approvals_change_overage_action_details_validator, 'device_approvals_change_unlink_action_details': EventDetails._device_approvals_change_unlink_action_details_validator, + 'device_approvals_remove_exception_details': EventDetails._device_approvals_remove_exception_details_validator, 'directory_restrictions_add_members_details': EventDetails._directory_restrictions_add_members_details_validator, 'directory_restrictions_remove_members_details': EventDetails._directory_restrictions_remove_members_details_validator, 'emm_add_exception_details': EventDetails._emm_add_exception_details_validator, @@ -73370,13 +96075,16 @@ def __repr__(self): 'emm_remove_exception_details': EventDetails._emm_remove_exception_details_validator, 'extended_version_history_change_policy_details': EventDetails._extended_version_history_change_policy_details_validator, 'file_comments_change_policy_details': EventDetails._file_comments_change_policy_details_validator, + 'file_locking_policy_changed_details': EventDetails._file_locking_policy_changed_details_validator, 'file_requests_change_policy_details': EventDetails._file_requests_change_policy_details_validator, 'file_requests_emails_enabled_details': EventDetails._file_requests_emails_enabled_details_validator, 'file_requests_emails_restricted_to_team_only_details': EventDetails._file_requests_emails_restricted_to_team_only_details_validator, + 'file_transfers_policy_changed_details': EventDetails._file_transfers_policy_changed_details_validator, 'google_sso_change_policy_details': EventDetails._google_sso_change_policy_details_validator, 'group_user_management_change_policy_details': EventDetails._group_user_management_change_policy_details_validator, 'integration_policy_changed_details': EventDetails._integration_policy_changed_details_validator, 'member_requests_change_policy_details': EventDetails._member_requests_change_policy_details_validator, + 'member_send_invite_policy_changed_details': EventDetails._member_send_invite_policy_changed_details_validator, 'member_space_limits_add_exception_details': EventDetails._member_space_limits_add_exception_details_validator, 'member_space_limits_change_caps_type_policy_details': EventDetails._member_space_limits_change_caps_type_policy_details_validator, 'member_space_limits_change_policy_details': EventDetails._member_space_limits_change_policy_details_validator, @@ -73392,23 +96100,31 @@ def __repr__(self): 'paper_desktop_policy_changed_details': EventDetails._paper_desktop_policy_changed_details_validator, 'paper_enabled_users_group_addition_details': EventDetails._paper_enabled_users_group_addition_details_validator, 'paper_enabled_users_group_removal_details': EventDetails._paper_enabled_users_group_removal_details_validator, + 'password_strength_requirements_change_policy_details': EventDetails._password_strength_requirements_change_policy_details_validator, 'permanent_delete_change_policy_details': EventDetails._permanent_delete_change_policy_details_validator, 'reseller_support_change_policy_details': EventDetails._reseller_support_change_policy_details_validator, + 'rewind_policy_changed_details': EventDetails._rewind_policy_changed_details_validator, 'sharing_change_folder_join_policy_details': EventDetails._sharing_change_folder_join_policy_details_validator, 'sharing_change_link_policy_details': EventDetails._sharing_change_link_policy_details_validator, 'sharing_change_member_policy_details': EventDetails._sharing_change_member_policy_details_validator, 'showcase_change_download_policy_details': EventDetails._showcase_change_download_policy_details_validator, 'showcase_change_enabled_policy_details': EventDetails._showcase_change_enabled_policy_details_validator, 'showcase_change_external_sharing_policy_details': EventDetails._showcase_change_external_sharing_policy_details_validator, + 'smarter_smart_sync_policy_changed_details': EventDetails._smarter_smart_sync_policy_changed_details_validator, 'smart_sync_change_policy_details': EventDetails._smart_sync_change_policy_details_validator, 'smart_sync_not_opt_out_details': EventDetails._smart_sync_not_opt_out_details_validator, 'smart_sync_opt_out_details': EventDetails._smart_sync_opt_out_details_validator, 'sso_change_policy_details': EventDetails._sso_change_policy_details_validator, 'team_extensions_policy_changed_details': EventDetails._team_extensions_policy_changed_details_validator, 'team_selective_sync_policy_changed_details': EventDetails._team_selective_sync_policy_changed_details_validator, + 'team_sharing_whitelist_subjects_changed_details': EventDetails._team_sharing_whitelist_subjects_changed_details_validator, + 'tfa_add_exception_details': EventDetails._tfa_add_exception_details_validator, 'tfa_change_policy_details': EventDetails._tfa_change_policy_details_validator, + 'tfa_remove_exception_details': EventDetails._tfa_remove_exception_details_validator, 'two_account_change_policy_details': EventDetails._two_account_change_policy_details_validator, 'viewer_info_policy_changed_details': EventDetails._viewer_info_policy_changed_details_validator, + 'watermarking_policy_changed_details': EventDetails._watermarking_policy_changed_details_validator, + 'web_sessions_change_active_session_limit_details': EventDetails._web_sessions_change_active_session_limit_details_validator, 'web_sessions_change_fixed_length_policy_details': EventDetails._web_sessions_change_fixed_length_policy_details_validator, 'web_sessions_change_idle_length_policy_details': EventDetails._web_sessions_change_idle_length_policy_details_validator, 'team_merge_from_details': EventDetails._team_merge_from_details_validator, @@ -73425,7 +96141,13 @@ def __repr__(self): 'tfa_remove_backup_phone_details': EventDetails._tfa_remove_backup_phone_details_validator, 'tfa_remove_security_key_details': EventDetails._tfa_remove_security_key_details_validator, 'tfa_reset_details': EventDetails._tfa_reset_details_validator, + 'changed_enterprise_admin_role_details': EventDetails._changed_enterprise_admin_role_details_validator, + 'changed_enterprise_connected_team_status_details': EventDetails._changed_enterprise_connected_team_status_details_validator, + 'ended_enterprise_admin_session_details': EventDetails._ended_enterprise_admin_session_details_validator, + 'ended_enterprise_admin_session_deprecated_details': EventDetails._ended_enterprise_admin_session_deprecated_details_validator, + 'enterprise_settings_locking_details': EventDetails._enterprise_settings_locking_details_validator, 'guest_admin_change_status_details': EventDetails._guest_admin_change_status_details_validator, + 'started_enterprise_admin_session_details': EventDetails._started_enterprise_admin_session_details_validator, 'team_merge_request_accepted_details': EventDetails._team_merge_request_accepted_details_validator, 'team_merge_request_accepted_shown_to_primary_team_details': EventDetails._team_merge_request_accepted_shown_to_primary_team_details_validator, 'team_merge_request_accepted_shown_to_secondary_team_details': EventDetails._team_merge_request_accepted_shown_to_secondary_team_details_validator, @@ -73497,6 +96219,7 @@ def __repr__(self): EventType._file_download_validator = FileDownloadType_validator EventType._file_edit_validator = FileEditType_validator EventType._file_get_copy_reference_validator = FileGetCopyReferenceType_validator +EventType._file_locking_lock_status_changed_validator = FileLockingLockStatusChangedType_validator EventType._file_move_validator = FileMoveType_validator EventType._file_permanently_delete_validator = FilePermanentlyDeleteType_validator EventType._file_preview_validator = FilePreviewType_validator @@ -73505,6 +96228,10 @@ def __repr__(self): EventType._file_revert_validator = FileRevertType_validator EventType._file_rollback_changes_validator = FileRollbackChangesType_validator EventType._file_save_copy_reference_validator = FileSaveCopyReferenceType_validator +EventType._folder_overview_description_changed_validator = FolderOverviewDescriptionChangedType_validator +EventType._folder_overview_item_pinned_validator = FolderOverviewItemPinnedType_validator +EventType._folder_overview_item_unpinned_validator = FolderOverviewItemUnpinnedType_validator +EventType._rewind_folder_validator = RewindFolderType_validator EventType._file_request_change_validator = FileRequestChangeType_validator EventType._file_request_close_validator = FileRequestCloseType_validator EventType._file_request_create_validator = FileRequestCreateType_validator @@ -73523,6 +96250,18 @@ def __repr__(self): EventType._group_remove_external_id_validator = GroupRemoveExternalIdType_validator EventType._group_remove_member_validator = GroupRemoveMemberType_validator EventType._group_rename_validator = GroupRenameType_validator +EventType._legal_holds_activate_a_hold_validator = LegalHoldsActivateAHoldType_validator +EventType._legal_holds_add_members_validator = LegalHoldsAddMembersType_validator +EventType._legal_holds_change_hold_details_validator = LegalHoldsChangeHoldDetailsType_validator +EventType._legal_holds_change_hold_name_validator = LegalHoldsChangeHoldNameType_validator +EventType._legal_holds_export_a_hold_validator = LegalHoldsExportAHoldType_validator +EventType._legal_holds_export_cancelled_validator = LegalHoldsExportCancelledType_validator +EventType._legal_holds_export_downloaded_validator = LegalHoldsExportDownloadedType_validator +EventType._legal_holds_export_removed_validator = LegalHoldsExportRemovedType_validator +EventType._legal_holds_release_a_hold_validator = LegalHoldsReleaseAHoldType_validator +EventType._legal_holds_remove_members_validator = LegalHoldsRemoveMembersType_validator +EventType._legal_holds_report_a_hold_validator = LegalHoldsReportAHoldType_validator +EventType._account_lock_or_unlocked_validator = AccountLockOrUnlockedType_validator EventType._emm_error_validator = EmmErrorType_validator EventType._guest_admin_signed_in_via_trusted_teams_validator = GuestAdminSignedInViaTrustedTeamsType_validator EventType._guest_admin_signed_out_via_trusted_teams_validator = GuestAdminSignedOutViaTrustedTeamsType_validator @@ -73534,6 +96273,8 @@ def __repr__(self): EventType._sign_in_as_session_end_validator = SignInAsSessionEndType_validator EventType._sign_in_as_session_start_validator = SignInAsSessionStartType_validator EventType._sso_error_validator = SsoErrorType_validator +EventType._create_team_invite_link_validator = CreateTeamInviteLinkType_validator +EventType._delete_team_invite_link_validator = DeleteTeamInviteLinkType_validator EventType._member_add_external_id_validator = MemberAddExternalIdType_validator EventType._member_add_name_validator = MemberAddNameType_validator EventType._member_change_admin_role_validator = MemberChangeAdminRoleType_validator @@ -73543,15 +96284,28 @@ def __repr__(self): EventType._member_change_name_validator = MemberChangeNameType_validator EventType._member_change_status_validator = MemberChangeStatusType_validator EventType._member_delete_manual_contacts_validator = MemberDeleteManualContactsType_validator +EventType._member_delete_profile_photo_validator = MemberDeleteProfilePhotoType_validator EventType._member_permanently_delete_account_contents_validator = MemberPermanentlyDeleteAccountContentsType_validator EventType._member_remove_external_id_validator = MemberRemoveExternalIdType_validator +EventType._member_set_profile_photo_validator = MemberSetProfilePhotoType_validator EventType._member_space_limits_add_custom_quota_validator = MemberSpaceLimitsAddCustomQuotaType_validator EventType._member_space_limits_change_custom_quota_validator = MemberSpaceLimitsChangeCustomQuotaType_validator EventType._member_space_limits_change_status_validator = MemberSpaceLimitsChangeStatusType_validator EventType._member_space_limits_remove_custom_quota_validator = MemberSpaceLimitsRemoveCustomQuotaType_validator EventType._member_suggest_validator = MemberSuggestType_validator EventType._member_transfer_account_contents_validator = MemberTransferAccountContentsType_validator +EventType._pending_secondary_email_added_validator = PendingSecondaryEmailAddedType_validator +EventType._secondary_email_deleted_validator = SecondaryEmailDeletedType_validator +EventType._secondary_email_verified_validator = SecondaryEmailVerifiedType_validator EventType._secondary_mails_policy_changed_validator = SecondaryMailsPolicyChangedType_validator +EventType._binder_add_page_validator = BinderAddPageType_validator +EventType._binder_add_section_validator = BinderAddSectionType_validator +EventType._binder_remove_page_validator = BinderRemovePageType_validator +EventType._binder_remove_section_validator = BinderRemoveSectionType_validator +EventType._binder_rename_page_validator = BinderRenamePageType_validator +EventType._binder_rename_section_validator = BinderRenameSectionType_validator +EventType._binder_reorder_page_validator = BinderReorderPageType_validator +EventType._binder_reorder_section_validator = BinderReorderSectionType_validator EventType._paper_content_add_member_validator = PaperContentAddMemberType_validator EventType._paper_content_add_to_folder_validator = PaperContentAddToFolderType_validator EventType._paper_content_archive_validator = PaperContentArchiveType_validator @@ -73589,6 +96343,7 @@ def __repr__(self): EventType._paper_folder_deleted_validator = PaperFolderDeletedType_validator EventType._paper_folder_followed_validator = PaperFolderFollowedType_validator EventType._paper_folder_team_invite_validator = PaperFolderTeamInviteType_validator +EventType._paper_published_link_change_permission_validator = PaperPublishedLinkChangePermissionType_validator EventType._paper_published_link_create_validator = PaperPublishedLinkCreateType_validator EventType._paper_published_link_disabled_validator = PaperPublishedLinkDisabledType_validator EventType._paper_published_link_view_validator = PaperPublishedLinkViewType_validator @@ -73598,11 +96353,25 @@ def __repr__(self): EventType._emm_create_exceptions_report_validator = EmmCreateExceptionsReportType_validator EventType._emm_create_usage_report_validator = EmmCreateUsageReportType_validator EventType._export_members_report_validator = ExportMembersReportType_validator +EventType._export_members_report_fail_validator = ExportMembersReportFailType_validator +EventType._no_expiration_link_gen_create_report_validator = NoExpirationLinkGenCreateReportType_validator +EventType._no_expiration_link_gen_report_failed_validator = NoExpirationLinkGenReportFailedType_validator +EventType._no_password_link_gen_create_report_validator = NoPasswordLinkGenCreateReportType_validator +EventType._no_password_link_gen_report_failed_validator = NoPasswordLinkGenReportFailedType_validator +EventType._no_password_link_view_create_report_validator = NoPasswordLinkViewCreateReportType_validator +EventType._no_password_link_view_report_failed_validator = NoPasswordLinkViewReportFailedType_validator +EventType._outdated_link_view_create_report_validator = OutdatedLinkViewCreateReportType_validator +EventType._outdated_link_view_report_failed_validator = OutdatedLinkViewReportFailedType_validator EventType._paper_admin_export_start_validator = PaperAdminExportStartType_validator EventType._smart_sync_create_admin_privilege_report_validator = SmartSyncCreateAdminPrivilegeReportType_validator EventType._team_activity_create_report_validator = TeamActivityCreateReportType_validator EventType._team_activity_create_report_fail_validator = TeamActivityCreateReportFailType_validator EventType._collection_share_validator = CollectionShareType_validator +EventType._file_transfers_file_add_validator = FileTransfersFileAddType_validator +EventType._file_transfers_transfer_delete_validator = FileTransfersTransferDeleteType_validator +EventType._file_transfers_transfer_download_validator = FileTransfersTransferDownloadType_validator +EventType._file_transfers_transfer_send_validator = FileTransfersTransferSendType_validator +EventType._file_transfers_transfer_view_validator = FileTransfersTransferViewType_validator EventType._note_acl_invite_only_validator = NoteAclInviteOnlyType_validator EventType._note_acl_link_validator = NoteAclLinkType_validator EventType._note_acl_team_link_validator = NoteAclTeamLinkType_validator @@ -73642,6 +96411,8 @@ def __repr__(self): EventType._shared_content_remove_link_password_validator = SharedContentRemoveLinkPasswordType_validator EventType._shared_content_remove_member_validator = SharedContentRemoveMemberType_validator EventType._shared_content_request_access_validator = SharedContentRequestAccessType_validator +EventType._shared_content_restore_invitees_validator = SharedContentRestoreInviteesType_validator +EventType._shared_content_restore_member_validator = SharedContentRestoreMemberType_validator EventType._shared_content_unshare_validator = SharedContentUnshareType_validator EventType._shared_content_view_validator = SharedContentViewType_validator EventType._shared_folder_change_link_policy_validator = SharedFolderChangeLinkPolicyType_validator @@ -73662,6 +96433,15 @@ def __repr__(self): EventType._shared_link_disable_validator = SharedLinkDisableType_validator EventType._shared_link_download_validator = SharedLinkDownloadType_validator EventType._shared_link_remove_expiry_validator = SharedLinkRemoveExpiryType_validator +EventType._shared_link_settings_add_expiration_validator = SharedLinkSettingsAddExpirationType_validator +EventType._shared_link_settings_add_password_validator = SharedLinkSettingsAddPasswordType_validator +EventType._shared_link_settings_allow_download_disabled_validator = SharedLinkSettingsAllowDownloadDisabledType_validator +EventType._shared_link_settings_allow_download_enabled_validator = SharedLinkSettingsAllowDownloadEnabledType_validator +EventType._shared_link_settings_change_audience_validator = SharedLinkSettingsChangeAudienceType_validator +EventType._shared_link_settings_change_expiration_validator = SharedLinkSettingsChangeExpirationType_validator +EventType._shared_link_settings_change_password_validator = SharedLinkSettingsChangePasswordType_validator +EventType._shared_link_settings_remove_expiration_validator = SharedLinkSettingsRemoveExpirationType_validator +EventType._shared_link_settings_remove_password_validator = SharedLinkSettingsRemovePasswordType_validator EventType._shared_link_share_validator = SharedLinkShareType_validator EventType._shared_link_view_validator = SharedLinkViewType_validator EventType._shared_note_opened_validator = SharedNoteOpenedType_validator @@ -73712,10 +96492,12 @@ def __repr__(self): EventType._camera_uploads_policy_changed_validator = CameraUploadsPolicyChangedType_validator EventType._data_placement_restriction_change_policy_validator = DataPlacementRestrictionChangePolicyType_validator EventType._data_placement_restriction_satisfy_policy_validator = DataPlacementRestrictionSatisfyPolicyType_validator +EventType._device_approvals_add_exception_validator = DeviceApprovalsAddExceptionType_validator EventType._device_approvals_change_desktop_policy_validator = DeviceApprovalsChangeDesktopPolicyType_validator EventType._device_approvals_change_mobile_policy_validator = DeviceApprovalsChangeMobilePolicyType_validator EventType._device_approvals_change_overage_action_validator = DeviceApprovalsChangeOverageActionType_validator EventType._device_approvals_change_unlink_action_validator = DeviceApprovalsChangeUnlinkActionType_validator +EventType._device_approvals_remove_exception_validator = DeviceApprovalsRemoveExceptionType_validator EventType._directory_restrictions_add_members_validator = DirectoryRestrictionsAddMembersType_validator EventType._directory_restrictions_remove_members_validator = DirectoryRestrictionsRemoveMembersType_validator EventType._emm_add_exception_validator = EmmAddExceptionType_validator @@ -73723,13 +96505,16 @@ def __repr__(self): EventType._emm_remove_exception_validator = EmmRemoveExceptionType_validator EventType._extended_version_history_change_policy_validator = ExtendedVersionHistoryChangePolicyType_validator EventType._file_comments_change_policy_validator = FileCommentsChangePolicyType_validator +EventType._file_locking_policy_changed_validator = FileLockingPolicyChangedType_validator EventType._file_requests_change_policy_validator = FileRequestsChangePolicyType_validator EventType._file_requests_emails_enabled_validator = FileRequestsEmailsEnabledType_validator EventType._file_requests_emails_restricted_to_team_only_validator = FileRequestsEmailsRestrictedToTeamOnlyType_validator +EventType._file_transfers_policy_changed_validator = FileTransfersPolicyChangedType_validator EventType._google_sso_change_policy_validator = GoogleSsoChangePolicyType_validator EventType._group_user_management_change_policy_validator = GroupUserManagementChangePolicyType_validator EventType._integration_policy_changed_validator = IntegrationPolicyChangedType_validator EventType._member_requests_change_policy_validator = MemberRequestsChangePolicyType_validator +EventType._member_send_invite_policy_changed_validator = MemberSendInvitePolicyChangedType_validator EventType._member_space_limits_add_exception_validator = MemberSpaceLimitsAddExceptionType_validator EventType._member_space_limits_change_caps_type_policy_validator = MemberSpaceLimitsChangeCapsTypePolicyType_validator EventType._member_space_limits_change_policy_validator = MemberSpaceLimitsChangePolicyType_validator @@ -73745,23 +96530,31 @@ def __repr__(self): EventType._paper_desktop_policy_changed_validator = PaperDesktopPolicyChangedType_validator EventType._paper_enabled_users_group_addition_validator = PaperEnabledUsersGroupAdditionType_validator EventType._paper_enabled_users_group_removal_validator = PaperEnabledUsersGroupRemovalType_validator +EventType._password_strength_requirements_change_policy_validator = PasswordStrengthRequirementsChangePolicyType_validator EventType._permanent_delete_change_policy_validator = PermanentDeleteChangePolicyType_validator EventType._reseller_support_change_policy_validator = ResellerSupportChangePolicyType_validator +EventType._rewind_policy_changed_validator = RewindPolicyChangedType_validator EventType._sharing_change_folder_join_policy_validator = SharingChangeFolderJoinPolicyType_validator EventType._sharing_change_link_policy_validator = SharingChangeLinkPolicyType_validator EventType._sharing_change_member_policy_validator = SharingChangeMemberPolicyType_validator EventType._showcase_change_download_policy_validator = ShowcaseChangeDownloadPolicyType_validator EventType._showcase_change_enabled_policy_validator = ShowcaseChangeEnabledPolicyType_validator EventType._showcase_change_external_sharing_policy_validator = ShowcaseChangeExternalSharingPolicyType_validator +EventType._smarter_smart_sync_policy_changed_validator = SmarterSmartSyncPolicyChangedType_validator EventType._smart_sync_change_policy_validator = SmartSyncChangePolicyType_validator EventType._smart_sync_not_opt_out_validator = SmartSyncNotOptOutType_validator EventType._smart_sync_opt_out_validator = SmartSyncOptOutType_validator EventType._sso_change_policy_validator = SsoChangePolicyType_validator EventType._team_extensions_policy_changed_validator = TeamExtensionsPolicyChangedType_validator EventType._team_selective_sync_policy_changed_validator = TeamSelectiveSyncPolicyChangedType_validator +EventType._team_sharing_whitelist_subjects_changed_validator = TeamSharingWhitelistSubjectsChangedType_validator +EventType._tfa_add_exception_validator = TfaAddExceptionType_validator EventType._tfa_change_policy_validator = TfaChangePolicyType_validator +EventType._tfa_remove_exception_validator = TfaRemoveExceptionType_validator EventType._two_account_change_policy_validator = TwoAccountChangePolicyType_validator EventType._viewer_info_policy_changed_validator = ViewerInfoPolicyChangedType_validator +EventType._watermarking_policy_changed_validator = WatermarkingPolicyChangedType_validator +EventType._web_sessions_change_active_session_limit_validator = WebSessionsChangeActiveSessionLimitType_validator EventType._web_sessions_change_fixed_length_policy_validator = WebSessionsChangeFixedLengthPolicyType_validator EventType._web_sessions_change_idle_length_policy_validator = WebSessionsChangeIdleLengthPolicyType_validator EventType._team_merge_from_validator = TeamMergeFromType_validator @@ -73778,7 +96571,13 @@ def __repr__(self): EventType._tfa_remove_backup_phone_validator = TfaRemoveBackupPhoneType_validator EventType._tfa_remove_security_key_validator = TfaRemoveSecurityKeyType_validator EventType._tfa_reset_validator = TfaResetType_validator +EventType._changed_enterprise_admin_role_validator = ChangedEnterpriseAdminRoleType_validator +EventType._changed_enterprise_connected_team_status_validator = ChangedEnterpriseConnectedTeamStatusType_validator +EventType._ended_enterprise_admin_session_validator = EndedEnterpriseAdminSessionType_validator +EventType._ended_enterprise_admin_session_deprecated_validator = EndedEnterpriseAdminSessionDeprecatedType_validator +EventType._enterprise_settings_locking_validator = EnterpriseSettingsLockingType_validator EventType._guest_admin_change_status_validator = GuestAdminChangeStatusType_validator +EventType._started_enterprise_admin_session_validator = StartedEnterpriseAdminSessionType_validator EventType._team_merge_request_accepted_validator = TeamMergeRequestAcceptedType_validator EventType._team_merge_request_accepted_shown_to_primary_team_validator = TeamMergeRequestAcceptedShownToPrimaryTeamType_validator EventType._team_merge_request_accepted_shown_to_secondary_team_validator = TeamMergeRequestAcceptedShownToSecondaryTeamType_validator @@ -73846,6 +96645,7 @@ def __repr__(self): 'file_download': EventType._file_download_validator, 'file_edit': EventType._file_edit_validator, 'file_get_copy_reference': EventType._file_get_copy_reference_validator, + 'file_locking_lock_status_changed': EventType._file_locking_lock_status_changed_validator, 'file_move': EventType._file_move_validator, 'file_permanently_delete': EventType._file_permanently_delete_validator, 'file_preview': EventType._file_preview_validator, @@ -73854,6 +96654,10 @@ def __repr__(self): 'file_revert': EventType._file_revert_validator, 'file_rollback_changes': EventType._file_rollback_changes_validator, 'file_save_copy_reference': EventType._file_save_copy_reference_validator, + 'folder_overview_description_changed': EventType._folder_overview_description_changed_validator, + 'folder_overview_item_pinned': EventType._folder_overview_item_pinned_validator, + 'folder_overview_item_unpinned': EventType._folder_overview_item_unpinned_validator, + 'rewind_folder': EventType._rewind_folder_validator, 'file_request_change': EventType._file_request_change_validator, 'file_request_close': EventType._file_request_close_validator, 'file_request_create': EventType._file_request_create_validator, @@ -73872,6 +96676,18 @@ def __repr__(self): 'group_remove_external_id': EventType._group_remove_external_id_validator, 'group_remove_member': EventType._group_remove_member_validator, 'group_rename': EventType._group_rename_validator, + 'legal_holds_activate_a_hold': EventType._legal_holds_activate_a_hold_validator, + 'legal_holds_add_members': EventType._legal_holds_add_members_validator, + 'legal_holds_change_hold_details': EventType._legal_holds_change_hold_details_validator, + 'legal_holds_change_hold_name': EventType._legal_holds_change_hold_name_validator, + 'legal_holds_export_a_hold': EventType._legal_holds_export_a_hold_validator, + 'legal_holds_export_cancelled': EventType._legal_holds_export_cancelled_validator, + 'legal_holds_export_downloaded': EventType._legal_holds_export_downloaded_validator, + 'legal_holds_export_removed': EventType._legal_holds_export_removed_validator, + 'legal_holds_release_a_hold': EventType._legal_holds_release_a_hold_validator, + 'legal_holds_remove_members': EventType._legal_holds_remove_members_validator, + 'legal_holds_report_a_hold': EventType._legal_holds_report_a_hold_validator, + 'account_lock_or_unlocked': EventType._account_lock_or_unlocked_validator, 'emm_error': EventType._emm_error_validator, 'guest_admin_signed_in_via_trusted_teams': EventType._guest_admin_signed_in_via_trusted_teams_validator, 'guest_admin_signed_out_via_trusted_teams': EventType._guest_admin_signed_out_via_trusted_teams_validator, @@ -73883,6 +96699,8 @@ def __repr__(self): 'sign_in_as_session_end': EventType._sign_in_as_session_end_validator, 'sign_in_as_session_start': EventType._sign_in_as_session_start_validator, 'sso_error': EventType._sso_error_validator, + 'create_team_invite_link': EventType._create_team_invite_link_validator, + 'delete_team_invite_link': EventType._delete_team_invite_link_validator, 'member_add_external_id': EventType._member_add_external_id_validator, 'member_add_name': EventType._member_add_name_validator, 'member_change_admin_role': EventType._member_change_admin_role_validator, @@ -73892,15 +96710,28 @@ def __repr__(self): 'member_change_name': EventType._member_change_name_validator, 'member_change_status': EventType._member_change_status_validator, 'member_delete_manual_contacts': EventType._member_delete_manual_contacts_validator, + 'member_delete_profile_photo': EventType._member_delete_profile_photo_validator, 'member_permanently_delete_account_contents': EventType._member_permanently_delete_account_contents_validator, 'member_remove_external_id': EventType._member_remove_external_id_validator, + 'member_set_profile_photo': EventType._member_set_profile_photo_validator, 'member_space_limits_add_custom_quota': EventType._member_space_limits_add_custom_quota_validator, 'member_space_limits_change_custom_quota': EventType._member_space_limits_change_custom_quota_validator, 'member_space_limits_change_status': EventType._member_space_limits_change_status_validator, 'member_space_limits_remove_custom_quota': EventType._member_space_limits_remove_custom_quota_validator, 'member_suggest': EventType._member_suggest_validator, 'member_transfer_account_contents': EventType._member_transfer_account_contents_validator, + 'pending_secondary_email_added': EventType._pending_secondary_email_added_validator, + 'secondary_email_deleted': EventType._secondary_email_deleted_validator, + 'secondary_email_verified': EventType._secondary_email_verified_validator, 'secondary_mails_policy_changed': EventType._secondary_mails_policy_changed_validator, + 'binder_add_page': EventType._binder_add_page_validator, + 'binder_add_section': EventType._binder_add_section_validator, + 'binder_remove_page': EventType._binder_remove_page_validator, + 'binder_remove_section': EventType._binder_remove_section_validator, + 'binder_rename_page': EventType._binder_rename_page_validator, + 'binder_rename_section': EventType._binder_rename_section_validator, + 'binder_reorder_page': EventType._binder_reorder_page_validator, + 'binder_reorder_section': EventType._binder_reorder_section_validator, 'paper_content_add_member': EventType._paper_content_add_member_validator, 'paper_content_add_to_folder': EventType._paper_content_add_to_folder_validator, 'paper_content_archive': EventType._paper_content_archive_validator, @@ -73938,6 +96769,7 @@ def __repr__(self): 'paper_folder_deleted': EventType._paper_folder_deleted_validator, 'paper_folder_followed': EventType._paper_folder_followed_validator, 'paper_folder_team_invite': EventType._paper_folder_team_invite_validator, + 'paper_published_link_change_permission': EventType._paper_published_link_change_permission_validator, 'paper_published_link_create': EventType._paper_published_link_create_validator, 'paper_published_link_disabled': EventType._paper_published_link_disabled_validator, 'paper_published_link_view': EventType._paper_published_link_view_validator, @@ -73947,11 +96779,25 @@ def __repr__(self): 'emm_create_exceptions_report': EventType._emm_create_exceptions_report_validator, 'emm_create_usage_report': EventType._emm_create_usage_report_validator, 'export_members_report': EventType._export_members_report_validator, + 'export_members_report_fail': EventType._export_members_report_fail_validator, + 'no_expiration_link_gen_create_report': EventType._no_expiration_link_gen_create_report_validator, + 'no_expiration_link_gen_report_failed': EventType._no_expiration_link_gen_report_failed_validator, + 'no_password_link_gen_create_report': EventType._no_password_link_gen_create_report_validator, + 'no_password_link_gen_report_failed': EventType._no_password_link_gen_report_failed_validator, + 'no_password_link_view_create_report': EventType._no_password_link_view_create_report_validator, + 'no_password_link_view_report_failed': EventType._no_password_link_view_report_failed_validator, + 'outdated_link_view_create_report': EventType._outdated_link_view_create_report_validator, + 'outdated_link_view_report_failed': EventType._outdated_link_view_report_failed_validator, 'paper_admin_export_start': EventType._paper_admin_export_start_validator, 'smart_sync_create_admin_privilege_report': EventType._smart_sync_create_admin_privilege_report_validator, 'team_activity_create_report': EventType._team_activity_create_report_validator, 'team_activity_create_report_fail': EventType._team_activity_create_report_fail_validator, 'collection_share': EventType._collection_share_validator, + 'file_transfers_file_add': EventType._file_transfers_file_add_validator, + 'file_transfers_transfer_delete': EventType._file_transfers_transfer_delete_validator, + 'file_transfers_transfer_download': EventType._file_transfers_transfer_download_validator, + 'file_transfers_transfer_send': EventType._file_transfers_transfer_send_validator, + 'file_transfers_transfer_view': EventType._file_transfers_transfer_view_validator, 'note_acl_invite_only': EventType._note_acl_invite_only_validator, 'note_acl_link': EventType._note_acl_link_validator, 'note_acl_team_link': EventType._note_acl_team_link_validator, @@ -73991,6 +96837,8 @@ def __repr__(self): 'shared_content_remove_link_password': EventType._shared_content_remove_link_password_validator, 'shared_content_remove_member': EventType._shared_content_remove_member_validator, 'shared_content_request_access': EventType._shared_content_request_access_validator, + 'shared_content_restore_invitees': EventType._shared_content_restore_invitees_validator, + 'shared_content_restore_member': EventType._shared_content_restore_member_validator, 'shared_content_unshare': EventType._shared_content_unshare_validator, 'shared_content_view': EventType._shared_content_view_validator, 'shared_folder_change_link_policy': EventType._shared_folder_change_link_policy_validator, @@ -74011,6 +96859,15 @@ def __repr__(self): 'shared_link_disable': EventType._shared_link_disable_validator, 'shared_link_download': EventType._shared_link_download_validator, 'shared_link_remove_expiry': EventType._shared_link_remove_expiry_validator, + 'shared_link_settings_add_expiration': EventType._shared_link_settings_add_expiration_validator, + 'shared_link_settings_add_password': EventType._shared_link_settings_add_password_validator, + 'shared_link_settings_allow_download_disabled': EventType._shared_link_settings_allow_download_disabled_validator, + 'shared_link_settings_allow_download_enabled': EventType._shared_link_settings_allow_download_enabled_validator, + 'shared_link_settings_change_audience': EventType._shared_link_settings_change_audience_validator, + 'shared_link_settings_change_expiration': EventType._shared_link_settings_change_expiration_validator, + 'shared_link_settings_change_password': EventType._shared_link_settings_change_password_validator, + 'shared_link_settings_remove_expiration': EventType._shared_link_settings_remove_expiration_validator, + 'shared_link_settings_remove_password': EventType._shared_link_settings_remove_password_validator, 'shared_link_share': EventType._shared_link_share_validator, 'shared_link_view': EventType._shared_link_view_validator, 'shared_note_opened': EventType._shared_note_opened_validator, @@ -74061,10 +96918,12 @@ def __repr__(self): 'camera_uploads_policy_changed': EventType._camera_uploads_policy_changed_validator, 'data_placement_restriction_change_policy': EventType._data_placement_restriction_change_policy_validator, 'data_placement_restriction_satisfy_policy': EventType._data_placement_restriction_satisfy_policy_validator, + 'device_approvals_add_exception': EventType._device_approvals_add_exception_validator, 'device_approvals_change_desktop_policy': EventType._device_approvals_change_desktop_policy_validator, 'device_approvals_change_mobile_policy': EventType._device_approvals_change_mobile_policy_validator, 'device_approvals_change_overage_action': EventType._device_approvals_change_overage_action_validator, 'device_approvals_change_unlink_action': EventType._device_approvals_change_unlink_action_validator, + 'device_approvals_remove_exception': EventType._device_approvals_remove_exception_validator, 'directory_restrictions_add_members': EventType._directory_restrictions_add_members_validator, 'directory_restrictions_remove_members': EventType._directory_restrictions_remove_members_validator, 'emm_add_exception': EventType._emm_add_exception_validator, @@ -74072,13 +96931,16 @@ def __repr__(self): 'emm_remove_exception': EventType._emm_remove_exception_validator, 'extended_version_history_change_policy': EventType._extended_version_history_change_policy_validator, 'file_comments_change_policy': EventType._file_comments_change_policy_validator, + 'file_locking_policy_changed': EventType._file_locking_policy_changed_validator, 'file_requests_change_policy': EventType._file_requests_change_policy_validator, 'file_requests_emails_enabled': EventType._file_requests_emails_enabled_validator, 'file_requests_emails_restricted_to_team_only': EventType._file_requests_emails_restricted_to_team_only_validator, + 'file_transfers_policy_changed': EventType._file_transfers_policy_changed_validator, 'google_sso_change_policy': EventType._google_sso_change_policy_validator, 'group_user_management_change_policy': EventType._group_user_management_change_policy_validator, 'integration_policy_changed': EventType._integration_policy_changed_validator, 'member_requests_change_policy': EventType._member_requests_change_policy_validator, + 'member_send_invite_policy_changed': EventType._member_send_invite_policy_changed_validator, 'member_space_limits_add_exception': EventType._member_space_limits_add_exception_validator, 'member_space_limits_change_caps_type_policy': EventType._member_space_limits_change_caps_type_policy_validator, 'member_space_limits_change_policy': EventType._member_space_limits_change_policy_validator, @@ -74094,23 +96956,31 @@ def __repr__(self): 'paper_desktop_policy_changed': EventType._paper_desktop_policy_changed_validator, 'paper_enabled_users_group_addition': EventType._paper_enabled_users_group_addition_validator, 'paper_enabled_users_group_removal': EventType._paper_enabled_users_group_removal_validator, + 'password_strength_requirements_change_policy': EventType._password_strength_requirements_change_policy_validator, 'permanent_delete_change_policy': EventType._permanent_delete_change_policy_validator, 'reseller_support_change_policy': EventType._reseller_support_change_policy_validator, + 'rewind_policy_changed': EventType._rewind_policy_changed_validator, 'sharing_change_folder_join_policy': EventType._sharing_change_folder_join_policy_validator, 'sharing_change_link_policy': EventType._sharing_change_link_policy_validator, 'sharing_change_member_policy': EventType._sharing_change_member_policy_validator, 'showcase_change_download_policy': EventType._showcase_change_download_policy_validator, 'showcase_change_enabled_policy': EventType._showcase_change_enabled_policy_validator, 'showcase_change_external_sharing_policy': EventType._showcase_change_external_sharing_policy_validator, + 'smarter_smart_sync_policy_changed': EventType._smarter_smart_sync_policy_changed_validator, 'smart_sync_change_policy': EventType._smart_sync_change_policy_validator, 'smart_sync_not_opt_out': EventType._smart_sync_not_opt_out_validator, 'smart_sync_opt_out': EventType._smart_sync_opt_out_validator, 'sso_change_policy': EventType._sso_change_policy_validator, 'team_extensions_policy_changed': EventType._team_extensions_policy_changed_validator, 'team_selective_sync_policy_changed': EventType._team_selective_sync_policy_changed_validator, + 'team_sharing_whitelist_subjects_changed': EventType._team_sharing_whitelist_subjects_changed_validator, + 'tfa_add_exception': EventType._tfa_add_exception_validator, 'tfa_change_policy': EventType._tfa_change_policy_validator, + 'tfa_remove_exception': EventType._tfa_remove_exception_validator, 'two_account_change_policy': EventType._two_account_change_policy_validator, 'viewer_info_policy_changed': EventType._viewer_info_policy_changed_validator, + 'watermarking_policy_changed': EventType._watermarking_policy_changed_validator, + 'web_sessions_change_active_session_limit': EventType._web_sessions_change_active_session_limit_validator, 'web_sessions_change_fixed_length_policy': EventType._web_sessions_change_fixed_length_policy_validator, 'web_sessions_change_idle_length_policy': EventType._web_sessions_change_idle_length_policy_validator, 'team_merge_from': EventType._team_merge_from_validator, @@ -74127,7 +96997,13 @@ def __repr__(self): 'tfa_remove_backup_phone': EventType._tfa_remove_backup_phone_validator, 'tfa_remove_security_key': EventType._tfa_remove_security_key_validator, 'tfa_reset': EventType._tfa_reset_validator, + 'changed_enterprise_admin_role': EventType._changed_enterprise_admin_role_validator, + 'changed_enterprise_connected_team_status': EventType._changed_enterprise_connected_team_status_validator, + 'ended_enterprise_admin_session': EventType._ended_enterprise_admin_session_validator, + 'ended_enterprise_admin_session_deprecated': EventType._ended_enterprise_admin_session_deprecated_validator, + 'enterprise_settings_locking': EventType._enterprise_settings_locking_validator, 'guest_admin_change_status': EventType._guest_admin_change_status_validator, + 'started_enterprise_admin_session': EventType._started_enterprise_admin_session_validator, 'team_merge_request_accepted': EventType._team_merge_request_accepted_validator, 'team_merge_request_accepted_shown_to_primary_team': EventType._team_merge_request_accepted_shown_to_primary_team_validator, 'team_merge_request_accepted_shown_to_secondary_team': EventType._team_merge_request_accepted_shown_to_secondary_team_validator, @@ -74151,9 +97027,1296 @@ def __repr__(self): EventType.other = EventType('other') +EventTypeArg._app_link_team_validator = bv.Void() +EventTypeArg._app_link_user_validator = bv.Void() +EventTypeArg._app_unlink_team_validator = bv.Void() +EventTypeArg._app_unlink_user_validator = bv.Void() +EventTypeArg._integration_connected_validator = bv.Void() +EventTypeArg._integration_disconnected_validator = bv.Void() +EventTypeArg._file_add_comment_validator = bv.Void() +EventTypeArg._file_change_comment_subscription_validator = bv.Void() +EventTypeArg._file_delete_comment_validator = bv.Void() +EventTypeArg._file_edit_comment_validator = bv.Void() +EventTypeArg._file_like_comment_validator = bv.Void() +EventTypeArg._file_resolve_comment_validator = bv.Void() +EventTypeArg._file_unlike_comment_validator = bv.Void() +EventTypeArg._file_unresolve_comment_validator = bv.Void() +EventTypeArg._device_change_ip_desktop_validator = bv.Void() +EventTypeArg._device_change_ip_mobile_validator = bv.Void() +EventTypeArg._device_change_ip_web_validator = bv.Void() +EventTypeArg._device_delete_on_unlink_fail_validator = bv.Void() +EventTypeArg._device_delete_on_unlink_success_validator = bv.Void() +EventTypeArg._device_link_fail_validator = bv.Void() +EventTypeArg._device_link_success_validator = bv.Void() +EventTypeArg._device_management_disabled_validator = bv.Void() +EventTypeArg._device_management_enabled_validator = bv.Void() +EventTypeArg._device_unlink_validator = bv.Void() +EventTypeArg._emm_refresh_auth_token_validator = bv.Void() +EventTypeArg._account_capture_change_availability_validator = bv.Void() +EventTypeArg._account_capture_migrate_account_validator = bv.Void() +EventTypeArg._account_capture_notification_emails_sent_validator = bv.Void() +EventTypeArg._account_capture_relinquish_account_validator = bv.Void() +EventTypeArg._disabled_domain_invites_validator = bv.Void() +EventTypeArg._domain_invites_approve_request_to_join_team_validator = bv.Void() +EventTypeArg._domain_invites_decline_request_to_join_team_validator = bv.Void() +EventTypeArg._domain_invites_email_existing_users_validator = bv.Void() +EventTypeArg._domain_invites_request_to_join_team_validator = bv.Void() +EventTypeArg._domain_invites_set_invite_new_user_pref_to_no_validator = bv.Void() +EventTypeArg._domain_invites_set_invite_new_user_pref_to_yes_validator = bv.Void() +EventTypeArg._domain_verification_add_domain_fail_validator = bv.Void() +EventTypeArg._domain_verification_add_domain_success_validator = bv.Void() +EventTypeArg._domain_verification_remove_domain_validator = bv.Void() +EventTypeArg._enabled_domain_invites_validator = bv.Void() +EventTypeArg._create_folder_validator = bv.Void() +EventTypeArg._file_add_validator = bv.Void() +EventTypeArg._file_copy_validator = bv.Void() +EventTypeArg._file_delete_validator = bv.Void() +EventTypeArg._file_download_validator = bv.Void() +EventTypeArg._file_edit_validator = bv.Void() +EventTypeArg._file_get_copy_reference_validator = bv.Void() +EventTypeArg._file_locking_lock_status_changed_validator = bv.Void() +EventTypeArg._file_move_validator = bv.Void() +EventTypeArg._file_permanently_delete_validator = bv.Void() +EventTypeArg._file_preview_validator = bv.Void() +EventTypeArg._file_rename_validator = bv.Void() +EventTypeArg._file_restore_validator = bv.Void() +EventTypeArg._file_revert_validator = bv.Void() +EventTypeArg._file_rollback_changes_validator = bv.Void() +EventTypeArg._file_save_copy_reference_validator = bv.Void() +EventTypeArg._folder_overview_description_changed_validator = bv.Void() +EventTypeArg._folder_overview_item_pinned_validator = bv.Void() +EventTypeArg._folder_overview_item_unpinned_validator = bv.Void() +EventTypeArg._rewind_folder_validator = bv.Void() +EventTypeArg._file_request_change_validator = bv.Void() +EventTypeArg._file_request_close_validator = bv.Void() +EventTypeArg._file_request_create_validator = bv.Void() +EventTypeArg._file_request_delete_validator = bv.Void() +EventTypeArg._file_request_receive_file_validator = bv.Void() +EventTypeArg._group_add_external_id_validator = bv.Void() +EventTypeArg._group_add_member_validator = bv.Void() +EventTypeArg._group_change_external_id_validator = bv.Void() +EventTypeArg._group_change_management_type_validator = bv.Void() +EventTypeArg._group_change_member_role_validator = bv.Void() +EventTypeArg._group_create_validator = bv.Void() +EventTypeArg._group_delete_validator = bv.Void() +EventTypeArg._group_description_updated_validator = bv.Void() +EventTypeArg._group_join_policy_updated_validator = bv.Void() +EventTypeArg._group_moved_validator = bv.Void() +EventTypeArg._group_remove_external_id_validator = bv.Void() +EventTypeArg._group_remove_member_validator = bv.Void() +EventTypeArg._group_rename_validator = bv.Void() +EventTypeArg._legal_holds_activate_a_hold_validator = bv.Void() +EventTypeArg._legal_holds_add_members_validator = bv.Void() +EventTypeArg._legal_holds_change_hold_details_validator = bv.Void() +EventTypeArg._legal_holds_change_hold_name_validator = bv.Void() +EventTypeArg._legal_holds_export_a_hold_validator = bv.Void() +EventTypeArg._legal_holds_export_cancelled_validator = bv.Void() +EventTypeArg._legal_holds_export_downloaded_validator = bv.Void() +EventTypeArg._legal_holds_export_removed_validator = bv.Void() +EventTypeArg._legal_holds_release_a_hold_validator = bv.Void() +EventTypeArg._legal_holds_remove_members_validator = bv.Void() +EventTypeArg._legal_holds_report_a_hold_validator = bv.Void() +EventTypeArg._account_lock_or_unlocked_validator = bv.Void() +EventTypeArg._emm_error_validator = bv.Void() +EventTypeArg._guest_admin_signed_in_via_trusted_teams_validator = bv.Void() +EventTypeArg._guest_admin_signed_out_via_trusted_teams_validator = bv.Void() +EventTypeArg._login_fail_validator = bv.Void() +EventTypeArg._login_success_validator = bv.Void() +EventTypeArg._logout_validator = bv.Void() +EventTypeArg._reseller_support_session_end_validator = bv.Void() +EventTypeArg._reseller_support_session_start_validator = bv.Void() +EventTypeArg._sign_in_as_session_end_validator = bv.Void() +EventTypeArg._sign_in_as_session_start_validator = bv.Void() +EventTypeArg._sso_error_validator = bv.Void() +EventTypeArg._create_team_invite_link_validator = bv.Void() +EventTypeArg._delete_team_invite_link_validator = bv.Void() +EventTypeArg._member_add_external_id_validator = bv.Void() +EventTypeArg._member_add_name_validator = bv.Void() +EventTypeArg._member_change_admin_role_validator = bv.Void() +EventTypeArg._member_change_email_validator = bv.Void() +EventTypeArg._member_change_external_id_validator = bv.Void() +EventTypeArg._member_change_membership_type_validator = bv.Void() +EventTypeArg._member_change_name_validator = bv.Void() +EventTypeArg._member_change_status_validator = bv.Void() +EventTypeArg._member_delete_manual_contacts_validator = bv.Void() +EventTypeArg._member_delete_profile_photo_validator = bv.Void() +EventTypeArg._member_permanently_delete_account_contents_validator = bv.Void() +EventTypeArg._member_remove_external_id_validator = bv.Void() +EventTypeArg._member_set_profile_photo_validator = bv.Void() +EventTypeArg._member_space_limits_add_custom_quota_validator = bv.Void() +EventTypeArg._member_space_limits_change_custom_quota_validator = bv.Void() +EventTypeArg._member_space_limits_change_status_validator = bv.Void() +EventTypeArg._member_space_limits_remove_custom_quota_validator = bv.Void() +EventTypeArg._member_suggest_validator = bv.Void() +EventTypeArg._member_transfer_account_contents_validator = bv.Void() +EventTypeArg._pending_secondary_email_added_validator = bv.Void() +EventTypeArg._secondary_email_deleted_validator = bv.Void() +EventTypeArg._secondary_email_verified_validator = bv.Void() +EventTypeArg._secondary_mails_policy_changed_validator = bv.Void() +EventTypeArg._binder_add_page_validator = bv.Void() +EventTypeArg._binder_add_section_validator = bv.Void() +EventTypeArg._binder_remove_page_validator = bv.Void() +EventTypeArg._binder_remove_section_validator = bv.Void() +EventTypeArg._binder_rename_page_validator = bv.Void() +EventTypeArg._binder_rename_section_validator = bv.Void() +EventTypeArg._binder_reorder_page_validator = bv.Void() +EventTypeArg._binder_reorder_section_validator = bv.Void() +EventTypeArg._paper_content_add_member_validator = bv.Void() +EventTypeArg._paper_content_add_to_folder_validator = bv.Void() +EventTypeArg._paper_content_archive_validator = bv.Void() +EventTypeArg._paper_content_create_validator = bv.Void() +EventTypeArg._paper_content_permanently_delete_validator = bv.Void() +EventTypeArg._paper_content_remove_from_folder_validator = bv.Void() +EventTypeArg._paper_content_remove_member_validator = bv.Void() +EventTypeArg._paper_content_rename_validator = bv.Void() +EventTypeArg._paper_content_restore_validator = bv.Void() +EventTypeArg._paper_doc_add_comment_validator = bv.Void() +EventTypeArg._paper_doc_change_member_role_validator = bv.Void() +EventTypeArg._paper_doc_change_sharing_policy_validator = bv.Void() +EventTypeArg._paper_doc_change_subscription_validator = bv.Void() +EventTypeArg._paper_doc_deleted_validator = bv.Void() +EventTypeArg._paper_doc_delete_comment_validator = bv.Void() +EventTypeArg._paper_doc_download_validator = bv.Void() +EventTypeArg._paper_doc_edit_validator = bv.Void() +EventTypeArg._paper_doc_edit_comment_validator = bv.Void() +EventTypeArg._paper_doc_followed_validator = bv.Void() +EventTypeArg._paper_doc_mention_validator = bv.Void() +EventTypeArg._paper_doc_ownership_changed_validator = bv.Void() +EventTypeArg._paper_doc_request_access_validator = bv.Void() +EventTypeArg._paper_doc_resolve_comment_validator = bv.Void() +EventTypeArg._paper_doc_revert_validator = bv.Void() +EventTypeArg._paper_doc_slack_share_validator = bv.Void() +EventTypeArg._paper_doc_team_invite_validator = bv.Void() +EventTypeArg._paper_doc_trashed_validator = bv.Void() +EventTypeArg._paper_doc_unresolve_comment_validator = bv.Void() +EventTypeArg._paper_doc_untrashed_validator = bv.Void() +EventTypeArg._paper_doc_view_validator = bv.Void() +EventTypeArg._paper_external_view_allow_validator = bv.Void() +EventTypeArg._paper_external_view_default_team_validator = bv.Void() +EventTypeArg._paper_external_view_forbid_validator = bv.Void() +EventTypeArg._paper_folder_change_subscription_validator = bv.Void() +EventTypeArg._paper_folder_deleted_validator = bv.Void() +EventTypeArg._paper_folder_followed_validator = bv.Void() +EventTypeArg._paper_folder_team_invite_validator = bv.Void() +EventTypeArg._paper_published_link_change_permission_validator = bv.Void() +EventTypeArg._paper_published_link_create_validator = bv.Void() +EventTypeArg._paper_published_link_disabled_validator = bv.Void() +EventTypeArg._paper_published_link_view_validator = bv.Void() +EventTypeArg._password_change_validator = bv.Void() +EventTypeArg._password_reset_validator = bv.Void() +EventTypeArg._password_reset_all_validator = bv.Void() +EventTypeArg._emm_create_exceptions_report_validator = bv.Void() +EventTypeArg._emm_create_usage_report_validator = bv.Void() +EventTypeArg._export_members_report_validator = bv.Void() +EventTypeArg._export_members_report_fail_validator = bv.Void() +EventTypeArg._no_expiration_link_gen_create_report_validator = bv.Void() +EventTypeArg._no_expiration_link_gen_report_failed_validator = bv.Void() +EventTypeArg._no_password_link_gen_create_report_validator = bv.Void() +EventTypeArg._no_password_link_gen_report_failed_validator = bv.Void() +EventTypeArg._no_password_link_view_create_report_validator = bv.Void() +EventTypeArg._no_password_link_view_report_failed_validator = bv.Void() +EventTypeArg._outdated_link_view_create_report_validator = bv.Void() +EventTypeArg._outdated_link_view_report_failed_validator = bv.Void() +EventTypeArg._paper_admin_export_start_validator = bv.Void() +EventTypeArg._smart_sync_create_admin_privilege_report_validator = bv.Void() +EventTypeArg._team_activity_create_report_validator = bv.Void() +EventTypeArg._team_activity_create_report_fail_validator = bv.Void() +EventTypeArg._collection_share_validator = bv.Void() +EventTypeArg._file_transfers_file_add_validator = bv.Void() +EventTypeArg._file_transfers_transfer_delete_validator = bv.Void() +EventTypeArg._file_transfers_transfer_download_validator = bv.Void() +EventTypeArg._file_transfers_transfer_send_validator = bv.Void() +EventTypeArg._file_transfers_transfer_view_validator = bv.Void() +EventTypeArg._note_acl_invite_only_validator = bv.Void() +EventTypeArg._note_acl_link_validator = bv.Void() +EventTypeArg._note_acl_team_link_validator = bv.Void() +EventTypeArg._note_shared_validator = bv.Void() +EventTypeArg._note_share_receive_validator = bv.Void() +EventTypeArg._open_note_shared_validator = bv.Void() +EventTypeArg._sf_add_group_validator = bv.Void() +EventTypeArg._sf_allow_non_members_to_view_shared_links_validator = bv.Void() +EventTypeArg._sf_external_invite_warn_validator = bv.Void() +EventTypeArg._sf_fb_invite_validator = bv.Void() +EventTypeArg._sf_fb_invite_change_role_validator = bv.Void() +EventTypeArg._sf_fb_uninvite_validator = bv.Void() +EventTypeArg._sf_invite_group_validator = bv.Void() +EventTypeArg._sf_team_grant_access_validator = bv.Void() +EventTypeArg._sf_team_invite_validator = bv.Void() +EventTypeArg._sf_team_invite_change_role_validator = bv.Void() +EventTypeArg._sf_team_join_validator = bv.Void() +EventTypeArg._sf_team_join_from_oob_link_validator = bv.Void() +EventTypeArg._sf_team_uninvite_validator = bv.Void() +EventTypeArg._shared_content_add_invitees_validator = bv.Void() +EventTypeArg._shared_content_add_link_expiry_validator = bv.Void() +EventTypeArg._shared_content_add_link_password_validator = bv.Void() +EventTypeArg._shared_content_add_member_validator = bv.Void() +EventTypeArg._shared_content_change_downloads_policy_validator = bv.Void() +EventTypeArg._shared_content_change_invitee_role_validator = bv.Void() +EventTypeArg._shared_content_change_link_audience_validator = bv.Void() +EventTypeArg._shared_content_change_link_expiry_validator = bv.Void() +EventTypeArg._shared_content_change_link_password_validator = bv.Void() +EventTypeArg._shared_content_change_member_role_validator = bv.Void() +EventTypeArg._shared_content_change_viewer_info_policy_validator = bv.Void() +EventTypeArg._shared_content_claim_invitation_validator = bv.Void() +EventTypeArg._shared_content_copy_validator = bv.Void() +EventTypeArg._shared_content_download_validator = bv.Void() +EventTypeArg._shared_content_relinquish_membership_validator = bv.Void() +EventTypeArg._shared_content_remove_invitees_validator = bv.Void() +EventTypeArg._shared_content_remove_link_expiry_validator = bv.Void() +EventTypeArg._shared_content_remove_link_password_validator = bv.Void() +EventTypeArg._shared_content_remove_member_validator = bv.Void() +EventTypeArg._shared_content_request_access_validator = bv.Void() +EventTypeArg._shared_content_restore_invitees_validator = bv.Void() +EventTypeArg._shared_content_restore_member_validator = bv.Void() +EventTypeArg._shared_content_unshare_validator = bv.Void() +EventTypeArg._shared_content_view_validator = bv.Void() +EventTypeArg._shared_folder_change_link_policy_validator = bv.Void() +EventTypeArg._shared_folder_change_members_inheritance_policy_validator = bv.Void() +EventTypeArg._shared_folder_change_members_management_policy_validator = bv.Void() +EventTypeArg._shared_folder_change_members_policy_validator = bv.Void() +EventTypeArg._shared_folder_create_validator = bv.Void() +EventTypeArg._shared_folder_decline_invitation_validator = bv.Void() +EventTypeArg._shared_folder_mount_validator = bv.Void() +EventTypeArg._shared_folder_nest_validator = bv.Void() +EventTypeArg._shared_folder_transfer_ownership_validator = bv.Void() +EventTypeArg._shared_folder_unmount_validator = bv.Void() +EventTypeArg._shared_link_add_expiry_validator = bv.Void() +EventTypeArg._shared_link_change_expiry_validator = bv.Void() +EventTypeArg._shared_link_change_visibility_validator = bv.Void() +EventTypeArg._shared_link_copy_validator = bv.Void() +EventTypeArg._shared_link_create_validator = bv.Void() +EventTypeArg._shared_link_disable_validator = bv.Void() +EventTypeArg._shared_link_download_validator = bv.Void() +EventTypeArg._shared_link_remove_expiry_validator = bv.Void() +EventTypeArg._shared_link_settings_add_expiration_validator = bv.Void() +EventTypeArg._shared_link_settings_add_password_validator = bv.Void() +EventTypeArg._shared_link_settings_allow_download_disabled_validator = bv.Void() +EventTypeArg._shared_link_settings_allow_download_enabled_validator = bv.Void() +EventTypeArg._shared_link_settings_change_audience_validator = bv.Void() +EventTypeArg._shared_link_settings_change_expiration_validator = bv.Void() +EventTypeArg._shared_link_settings_change_password_validator = bv.Void() +EventTypeArg._shared_link_settings_remove_expiration_validator = bv.Void() +EventTypeArg._shared_link_settings_remove_password_validator = bv.Void() +EventTypeArg._shared_link_share_validator = bv.Void() +EventTypeArg._shared_link_view_validator = bv.Void() +EventTypeArg._shared_note_opened_validator = bv.Void() +EventTypeArg._shmodel_group_share_validator = bv.Void() +EventTypeArg._showcase_access_granted_validator = bv.Void() +EventTypeArg._showcase_add_member_validator = bv.Void() +EventTypeArg._showcase_archived_validator = bv.Void() +EventTypeArg._showcase_created_validator = bv.Void() +EventTypeArg._showcase_delete_comment_validator = bv.Void() +EventTypeArg._showcase_edited_validator = bv.Void() +EventTypeArg._showcase_edit_comment_validator = bv.Void() +EventTypeArg._showcase_file_added_validator = bv.Void() +EventTypeArg._showcase_file_download_validator = bv.Void() +EventTypeArg._showcase_file_removed_validator = bv.Void() +EventTypeArg._showcase_file_view_validator = bv.Void() +EventTypeArg._showcase_permanently_deleted_validator = bv.Void() +EventTypeArg._showcase_post_comment_validator = bv.Void() +EventTypeArg._showcase_remove_member_validator = bv.Void() +EventTypeArg._showcase_renamed_validator = bv.Void() +EventTypeArg._showcase_request_access_validator = bv.Void() +EventTypeArg._showcase_resolve_comment_validator = bv.Void() +EventTypeArg._showcase_restored_validator = bv.Void() +EventTypeArg._showcase_trashed_validator = bv.Void() +EventTypeArg._showcase_trashed_deprecated_validator = bv.Void() +EventTypeArg._showcase_unresolve_comment_validator = bv.Void() +EventTypeArg._showcase_untrashed_validator = bv.Void() +EventTypeArg._showcase_untrashed_deprecated_validator = bv.Void() +EventTypeArg._showcase_view_validator = bv.Void() +EventTypeArg._sso_add_cert_validator = bv.Void() +EventTypeArg._sso_add_login_url_validator = bv.Void() +EventTypeArg._sso_add_logout_url_validator = bv.Void() +EventTypeArg._sso_change_cert_validator = bv.Void() +EventTypeArg._sso_change_login_url_validator = bv.Void() +EventTypeArg._sso_change_logout_url_validator = bv.Void() +EventTypeArg._sso_change_saml_identity_mode_validator = bv.Void() +EventTypeArg._sso_remove_cert_validator = bv.Void() +EventTypeArg._sso_remove_login_url_validator = bv.Void() +EventTypeArg._sso_remove_logout_url_validator = bv.Void() +EventTypeArg._team_folder_change_status_validator = bv.Void() +EventTypeArg._team_folder_create_validator = bv.Void() +EventTypeArg._team_folder_downgrade_validator = bv.Void() +EventTypeArg._team_folder_permanently_delete_validator = bv.Void() +EventTypeArg._team_folder_rename_validator = bv.Void() +EventTypeArg._team_selective_sync_settings_changed_validator = bv.Void() +EventTypeArg._account_capture_change_policy_validator = bv.Void() +EventTypeArg._allow_download_disabled_validator = bv.Void() +EventTypeArg._allow_download_enabled_validator = bv.Void() +EventTypeArg._camera_uploads_policy_changed_validator = bv.Void() +EventTypeArg._data_placement_restriction_change_policy_validator = bv.Void() +EventTypeArg._data_placement_restriction_satisfy_policy_validator = bv.Void() +EventTypeArg._device_approvals_add_exception_validator = bv.Void() +EventTypeArg._device_approvals_change_desktop_policy_validator = bv.Void() +EventTypeArg._device_approvals_change_mobile_policy_validator = bv.Void() +EventTypeArg._device_approvals_change_overage_action_validator = bv.Void() +EventTypeArg._device_approvals_change_unlink_action_validator = bv.Void() +EventTypeArg._device_approvals_remove_exception_validator = bv.Void() +EventTypeArg._directory_restrictions_add_members_validator = bv.Void() +EventTypeArg._directory_restrictions_remove_members_validator = bv.Void() +EventTypeArg._emm_add_exception_validator = bv.Void() +EventTypeArg._emm_change_policy_validator = bv.Void() +EventTypeArg._emm_remove_exception_validator = bv.Void() +EventTypeArg._extended_version_history_change_policy_validator = bv.Void() +EventTypeArg._file_comments_change_policy_validator = bv.Void() +EventTypeArg._file_locking_policy_changed_validator = bv.Void() +EventTypeArg._file_requests_change_policy_validator = bv.Void() +EventTypeArg._file_requests_emails_enabled_validator = bv.Void() +EventTypeArg._file_requests_emails_restricted_to_team_only_validator = bv.Void() +EventTypeArg._file_transfers_policy_changed_validator = bv.Void() +EventTypeArg._google_sso_change_policy_validator = bv.Void() +EventTypeArg._group_user_management_change_policy_validator = bv.Void() +EventTypeArg._integration_policy_changed_validator = bv.Void() +EventTypeArg._member_requests_change_policy_validator = bv.Void() +EventTypeArg._member_send_invite_policy_changed_validator = bv.Void() +EventTypeArg._member_space_limits_add_exception_validator = bv.Void() +EventTypeArg._member_space_limits_change_caps_type_policy_validator = bv.Void() +EventTypeArg._member_space_limits_change_policy_validator = bv.Void() +EventTypeArg._member_space_limits_remove_exception_validator = bv.Void() +EventTypeArg._member_suggestions_change_policy_validator = bv.Void() +EventTypeArg._microsoft_office_addin_change_policy_validator = bv.Void() +EventTypeArg._network_control_change_policy_validator = bv.Void() +EventTypeArg._paper_change_deployment_policy_validator = bv.Void() +EventTypeArg._paper_change_member_link_policy_validator = bv.Void() +EventTypeArg._paper_change_member_policy_validator = bv.Void() +EventTypeArg._paper_change_policy_validator = bv.Void() +EventTypeArg._paper_default_folder_policy_changed_validator = bv.Void() +EventTypeArg._paper_desktop_policy_changed_validator = bv.Void() +EventTypeArg._paper_enabled_users_group_addition_validator = bv.Void() +EventTypeArg._paper_enabled_users_group_removal_validator = bv.Void() +EventTypeArg._password_strength_requirements_change_policy_validator = bv.Void() +EventTypeArg._permanent_delete_change_policy_validator = bv.Void() +EventTypeArg._reseller_support_change_policy_validator = bv.Void() +EventTypeArg._rewind_policy_changed_validator = bv.Void() +EventTypeArg._sharing_change_folder_join_policy_validator = bv.Void() +EventTypeArg._sharing_change_link_policy_validator = bv.Void() +EventTypeArg._sharing_change_member_policy_validator = bv.Void() +EventTypeArg._showcase_change_download_policy_validator = bv.Void() +EventTypeArg._showcase_change_enabled_policy_validator = bv.Void() +EventTypeArg._showcase_change_external_sharing_policy_validator = bv.Void() +EventTypeArg._smarter_smart_sync_policy_changed_validator = bv.Void() +EventTypeArg._smart_sync_change_policy_validator = bv.Void() +EventTypeArg._smart_sync_not_opt_out_validator = bv.Void() +EventTypeArg._smart_sync_opt_out_validator = bv.Void() +EventTypeArg._sso_change_policy_validator = bv.Void() +EventTypeArg._team_extensions_policy_changed_validator = bv.Void() +EventTypeArg._team_selective_sync_policy_changed_validator = bv.Void() +EventTypeArg._team_sharing_whitelist_subjects_changed_validator = bv.Void() +EventTypeArg._tfa_add_exception_validator = bv.Void() +EventTypeArg._tfa_change_policy_validator = bv.Void() +EventTypeArg._tfa_remove_exception_validator = bv.Void() +EventTypeArg._two_account_change_policy_validator = bv.Void() +EventTypeArg._viewer_info_policy_changed_validator = bv.Void() +EventTypeArg._watermarking_policy_changed_validator = bv.Void() +EventTypeArg._web_sessions_change_active_session_limit_validator = bv.Void() +EventTypeArg._web_sessions_change_fixed_length_policy_validator = bv.Void() +EventTypeArg._web_sessions_change_idle_length_policy_validator = bv.Void() +EventTypeArg._team_merge_from_validator = bv.Void() +EventTypeArg._team_merge_to_validator = bv.Void() +EventTypeArg._team_profile_add_logo_validator = bv.Void() +EventTypeArg._team_profile_change_default_language_validator = bv.Void() +EventTypeArg._team_profile_change_logo_validator = bv.Void() +EventTypeArg._team_profile_change_name_validator = bv.Void() +EventTypeArg._team_profile_remove_logo_validator = bv.Void() +EventTypeArg._tfa_add_backup_phone_validator = bv.Void() +EventTypeArg._tfa_add_security_key_validator = bv.Void() +EventTypeArg._tfa_change_backup_phone_validator = bv.Void() +EventTypeArg._tfa_change_status_validator = bv.Void() +EventTypeArg._tfa_remove_backup_phone_validator = bv.Void() +EventTypeArg._tfa_remove_security_key_validator = bv.Void() +EventTypeArg._tfa_reset_validator = bv.Void() +EventTypeArg._changed_enterprise_admin_role_validator = bv.Void() +EventTypeArg._changed_enterprise_connected_team_status_validator = bv.Void() +EventTypeArg._ended_enterprise_admin_session_validator = bv.Void() +EventTypeArg._ended_enterprise_admin_session_deprecated_validator = bv.Void() +EventTypeArg._enterprise_settings_locking_validator = bv.Void() +EventTypeArg._guest_admin_change_status_validator = bv.Void() +EventTypeArg._started_enterprise_admin_session_validator = bv.Void() +EventTypeArg._team_merge_request_accepted_validator = bv.Void() +EventTypeArg._team_merge_request_accepted_shown_to_primary_team_validator = bv.Void() +EventTypeArg._team_merge_request_accepted_shown_to_secondary_team_validator = bv.Void() +EventTypeArg._team_merge_request_auto_canceled_validator = bv.Void() +EventTypeArg._team_merge_request_canceled_validator = bv.Void() +EventTypeArg._team_merge_request_canceled_shown_to_primary_team_validator = bv.Void() +EventTypeArg._team_merge_request_canceled_shown_to_secondary_team_validator = bv.Void() +EventTypeArg._team_merge_request_expired_validator = bv.Void() +EventTypeArg._team_merge_request_expired_shown_to_primary_team_validator = bv.Void() +EventTypeArg._team_merge_request_expired_shown_to_secondary_team_validator = bv.Void() +EventTypeArg._team_merge_request_rejected_shown_to_primary_team_validator = bv.Void() +EventTypeArg._team_merge_request_rejected_shown_to_secondary_team_validator = bv.Void() +EventTypeArg._team_merge_request_reminder_validator = bv.Void() +EventTypeArg._team_merge_request_reminder_shown_to_primary_team_validator = bv.Void() +EventTypeArg._team_merge_request_reminder_shown_to_secondary_team_validator = bv.Void() +EventTypeArg._team_merge_request_revoked_validator = bv.Void() +EventTypeArg._team_merge_request_sent_shown_to_primary_team_validator = bv.Void() +EventTypeArg._team_merge_request_sent_shown_to_secondary_team_validator = bv.Void() +EventTypeArg._other_validator = bv.Void() +EventTypeArg._tagmap = { + 'app_link_team': EventTypeArg._app_link_team_validator, + 'app_link_user': EventTypeArg._app_link_user_validator, + 'app_unlink_team': EventTypeArg._app_unlink_team_validator, + 'app_unlink_user': EventTypeArg._app_unlink_user_validator, + 'integration_connected': EventTypeArg._integration_connected_validator, + 'integration_disconnected': EventTypeArg._integration_disconnected_validator, + 'file_add_comment': EventTypeArg._file_add_comment_validator, + 'file_change_comment_subscription': EventTypeArg._file_change_comment_subscription_validator, + 'file_delete_comment': EventTypeArg._file_delete_comment_validator, + 'file_edit_comment': EventTypeArg._file_edit_comment_validator, + 'file_like_comment': EventTypeArg._file_like_comment_validator, + 'file_resolve_comment': EventTypeArg._file_resolve_comment_validator, + 'file_unlike_comment': EventTypeArg._file_unlike_comment_validator, + 'file_unresolve_comment': EventTypeArg._file_unresolve_comment_validator, + 'device_change_ip_desktop': EventTypeArg._device_change_ip_desktop_validator, + 'device_change_ip_mobile': EventTypeArg._device_change_ip_mobile_validator, + 'device_change_ip_web': EventTypeArg._device_change_ip_web_validator, + 'device_delete_on_unlink_fail': EventTypeArg._device_delete_on_unlink_fail_validator, + 'device_delete_on_unlink_success': EventTypeArg._device_delete_on_unlink_success_validator, + 'device_link_fail': EventTypeArg._device_link_fail_validator, + 'device_link_success': EventTypeArg._device_link_success_validator, + 'device_management_disabled': EventTypeArg._device_management_disabled_validator, + 'device_management_enabled': EventTypeArg._device_management_enabled_validator, + 'device_unlink': EventTypeArg._device_unlink_validator, + 'emm_refresh_auth_token': EventTypeArg._emm_refresh_auth_token_validator, + 'account_capture_change_availability': EventTypeArg._account_capture_change_availability_validator, + 'account_capture_migrate_account': EventTypeArg._account_capture_migrate_account_validator, + 'account_capture_notification_emails_sent': EventTypeArg._account_capture_notification_emails_sent_validator, + 'account_capture_relinquish_account': EventTypeArg._account_capture_relinquish_account_validator, + 'disabled_domain_invites': EventTypeArg._disabled_domain_invites_validator, + 'domain_invites_approve_request_to_join_team': EventTypeArg._domain_invites_approve_request_to_join_team_validator, + 'domain_invites_decline_request_to_join_team': EventTypeArg._domain_invites_decline_request_to_join_team_validator, + 'domain_invites_email_existing_users': EventTypeArg._domain_invites_email_existing_users_validator, + 'domain_invites_request_to_join_team': EventTypeArg._domain_invites_request_to_join_team_validator, + 'domain_invites_set_invite_new_user_pref_to_no': EventTypeArg._domain_invites_set_invite_new_user_pref_to_no_validator, + 'domain_invites_set_invite_new_user_pref_to_yes': EventTypeArg._domain_invites_set_invite_new_user_pref_to_yes_validator, + 'domain_verification_add_domain_fail': EventTypeArg._domain_verification_add_domain_fail_validator, + 'domain_verification_add_domain_success': EventTypeArg._domain_verification_add_domain_success_validator, + 'domain_verification_remove_domain': EventTypeArg._domain_verification_remove_domain_validator, + 'enabled_domain_invites': EventTypeArg._enabled_domain_invites_validator, + 'create_folder': EventTypeArg._create_folder_validator, + 'file_add': EventTypeArg._file_add_validator, + 'file_copy': EventTypeArg._file_copy_validator, + 'file_delete': EventTypeArg._file_delete_validator, + 'file_download': EventTypeArg._file_download_validator, + 'file_edit': EventTypeArg._file_edit_validator, + 'file_get_copy_reference': EventTypeArg._file_get_copy_reference_validator, + 'file_locking_lock_status_changed': EventTypeArg._file_locking_lock_status_changed_validator, + 'file_move': EventTypeArg._file_move_validator, + 'file_permanently_delete': EventTypeArg._file_permanently_delete_validator, + 'file_preview': EventTypeArg._file_preview_validator, + 'file_rename': EventTypeArg._file_rename_validator, + 'file_restore': EventTypeArg._file_restore_validator, + 'file_revert': EventTypeArg._file_revert_validator, + 'file_rollback_changes': EventTypeArg._file_rollback_changes_validator, + 'file_save_copy_reference': EventTypeArg._file_save_copy_reference_validator, + 'folder_overview_description_changed': EventTypeArg._folder_overview_description_changed_validator, + 'folder_overview_item_pinned': EventTypeArg._folder_overview_item_pinned_validator, + 'folder_overview_item_unpinned': EventTypeArg._folder_overview_item_unpinned_validator, + 'rewind_folder': EventTypeArg._rewind_folder_validator, + 'file_request_change': EventTypeArg._file_request_change_validator, + 'file_request_close': EventTypeArg._file_request_close_validator, + 'file_request_create': EventTypeArg._file_request_create_validator, + 'file_request_delete': EventTypeArg._file_request_delete_validator, + 'file_request_receive_file': EventTypeArg._file_request_receive_file_validator, + 'group_add_external_id': EventTypeArg._group_add_external_id_validator, + 'group_add_member': EventTypeArg._group_add_member_validator, + 'group_change_external_id': EventTypeArg._group_change_external_id_validator, + 'group_change_management_type': EventTypeArg._group_change_management_type_validator, + 'group_change_member_role': EventTypeArg._group_change_member_role_validator, + 'group_create': EventTypeArg._group_create_validator, + 'group_delete': EventTypeArg._group_delete_validator, + 'group_description_updated': EventTypeArg._group_description_updated_validator, + 'group_join_policy_updated': EventTypeArg._group_join_policy_updated_validator, + 'group_moved': EventTypeArg._group_moved_validator, + 'group_remove_external_id': EventTypeArg._group_remove_external_id_validator, + 'group_remove_member': EventTypeArg._group_remove_member_validator, + 'group_rename': EventTypeArg._group_rename_validator, + 'legal_holds_activate_a_hold': EventTypeArg._legal_holds_activate_a_hold_validator, + 'legal_holds_add_members': EventTypeArg._legal_holds_add_members_validator, + 'legal_holds_change_hold_details': EventTypeArg._legal_holds_change_hold_details_validator, + 'legal_holds_change_hold_name': EventTypeArg._legal_holds_change_hold_name_validator, + 'legal_holds_export_a_hold': EventTypeArg._legal_holds_export_a_hold_validator, + 'legal_holds_export_cancelled': EventTypeArg._legal_holds_export_cancelled_validator, + 'legal_holds_export_downloaded': EventTypeArg._legal_holds_export_downloaded_validator, + 'legal_holds_export_removed': EventTypeArg._legal_holds_export_removed_validator, + 'legal_holds_release_a_hold': EventTypeArg._legal_holds_release_a_hold_validator, + 'legal_holds_remove_members': EventTypeArg._legal_holds_remove_members_validator, + 'legal_holds_report_a_hold': EventTypeArg._legal_holds_report_a_hold_validator, + 'account_lock_or_unlocked': EventTypeArg._account_lock_or_unlocked_validator, + 'emm_error': EventTypeArg._emm_error_validator, + 'guest_admin_signed_in_via_trusted_teams': EventTypeArg._guest_admin_signed_in_via_trusted_teams_validator, + 'guest_admin_signed_out_via_trusted_teams': EventTypeArg._guest_admin_signed_out_via_trusted_teams_validator, + 'login_fail': EventTypeArg._login_fail_validator, + 'login_success': EventTypeArg._login_success_validator, + 'logout': EventTypeArg._logout_validator, + 'reseller_support_session_end': EventTypeArg._reseller_support_session_end_validator, + 'reseller_support_session_start': EventTypeArg._reseller_support_session_start_validator, + 'sign_in_as_session_end': EventTypeArg._sign_in_as_session_end_validator, + 'sign_in_as_session_start': EventTypeArg._sign_in_as_session_start_validator, + 'sso_error': EventTypeArg._sso_error_validator, + 'create_team_invite_link': EventTypeArg._create_team_invite_link_validator, + 'delete_team_invite_link': EventTypeArg._delete_team_invite_link_validator, + 'member_add_external_id': EventTypeArg._member_add_external_id_validator, + 'member_add_name': EventTypeArg._member_add_name_validator, + 'member_change_admin_role': EventTypeArg._member_change_admin_role_validator, + 'member_change_email': EventTypeArg._member_change_email_validator, + 'member_change_external_id': EventTypeArg._member_change_external_id_validator, + 'member_change_membership_type': EventTypeArg._member_change_membership_type_validator, + 'member_change_name': EventTypeArg._member_change_name_validator, + 'member_change_status': EventTypeArg._member_change_status_validator, + 'member_delete_manual_contacts': EventTypeArg._member_delete_manual_contacts_validator, + 'member_delete_profile_photo': EventTypeArg._member_delete_profile_photo_validator, + 'member_permanently_delete_account_contents': EventTypeArg._member_permanently_delete_account_contents_validator, + 'member_remove_external_id': EventTypeArg._member_remove_external_id_validator, + 'member_set_profile_photo': EventTypeArg._member_set_profile_photo_validator, + 'member_space_limits_add_custom_quota': EventTypeArg._member_space_limits_add_custom_quota_validator, + 'member_space_limits_change_custom_quota': EventTypeArg._member_space_limits_change_custom_quota_validator, + 'member_space_limits_change_status': EventTypeArg._member_space_limits_change_status_validator, + 'member_space_limits_remove_custom_quota': EventTypeArg._member_space_limits_remove_custom_quota_validator, + 'member_suggest': EventTypeArg._member_suggest_validator, + 'member_transfer_account_contents': EventTypeArg._member_transfer_account_contents_validator, + 'pending_secondary_email_added': EventTypeArg._pending_secondary_email_added_validator, + 'secondary_email_deleted': EventTypeArg._secondary_email_deleted_validator, + 'secondary_email_verified': EventTypeArg._secondary_email_verified_validator, + 'secondary_mails_policy_changed': EventTypeArg._secondary_mails_policy_changed_validator, + 'binder_add_page': EventTypeArg._binder_add_page_validator, + 'binder_add_section': EventTypeArg._binder_add_section_validator, + 'binder_remove_page': EventTypeArg._binder_remove_page_validator, + 'binder_remove_section': EventTypeArg._binder_remove_section_validator, + 'binder_rename_page': EventTypeArg._binder_rename_page_validator, + 'binder_rename_section': EventTypeArg._binder_rename_section_validator, + 'binder_reorder_page': EventTypeArg._binder_reorder_page_validator, + 'binder_reorder_section': EventTypeArg._binder_reorder_section_validator, + 'paper_content_add_member': EventTypeArg._paper_content_add_member_validator, + 'paper_content_add_to_folder': EventTypeArg._paper_content_add_to_folder_validator, + 'paper_content_archive': EventTypeArg._paper_content_archive_validator, + 'paper_content_create': EventTypeArg._paper_content_create_validator, + 'paper_content_permanently_delete': EventTypeArg._paper_content_permanently_delete_validator, + 'paper_content_remove_from_folder': EventTypeArg._paper_content_remove_from_folder_validator, + 'paper_content_remove_member': EventTypeArg._paper_content_remove_member_validator, + 'paper_content_rename': EventTypeArg._paper_content_rename_validator, + 'paper_content_restore': EventTypeArg._paper_content_restore_validator, + 'paper_doc_add_comment': EventTypeArg._paper_doc_add_comment_validator, + 'paper_doc_change_member_role': EventTypeArg._paper_doc_change_member_role_validator, + 'paper_doc_change_sharing_policy': EventTypeArg._paper_doc_change_sharing_policy_validator, + 'paper_doc_change_subscription': EventTypeArg._paper_doc_change_subscription_validator, + 'paper_doc_deleted': EventTypeArg._paper_doc_deleted_validator, + 'paper_doc_delete_comment': EventTypeArg._paper_doc_delete_comment_validator, + 'paper_doc_download': EventTypeArg._paper_doc_download_validator, + 'paper_doc_edit': EventTypeArg._paper_doc_edit_validator, + 'paper_doc_edit_comment': EventTypeArg._paper_doc_edit_comment_validator, + 'paper_doc_followed': EventTypeArg._paper_doc_followed_validator, + 'paper_doc_mention': EventTypeArg._paper_doc_mention_validator, + 'paper_doc_ownership_changed': EventTypeArg._paper_doc_ownership_changed_validator, + 'paper_doc_request_access': EventTypeArg._paper_doc_request_access_validator, + 'paper_doc_resolve_comment': EventTypeArg._paper_doc_resolve_comment_validator, + 'paper_doc_revert': EventTypeArg._paper_doc_revert_validator, + 'paper_doc_slack_share': EventTypeArg._paper_doc_slack_share_validator, + 'paper_doc_team_invite': EventTypeArg._paper_doc_team_invite_validator, + 'paper_doc_trashed': EventTypeArg._paper_doc_trashed_validator, + 'paper_doc_unresolve_comment': EventTypeArg._paper_doc_unresolve_comment_validator, + 'paper_doc_untrashed': EventTypeArg._paper_doc_untrashed_validator, + 'paper_doc_view': EventTypeArg._paper_doc_view_validator, + 'paper_external_view_allow': EventTypeArg._paper_external_view_allow_validator, + 'paper_external_view_default_team': EventTypeArg._paper_external_view_default_team_validator, + 'paper_external_view_forbid': EventTypeArg._paper_external_view_forbid_validator, + 'paper_folder_change_subscription': EventTypeArg._paper_folder_change_subscription_validator, + 'paper_folder_deleted': EventTypeArg._paper_folder_deleted_validator, + 'paper_folder_followed': EventTypeArg._paper_folder_followed_validator, + 'paper_folder_team_invite': EventTypeArg._paper_folder_team_invite_validator, + 'paper_published_link_change_permission': EventTypeArg._paper_published_link_change_permission_validator, + 'paper_published_link_create': EventTypeArg._paper_published_link_create_validator, + 'paper_published_link_disabled': EventTypeArg._paper_published_link_disabled_validator, + 'paper_published_link_view': EventTypeArg._paper_published_link_view_validator, + 'password_change': EventTypeArg._password_change_validator, + 'password_reset': EventTypeArg._password_reset_validator, + 'password_reset_all': EventTypeArg._password_reset_all_validator, + 'emm_create_exceptions_report': EventTypeArg._emm_create_exceptions_report_validator, + 'emm_create_usage_report': EventTypeArg._emm_create_usage_report_validator, + 'export_members_report': EventTypeArg._export_members_report_validator, + 'export_members_report_fail': EventTypeArg._export_members_report_fail_validator, + 'no_expiration_link_gen_create_report': EventTypeArg._no_expiration_link_gen_create_report_validator, + 'no_expiration_link_gen_report_failed': EventTypeArg._no_expiration_link_gen_report_failed_validator, + 'no_password_link_gen_create_report': EventTypeArg._no_password_link_gen_create_report_validator, + 'no_password_link_gen_report_failed': EventTypeArg._no_password_link_gen_report_failed_validator, + 'no_password_link_view_create_report': EventTypeArg._no_password_link_view_create_report_validator, + 'no_password_link_view_report_failed': EventTypeArg._no_password_link_view_report_failed_validator, + 'outdated_link_view_create_report': EventTypeArg._outdated_link_view_create_report_validator, + 'outdated_link_view_report_failed': EventTypeArg._outdated_link_view_report_failed_validator, + 'paper_admin_export_start': EventTypeArg._paper_admin_export_start_validator, + 'smart_sync_create_admin_privilege_report': EventTypeArg._smart_sync_create_admin_privilege_report_validator, + 'team_activity_create_report': EventTypeArg._team_activity_create_report_validator, + 'team_activity_create_report_fail': EventTypeArg._team_activity_create_report_fail_validator, + 'collection_share': EventTypeArg._collection_share_validator, + 'file_transfers_file_add': EventTypeArg._file_transfers_file_add_validator, + 'file_transfers_transfer_delete': EventTypeArg._file_transfers_transfer_delete_validator, + 'file_transfers_transfer_download': EventTypeArg._file_transfers_transfer_download_validator, + 'file_transfers_transfer_send': EventTypeArg._file_transfers_transfer_send_validator, + 'file_transfers_transfer_view': EventTypeArg._file_transfers_transfer_view_validator, + 'note_acl_invite_only': EventTypeArg._note_acl_invite_only_validator, + 'note_acl_link': EventTypeArg._note_acl_link_validator, + 'note_acl_team_link': EventTypeArg._note_acl_team_link_validator, + 'note_shared': EventTypeArg._note_shared_validator, + 'note_share_receive': EventTypeArg._note_share_receive_validator, + 'open_note_shared': EventTypeArg._open_note_shared_validator, + 'sf_add_group': EventTypeArg._sf_add_group_validator, + 'sf_allow_non_members_to_view_shared_links': EventTypeArg._sf_allow_non_members_to_view_shared_links_validator, + 'sf_external_invite_warn': EventTypeArg._sf_external_invite_warn_validator, + 'sf_fb_invite': EventTypeArg._sf_fb_invite_validator, + 'sf_fb_invite_change_role': EventTypeArg._sf_fb_invite_change_role_validator, + 'sf_fb_uninvite': EventTypeArg._sf_fb_uninvite_validator, + 'sf_invite_group': EventTypeArg._sf_invite_group_validator, + 'sf_team_grant_access': EventTypeArg._sf_team_grant_access_validator, + 'sf_team_invite': EventTypeArg._sf_team_invite_validator, + 'sf_team_invite_change_role': EventTypeArg._sf_team_invite_change_role_validator, + 'sf_team_join': EventTypeArg._sf_team_join_validator, + 'sf_team_join_from_oob_link': EventTypeArg._sf_team_join_from_oob_link_validator, + 'sf_team_uninvite': EventTypeArg._sf_team_uninvite_validator, + 'shared_content_add_invitees': EventTypeArg._shared_content_add_invitees_validator, + 'shared_content_add_link_expiry': EventTypeArg._shared_content_add_link_expiry_validator, + 'shared_content_add_link_password': EventTypeArg._shared_content_add_link_password_validator, + 'shared_content_add_member': EventTypeArg._shared_content_add_member_validator, + 'shared_content_change_downloads_policy': EventTypeArg._shared_content_change_downloads_policy_validator, + 'shared_content_change_invitee_role': EventTypeArg._shared_content_change_invitee_role_validator, + 'shared_content_change_link_audience': EventTypeArg._shared_content_change_link_audience_validator, + 'shared_content_change_link_expiry': EventTypeArg._shared_content_change_link_expiry_validator, + 'shared_content_change_link_password': EventTypeArg._shared_content_change_link_password_validator, + 'shared_content_change_member_role': EventTypeArg._shared_content_change_member_role_validator, + 'shared_content_change_viewer_info_policy': EventTypeArg._shared_content_change_viewer_info_policy_validator, + 'shared_content_claim_invitation': EventTypeArg._shared_content_claim_invitation_validator, + 'shared_content_copy': EventTypeArg._shared_content_copy_validator, + 'shared_content_download': EventTypeArg._shared_content_download_validator, + 'shared_content_relinquish_membership': EventTypeArg._shared_content_relinquish_membership_validator, + 'shared_content_remove_invitees': EventTypeArg._shared_content_remove_invitees_validator, + 'shared_content_remove_link_expiry': EventTypeArg._shared_content_remove_link_expiry_validator, + 'shared_content_remove_link_password': EventTypeArg._shared_content_remove_link_password_validator, + 'shared_content_remove_member': EventTypeArg._shared_content_remove_member_validator, + 'shared_content_request_access': EventTypeArg._shared_content_request_access_validator, + 'shared_content_restore_invitees': EventTypeArg._shared_content_restore_invitees_validator, + 'shared_content_restore_member': EventTypeArg._shared_content_restore_member_validator, + 'shared_content_unshare': EventTypeArg._shared_content_unshare_validator, + 'shared_content_view': EventTypeArg._shared_content_view_validator, + 'shared_folder_change_link_policy': EventTypeArg._shared_folder_change_link_policy_validator, + 'shared_folder_change_members_inheritance_policy': EventTypeArg._shared_folder_change_members_inheritance_policy_validator, + 'shared_folder_change_members_management_policy': EventTypeArg._shared_folder_change_members_management_policy_validator, + 'shared_folder_change_members_policy': EventTypeArg._shared_folder_change_members_policy_validator, + 'shared_folder_create': EventTypeArg._shared_folder_create_validator, + 'shared_folder_decline_invitation': EventTypeArg._shared_folder_decline_invitation_validator, + 'shared_folder_mount': EventTypeArg._shared_folder_mount_validator, + 'shared_folder_nest': EventTypeArg._shared_folder_nest_validator, + 'shared_folder_transfer_ownership': EventTypeArg._shared_folder_transfer_ownership_validator, + 'shared_folder_unmount': EventTypeArg._shared_folder_unmount_validator, + 'shared_link_add_expiry': EventTypeArg._shared_link_add_expiry_validator, + 'shared_link_change_expiry': EventTypeArg._shared_link_change_expiry_validator, + 'shared_link_change_visibility': EventTypeArg._shared_link_change_visibility_validator, + 'shared_link_copy': EventTypeArg._shared_link_copy_validator, + 'shared_link_create': EventTypeArg._shared_link_create_validator, + 'shared_link_disable': EventTypeArg._shared_link_disable_validator, + 'shared_link_download': EventTypeArg._shared_link_download_validator, + 'shared_link_remove_expiry': EventTypeArg._shared_link_remove_expiry_validator, + 'shared_link_settings_add_expiration': EventTypeArg._shared_link_settings_add_expiration_validator, + 'shared_link_settings_add_password': EventTypeArg._shared_link_settings_add_password_validator, + 'shared_link_settings_allow_download_disabled': EventTypeArg._shared_link_settings_allow_download_disabled_validator, + 'shared_link_settings_allow_download_enabled': EventTypeArg._shared_link_settings_allow_download_enabled_validator, + 'shared_link_settings_change_audience': EventTypeArg._shared_link_settings_change_audience_validator, + 'shared_link_settings_change_expiration': EventTypeArg._shared_link_settings_change_expiration_validator, + 'shared_link_settings_change_password': EventTypeArg._shared_link_settings_change_password_validator, + 'shared_link_settings_remove_expiration': EventTypeArg._shared_link_settings_remove_expiration_validator, + 'shared_link_settings_remove_password': EventTypeArg._shared_link_settings_remove_password_validator, + 'shared_link_share': EventTypeArg._shared_link_share_validator, + 'shared_link_view': EventTypeArg._shared_link_view_validator, + 'shared_note_opened': EventTypeArg._shared_note_opened_validator, + 'shmodel_group_share': EventTypeArg._shmodel_group_share_validator, + 'showcase_access_granted': EventTypeArg._showcase_access_granted_validator, + 'showcase_add_member': EventTypeArg._showcase_add_member_validator, + 'showcase_archived': EventTypeArg._showcase_archived_validator, + 'showcase_created': EventTypeArg._showcase_created_validator, + 'showcase_delete_comment': EventTypeArg._showcase_delete_comment_validator, + 'showcase_edited': EventTypeArg._showcase_edited_validator, + 'showcase_edit_comment': EventTypeArg._showcase_edit_comment_validator, + 'showcase_file_added': EventTypeArg._showcase_file_added_validator, + 'showcase_file_download': EventTypeArg._showcase_file_download_validator, + 'showcase_file_removed': EventTypeArg._showcase_file_removed_validator, + 'showcase_file_view': EventTypeArg._showcase_file_view_validator, + 'showcase_permanently_deleted': EventTypeArg._showcase_permanently_deleted_validator, + 'showcase_post_comment': EventTypeArg._showcase_post_comment_validator, + 'showcase_remove_member': EventTypeArg._showcase_remove_member_validator, + 'showcase_renamed': EventTypeArg._showcase_renamed_validator, + 'showcase_request_access': EventTypeArg._showcase_request_access_validator, + 'showcase_resolve_comment': EventTypeArg._showcase_resolve_comment_validator, + 'showcase_restored': EventTypeArg._showcase_restored_validator, + 'showcase_trashed': EventTypeArg._showcase_trashed_validator, + 'showcase_trashed_deprecated': EventTypeArg._showcase_trashed_deprecated_validator, + 'showcase_unresolve_comment': EventTypeArg._showcase_unresolve_comment_validator, + 'showcase_untrashed': EventTypeArg._showcase_untrashed_validator, + 'showcase_untrashed_deprecated': EventTypeArg._showcase_untrashed_deprecated_validator, + 'showcase_view': EventTypeArg._showcase_view_validator, + 'sso_add_cert': EventTypeArg._sso_add_cert_validator, + 'sso_add_login_url': EventTypeArg._sso_add_login_url_validator, + 'sso_add_logout_url': EventTypeArg._sso_add_logout_url_validator, + 'sso_change_cert': EventTypeArg._sso_change_cert_validator, + 'sso_change_login_url': EventTypeArg._sso_change_login_url_validator, + 'sso_change_logout_url': EventTypeArg._sso_change_logout_url_validator, + 'sso_change_saml_identity_mode': EventTypeArg._sso_change_saml_identity_mode_validator, + 'sso_remove_cert': EventTypeArg._sso_remove_cert_validator, + 'sso_remove_login_url': EventTypeArg._sso_remove_login_url_validator, + 'sso_remove_logout_url': EventTypeArg._sso_remove_logout_url_validator, + 'team_folder_change_status': EventTypeArg._team_folder_change_status_validator, + 'team_folder_create': EventTypeArg._team_folder_create_validator, + 'team_folder_downgrade': EventTypeArg._team_folder_downgrade_validator, + 'team_folder_permanently_delete': EventTypeArg._team_folder_permanently_delete_validator, + 'team_folder_rename': EventTypeArg._team_folder_rename_validator, + 'team_selective_sync_settings_changed': EventTypeArg._team_selective_sync_settings_changed_validator, + 'account_capture_change_policy': EventTypeArg._account_capture_change_policy_validator, + 'allow_download_disabled': EventTypeArg._allow_download_disabled_validator, + 'allow_download_enabled': EventTypeArg._allow_download_enabled_validator, + 'camera_uploads_policy_changed': EventTypeArg._camera_uploads_policy_changed_validator, + 'data_placement_restriction_change_policy': EventTypeArg._data_placement_restriction_change_policy_validator, + 'data_placement_restriction_satisfy_policy': EventTypeArg._data_placement_restriction_satisfy_policy_validator, + 'device_approvals_add_exception': EventTypeArg._device_approvals_add_exception_validator, + 'device_approvals_change_desktop_policy': EventTypeArg._device_approvals_change_desktop_policy_validator, + 'device_approvals_change_mobile_policy': EventTypeArg._device_approvals_change_mobile_policy_validator, + 'device_approvals_change_overage_action': EventTypeArg._device_approvals_change_overage_action_validator, + 'device_approvals_change_unlink_action': EventTypeArg._device_approvals_change_unlink_action_validator, + 'device_approvals_remove_exception': EventTypeArg._device_approvals_remove_exception_validator, + 'directory_restrictions_add_members': EventTypeArg._directory_restrictions_add_members_validator, + 'directory_restrictions_remove_members': EventTypeArg._directory_restrictions_remove_members_validator, + 'emm_add_exception': EventTypeArg._emm_add_exception_validator, + 'emm_change_policy': EventTypeArg._emm_change_policy_validator, + 'emm_remove_exception': EventTypeArg._emm_remove_exception_validator, + 'extended_version_history_change_policy': EventTypeArg._extended_version_history_change_policy_validator, + 'file_comments_change_policy': EventTypeArg._file_comments_change_policy_validator, + 'file_locking_policy_changed': EventTypeArg._file_locking_policy_changed_validator, + 'file_requests_change_policy': EventTypeArg._file_requests_change_policy_validator, + 'file_requests_emails_enabled': EventTypeArg._file_requests_emails_enabled_validator, + 'file_requests_emails_restricted_to_team_only': EventTypeArg._file_requests_emails_restricted_to_team_only_validator, + 'file_transfers_policy_changed': EventTypeArg._file_transfers_policy_changed_validator, + 'google_sso_change_policy': EventTypeArg._google_sso_change_policy_validator, + 'group_user_management_change_policy': EventTypeArg._group_user_management_change_policy_validator, + 'integration_policy_changed': EventTypeArg._integration_policy_changed_validator, + 'member_requests_change_policy': EventTypeArg._member_requests_change_policy_validator, + 'member_send_invite_policy_changed': EventTypeArg._member_send_invite_policy_changed_validator, + 'member_space_limits_add_exception': EventTypeArg._member_space_limits_add_exception_validator, + 'member_space_limits_change_caps_type_policy': EventTypeArg._member_space_limits_change_caps_type_policy_validator, + 'member_space_limits_change_policy': EventTypeArg._member_space_limits_change_policy_validator, + 'member_space_limits_remove_exception': EventTypeArg._member_space_limits_remove_exception_validator, + 'member_suggestions_change_policy': EventTypeArg._member_suggestions_change_policy_validator, + 'microsoft_office_addin_change_policy': EventTypeArg._microsoft_office_addin_change_policy_validator, + 'network_control_change_policy': EventTypeArg._network_control_change_policy_validator, + 'paper_change_deployment_policy': EventTypeArg._paper_change_deployment_policy_validator, + 'paper_change_member_link_policy': EventTypeArg._paper_change_member_link_policy_validator, + 'paper_change_member_policy': EventTypeArg._paper_change_member_policy_validator, + 'paper_change_policy': EventTypeArg._paper_change_policy_validator, + 'paper_default_folder_policy_changed': EventTypeArg._paper_default_folder_policy_changed_validator, + 'paper_desktop_policy_changed': EventTypeArg._paper_desktop_policy_changed_validator, + 'paper_enabled_users_group_addition': EventTypeArg._paper_enabled_users_group_addition_validator, + 'paper_enabled_users_group_removal': EventTypeArg._paper_enabled_users_group_removal_validator, + 'password_strength_requirements_change_policy': EventTypeArg._password_strength_requirements_change_policy_validator, + 'permanent_delete_change_policy': EventTypeArg._permanent_delete_change_policy_validator, + 'reseller_support_change_policy': EventTypeArg._reseller_support_change_policy_validator, + 'rewind_policy_changed': EventTypeArg._rewind_policy_changed_validator, + 'sharing_change_folder_join_policy': EventTypeArg._sharing_change_folder_join_policy_validator, + 'sharing_change_link_policy': EventTypeArg._sharing_change_link_policy_validator, + 'sharing_change_member_policy': EventTypeArg._sharing_change_member_policy_validator, + 'showcase_change_download_policy': EventTypeArg._showcase_change_download_policy_validator, + 'showcase_change_enabled_policy': EventTypeArg._showcase_change_enabled_policy_validator, + 'showcase_change_external_sharing_policy': EventTypeArg._showcase_change_external_sharing_policy_validator, + 'smarter_smart_sync_policy_changed': EventTypeArg._smarter_smart_sync_policy_changed_validator, + 'smart_sync_change_policy': EventTypeArg._smart_sync_change_policy_validator, + 'smart_sync_not_opt_out': EventTypeArg._smart_sync_not_opt_out_validator, + 'smart_sync_opt_out': EventTypeArg._smart_sync_opt_out_validator, + 'sso_change_policy': EventTypeArg._sso_change_policy_validator, + 'team_extensions_policy_changed': EventTypeArg._team_extensions_policy_changed_validator, + 'team_selective_sync_policy_changed': EventTypeArg._team_selective_sync_policy_changed_validator, + 'team_sharing_whitelist_subjects_changed': EventTypeArg._team_sharing_whitelist_subjects_changed_validator, + 'tfa_add_exception': EventTypeArg._tfa_add_exception_validator, + 'tfa_change_policy': EventTypeArg._tfa_change_policy_validator, + 'tfa_remove_exception': EventTypeArg._tfa_remove_exception_validator, + 'two_account_change_policy': EventTypeArg._two_account_change_policy_validator, + 'viewer_info_policy_changed': EventTypeArg._viewer_info_policy_changed_validator, + 'watermarking_policy_changed': EventTypeArg._watermarking_policy_changed_validator, + 'web_sessions_change_active_session_limit': EventTypeArg._web_sessions_change_active_session_limit_validator, + 'web_sessions_change_fixed_length_policy': EventTypeArg._web_sessions_change_fixed_length_policy_validator, + 'web_sessions_change_idle_length_policy': EventTypeArg._web_sessions_change_idle_length_policy_validator, + 'team_merge_from': EventTypeArg._team_merge_from_validator, + 'team_merge_to': EventTypeArg._team_merge_to_validator, + 'team_profile_add_logo': EventTypeArg._team_profile_add_logo_validator, + 'team_profile_change_default_language': EventTypeArg._team_profile_change_default_language_validator, + 'team_profile_change_logo': EventTypeArg._team_profile_change_logo_validator, + 'team_profile_change_name': EventTypeArg._team_profile_change_name_validator, + 'team_profile_remove_logo': EventTypeArg._team_profile_remove_logo_validator, + 'tfa_add_backup_phone': EventTypeArg._tfa_add_backup_phone_validator, + 'tfa_add_security_key': EventTypeArg._tfa_add_security_key_validator, + 'tfa_change_backup_phone': EventTypeArg._tfa_change_backup_phone_validator, + 'tfa_change_status': EventTypeArg._tfa_change_status_validator, + 'tfa_remove_backup_phone': EventTypeArg._tfa_remove_backup_phone_validator, + 'tfa_remove_security_key': EventTypeArg._tfa_remove_security_key_validator, + 'tfa_reset': EventTypeArg._tfa_reset_validator, + 'changed_enterprise_admin_role': EventTypeArg._changed_enterprise_admin_role_validator, + 'changed_enterprise_connected_team_status': EventTypeArg._changed_enterprise_connected_team_status_validator, + 'ended_enterprise_admin_session': EventTypeArg._ended_enterprise_admin_session_validator, + 'ended_enterprise_admin_session_deprecated': EventTypeArg._ended_enterprise_admin_session_deprecated_validator, + 'enterprise_settings_locking': EventTypeArg._enterprise_settings_locking_validator, + 'guest_admin_change_status': EventTypeArg._guest_admin_change_status_validator, + 'started_enterprise_admin_session': EventTypeArg._started_enterprise_admin_session_validator, + 'team_merge_request_accepted': EventTypeArg._team_merge_request_accepted_validator, + 'team_merge_request_accepted_shown_to_primary_team': EventTypeArg._team_merge_request_accepted_shown_to_primary_team_validator, + 'team_merge_request_accepted_shown_to_secondary_team': EventTypeArg._team_merge_request_accepted_shown_to_secondary_team_validator, + 'team_merge_request_auto_canceled': EventTypeArg._team_merge_request_auto_canceled_validator, + 'team_merge_request_canceled': EventTypeArg._team_merge_request_canceled_validator, + 'team_merge_request_canceled_shown_to_primary_team': EventTypeArg._team_merge_request_canceled_shown_to_primary_team_validator, + 'team_merge_request_canceled_shown_to_secondary_team': EventTypeArg._team_merge_request_canceled_shown_to_secondary_team_validator, + 'team_merge_request_expired': EventTypeArg._team_merge_request_expired_validator, + 'team_merge_request_expired_shown_to_primary_team': EventTypeArg._team_merge_request_expired_shown_to_primary_team_validator, + 'team_merge_request_expired_shown_to_secondary_team': EventTypeArg._team_merge_request_expired_shown_to_secondary_team_validator, + 'team_merge_request_rejected_shown_to_primary_team': EventTypeArg._team_merge_request_rejected_shown_to_primary_team_validator, + 'team_merge_request_rejected_shown_to_secondary_team': EventTypeArg._team_merge_request_rejected_shown_to_secondary_team_validator, + 'team_merge_request_reminder': EventTypeArg._team_merge_request_reminder_validator, + 'team_merge_request_reminder_shown_to_primary_team': EventTypeArg._team_merge_request_reminder_shown_to_primary_team_validator, + 'team_merge_request_reminder_shown_to_secondary_team': EventTypeArg._team_merge_request_reminder_shown_to_secondary_team_validator, + 'team_merge_request_revoked': EventTypeArg._team_merge_request_revoked_validator, + 'team_merge_request_sent_shown_to_primary_team': EventTypeArg._team_merge_request_sent_shown_to_primary_team_validator, + 'team_merge_request_sent_shown_to_secondary_team': EventTypeArg._team_merge_request_sent_shown_to_secondary_team_validator, + 'other': EventTypeArg._other_validator, +} + +EventTypeArg.app_link_team = EventTypeArg('app_link_team') +EventTypeArg.app_link_user = EventTypeArg('app_link_user') +EventTypeArg.app_unlink_team = EventTypeArg('app_unlink_team') +EventTypeArg.app_unlink_user = EventTypeArg('app_unlink_user') +EventTypeArg.integration_connected = EventTypeArg('integration_connected') +EventTypeArg.integration_disconnected = EventTypeArg('integration_disconnected') +EventTypeArg.file_add_comment = EventTypeArg('file_add_comment') +EventTypeArg.file_change_comment_subscription = EventTypeArg('file_change_comment_subscription') +EventTypeArg.file_delete_comment = EventTypeArg('file_delete_comment') +EventTypeArg.file_edit_comment = EventTypeArg('file_edit_comment') +EventTypeArg.file_like_comment = EventTypeArg('file_like_comment') +EventTypeArg.file_resolve_comment = EventTypeArg('file_resolve_comment') +EventTypeArg.file_unlike_comment = EventTypeArg('file_unlike_comment') +EventTypeArg.file_unresolve_comment = EventTypeArg('file_unresolve_comment') +EventTypeArg.device_change_ip_desktop = EventTypeArg('device_change_ip_desktop') +EventTypeArg.device_change_ip_mobile = EventTypeArg('device_change_ip_mobile') +EventTypeArg.device_change_ip_web = EventTypeArg('device_change_ip_web') +EventTypeArg.device_delete_on_unlink_fail = EventTypeArg('device_delete_on_unlink_fail') +EventTypeArg.device_delete_on_unlink_success = EventTypeArg('device_delete_on_unlink_success') +EventTypeArg.device_link_fail = EventTypeArg('device_link_fail') +EventTypeArg.device_link_success = EventTypeArg('device_link_success') +EventTypeArg.device_management_disabled = EventTypeArg('device_management_disabled') +EventTypeArg.device_management_enabled = EventTypeArg('device_management_enabled') +EventTypeArg.device_unlink = EventTypeArg('device_unlink') +EventTypeArg.emm_refresh_auth_token = EventTypeArg('emm_refresh_auth_token') +EventTypeArg.account_capture_change_availability = EventTypeArg('account_capture_change_availability') +EventTypeArg.account_capture_migrate_account = EventTypeArg('account_capture_migrate_account') +EventTypeArg.account_capture_notification_emails_sent = EventTypeArg('account_capture_notification_emails_sent') +EventTypeArg.account_capture_relinquish_account = EventTypeArg('account_capture_relinquish_account') +EventTypeArg.disabled_domain_invites = EventTypeArg('disabled_domain_invites') +EventTypeArg.domain_invites_approve_request_to_join_team = EventTypeArg('domain_invites_approve_request_to_join_team') +EventTypeArg.domain_invites_decline_request_to_join_team = EventTypeArg('domain_invites_decline_request_to_join_team') +EventTypeArg.domain_invites_email_existing_users = EventTypeArg('domain_invites_email_existing_users') +EventTypeArg.domain_invites_request_to_join_team = EventTypeArg('domain_invites_request_to_join_team') +EventTypeArg.domain_invites_set_invite_new_user_pref_to_no = EventTypeArg('domain_invites_set_invite_new_user_pref_to_no') +EventTypeArg.domain_invites_set_invite_new_user_pref_to_yes = EventTypeArg('domain_invites_set_invite_new_user_pref_to_yes') +EventTypeArg.domain_verification_add_domain_fail = EventTypeArg('domain_verification_add_domain_fail') +EventTypeArg.domain_verification_add_domain_success = EventTypeArg('domain_verification_add_domain_success') +EventTypeArg.domain_verification_remove_domain = EventTypeArg('domain_verification_remove_domain') +EventTypeArg.enabled_domain_invites = EventTypeArg('enabled_domain_invites') +EventTypeArg.create_folder = EventTypeArg('create_folder') +EventTypeArg.file_add = EventTypeArg('file_add') +EventTypeArg.file_copy = EventTypeArg('file_copy') +EventTypeArg.file_delete = EventTypeArg('file_delete') +EventTypeArg.file_download = EventTypeArg('file_download') +EventTypeArg.file_edit = EventTypeArg('file_edit') +EventTypeArg.file_get_copy_reference = EventTypeArg('file_get_copy_reference') +EventTypeArg.file_locking_lock_status_changed = EventTypeArg('file_locking_lock_status_changed') +EventTypeArg.file_move = EventTypeArg('file_move') +EventTypeArg.file_permanently_delete = EventTypeArg('file_permanently_delete') +EventTypeArg.file_preview = EventTypeArg('file_preview') +EventTypeArg.file_rename = EventTypeArg('file_rename') +EventTypeArg.file_restore = EventTypeArg('file_restore') +EventTypeArg.file_revert = EventTypeArg('file_revert') +EventTypeArg.file_rollback_changes = EventTypeArg('file_rollback_changes') +EventTypeArg.file_save_copy_reference = EventTypeArg('file_save_copy_reference') +EventTypeArg.folder_overview_description_changed = EventTypeArg('folder_overview_description_changed') +EventTypeArg.folder_overview_item_pinned = EventTypeArg('folder_overview_item_pinned') +EventTypeArg.folder_overview_item_unpinned = EventTypeArg('folder_overview_item_unpinned') +EventTypeArg.rewind_folder = EventTypeArg('rewind_folder') +EventTypeArg.file_request_change = EventTypeArg('file_request_change') +EventTypeArg.file_request_close = EventTypeArg('file_request_close') +EventTypeArg.file_request_create = EventTypeArg('file_request_create') +EventTypeArg.file_request_delete = EventTypeArg('file_request_delete') +EventTypeArg.file_request_receive_file = EventTypeArg('file_request_receive_file') +EventTypeArg.group_add_external_id = EventTypeArg('group_add_external_id') +EventTypeArg.group_add_member = EventTypeArg('group_add_member') +EventTypeArg.group_change_external_id = EventTypeArg('group_change_external_id') +EventTypeArg.group_change_management_type = EventTypeArg('group_change_management_type') +EventTypeArg.group_change_member_role = EventTypeArg('group_change_member_role') +EventTypeArg.group_create = EventTypeArg('group_create') +EventTypeArg.group_delete = EventTypeArg('group_delete') +EventTypeArg.group_description_updated = EventTypeArg('group_description_updated') +EventTypeArg.group_join_policy_updated = EventTypeArg('group_join_policy_updated') +EventTypeArg.group_moved = EventTypeArg('group_moved') +EventTypeArg.group_remove_external_id = EventTypeArg('group_remove_external_id') +EventTypeArg.group_remove_member = EventTypeArg('group_remove_member') +EventTypeArg.group_rename = EventTypeArg('group_rename') +EventTypeArg.legal_holds_activate_a_hold = EventTypeArg('legal_holds_activate_a_hold') +EventTypeArg.legal_holds_add_members = EventTypeArg('legal_holds_add_members') +EventTypeArg.legal_holds_change_hold_details = EventTypeArg('legal_holds_change_hold_details') +EventTypeArg.legal_holds_change_hold_name = EventTypeArg('legal_holds_change_hold_name') +EventTypeArg.legal_holds_export_a_hold = EventTypeArg('legal_holds_export_a_hold') +EventTypeArg.legal_holds_export_cancelled = EventTypeArg('legal_holds_export_cancelled') +EventTypeArg.legal_holds_export_downloaded = EventTypeArg('legal_holds_export_downloaded') +EventTypeArg.legal_holds_export_removed = EventTypeArg('legal_holds_export_removed') +EventTypeArg.legal_holds_release_a_hold = EventTypeArg('legal_holds_release_a_hold') +EventTypeArg.legal_holds_remove_members = EventTypeArg('legal_holds_remove_members') +EventTypeArg.legal_holds_report_a_hold = EventTypeArg('legal_holds_report_a_hold') +EventTypeArg.account_lock_or_unlocked = EventTypeArg('account_lock_or_unlocked') +EventTypeArg.emm_error = EventTypeArg('emm_error') +EventTypeArg.guest_admin_signed_in_via_trusted_teams = EventTypeArg('guest_admin_signed_in_via_trusted_teams') +EventTypeArg.guest_admin_signed_out_via_trusted_teams = EventTypeArg('guest_admin_signed_out_via_trusted_teams') +EventTypeArg.login_fail = EventTypeArg('login_fail') +EventTypeArg.login_success = EventTypeArg('login_success') +EventTypeArg.logout = EventTypeArg('logout') +EventTypeArg.reseller_support_session_end = EventTypeArg('reseller_support_session_end') +EventTypeArg.reseller_support_session_start = EventTypeArg('reseller_support_session_start') +EventTypeArg.sign_in_as_session_end = EventTypeArg('sign_in_as_session_end') +EventTypeArg.sign_in_as_session_start = EventTypeArg('sign_in_as_session_start') +EventTypeArg.sso_error = EventTypeArg('sso_error') +EventTypeArg.create_team_invite_link = EventTypeArg('create_team_invite_link') +EventTypeArg.delete_team_invite_link = EventTypeArg('delete_team_invite_link') +EventTypeArg.member_add_external_id = EventTypeArg('member_add_external_id') +EventTypeArg.member_add_name = EventTypeArg('member_add_name') +EventTypeArg.member_change_admin_role = EventTypeArg('member_change_admin_role') +EventTypeArg.member_change_email = EventTypeArg('member_change_email') +EventTypeArg.member_change_external_id = EventTypeArg('member_change_external_id') +EventTypeArg.member_change_membership_type = EventTypeArg('member_change_membership_type') +EventTypeArg.member_change_name = EventTypeArg('member_change_name') +EventTypeArg.member_change_status = EventTypeArg('member_change_status') +EventTypeArg.member_delete_manual_contacts = EventTypeArg('member_delete_manual_contacts') +EventTypeArg.member_delete_profile_photo = EventTypeArg('member_delete_profile_photo') +EventTypeArg.member_permanently_delete_account_contents = EventTypeArg('member_permanently_delete_account_contents') +EventTypeArg.member_remove_external_id = EventTypeArg('member_remove_external_id') +EventTypeArg.member_set_profile_photo = EventTypeArg('member_set_profile_photo') +EventTypeArg.member_space_limits_add_custom_quota = EventTypeArg('member_space_limits_add_custom_quota') +EventTypeArg.member_space_limits_change_custom_quota = EventTypeArg('member_space_limits_change_custom_quota') +EventTypeArg.member_space_limits_change_status = EventTypeArg('member_space_limits_change_status') +EventTypeArg.member_space_limits_remove_custom_quota = EventTypeArg('member_space_limits_remove_custom_quota') +EventTypeArg.member_suggest = EventTypeArg('member_suggest') +EventTypeArg.member_transfer_account_contents = EventTypeArg('member_transfer_account_contents') +EventTypeArg.pending_secondary_email_added = EventTypeArg('pending_secondary_email_added') +EventTypeArg.secondary_email_deleted = EventTypeArg('secondary_email_deleted') +EventTypeArg.secondary_email_verified = EventTypeArg('secondary_email_verified') +EventTypeArg.secondary_mails_policy_changed = EventTypeArg('secondary_mails_policy_changed') +EventTypeArg.binder_add_page = EventTypeArg('binder_add_page') +EventTypeArg.binder_add_section = EventTypeArg('binder_add_section') +EventTypeArg.binder_remove_page = EventTypeArg('binder_remove_page') +EventTypeArg.binder_remove_section = EventTypeArg('binder_remove_section') +EventTypeArg.binder_rename_page = EventTypeArg('binder_rename_page') +EventTypeArg.binder_rename_section = EventTypeArg('binder_rename_section') +EventTypeArg.binder_reorder_page = EventTypeArg('binder_reorder_page') +EventTypeArg.binder_reorder_section = EventTypeArg('binder_reorder_section') +EventTypeArg.paper_content_add_member = EventTypeArg('paper_content_add_member') +EventTypeArg.paper_content_add_to_folder = EventTypeArg('paper_content_add_to_folder') +EventTypeArg.paper_content_archive = EventTypeArg('paper_content_archive') +EventTypeArg.paper_content_create = EventTypeArg('paper_content_create') +EventTypeArg.paper_content_permanently_delete = EventTypeArg('paper_content_permanently_delete') +EventTypeArg.paper_content_remove_from_folder = EventTypeArg('paper_content_remove_from_folder') +EventTypeArg.paper_content_remove_member = EventTypeArg('paper_content_remove_member') +EventTypeArg.paper_content_rename = EventTypeArg('paper_content_rename') +EventTypeArg.paper_content_restore = EventTypeArg('paper_content_restore') +EventTypeArg.paper_doc_add_comment = EventTypeArg('paper_doc_add_comment') +EventTypeArg.paper_doc_change_member_role = EventTypeArg('paper_doc_change_member_role') +EventTypeArg.paper_doc_change_sharing_policy = EventTypeArg('paper_doc_change_sharing_policy') +EventTypeArg.paper_doc_change_subscription = EventTypeArg('paper_doc_change_subscription') +EventTypeArg.paper_doc_deleted = EventTypeArg('paper_doc_deleted') +EventTypeArg.paper_doc_delete_comment = EventTypeArg('paper_doc_delete_comment') +EventTypeArg.paper_doc_download = EventTypeArg('paper_doc_download') +EventTypeArg.paper_doc_edit = EventTypeArg('paper_doc_edit') +EventTypeArg.paper_doc_edit_comment = EventTypeArg('paper_doc_edit_comment') +EventTypeArg.paper_doc_followed = EventTypeArg('paper_doc_followed') +EventTypeArg.paper_doc_mention = EventTypeArg('paper_doc_mention') +EventTypeArg.paper_doc_ownership_changed = EventTypeArg('paper_doc_ownership_changed') +EventTypeArg.paper_doc_request_access = EventTypeArg('paper_doc_request_access') +EventTypeArg.paper_doc_resolve_comment = EventTypeArg('paper_doc_resolve_comment') +EventTypeArg.paper_doc_revert = EventTypeArg('paper_doc_revert') +EventTypeArg.paper_doc_slack_share = EventTypeArg('paper_doc_slack_share') +EventTypeArg.paper_doc_team_invite = EventTypeArg('paper_doc_team_invite') +EventTypeArg.paper_doc_trashed = EventTypeArg('paper_doc_trashed') +EventTypeArg.paper_doc_unresolve_comment = EventTypeArg('paper_doc_unresolve_comment') +EventTypeArg.paper_doc_untrashed = EventTypeArg('paper_doc_untrashed') +EventTypeArg.paper_doc_view = EventTypeArg('paper_doc_view') +EventTypeArg.paper_external_view_allow = EventTypeArg('paper_external_view_allow') +EventTypeArg.paper_external_view_default_team = EventTypeArg('paper_external_view_default_team') +EventTypeArg.paper_external_view_forbid = EventTypeArg('paper_external_view_forbid') +EventTypeArg.paper_folder_change_subscription = EventTypeArg('paper_folder_change_subscription') +EventTypeArg.paper_folder_deleted = EventTypeArg('paper_folder_deleted') +EventTypeArg.paper_folder_followed = EventTypeArg('paper_folder_followed') +EventTypeArg.paper_folder_team_invite = EventTypeArg('paper_folder_team_invite') +EventTypeArg.paper_published_link_change_permission = EventTypeArg('paper_published_link_change_permission') +EventTypeArg.paper_published_link_create = EventTypeArg('paper_published_link_create') +EventTypeArg.paper_published_link_disabled = EventTypeArg('paper_published_link_disabled') +EventTypeArg.paper_published_link_view = EventTypeArg('paper_published_link_view') +EventTypeArg.password_change = EventTypeArg('password_change') +EventTypeArg.password_reset = EventTypeArg('password_reset') +EventTypeArg.password_reset_all = EventTypeArg('password_reset_all') +EventTypeArg.emm_create_exceptions_report = EventTypeArg('emm_create_exceptions_report') +EventTypeArg.emm_create_usage_report = EventTypeArg('emm_create_usage_report') +EventTypeArg.export_members_report = EventTypeArg('export_members_report') +EventTypeArg.export_members_report_fail = EventTypeArg('export_members_report_fail') +EventTypeArg.no_expiration_link_gen_create_report = EventTypeArg('no_expiration_link_gen_create_report') +EventTypeArg.no_expiration_link_gen_report_failed = EventTypeArg('no_expiration_link_gen_report_failed') +EventTypeArg.no_password_link_gen_create_report = EventTypeArg('no_password_link_gen_create_report') +EventTypeArg.no_password_link_gen_report_failed = EventTypeArg('no_password_link_gen_report_failed') +EventTypeArg.no_password_link_view_create_report = EventTypeArg('no_password_link_view_create_report') +EventTypeArg.no_password_link_view_report_failed = EventTypeArg('no_password_link_view_report_failed') +EventTypeArg.outdated_link_view_create_report = EventTypeArg('outdated_link_view_create_report') +EventTypeArg.outdated_link_view_report_failed = EventTypeArg('outdated_link_view_report_failed') +EventTypeArg.paper_admin_export_start = EventTypeArg('paper_admin_export_start') +EventTypeArg.smart_sync_create_admin_privilege_report = EventTypeArg('smart_sync_create_admin_privilege_report') +EventTypeArg.team_activity_create_report = EventTypeArg('team_activity_create_report') +EventTypeArg.team_activity_create_report_fail = EventTypeArg('team_activity_create_report_fail') +EventTypeArg.collection_share = EventTypeArg('collection_share') +EventTypeArg.file_transfers_file_add = EventTypeArg('file_transfers_file_add') +EventTypeArg.file_transfers_transfer_delete = EventTypeArg('file_transfers_transfer_delete') +EventTypeArg.file_transfers_transfer_download = EventTypeArg('file_transfers_transfer_download') +EventTypeArg.file_transfers_transfer_send = EventTypeArg('file_transfers_transfer_send') +EventTypeArg.file_transfers_transfer_view = EventTypeArg('file_transfers_transfer_view') +EventTypeArg.note_acl_invite_only = EventTypeArg('note_acl_invite_only') +EventTypeArg.note_acl_link = EventTypeArg('note_acl_link') +EventTypeArg.note_acl_team_link = EventTypeArg('note_acl_team_link') +EventTypeArg.note_shared = EventTypeArg('note_shared') +EventTypeArg.note_share_receive = EventTypeArg('note_share_receive') +EventTypeArg.open_note_shared = EventTypeArg('open_note_shared') +EventTypeArg.sf_add_group = EventTypeArg('sf_add_group') +EventTypeArg.sf_allow_non_members_to_view_shared_links = EventTypeArg('sf_allow_non_members_to_view_shared_links') +EventTypeArg.sf_external_invite_warn = EventTypeArg('sf_external_invite_warn') +EventTypeArg.sf_fb_invite = EventTypeArg('sf_fb_invite') +EventTypeArg.sf_fb_invite_change_role = EventTypeArg('sf_fb_invite_change_role') +EventTypeArg.sf_fb_uninvite = EventTypeArg('sf_fb_uninvite') +EventTypeArg.sf_invite_group = EventTypeArg('sf_invite_group') +EventTypeArg.sf_team_grant_access = EventTypeArg('sf_team_grant_access') +EventTypeArg.sf_team_invite = EventTypeArg('sf_team_invite') +EventTypeArg.sf_team_invite_change_role = EventTypeArg('sf_team_invite_change_role') +EventTypeArg.sf_team_join = EventTypeArg('sf_team_join') +EventTypeArg.sf_team_join_from_oob_link = EventTypeArg('sf_team_join_from_oob_link') +EventTypeArg.sf_team_uninvite = EventTypeArg('sf_team_uninvite') +EventTypeArg.shared_content_add_invitees = EventTypeArg('shared_content_add_invitees') +EventTypeArg.shared_content_add_link_expiry = EventTypeArg('shared_content_add_link_expiry') +EventTypeArg.shared_content_add_link_password = EventTypeArg('shared_content_add_link_password') +EventTypeArg.shared_content_add_member = EventTypeArg('shared_content_add_member') +EventTypeArg.shared_content_change_downloads_policy = EventTypeArg('shared_content_change_downloads_policy') +EventTypeArg.shared_content_change_invitee_role = EventTypeArg('shared_content_change_invitee_role') +EventTypeArg.shared_content_change_link_audience = EventTypeArg('shared_content_change_link_audience') +EventTypeArg.shared_content_change_link_expiry = EventTypeArg('shared_content_change_link_expiry') +EventTypeArg.shared_content_change_link_password = EventTypeArg('shared_content_change_link_password') +EventTypeArg.shared_content_change_member_role = EventTypeArg('shared_content_change_member_role') +EventTypeArg.shared_content_change_viewer_info_policy = EventTypeArg('shared_content_change_viewer_info_policy') +EventTypeArg.shared_content_claim_invitation = EventTypeArg('shared_content_claim_invitation') +EventTypeArg.shared_content_copy = EventTypeArg('shared_content_copy') +EventTypeArg.shared_content_download = EventTypeArg('shared_content_download') +EventTypeArg.shared_content_relinquish_membership = EventTypeArg('shared_content_relinquish_membership') +EventTypeArg.shared_content_remove_invitees = EventTypeArg('shared_content_remove_invitees') +EventTypeArg.shared_content_remove_link_expiry = EventTypeArg('shared_content_remove_link_expiry') +EventTypeArg.shared_content_remove_link_password = EventTypeArg('shared_content_remove_link_password') +EventTypeArg.shared_content_remove_member = EventTypeArg('shared_content_remove_member') +EventTypeArg.shared_content_request_access = EventTypeArg('shared_content_request_access') +EventTypeArg.shared_content_restore_invitees = EventTypeArg('shared_content_restore_invitees') +EventTypeArg.shared_content_restore_member = EventTypeArg('shared_content_restore_member') +EventTypeArg.shared_content_unshare = EventTypeArg('shared_content_unshare') +EventTypeArg.shared_content_view = EventTypeArg('shared_content_view') +EventTypeArg.shared_folder_change_link_policy = EventTypeArg('shared_folder_change_link_policy') +EventTypeArg.shared_folder_change_members_inheritance_policy = EventTypeArg('shared_folder_change_members_inheritance_policy') +EventTypeArg.shared_folder_change_members_management_policy = EventTypeArg('shared_folder_change_members_management_policy') +EventTypeArg.shared_folder_change_members_policy = EventTypeArg('shared_folder_change_members_policy') +EventTypeArg.shared_folder_create = EventTypeArg('shared_folder_create') +EventTypeArg.shared_folder_decline_invitation = EventTypeArg('shared_folder_decline_invitation') +EventTypeArg.shared_folder_mount = EventTypeArg('shared_folder_mount') +EventTypeArg.shared_folder_nest = EventTypeArg('shared_folder_nest') +EventTypeArg.shared_folder_transfer_ownership = EventTypeArg('shared_folder_transfer_ownership') +EventTypeArg.shared_folder_unmount = EventTypeArg('shared_folder_unmount') +EventTypeArg.shared_link_add_expiry = EventTypeArg('shared_link_add_expiry') +EventTypeArg.shared_link_change_expiry = EventTypeArg('shared_link_change_expiry') +EventTypeArg.shared_link_change_visibility = EventTypeArg('shared_link_change_visibility') +EventTypeArg.shared_link_copy = EventTypeArg('shared_link_copy') +EventTypeArg.shared_link_create = EventTypeArg('shared_link_create') +EventTypeArg.shared_link_disable = EventTypeArg('shared_link_disable') +EventTypeArg.shared_link_download = EventTypeArg('shared_link_download') +EventTypeArg.shared_link_remove_expiry = EventTypeArg('shared_link_remove_expiry') +EventTypeArg.shared_link_settings_add_expiration = EventTypeArg('shared_link_settings_add_expiration') +EventTypeArg.shared_link_settings_add_password = EventTypeArg('shared_link_settings_add_password') +EventTypeArg.shared_link_settings_allow_download_disabled = EventTypeArg('shared_link_settings_allow_download_disabled') +EventTypeArg.shared_link_settings_allow_download_enabled = EventTypeArg('shared_link_settings_allow_download_enabled') +EventTypeArg.shared_link_settings_change_audience = EventTypeArg('shared_link_settings_change_audience') +EventTypeArg.shared_link_settings_change_expiration = EventTypeArg('shared_link_settings_change_expiration') +EventTypeArg.shared_link_settings_change_password = EventTypeArg('shared_link_settings_change_password') +EventTypeArg.shared_link_settings_remove_expiration = EventTypeArg('shared_link_settings_remove_expiration') +EventTypeArg.shared_link_settings_remove_password = EventTypeArg('shared_link_settings_remove_password') +EventTypeArg.shared_link_share = EventTypeArg('shared_link_share') +EventTypeArg.shared_link_view = EventTypeArg('shared_link_view') +EventTypeArg.shared_note_opened = EventTypeArg('shared_note_opened') +EventTypeArg.shmodel_group_share = EventTypeArg('shmodel_group_share') +EventTypeArg.showcase_access_granted = EventTypeArg('showcase_access_granted') +EventTypeArg.showcase_add_member = EventTypeArg('showcase_add_member') +EventTypeArg.showcase_archived = EventTypeArg('showcase_archived') +EventTypeArg.showcase_created = EventTypeArg('showcase_created') +EventTypeArg.showcase_delete_comment = EventTypeArg('showcase_delete_comment') +EventTypeArg.showcase_edited = EventTypeArg('showcase_edited') +EventTypeArg.showcase_edit_comment = EventTypeArg('showcase_edit_comment') +EventTypeArg.showcase_file_added = EventTypeArg('showcase_file_added') +EventTypeArg.showcase_file_download = EventTypeArg('showcase_file_download') +EventTypeArg.showcase_file_removed = EventTypeArg('showcase_file_removed') +EventTypeArg.showcase_file_view = EventTypeArg('showcase_file_view') +EventTypeArg.showcase_permanently_deleted = EventTypeArg('showcase_permanently_deleted') +EventTypeArg.showcase_post_comment = EventTypeArg('showcase_post_comment') +EventTypeArg.showcase_remove_member = EventTypeArg('showcase_remove_member') +EventTypeArg.showcase_renamed = EventTypeArg('showcase_renamed') +EventTypeArg.showcase_request_access = EventTypeArg('showcase_request_access') +EventTypeArg.showcase_resolve_comment = EventTypeArg('showcase_resolve_comment') +EventTypeArg.showcase_restored = EventTypeArg('showcase_restored') +EventTypeArg.showcase_trashed = EventTypeArg('showcase_trashed') +EventTypeArg.showcase_trashed_deprecated = EventTypeArg('showcase_trashed_deprecated') +EventTypeArg.showcase_unresolve_comment = EventTypeArg('showcase_unresolve_comment') +EventTypeArg.showcase_untrashed = EventTypeArg('showcase_untrashed') +EventTypeArg.showcase_untrashed_deprecated = EventTypeArg('showcase_untrashed_deprecated') +EventTypeArg.showcase_view = EventTypeArg('showcase_view') +EventTypeArg.sso_add_cert = EventTypeArg('sso_add_cert') +EventTypeArg.sso_add_login_url = EventTypeArg('sso_add_login_url') +EventTypeArg.sso_add_logout_url = EventTypeArg('sso_add_logout_url') +EventTypeArg.sso_change_cert = EventTypeArg('sso_change_cert') +EventTypeArg.sso_change_login_url = EventTypeArg('sso_change_login_url') +EventTypeArg.sso_change_logout_url = EventTypeArg('sso_change_logout_url') +EventTypeArg.sso_change_saml_identity_mode = EventTypeArg('sso_change_saml_identity_mode') +EventTypeArg.sso_remove_cert = EventTypeArg('sso_remove_cert') +EventTypeArg.sso_remove_login_url = EventTypeArg('sso_remove_login_url') +EventTypeArg.sso_remove_logout_url = EventTypeArg('sso_remove_logout_url') +EventTypeArg.team_folder_change_status = EventTypeArg('team_folder_change_status') +EventTypeArg.team_folder_create = EventTypeArg('team_folder_create') +EventTypeArg.team_folder_downgrade = EventTypeArg('team_folder_downgrade') +EventTypeArg.team_folder_permanently_delete = EventTypeArg('team_folder_permanently_delete') +EventTypeArg.team_folder_rename = EventTypeArg('team_folder_rename') +EventTypeArg.team_selective_sync_settings_changed = EventTypeArg('team_selective_sync_settings_changed') +EventTypeArg.account_capture_change_policy = EventTypeArg('account_capture_change_policy') +EventTypeArg.allow_download_disabled = EventTypeArg('allow_download_disabled') +EventTypeArg.allow_download_enabled = EventTypeArg('allow_download_enabled') +EventTypeArg.camera_uploads_policy_changed = EventTypeArg('camera_uploads_policy_changed') +EventTypeArg.data_placement_restriction_change_policy = EventTypeArg('data_placement_restriction_change_policy') +EventTypeArg.data_placement_restriction_satisfy_policy = EventTypeArg('data_placement_restriction_satisfy_policy') +EventTypeArg.device_approvals_add_exception = EventTypeArg('device_approvals_add_exception') +EventTypeArg.device_approvals_change_desktop_policy = EventTypeArg('device_approvals_change_desktop_policy') +EventTypeArg.device_approvals_change_mobile_policy = EventTypeArg('device_approvals_change_mobile_policy') +EventTypeArg.device_approvals_change_overage_action = EventTypeArg('device_approvals_change_overage_action') +EventTypeArg.device_approvals_change_unlink_action = EventTypeArg('device_approvals_change_unlink_action') +EventTypeArg.device_approvals_remove_exception = EventTypeArg('device_approvals_remove_exception') +EventTypeArg.directory_restrictions_add_members = EventTypeArg('directory_restrictions_add_members') +EventTypeArg.directory_restrictions_remove_members = EventTypeArg('directory_restrictions_remove_members') +EventTypeArg.emm_add_exception = EventTypeArg('emm_add_exception') +EventTypeArg.emm_change_policy = EventTypeArg('emm_change_policy') +EventTypeArg.emm_remove_exception = EventTypeArg('emm_remove_exception') +EventTypeArg.extended_version_history_change_policy = EventTypeArg('extended_version_history_change_policy') +EventTypeArg.file_comments_change_policy = EventTypeArg('file_comments_change_policy') +EventTypeArg.file_locking_policy_changed = EventTypeArg('file_locking_policy_changed') +EventTypeArg.file_requests_change_policy = EventTypeArg('file_requests_change_policy') +EventTypeArg.file_requests_emails_enabled = EventTypeArg('file_requests_emails_enabled') +EventTypeArg.file_requests_emails_restricted_to_team_only = EventTypeArg('file_requests_emails_restricted_to_team_only') +EventTypeArg.file_transfers_policy_changed = EventTypeArg('file_transfers_policy_changed') +EventTypeArg.google_sso_change_policy = EventTypeArg('google_sso_change_policy') +EventTypeArg.group_user_management_change_policy = EventTypeArg('group_user_management_change_policy') +EventTypeArg.integration_policy_changed = EventTypeArg('integration_policy_changed') +EventTypeArg.member_requests_change_policy = EventTypeArg('member_requests_change_policy') +EventTypeArg.member_send_invite_policy_changed = EventTypeArg('member_send_invite_policy_changed') +EventTypeArg.member_space_limits_add_exception = EventTypeArg('member_space_limits_add_exception') +EventTypeArg.member_space_limits_change_caps_type_policy = EventTypeArg('member_space_limits_change_caps_type_policy') +EventTypeArg.member_space_limits_change_policy = EventTypeArg('member_space_limits_change_policy') +EventTypeArg.member_space_limits_remove_exception = EventTypeArg('member_space_limits_remove_exception') +EventTypeArg.member_suggestions_change_policy = EventTypeArg('member_suggestions_change_policy') +EventTypeArg.microsoft_office_addin_change_policy = EventTypeArg('microsoft_office_addin_change_policy') +EventTypeArg.network_control_change_policy = EventTypeArg('network_control_change_policy') +EventTypeArg.paper_change_deployment_policy = EventTypeArg('paper_change_deployment_policy') +EventTypeArg.paper_change_member_link_policy = EventTypeArg('paper_change_member_link_policy') +EventTypeArg.paper_change_member_policy = EventTypeArg('paper_change_member_policy') +EventTypeArg.paper_change_policy = EventTypeArg('paper_change_policy') +EventTypeArg.paper_default_folder_policy_changed = EventTypeArg('paper_default_folder_policy_changed') +EventTypeArg.paper_desktop_policy_changed = EventTypeArg('paper_desktop_policy_changed') +EventTypeArg.paper_enabled_users_group_addition = EventTypeArg('paper_enabled_users_group_addition') +EventTypeArg.paper_enabled_users_group_removal = EventTypeArg('paper_enabled_users_group_removal') +EventTypeArg.password_strength_requirements_change_policy = EventTypeArg('password_strength_requirements_change_policy') +EventTypeArg.permanent_delete_change_policy = EventTypeArg('permanent_delete_change_policy') +EventTypeArg.reseller_support_change_policy = EventTypeArg('reseller_support_change_policy') +EventTypeArg.rewind_policy_changed = EventTypeArg('rewind_policy_changed') +EventTypeArg.sharing_change_folder_join_policy = EventTypeArg('sharing_change_folder_join_policy') +EventTypeArg.sharing_change_link_policy = EventTypeArg('sharing_change_link_policy') +EventTypeArg.sharing_change_member_policy = EventTypeArg('sharing_change_member_policy') +EventTypeArg.showcase_change_download_policy = EventTypeArg('showcase_change_download_policy') +EventTypeArg.showcase_change_enabled_policy = EventTypeArg('showcase_change_enabled_policy') +EventTypeArg.showcase_change_external_sharing_policy = EventTypeArg('showcase_change_external_sharing_policy') +EventTypeArg.smarter_smart_sync_policy_changed = EventTypeArg('smarter_smart_sync_policy_changed') +EventTypeArg.smart_sync_change_policy = EventTypeArg('smart_sync_change_policy') +EventTypeArg.smart_sync_not_opt_out = EventTypeArg('smart_sync_not_opt_out') +EventTypeArg.smart_sync_opt_out = EventTypeArg('smart_sync_opt_out') +EventTypeArg.sso_change_policy = EventTypeArg('sso_change_policy') +EventTypeArg.team_extensions_policy_changed = EventTypeArg('team_extensions_policy_changed') +EventTypeArg.team_selective_sync_policy_changed = EventTypeArg('team_selective_sync_policy_changed') +EventTypeArg.team_sharing_whitelist_subjects_changed = EventTypeArg('team_sharing_whitelist_subjects_changed') +EventTypeArg.tfa_add_exception = EventTypeArg('tfa_add_exception') +EventTypeArg.tfa_change_policy = EventTypeArg('tfa_change_policy') +EventTypeArg.tfa_remove_exception = EventTypeArg('tfa_remove_exception') +EventTypeArg.two_account_change_policy = EventTypeArg('two_account_change_policy') +EventTypeArg.viewer_info_policy_changed = EventTypeArg('viewer_info_policy_changed') +EventTypeArg.watermarking_policy_changed = EventTypeArg('watermarking_policy_changed') +EventTypeArg.web_sessions_change_active_session_limit = EventTypeArg('web_sessions_change_active_session_limit') +EventTypeArg.web_sessions_change_fixed_length_policy = EventTypeArg('web_sessions_change_fixed_length_policy') +EventTypeArg.web_sessions_change_idle_length_policy = EventTypeArg('web_sessions_change_idle_length_policy') +EventTypeArg.team_merge_from = EventTypeArg('team_merge_from') +EventTypeArg.team_merge_to = EventTypeArg('team_merge_to') +EventTypeArg.team_profile_add_logo = EventTypeArg('team_profile_add_logo') +EventTypeArg.team_profile_change_default_language = EventTypeArg('team_profile_change_default_language') +EventTypeArg.team_profile_change_logo = EventTypeArg('team_profile_change_logo') +EventTypeArg.team_profile_change_name = EventTypeArg('team_profile_change_name') +EventTypeArg.team_profile_remove_logo = EventTypeArg('team_profile_remove_logo') +EventTypeArg.tfa_add_backup_phone = EventTypeArg('tfa_add_backup_phone') +EventTypeArg.tfa_add_security_key = EventTypeArg('tfa_add_security_key') +EventTypeArg.tfa_change_backup_phone = EventTypeArg('tfa_change_backup_phone') +EventTypeArg.tfa_change_status = EventTypeArg('tfa_change_status') +EventTypeArg.tfa_remove_backup_phone = EventTypeArg('tfa_remove_backup_phone') +EventTypeArg.tfa_remove_security_key = EventTypeArg('tfa_remove_security_key') +EventTypeArg.tfa_reset = EventTypeArg('tfa_reset') +EventTypeArg.changed_enterprise_admin_role = EventTypeArg('changed_enterprise_admin_role') +EventTypeArg.changed_enterprise_connected_team_status = EventTypeArg('changed_enterprise_connected_team_status') +EventTypeArg.ended_enterprise_admin_session = EventTypeArg('ended_enterprise_admin_session') +EventTypeArg.ended_enterprise_admin_session_deprecated = EventTypeArg('ended_enterprise_admin_session_deprecated') +EventTypeArg.enterprise_settings_locking = EventTypeArg('enterprise_settings_locking') +EventTypeArg.guest_admin_change_status = EventTypeArg('guest_admin_change_status') +EventTypeArg.started_enterprise_admin_session = EventTypeArg('started_enterprise_admin_session') +EventTypeArg.team_merge_request_accepted = EventTypeArg('team_merge_request_accepted') +EventTypeArg.team_merge_request_accepted_shown_to_primary_team = EventTypeArg('team_merge_request_accepted_shown_to_primary_team') +EventTypeArg.team_merge_request_accepted_shown_to_secondary_team = EventTypeArg('team_merge_request_accepted_shown_to_secondary_team') +EventTypeArg.team_merge_request_auto_canceled = EventTypeArg('team_merge_request_auto_canceled') +EventTypeArg.team_merge_request_canceled = EventTypeArg('team_merge_request_canceled') +EventTypeArg.team_merge_request_canceled_shown_to_primary_team = EventTypeArg('team_merge_request_canceled_shown_to_primary_team') +EventTypeArg.team_merge_request_canceled_shown_to_secondary_team = EventTypeArg('team_merge_request_canceled_shown_to_secondary_team') +EventTypeArg.team_merge_request_expired = EventTypeArg('team_merge_request_expired') +EventTypeArg.team_merge_request_expired_shown_to_primary_team = EventTypeArg('team_merge_request_expired_shown_to_primary_team') +EventTypeArg.team_merge_request_expired_shown_to_secondary_team = EventTypeArg('team_merge_request_expired_shown_to_secondary_team') +EventTypeArg.team_merge_request_rejected_shown_to_primary_team = EventTypeArg('team_merge_request_rejected_shown_to_primary_team') +EventTypeArg.team_merge_request_rejected_shown_to_secondary_team = EventTypeArg('team_merge_request_rejected_shown_to_secondary_team') +EventTypeArg.team_merge_request_reminder = EventTypeArg('team_merge_request_reminder') +EventTypeArg.team_merge_request_reminder_shown_to_primary_team = EventTypeArg('team_merge_request_reminder_shown_to_primary_team') +EventTypeArg.team_merge_request_reminder_shown_to_secondary_team = EventTypeArg('team_merge_request_reminder_shown_to_secondary_team') +EventTypeArg.team_merge_request_revoked = EventTypeArg('team_merge_request_revoked') +EventTypeArg.team_merge_request_sent_shown_to_primary_team = EventTypeArg('team_merge_request_sent_shown_to_primary_team') +EventTypeArg.team_merge_request_sent_shown_to_secondary_team = EventTypeArg('team_merge_request_sent_shown_to_secondary_team') +EventTypeArg.other = EventTypeArg('other') + ExportMembersReportDetails._all_field_names_ = set([]) ExportMembersReportDetails._all_fields_ = [] +ExportMembersReportFailDetails._failure_reason_validator = team.TeamReportFailureReason_validator +ExportMembersReportFailDetails._all_field_names_ = set(['failure_reason']) +ExportMembersReportFailDetails._all_fields_ = [('failure_reason', ExportMembersReportFailDetails._failure_reason_validator)] + +ExportMembersReportFailType._description_validator = bv.String() +ExportMembersReportFailType._all_field_names_ = set(['description']) +ExportMembersReportFailType._all_fields_ = [('description', ExportMembersReportFailType._description_validator)] + ExportMembersReportType._description_validator = bv.String() ExportMembersReportType._all_field_names_ = set(['description']) ExportMembersReportType._all_fields_ = [('description', ExportMembersReportType._description_validator)] @@ -74214,6 +98377,68 @@ def __repr__(self): ('technical_error_message', FailureDetailsLogInfo._technical_error_message_validator), ] +FedAdminRole._not_enterprise_admin_validator = bv.Void() +FedAdminRole._enterprise_admin_validator = bv.Void() +FedAdminRole._other_validator = bv.Void() +FedAdminRole._tagmap = { + 'not_enterprise_admin': FedAdminRole._not_enterprise_admin_validator, + 'enterprise_admin': FedAdminRole._enterprise_admin_validator, + 'other': FedAdminRole._other_validator, +} + +FedAdminRole.not_enterprise_admin = FedAdminRole('not_enterprise_admin') +FedAdminRole.enterprise_admin = FedAdminRole('enterprise_admin') +FedAdminRole.other = FedAdminRole('other') + +FedExtraDetails._team_validator = TeamDetails_validator +FedExtraDetails._organization_validator = OrganizationDetails_validator +FedExtraDetails._other_validator = bv.Void() +FedExtraDetails._tagmap = { + 'team': FedExtraDetails._team_validator, + 'organization': FedExtraDetails._organization_validator, + 'other': FedExtraDetails._other_validator, +} + +FedExtraDetails.other = FedExtraDetails('other') + +FedHandshakeAction._invited_validator = bv.Void() +FedHandshakeAction._accepted_invite_validator = bv.Void() +FedHandshakeAction._rejected_invite_validator = bv.Void() +FedHandshakeAction._canceled_invite_validator = bv.Void() +FedHandshakeAction._removed_team_validator = bv.Void() +FedHandshakeAction._invite_expired_validator = bv.Void() +FedHandshakeAction._other_validator = bv.Void() +FedHandshakeAction._tagmap = { + 'invited': FedHandshakeAction._invited_validator, + 'accepted_invite': FedHandshakeAction._accepted_invite_validator, + 'rejected_invite': FedHandshakeAction._rejected_invite_validator, + 'canceled_invite': FedHandshakeAction._canceled_invite_validator, + 'removed_team': FedHandshakeAction._removed_team_validator, + 'invite_expired': FedHandshakeAction._invite_expired_validator, + 'other': FedHandshakeAction._other_validator, +} + +FedHandshakeAction.invited = FedHandshakeAction('invited') +FedHandshakeAction.accepted_invite = FedHandshakeAction('accepted_invite') +FedHandshakeAction.rejected_invite = FedHandshakeAction('rejected_invite') +FedHandshakeAction.canceled_invite = FedHandshakeAction('canceled_invite') +FedHandshakeAction.removed_team = FedHandshakeAction('removed_team') +FedHandshakeAction.invite_expired = FedHandshakeAction('invite_expired') +FedHandshakeAction.other = FedHandshakeAction('other') + +FederationStatusChangeAdditionalInfo._connected_team_name_validator = ConnectedTeamName_validator +FederationStatusChangeAdditionalInfo._non_trusted_team_details_validator = NonTrustedTeamDetails_validator +FederationStatusChangeAdditionalInfo._organization_name_validator = OrganizationName_validator +FederationStatusChangeAdditionalInfo._other_validator = bv.Void() +FederationStatusChangeAdditionalInfo._tagmap = { + 'connected_team_name': FederationStatusChangeAdditionalInfo._connected_team_name_validator, + 'non_trusted_team_details': FederationStatusChangeAdditionalInfo._non_trusted_team_details_validator, + 'organization_name': FederationStatusChangeAdditionalInfo._organization_name_validator, + 'other': FederationStatusChangeAdditionalInfo._other_validator, +} + +FederationStatusChangeAdditionalInfo.other = FederationStatusChangeAdditionalInfo('other') + FileAddCommentDetails._comment_text_validator = bv.Nullable(bv.String()) FileAddCommentDetails._all_field_names_ = set(['comment_text']) FileAddCommentDetails._all_fields_ = [('comment_text', FileAddCommentDetails._comment_text_validator)] @@ -74352,18 +98577,51 @@ def __repr__(self): FileLikeCommentType._all_field_names_ = set(['description']) FileLikeCommentType._all_fields_ = [('description', FileLikeCommentType._description_validator)] +FileLockingLockStatusChangedDetails._previous_value_validator = LockStatus_validator +FileLockingLockStatusChangedDetails._new_value_validator = LockStatus_validator +FileLockingLockStatusChangedDetails._all_field_names_ = set([ + 'previous_value', + 'new_value', +]) +FileLockingLockStatusChangedDetails._all_fields_ = [ + ('previous_value', FileLockingLockStatusChangedDetails._previous_value_validator), + ('new_value', FileLockingLockStatusChangedDetails._new_value_validator), +] + +FileLockingLockStatusChangedType._description_validator = bv.String() +FileLockingLockStatusChangedType._all_field_names_ = set(['description']) +FileLockingLockStatusChangedType._all_fields_ = [('description', FileLockingLockStatusChangedType._description_validator)] + +FileLockingPolicyChangedDetails._new_value_validator = team_policies.FileLockingPolicyState_validator +FileLockingPolicyChangedDetails._previous_value_validator = team_policies.FileLockingPolicyState_validator +FileLockingPolicyChangedDetails._all_field_names_ = set([ + 'new_value', + 'previous_value', +]) +FileLockingPolicyChangedDetails._all_fields_ = [ + ('new_value', FileLockingPolicyChangedDetails._new_value_validator), + ('previous_value', FileLockingPolicyChangedDetails._previous_value_validator), +] + +FileLockingPolicyChangedType._description_validator = bv.String() +FileLockingPolicyChangedType._all_field_names_ = set(['description']) +FileLockingPolicyChangedType._all_fields_ = [('description', FileLockingPolicyChangedType._description_validator)] + FileOrFolderLogInfo._path_validator = PathLogInfo_validator FileOrFolderLogInfo._display_name_validator = bv.Nullable(bv.String()) FileOrFolderLogInfo._file_id_validator = bv.Nullable(bv.String()) +FileOrFolderLogInfo._file_size_validator = bv.Nullable(bv.UInt64()) FileOrFolderLogInfo._all_field_names_ = set([ 'path', 'display_name', 'file_id', + 'file_size', ]) FileOrFolderLogInfo._all_fields_ = [ ('path', FileOrFolderLogInfo._path_validator), ('display_name', FileOrFolderLogInfo._display_name_validator), ('file_id', FileOrFolderLogInfo._file_id_validator), + ('file_size', FileOrFolderLogInfo._file_size_validator), ] FileLogInfo._all_field_names_ = FileOrFolderLogInfo._all_field_names_.union(set([])) @@ -74587,6 +98845,74 @@ def __repr__(self): FileSaveCopyReferenceType._all_field_names_ = set(['description']) FileSaveCopyReferenceType._all_fields_ = [('description', FileSaveCopyReferenceType._description_validator)] +FileTransfersFileAddDetails._file_transfer_id_validator = bv.String() +FileTransfersFileAddDetails._all_field_names_ = set(['file_transfer_id']) +FileTransfersFileAddDetails._all_fields_ = [('file_transfer_id', FileTransfersFileAddDetails._file_transfer_id_validator)] + +FileTransfersFileAddType._description_validator = bv.String() +FileTransfersFileAddType._all_field_names_ = set(['description']) +FileTransfersFileAddType._all_fields_ = [('description', FileTransfersFileAddType._description_validator)] + +FileTransfersPolicy._disabled_validator = bv.Void() +FileTransfersPolicy._enabled_validator = bv.Void() +FileTransfersPolicy._other_validator = bv.Void() +FileTransfersPolicy._tagmap = { + 'disabled': FileTransfersPolicy._disabled_validator, + 'enabled': FileTransfersPolicy._enabled_validator, + 'other': FileTransfersPolicy._other_validator, +} + +FileTransfersPolicy.disabled = FileTransfersPolicy('disabled') +FileTransfersPolicy.enabled = FileTransfersPolicy('enabled') +FileTransfersPolicy.other = FileTransfersPolicy('other') + +FileTransfersPolicyChangedDetails._new_value_validator = FileTransfersPolicy_validator +FileTransfersPolicyChangedDetails._previous_value_validator = FileTransfersPolicy_validator +FileTransfersPolicyChangedDetails._all_field_names_ = set([ + 'new_value', + 'previous_value', +]) +FileTransfersPolicyChangedDetails._all_fields_ = [ + ('new_value', FileTransfersPolicyChangedDetails._new_value_validator), + ('previous_value', FileTransfersPolicyChangedDetails._previous_value_validator), +] + +FileTransfersPolicyChangedType._description_validator = bv.String() +FileTransfersPolicyChangedType._all_field_names_ = set(['description']) +FileTransfersPolicyChangedType._all_fields_ = [('description', FileTransfersPolicyChangedType._description_validator)] + +FileTransfersTransferDeleteDetails._file_transfer_id_validator = bv.String() +FileTransfersTransferDeleteDetails._all_field_names_ = set(['file_transfer_id']) +FileTransfersTransferDeleteDetails._all_fields_ = [('file_transfer_id', FileTransfersTransferDeleteDetails._file_transfer_id_validator)] + +FileTransfersTransferDeleteType._description_validator = bv.String() +FileTransfersTransferDeleteType._all_field_names_ = set(['description']) +FileTransfersTransferDeleteType._all_fields_ = [('description', FileTransfersTransferDeleteType._description_validator)] + +FileTransfersTransferDownloadDetails._file_transfer_id_validator = bv.String() +FileTransfersTransferDownloadDetails._all_field_names_ = set(['file_transfer_id']) +FileTransfersTransferDownloadDetails._all_fields_ = [('file_transfer_id', FileTransfersTransferDownloadDetails._file_transfer_id_validator)] + +FileTransfersTransferDownloadType._description_validator = bv.String() +FileTransfersTransferDownloadType._all_field_names_ = set(['description']) +FileTransfersTransferDownloadType._all_fields_ = [('description', FileTransfersTransferDownloadType._description_validator)] + +FileTransfersTransferSendDetails._file_transfer_id_validator = bv.String() +FileTransfersTransferSendDetails._all_field_names_ = set(['file_transfer_id']) +FileTransfersTransferSendDetails._all_fields_ = [('file_transfer_id', FileTransfersTransferSendDetails._file_transfer_id_validator)] + +FileTransfersTransferSendType._description_validator = bv.String() +FileTransfersTransferSendType._all_field_names_ = set(['description']) +FileTransfersTransferSendType._all_fields_ = [('description', FileTransfersTransferSendType._description_validator)] + +FileTransfersTransferViewDetails._file_transfer_id_validator = bv.String() +FileTransfersTransferViewDetails._all_field_names_ = set(['file_transfer_id']) +FileTransfersTransferViewDetails._all_fields_ = [('file_transfer_id', FileTransfersTransferViewDetails._file_transfer_id_validator)] + +FileTransfersTransferViewType._description_validator = bv.String() +FileTransfersTransferViewType._all_field_names_ = set(['description']) +FileTransfersTransferViewType._all_fields_ = [('description', FileTransfersTransferViewType._description_validator)] + FileUnlikeCommentDetails._comment_text_validator = bv.Nullable(bv.String()) FileUnlikeCommentDetails._all_field_names_ = set(['comment_text']) FileUnlikeCommentDetails._all_fields_ = [('comment_text', FileUnlikeCommentDetails._comment_text_validator)] @@ -74603,8 +98929,47 @@ def __repr__(self): FileUnresolveCommentType._all_field_names_ = set(['description']) FileUnresolveCommentType._all_fields_ = [('description', FileUnresolveCommentType._description_validator)] -FolderLogInfo._all_field_names_ = FileOrFolderLogInfo._all_field_names_.union(set([])) -FolderLogInfo._all_fields_ = FileOrFolderLogInfo._all_fields_ + [] +FolderLogInfo._file_count_validator = bv.Nullable(bv.UInt64()) +FolderLogInfo._all_field_names_ = FileOrFolderLogInfo._all_field_names_.union(set(['file_count'])) +FolderLogInfo._all_fields_ = FileOrFolderLogInfo._all_fields_ + [('file_count', FolderLogInfo._file_count_validator)] + +FolderOverviewDescriptionChangedDetails._folder_overview_location_asset_validator = bv.UInt64() +FolderOverviewDescriptionChangedDetails._all_field_names_ = set(['folder_overview_location_asset']) +FolderOverviewDescriptionChangedDetails._all_fields_ = [('folder_overview_location_asset', FolderOverviewDescriptionChangedDetails._folder_overview_location_asset_validator)] + +FolderOverviewDescriptionChangedType._description_validator = bv.String() +FolderOverviewDescriptionChangedType._all_field_names_ = set(['description']) +FolderOverviewDescriptionChangedType._all_fields_ = [('description', FolderOverviewDescriptionChangedType._description_validator)] + +FolderOverviewItemPinnedDetails._folder_overview_location_asset_validator = bv.UInt64() +FolderOverviewItemPinnedDetails._pinned_items_asset_indices_validator = bv.List(bv.UInt64()) +FolderOverviewItemPinnedDetails._all_field_names_ = set([ + 'folder_overview_location_asset', + 'pinned_items_asset_indices', +]) +FolderOverviewItemPinnedDetails._all_fields_ = [ + ('folder_overview_location_asset', FolderOverviewItemPinnedDetails._folder_overview_location_asset_validator), + ('pinned_items_asset_indices', FolderOverviewItemPinnedDetails._pinned_items_asset_indices_validator), +] + +FolderOverviewItemPinnedType._description_validator = bv.String() +FolderOverviewItemPinnedType._all_field_names_ = set(['description']) +FolderOverviewItemPinnedType._all_fields_ = [('description', FolderOverviewItemPinnedType._description_validator)] + +FolderOverviewItemUnpinnedDetails._folder_overview_location_asset_validator = bv.UInt64() +FolderOverviewItemUnpinnedDetails._pinned_items_asset_indices_validator = bv.List(bv.UInt64()) +FolderOverviewItemUnpinnedDetails._all_field_names_ = set([ + 'folder_overview_location_asset', + 'pinned_items_asset_indices', +]) +FolderOverviewItemUnpinnedDetails._all_fields_ = [ + ('folder_overview_location_asset', FolderOverviewItemUnpinnedDetails._folder_overview_location_asset_validator), + ('pinned_items_asset_indices', FolderOverviewItemUnpinnedDetails._pinned_items_asset_indices_validator), +] + +FolderOverviewItemUnpinnedType._description_validator = bv.String() +FolderOverviewItemUnpinnedType._all_field_names_ = set(['description']) +FolderOverviewItemUnpinnedType._all_fields_ = [('description', FolderOverviewItemUnpinnedType._description_validator)] GeoLocationLogInfo._city_validator = bv.Nullable(bv.String()) GeoLocationLogInfo._region_validator = bv.Nullable(bv.String()) @@ -74627,17 +98992,20 @@ def __repr__(self): GetTeamEventsArg._account_id_validator = bv.Nullable(users_common.AccountId_validator) GetTeamEventsArg._time_validator = bv.Nullable(team_common.TimeRange_validator) GetTeamEventsArg._category_validator = bv.Nullable(EventCategory_validator) +GetTeamEventsArg._event_type_validator = bv.Nullable(EventTypeArg_validator) GetTeamEventsArg._all_field_names_ = set([ 'limit', 'account_id', 'time', 'category', + 'event_type', ]) GetTeamEventsArg._all_fields_ = [ ('limit', GetTeamEventsArg._limit_validator), ('account_id', GetTeamEventsArg._account_id_validator), ('time', GetTeamEventsArg._time_validator), ('category', GetTeamEventsArg._category_validator), + ('event_type', GetTeamEventsArg._event_type_validator), ] GetTeamEventsContinueArg._cursor_validator = bv.String() @@ -74658,15 +99026,18 @@ def __repr__(self): GetTeamEventsError._account_id_not_found_validator = bv.Void() GetTeamEventsError._invalid_time_range_validator = bv.Void() +GetTeamEventsError._invalid_filters_validator = bv.Void() GetTeamEventsError._other_validator = bv.Void() GetTeamEventsError._tagmap = { 'account_id_not_found': GetTeamEventsError._account_id_not_found_validator, 'invalid_time_range': GetTeamEventsError._invalid_time_range_validator, + 'invalid_filters': GetTeamEventsError._invalid_filters_validator, 'other': GetTeamEventsError._other_validator, } GetTeamEventsError.account_id_not_found = GetTeamEventsError('account_id_not_found') GetTeamEventsError.invalid_time_range = GetTeamEventsError('invalid_time_range') +GetTeamEventsError.invalid_filters = GetTeamEventsError('invalid_filters') GetTeamEventsError.other = GetTeamEventsError('other') GetTeamEventsResult._events_validator = bv.List(TeamEvent_validator) @@ -75006,18 +99377,46 @@ def __repr__(self): IntegrationPolicyChangedType._all_field_names_ = set(['description']) IntegrationPolicyChangedType._all_fields_ = [('description', IntegrationPolicyChangedType._description_validator)] +InviteMethod._invite_link_validator = bv.Void() +InviteMethod._other_validator = bv.Void() +InviteMethod._tagmap = { + 'invite_link': InviteMethod._invite_link_validator, + 'other': InviteMethod._other_validator, +} + +InviteMethod.invite_link = InviteMethod('invite_link') +InviteMethod.other = InviteMethod('other') + JoinTeamDetails._linked_apps_validator = bv.List(UserLinkedAppLogInfo_validator) JoinTeamDetails._linked_devices_validator = bv.List(LinkedDeviceLogInfo_validator) JoinTeamDetails._linked_shared_folders_validator = bv.List(FolderLogInfo_validator) +JoinTeamDetails._was_linked_apps_truncated_validator = bv.Nullable(bv.Boolean()) +JoinTeamDetails._was_linked_devices_truncated_validator = bv.Nullable(bv.Boolean()) +JoinTeamDetails._was_linked_shared_folders_truncated_validator = bv.Nullable(bv.Boolean()) +JoinTeamDetails._has_linked_apps_validator = bv.Nullable(bv.Boolean()) +JoinTeamDetails._has_linked_devices_validator = bv.Nullable(bv.Boolean()) +JoinTeamDetails._has_linked_shared_folders_validator = bv.Nullable(bv.Boolean()) JoinTeamDetails._all_field_names_ = set([ 'linked_apps', 'linked_devices', 'linked_shared_folders', + 'was_linked_apps_truncated', + 'was_linked_devices_truncated', + 'was_linked_shared_folders_truncated', + 'has_linked_apps', + 'has_linked_devices', + 'has_linked_shared_folders', ]) JoinTeamDetails._all_fields_ = [ ('linked_apps', JoinTeamDetails._linked_apps_validator), ('linked_devices', JoinTeamDetails._linked_devices_validator), ('linked_shared_folders', JoinTeamDetails._linked_shared_folders_validator), + ('was_linked_apps_truncated', JoinTeamDetails._was_linked_apps_truncated_validator), + ('was_linked_devices_truncated', JoinTeamDetails._was_linked_devices_truncated_validator), + ('was_linked_shared_folders_truncated', JoinTeamDetails._was_linked_shared_folders_truncated_validator), + ('has_linked_apps', JoinTeamDetails._has_linked_apps_validator), + ('has_linked_devices', JoinTeamDetails._has_linked_devices_validator), + ('has_linked_shared_folders', JoinTeamDetails._has_linked_shared_folders_validator), ] LegacyDeviceSessionLogInfo._session_info_validator = bv.Nullable(SessionLogInfo_validator) @@ -75054,6 +99453,204 @@ def __repr__(self): ] LegacyDeviceSessionLogInfo._all_fields_ = DeviceSessionLogInfo._all_fields_ + LegacyDeviceSessionLogInfo._fields_ +LegalHoldsActivateAHoldDetails._legal_hold_id_validator = bv.String() +LegalHoldsActivateAHoldDetails._name_validator = bv.String() +LegalHoldsActivateAHoldDetails._start_date_validator = common.DropboxTimestamp_validator +LegalHoldsActivateAHoldDetails._end_date_validator = bv.Nullable(common.DropboxTimestamp_validator) +LegalHoldsActivateAHoldDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', + 'start_date', + 'end_date', +]) +LegalHoldsActivateAHoldDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsActivateAHoldDetails._legal_hold_id_validator), + ('name', LegalHoldsActivateAHoldDetails._name_validator), + ('start_date', LegalHoldsActivateAHoldDetails._start_date_validator), + ('end_date', LegalHoldsActivateAHoldDetails._end_date_validator), +] + +LegalHoldsActivateAHoldType._description_validator = bv.String() +LegalHoldsActivateAHoldType._all_field_names_ = set(['description']) +LegalHoldsActivateAHoldType._all_fields_ = [('description', LegalHoldsActivateAHoldType._description_validator)] + +LegalHoldsAddMembersDetails._legal_hold_id_validator = bv.String() +LegalHoldsAddMembersDetails._name_validator = bv.String() +LegalHoldsAddMembersDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', +]) +LegalHoldsAddMembersDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsAddMembersDetails._legal_hold_id_validator), + ('name', LegalHoldsAddMembersDetails._name_validator), +] + +LegalHoldsAddMembersType._description_validator = bv.String() +LegalHoldsAddMembersType._all_field_names_ = set(['description']) +LegalHoldsAddMembersType._all_fields_ = [('description', LegalHoldsAddMembersType._description_validator)] + +LegalHoldsChangeHoldDetailsDetails._legal_hold_id_validator = bv.String() +LegalHoldsChangeHoldDetailsDetails._name_validator = bv.String() +LegalHoldsChangeHoldDetailsDetails._previous_value_validator = bv.String() +LegalHoldsChangeHoldDetailsDetails._new_value_validator = bv.String() +LegalHoldsChangeHoldDetailsDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', + 'previous_value', + 'new_value', +]) +LegalHoldsChangeHoldDetailsDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsChangeHoldDetailsDetails._legal_hold_id_validator), + ('name', LegalHoldsChangeHoldDetailsDetails._name_validator), + ('previous_value', LegalHoldsChangeHoldDetailsDetails._previous_value_validator), + ('new_value', LegalHoldsChangeHoldDetailsDetails._new_value_validator), +] + +LegalHoldsChangeHoldDetailsType._description_validator = bv.String() +LegalHoldsChangeHoldDetailsType._all_field_names_ = set(['description']) +LegalHoldsChangeHoldDetailsType._all_fields_ = [('description', LegalHoldsChangeHoldDetailsType._description_validator)] + +LegalHoldsChangeHoldNameDetails._legal_hold_id_validator = bv.String() +LegalHoldsChangeHoldNameDetails._previous_value_validator = bv.String() +LegalHoldsChangeHoldNameDetails._new_value_validator = bv.String() +LegalHoldsChangeHoldNameDetails._all_field_names_ = set([ + 'legal_hold_id', + 'previous_value', + 'new_value', +]) +LegalHoldsChangeHoldNameDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsChangeHoldNameDetails._legal_hold_id_validator), + ('previous_value', LegalHoldsChangeHoldNameDetails._previous_value_validator), + ('new_value', LegalHoldsChangeHoldNameDetails._new_value_validator), +] + +LegalHoldsChangeHoldNameType._description_validator = bv.String() +LegalHoldsChangeHoldNameType._all_field_names_ = set(['description']) +LegalHoldsChangeHoldNameType._all_fields_ = [('description', LegalHoldsChangeHoldNameType._description_validator)] + +LegalHoldsExportAHoldDetails._legal_hold_id_validator = bv.String() +LegalHoldsExportAHoldDetails._name_validator = bv.String() +LegalHoldsExportAHoldDetails._export_name_validator = bv.Nullable(bv.String()) +LegalHoldsExportAHoldDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', + 'export_name', +]) +LegalHoldsExportAHoldDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsExportAHoldDetails._legal_hold_id_validator), + ('name', LegalHoldsExportAHoldDetails._name_validator), + ('export_name', LegalHoldsExportAHoldDetails._export_name_validator), +] + +LegalHoldsExportAHoldType._description_validator = bv.String() +LegalHoldsExportAHoldType._all_field_names_ = set(['description']) +LegalHoldsExportAHoldType._all_fields_ = [('description', LegalHoldsExportAHoldType._description_validator)] + +LegalHoldsExportCancelledDetails._legal_hold_id_validator = bv.String() +LegalHoldsExportCancelledDetails._name_validator = bv.String() +LegalHoldsExportCancelledDetails._export_name_validator = bv.String() +LegalHoldsExportCancelledDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', + 'export_name', +]) +LegalHoldsExportCancelledDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsExportCancelledDetails._legal_hold_id_validator), + ('name', LegalHoldsExportCancelledDetails._name_validator), + ('export_name', LegalHoldsExportCancelledDetails._export_name_validator), +] + +LegalHoldsExportCancelledType._description_validator = bv.String() +LegalHoldsExportCancelledType._all_field_names_ = set(['description']) +LegalHoldsExportCancelledType._all_fields_ = [('description', LegalHoldsExportCancelledType._description_validator)] + +LegalHoldsExportDownloadedDetails._legal_hold_id_validator = bv.String() +LegalHoldsExportDownloadedDetails._name_validator = bv.String() +LegalHoldsExportDownloadedDetails._export_name_validator = bv.String() +LegalHoldsExportDownloadedDetails._part_validator = bv.Nullable(bv.String()) +LegalHoldsExportDownloadedDetails._file_name_validator = bv.Nullable(bv.String()) +LegalHoldsExportDownloadedDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', + 'export_name', + 'part', + 'file_name', +]) +LegalHoldsExportDownloadedDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsExportDownloadedDetails._legal_hold_id_validator), + ('name', LegalHoldsExportDownloadedDetails._name_validator), + ('export_name', LegalHoldsExportDownloadedDetails._export_name_validator), + ('part', LegalHoldsExportDownloadedDetails._part_validator), + ('file_name', LegalHoldsExportDownloadedDetails._file_name_validator), +] + +LegalHoldsExportDownloadedType._description_validator = bv.String() +LegalHoldsExportDownloadedType._all_field_names_ = set(['description']) +LegalHoldsExportDownloadedType._all_fields_ = [('description', LegalHoldsExportDownloadedType._description_validator)] + +LegalHoldsExportRemovedDetails._legal_hold_id_validator = bv.String() +LegalHoldsExportRemovedDetails._name_validator = bv.String() +LegalHoldsExportRemovedDetails._export_name_validator = bv.String() +LegalHoldsExportRemovedDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', + 'export_name', +]) +LegalHoldsExportRemovedDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsExportRemovedDetails._legal_hold_id_validator), + ('name', LegalHoldsExportRemovedDetails._name_validator), + ('export_name', LegalHoldsExportRemovedDetails._export_name_validator), +] + +LegalHoldsExportRemovedType._description_validator = bv.String() +LegalHoldsExportRemovedType._all_field_names_ = set(['description']) +LegalHoldsExportRemovedType._all_fields_ = [('description', LegalHoldsExportRemovedType._description_validator)] + +LegalHoldsReleaseAHoldDetails._legal_hold_id_validator = bv.String() +LegalHoldsReleaseAHoldDetails._name_validator = bv.String() +LegalHoldsReleaseAHoldDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', +]) +LegalHoldsReleaseAHoldDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsReleaseAHoldDetails._legal_hold_id_validator), + ('name', LegalHoldsReleaseAHoldDetails._name_validator), +] + +LegalHoldsReleaseAHoldType._description_validator = bv.String() +LegalHoldsReleaseAHoldType._all_field_names_ = set(['description']) +LegalHoldsReleaseAHoldType._all_fields_ = [('description', LegalHoldsReleaseAHoldType._description_validator)] + +LegalHoldsRemoveMembersDetails._legal_hold_id_validator = bv.String() +LegalHoldsRemoveMembersDetails._name_validator = bv.String() +LegalHoldsRemoveMembersDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', +]) +LegalHoldsRemoveMembersDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsRemoveMembersDetails._legal_hold_id_validator), + ('name', LegalHoldsRemoveMembersDetails._name_validator), +] + +LegalHoldsRemoveMembersType._description_validator = bv.String() +LegalHoldsRemoveMembersType._all_field_names_ = set(['description']) +LegalHoldsRemoveMembersType._all_fields_ = [('description', LegalHoldsRemoveMembersType._description_validator)] + +LegalHoldsReportAHoldDetails._legal_hold_id_validator = bv.String() +LegalHoldsReportAHoldDetails._name_validator = bv.String() +LegalHoldsReportAHoldDetails._all_field_names_ = set([ + 'legal_hold_id', + 'name', +]) +LegalHoldsReportAHoldDetails._all_fields_ = [ + ('legal_hold_id', LegalHoldsReportAHoldDetails._legal_hold_id_validator), + ('name', LegalHoldsReportAHoldDetails._name_validator), +] + +LegalHoldsReportAHoldType._description_validator = bv.String() +LegalHoldsReportAHoldType._all_field_names_ = set(['description']) +LegalHoldsReportAHoldType._all_fields_ = [('description', LegalHoldsReportAHoldType._description_validator)] + LinkedDeviceLogInfo._mobile_device_session_validator = MobileDeviceSessionLogInfo_validator LinkedDeviceLogInfo._desktop_device_session_validator = DesktopDeviceSessionLogInfo_validator LinkedDeviceLogInfo._web_device_session_validator = WebDeviceSessionLogInfo_validator @@ -75069,6 +99666,19 @@ def __repr__(self): LinkedDeviceLogInfo.other = LinkedDeviceLogInfo('other') +LockStatus._locked_validator = bv.Void() +LockStatus._unlocked_validator = bv.Void() +LockStatus._other_validator = bv.Void() +LockStatus._tagmap = { + 'locked': LockStatus._locked_validator, + 'unlocked': LockStatus._unlocked_validator, + 'other': LockStatus._other_validator, +} + +LockStatus.locked = LockStatus('locked') +LockStatus.unlocked = LockStatus('unlocked') +LockStatus.other = LockStatus('other') + LoginFailDetails._is_emm_managed_validator = bv.Nullable(bv.Boolean()) LoginFailDetails._login_method_validator = LoginMethod_validator LoginFailDetails._error_details_validator = FailureDetailsLogInfo_validator @@ -75091,12 +99701,20 @@ def __repr__(self): LoginMethod._two_factor_authentication_validator = bv.Void() LoginMethod._saml_validator = bv.Void() LoginMethod._google_oauth_validator = bv.Void() +LoginMethod._web_session_validator = bv.Void() +LoginMethod._qr_code_validator = bv.Void() +LoginMethod._apple_oauth_validator = bv.Void() +LoginMethod._first_party_token_exchange_validator = bv.Void() LoginMethod._other_validator = bv.Void() LoginMethod._tagmap = { 'password': LoginMethod._password_validator, 'two_factor_authentication': LoginMethod._two_factor_authentication_validator, 'saml': LoginMethod._saml_validator, 'google_oauth': LoginMethod._google_oauth_validator, + 'web_session': LoginMethod._web_session_validator, + 'qr_code': LoginMethod._qr_code_validator, + 'apple_oauth': LoginMethod._apple_oauth_validator, + 'first_party_token_exchange': LoginMethod._first_party_token_exchange_validator, 'other': LoginMethod._other_validator, } @@ -75104,6 +99722,10 @@ def __repr__(self): LoginMethod.two_factor_authentication = LoginMethod('two_factor_authentication') LoginMethod.saml = LoginMethod('saml') LoginMethod.google_oauth = LoginMethod('google_oauth') +LoginMethod.web_session = LoginMethod('web_session') +LoginMethod.qr_code = LoginMethod('qr_code') +LoginMethod.apple_oauth = LoginMethod('apple_oauth') +LoginMethod.first_party_token_exchange = LoginMethod('first_party_token_exchange') LoginMethod.other = LoginMethod('other') LoginSuccessDetails._is_emm_managed_validator = bv.Nullable(bv.Boolean()) @@ -75244,6 +99866,13 @@ def __repr__(self): MemberDeleteManualContactsType._all_field_names_ = set(['description']) MemberDeleteManualContactsType._all_fields_ = [('description', MemberDeleteManualContactsType._description_validator)] +MemberDeleteProfilePhotoDetails._all_field_names_ = set([]) +MemberDeleteProfilePhotoDetails._all_fields_ = [] + +MemberDeleteProfilePhotoType._description_validator = bv.String() +MemberDeleteProfilePhotoType._all_field_names_ = set(['description']) +MemberDeleteProfilePhotoType._all_fields_ = [('description', MemberDeleteProfilePhotoType._description_validator)] + MemberPermanentlyDeleteAccountContentsDetails._all_field_names_ = set([]) MemberPermanentlyDeleteAccountContentsDetails._all_fields_ = [] @@ -75309,6 +99938,44 @@ def __repr__(self): MemberRequestsPolicy.require_approval = MemberRequestsPolicy('require_approval') MemberRequestsPolicy.other = MemberRequestsPolicy('other') +MemberSendInvitePolicy._disabled_validator = bv.Void() +MemberSendInvitePolicy._specific_members_validator = bv.Void() +MemberSendInvitePolicy._everyone_validator = bv.Void() +MemberSendInvitePolicy._other_validator = bv.Void() +MemberSendInvitePolicy._tagmap = { + 'disabled': MemberSendInvitePolicy._disabled_validator, + 'specific_members': MemberSendInvitePolicy._specific_members_validator, + 'everyone': MemberSendInvitePolicy._everyone_validator, + 'other': MemberSendInvitePolicy._other_validator, +} + +MemberSendInvitePolicy.disabled = MemberSendInvitePolicy('disabled') +MemberSendInvitePolicy.specific_members = MemberSendInvitePolicy('specific_members') +MemberSendInvitePolicy.everyone = MemberSendInvitePolicy('everyone') +MemberSendInvitePolicy.other = MemberSendInvitePolicy('other') + +MemberSendInvitePolicyChangedDetails._new_value_validator = MemberSendInvitePolicy_validator +MemberSendInvitePolicyChangedDetails._previous_value_validator = MemberSendInvitePolicy_validator +MemberSendInvitePolicyChangedDetails._all_field_names_ = set([ + 'new_value', + 'previous_value', +]) +MemberSendInvitePolicyChangedDetails._all_fields_ = [ + ('new_value', MemberSendInvitePolicyChangedDetails._new_value_validator), + ('previous_value', MemberSendInvitePolicyChangedDetails._previous_value_validator), +] + +MemberSendInvitePolicyChangedType._description_validator = bv.String() +MemberSendInvitePolicyChangedType._all_field_names_ = set(['description']) +MemberSendInvitePolicyChangedType._all_fields_ = [('description', MemberSendInvitePolicyChangedType._description_validator)] + +MemberSetProfilePhotoDetails._all_field_names_ = set([]) +MemberSetProfilePhotoDetails._all_fields_ = [] + +MemberSetProfilePhotoType._description_validator = bv.String() +MemberSetProfilePhotoType._all_field_names_ = set(['description']) +MemberSetProfilePhotoType._all_fields_ = [('description', MemberSetProfilePhotoType._description_validator)] + MemberSpaceLimitsAddCustomQuotaDetails._new_value_validator = bv.UInt64() MemberSpaceLimitsAddCustomQuotaDetails._all_field_names_ = set(['new_value']) MemberSpaceLimitsAddCustomQuotaDetails._all_fields_ = [('new_value', MemberSpaceLimitsAddCustomQuotaDetails._new_value_validator)] @@ -75527,13 +100194,16 @@ def __repr__(self): NamespaceRelativePathLogInfo._ns_id_validator = bv.Nullable(NamespaceId_validator) NamespaceRelativePathLogInfo._relative_path_validator = bv.Nullable(FilePath_validator) +NamespaceRelativePathLogInfo._is_shared_namespace_validator = bv.Nullable(bv.Boolean()) NamespaceRelativePathLogInfo._all_field_names_ = set([ 'ns_id', 'relative_path', + 'is_shared_namespace', ]) NamespaceRelativePathLogInfo._all_fields_ = [ ('ns_id', NamespaceRelativePathLogInfo._ns_id_validator), ('relative_path', NamespaceRelativePathLogInfo._relative_path_validator), + ('is_shared_namespace', NamespaceRelativePathLogInfo._is_shared_namespace_validator), ] NetworkControlChangePolicyDetails._new_value_validator = NetworkControlPolicy_validator @@ -75564,6 +100234,75 @@ def __repr__(self): NetworkControlPolicy.enabled = NetworkControlPolicy('enabled') NetworkControlPolicy.other = NetworkControlPolicy('other') +NoExpirationLinkGenCreateReportDetails._start_date_validator = common.DropboxTimestamp_validator +NoExpirationLinkGenCreateReportDetails._end_date_validator = common.DropboxTimestamp_validator +NoExpirationLinkGenCreateReportDetails._all_field_names_ = set([ + 'start_date', + 'end_date', +]) +NoExpirationLinkGenCreateReportDetails._all_fields_ = [ + ('start_date', NoExpirationLinkGenCreateReportDetails._start_date_validator), + ('end_date', NoExpirationLinkGenCreateReportDetails._end_date_validator), +] + +NoExpirationLinkGenCreateReportType._description_validator = bv.String() +NoExpirationLinkGenCreateReportType._all_field_names_ = set(['description']) +NoExpirationLinkGenCreateReportType._all_fields_ = [('description', NoExpirationLinkGenCreateReportType._description_validator)] + +NoExpirationLinkGenReportFailedDetails._failure_reason_validator = team.TeamReportFailureReason_validator +NoExpirationLinkGenReportFailedDetails._all_field_names_ = set(['failure_reason']) +NoExpirationLinkGenReportFailedDetails._all_fields_ = [('failure_reason', NoExpirationLinkGenReportFailedDetails._failure_reason_validator)] + +NoExpirationLinkGenReportFailedType._description_validator = bv.String() +NoExpirationLinkGenReportFailedType._all_field_names_ = set(['description']) +NoExpirationLinkGenReportFailedType._all_fields_ = [('description', NoExpirationLinkGenReportFailedType._description_validator)] + +NoPasswordLinkGenCreateReportDetails._start_date_validator = common.DropboxTimestamp_validator +NoPasswordLinkGenCreateReportDetails._end_date_validator = common.DropboxTimestamp_validator +NoPasswordLinkGenCreateReportDetails._all_field_names_ = set([ + 'start_date', + 'end_date', +]) +NoPasswordLinkGenCreateReportDetails._all_fields_ = [ + ('start_date', NoPasswordLinkGenCreateReportDetails._start_date_validator), + ('end_date', NoPasswordLinkGenCreateReportDetails._end_date_validator), +] + +NoPasswordLinkGenCreateReportType._description_validator = bv.String() +NoPasswordLinkGenCreateReportType._all_field_names_ = set(['description']) +NoPasswordLinkGenCreateReportType._all_fields_ = [('description', NoPasswordLinkGenCreateReportType._description_validator)] + +NoPasswordLinkGenReportFailedDetails._failure_reason_validator = team.TeamReportFailureReason_validator +NoPasswordLinkGenReportFailedDetails._all_field_names_ = set(['failure_reason']) +NoPasswordLinkGenReportFailedDetails._all_fields_ = [('failure_reason', NoPasswordLinkGenReportFailedDetails._failure_reason_validator)] + +NoPasswordLinkGenReportFailedType._description_validator = bv.String() +NoPasswordLinkGenReportFailedType._all_field_names_ = set(['description']) +NoPasswordLinkGenReportFailedType._all_fields_ = [('description', NoPasswordLinkGenReportFailedType._description_validator)] + +NoPasswordLinkViewCreateReportDetails._start_date_validator = common.DropboxTimestamp_validator +NoPasswordLinkViewCreateReportDetails._end_date_validator = common.DropboxTimestamp_validator +NoPasswordLinkViewCreateReportDetails._all_field_names_ = set([ + 'start_date', + 'end_date', +]) +NoPasswordLinkViewCreateReportDetails._all_fields_ = [ + ('start_date', NoPasswordLinkViewCreateReportDetails._start_date_validator), + ('end_date', NoPasswordLinkViewCreateReportDetails._end_date_validator), +] + +NoPasswordLinkViewCreateReportType._description_validator = bv.String() +NoPasswordLinkViewCreateReportType._all_field_names_ = set(['description']) +NoPasswordLinkViewCreateReportType._all_fields_ = [('description', NoPasswordLinkViewCreateReportType._description_validator)] + +NoPasswordLinkViewReportFailedDetails._failure_reason_validator = team.TeamReportFailureReason_validator +NoPasswordLinkViewReportFailedDetails._all_field_names_ = set(['failure_reason']) +NoPasswordLinkViewReportFailedDetails._all_fields_ = [('failure_reason', NoPasswordLinkViewReportFailedDetails._failure_reason_validator)] + +NoPasswordLinkViewReportFailedType._description_validator = bv.String() +NoPasswordLinkViewReportFailedType._all_field_names_ = set(['description']) +NoPasswordLinkViewReportFailedType._all_fields_ = [('description', NoPasswordLinkViewReportFailedType._description_validator)] + UserLogInfo._account_id_validator = bv.Nullable(users_common.AccountId_validator) UserLogInfo._display_name_validator = bv.Nullable(common.DisplayNameLegacy_validator) UserLogInfo._email_validator = bv.Nullable(EmailAddress_validator) @@ -75597,6 +100336,10 @@ def __repr__(self): NonTeamMemberLogInfo._fields_ = [] NonTeamMemberLogInfo._all_fields_ = UserLogInfo._all_fields_ + NonTeamMemberLogInfo._fields_ +NonTrustedTeamDetails._team_validator = bv.String() +NonTrustedTeamDetails._all_field_names_ = set(['team']) +NonTrustedTeamDetails._all_fields_ = [('team', NonTrustedTeamDetails._team_validator)] + NoteAclInviteOnlyDetails._all_field_names_ = set([]) NoteAclInviteOnlyDetails._all_fields_ = [] @@ -75639,6 +100382,14 @@ def __repr__(self): OpenNoteSharedType._all_field_names_ = set(['description']) OpenNoteSharedType._all_fields_ = [('description', OpenNoteSharedType._description_validator)] +OrganizationDetails._organization_validator = bv.String() +OrganizationDetails._all_field_names_ = set(['organization']) +OrganizationDetails._all_fields_ = [('organization', OrganizationDetails._organization_validator)] + +OrganizationName._organization_validator = bv.String() +OrganizationName._all_field_names_ = set(['organization']) +OrganizationName._all_fields_ = [('organization', OrganizationName._organization_validator)] + OriginLogInfo._geo_location_validator = bv.Nullable(GeoLocationLogInfo_validator) OriginLogInfo._access_method_validator = AccessMethodLogInfo_validator OriginLogInfo._all_field_names_ = set([ @@ -75650,6 +100401,29 @@ def __repr__(self): ('access_method', OriginLogInfo._access_method_validator), ] +OutdatedLinkViewCreateReportDetails._start_date_validator = common.DropboxTimestamp_validator +OutdatedLinkViewCreateReportDetails._end_date_validator = common.DropboxTimestamp_validator +OutdatedLinkViewCreateReportDetails._all_field_names_ = set([ + 'start_date', + 'end_date', +]) +OutdatedLinkViewCreateReportDetails._all_fields_ = [ + ('start_date', OutdatedLinkViewCreateReportDetails._start_date_validator), + ('end_date', OutdatedLinkViewCreateReportDetails._end_date_validator), +] + +OutdatedLinkViewCreateReportType._description_validator = bv.String() +OutdatedLinkViewCreateReportType._all_field_names_ = set(['description']) +OutdatedLinkViewCreateReportType._all_fields_ = [('description', OutdatedLinkViewCreateReportType._description_validator)] + +OutdatedLinkViewReportFailedDetails._failure_reason_validator = team.TeamReportFailureReason_validator +OutdatedLinkViewReportFailedDetails._all_field_names_ = set(['failure_reason']) +OutdatedLinkViewReportFailedDetails._all_fields_ = [('failure_reason', OutdatedLinkViewReportFailedDetails._failure_reason_validator)] + +OutdatedLinkViewReportFailedType._description_validator = bv.String() +OutdatedLinkViewReportFailedType._all_field_names_ = set(['description']) +OutdatedLinkViewReportFailedType._all_fields_ = [('description', OutdatedLinkViewReportFailedType._description_validator)] + PaperAccessType._viewer_validator = bv.Void() PaperAccessType._commenter_validator = bv.Void() PaperAccessType._editor_validator = bv.Void() @@ -75777,8 +100551,8 @@ def __repr__(self): PaperContentPermanentlyDeleteType._all_fields_ = [('description', PaperContentPermanentlyDeleteType._description_validator)] PaperContentRemoveFromFolderDetails._event_uuid_validator = bv.String() -PaperContentRemoveFromFolderDetails._target_asset_index_validator = bv.UInt64() -PaperContentRemoveFromFolderDetails._parent_asset_index_validator = bv.UInt64() +PaperContentRemoveFromFolderDetails._target_asset_index_validator = bv.Nullable(bv.UInt64()) +PaperContentRemoveFromFolderDetails._parent_asset_index_validator = bv.Nullable(bv.UInt64()) PaperContentRemoveFromFolderDetails._all_field_names_ = set([ 'event_uuid', 'target_asset_index', @@ -76258,6 +101032,24 @@ def __repr__(self): PaperMemberPolicy.team_and_explicitly_shared = PaperMemberPolicy('team_and_explicitly_shared') PaperMemberPolicy.other = PaperMemberPolicy('other') +PaperPublishedLinkChangePermissionDetails._event_uuid_validator = bv.String() +PaperPublishedLinkChangePermissionDetails._new_permission_level_validator = bv.String() +PaperPublishedLinkChangePermissionDetails._previous_permission_level_validator = bv.String() +PaperPublishedLinkChangePermissionDetails._all_field_names_ = set([ + 'event_uuid', + 'new_permission_level', + 'previous_permission_level', +]) +PaperPublishedLinkChangePermissionDetails._all_fields_ = [ + ('event_uuid', PaperPublishedLinkChangePermissionDetails._event_uuid_validator), + ('new_permission_level', PaperPublishedLinkChangePermissionDetails._new_permission_level_validator), + ('previous_permission_level', PaperPublishedLinkChangePermissionDetails._previous_permission_level_validator), +] + +PaperPublishedLinkChangePermissionType._description_validator = bv.String() +PaperPublishedLinkChangePermissionType._all_field_names_ = set(['description']) +PaperPublishedLinkChangePermissionType._all_fields_ = [('description', PaperPublishedLinkChangePermissionType._description_validator)] + PaperPublishedLinkCreateDetails._event_uuid_validator = bv.String() PaperPublishedLinkCreateDetails._all_field_names_ = set(['event_uuid']) PaperPublishedLinkCreateDetails._all_fields_ = [('event_uuid', PaperPublishedLinkCreateDetails._event_uuid_validator)] @@ -76330,6 +101122,21 @@ def __repr__(self): PasswordResetType._all_field_names_ = set(['description']) PasswordResetType._all_fields_ = [('description', PasswordResetType._description_validator)] +PasswordStrengthRequirementsChangePolicyDetails._previous_value_validator = team_policies.PasswordStrengthPolicy_validator +PasswordStrengthRequirementsChangePolicyDetails._new_value_validator = team_policies.PasswordStrengthPolicy_validator +PasswordStrengthRequirementsChangePolicyDetails._all_field_names_ = set([ + 'previous_value', + 'new_value', +]) +PasswordStrengthRequirementsChangePolicyDetails._all_fields_ = [ + ('previous_value', PasswordStrengthRequirementsChangePolicyDetails._previous_value_validator), + ('new_value', PasswordStrengthRequirementsChangePolicyDetails._new_value_validator), +] + +PasswordStrengthRequirementsChangePolicyType._description_validator = bv.String() +PasswordStrengthRequirementsChangePolicyType._all_field_names_ = set(['description']) +PasswordStrengthRequirementsChangePolicyType._all_fields_ = [('description', PasswordStrengthRequirementsChangePolicyType._description_validator)] + PathLogInfo._contextual_validator = bv.Nullable(FilePath_validator) PathLogInfo._namespace_relative_validator = NamespaceRelativePathLogInfo_validator PathLogInfo._all_field_names_ = set([ @@ -76341,6 +101148,14 @@ def __repr__(self): ('namespace_relative', PathLogInfo._namespace_relative_validator), ] +PendingSecondaryEmailAddedDetails._secondary_email_validator = EmailAddress_validator +PendingSecondaryEmailAddedDetails._all_field_names_ = set(['secondary_email']) +PendingSecondaryEmailAddedDetails._all_fields_ = [('secondary_email', PendingSecondaryEmailAddedDetails._secondary_email_validator)] + +PendingSecondaryEmailAddedType._description_validator = bv.String() +PendingSecondaryEmailAddedType._all_field_names_ = set(['description']) +PendingSecondaryEmailAddedType._all_fields_ = [('description', PendingSecondaryEmailAddedType._description_validator)] + PermanentDeleteChangePolicyDetails._new_value_validator = ContentPermanentDeletePolicy_validator PermanentDeleteChangePolicyDetails._previous_value_validator = bv.Nullable(ContentPermanentDeletePolicy_validator) PermanentDeleteChangePolicyDetails._all_field_names_ = set([ @@ -76423,6 +101238,7 @@ def __repr__(self): QuickActionType._reset_password_validator = bv.Void() QuickActionType._restore_file_or_folder_validator = bv.Void() QuickActionType._unlink_app_validator = bv.Void() +QuickActionType._unlink_device_validator = bv.Void() QuickActionType._unlink_session_validator = bv.Void() QuickActionType._other_validator = bv.Void() QuickActionType._tagmap = { @@ -76430,6 +101246,7 @@ def __repr__(self): 'reset_password': QuickActionType._reset_password_validator, 'restore_file_or_folder': QuickActionType._restore_file_or_folder_validator, 'unlink_app': QuickActionType._unlink_app_validator, + 'unlink_device': QuickActionType._unlink_device_validator, 'unlink_session': QuickActionType._unlink_session_validator, 'other': QuickActionType._other_validator, } @@ -76438,6 +101255,7 @@ def __repr__(self): QuickActionType.reset_password = QuickActionType('reset_password') QuickActionType.restore_file_or_folder = QuickActionType('restore_file_or_folder') QuickActionType.unlink_app = QuickActionType('unlink_app') +QuickActionType.unlink_device = QuickActionType('unlink_device') QuickActionType.unlink_session = QuickActionType('unlink_session') QuickActionType.other = QuickActionType('other') @@ -76505,6 +101323,58 @@ def __repr__(self): ResellerSupportSessionStartType._all_field_names_ = set(['description']) ResellerSupportSessionStartType._all_fields_ = [('description', ResellerSupportSessionStartType._description_validator)] +RewindFolderDetails._rewind_folder_target_ts_ms_validator = common.DropboxTimestamp_validator +RewindFolderDetails._all_field_names_ = set(['rewind_folder_target_ts_ms']) +RewindFolderDetails._all_fields_ = [('rewind_folder_target_ts_ms', RewindFolderDetails._rewind_folder_target_ts_ms_validator)] + +RewindFolderType._description_validator = bv.String() +RewindFolderType._all_field_names_ = set(['description']) +RewindFolderType._all_fields_ = [('description', RewindFolderType._description_validator)] + +RewindPolicy._admins_only_validator = bv.Void() +RewindPolicy._everyone_validator = bv.Void() +RewindPolicy._other_validator = bv.Void() +RewindPolicy._tagmap = { + 'admins_only': RewindPolicy._admins_only_validator, + 'everyone': RewindPolicy._everyone_validator, + 'other': RewindPolicy._other_validator, +} + +RewindPolicy.admins_only = RewindPolicy('admins_only') +RewindPolicy.everyone = RewindPolicy('everyone') +RewindPolicy.other = RewindPolicy('other') + +RewindPolicyChangedDetails._new_value_validator = RewindPolicy_validator +RewindPolicyChangedDetails._previous_value_validator = RewindPolicy_validator +RewindPolicyChangedDetails._all_field_names_ = set([ + 'new_value', + 'previous_value', +]) +RewindPolicyChangedDetails._all_fields_ = [ + ('new_value', RewindPolicyChangedDetails._new_value_validator), + ('previous_value', RewindPolicyChangedDetails._previous_value_validator), +] + +RewindPolicyChangedType._description_validator = bv.String() +RewindPolicyChangedType._all_field_names_ = set(['description']) +RewindPolicyChangedType._all_fields_ = [('description', RewindPolicyChangedType._description_validator)] + +SecondaryEmailDeletedDetails._secondary_email_validator = EmailAddress_validator +SecondaryEmailDeletedDetails._all_field_names_ = set(['secondary_email']) +SecondaryEmailDeletedDetails._all_fields_ = [('secondary_email', SecondaryEmailDeletedDetails._secondary_email_validator)] + +SecondaryEmailDeletedType._description_validator = bv.String() +SecondaryEmailDeletedType._all_field_names_ = set(['description']) +SecondaryEmailDeletedType._all_fields_ = [('description', SecondaryEmailDeletedType._description_validator)] + +SecondaryEmailVerifiedDetails._secondary_email_validator = EmailAddress_validator +SecondaryEmailVerifiedDetails._all_field_names_ = set(['secondary_email']) +SecondaryEmailVerifiedDetails._all_fields_ = [('secondary_email', SecondaryEmailVerifiedDetails._secondary_email_validator)] + +SecondaryEmailVerifiedType._description_validator = bv.String() +SecondaryEmailVerifiedType._all_field_names_ = set(['description']) +SecondaryEmailVerifiedType._all_fields_ = [('description', SecondaryEmailVerifiedType._description_validator)] + SecondaryMailsPolicy._disabled_validator = bv.Void() SecondaryMailsPolicy._enabled_validator = bv.Void() SecondaryMailsPolicy._other_validator = bv.Void() @@ -77021,6 +101891,29 @@ def __repr__(self): SharedContentRequestAccessType._all_field_names_ = set(['description']) SharedContentRequestAccessType._all_fields_ = [('description', SharedContentRequestAccessType._description_validator)] +SharedContentRestoreInviteesDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedContentRestoreInviteesDetails._invitees_validator = bv.List(EmailAddress_validator) +SharedContentRestoreInviteesDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'invitees', +]) +SharedContentRestoreInviteesDetails._all_fields_ = [ + ('shared_content_access_level', SharedContentRestoreInviteesDetails._shared_content_access_level_validator), + ('invitees', SharedContentRestoreInviteesDetails._invitees_validator), +] + +SharedContentRestoreInviteesType._description_validator = bv.String() +SharedContentRestoreInviteesType._all_field_names_ = set(['description']) +SharedContentRestoreInviteesType._all_fields_ = [('description', SharedContentRestoreInviteesType._description_validator)] + +SharedContentRestoreMemberDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedContentRestoreMemberDetails._all_field_names_ = set(['shared_content_access_level']) +SharedContentRestoreMemberDetails._all_fields_ = [('shared_content_access_level', SharedContentRestoreMemberDetails._shared_content_access_level_validator)] + +SharedContentRestoreMemberType._description_validator = bv.String() +SharedContentRestoreMemberType._all_field_names_ = set(['description']) +SharedContentRestoreMemberType._all_fields_ = [('description', SharedContentRestoreMemberType._description_validator)] + SharedContentUnshareDetails._all_field_names_ = set([]) SharedContentUnshareDetails._all_fields_ = [] @@ -77278,6 +102171,159 @@ def __repr__(self): SharedLinkRemoveExpiryType._all_field_names_ = set(['description']) SharedLinkRemoveExpiryType._all_fields_ = [('description', SharedLinkRemoveExpiryType._description_validator)] +SharedLinkSettingsAddExpirationDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsAddExpirationDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsAddExpirationDetails._new_value_validator = bv.Nullable(common.DropboxTimestamp_validator) +SharedLinkSettingsAddExpirationDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', + 'new_value', +]) +SharedLinkSettingsAddExpirationDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsAddExpirationDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsAddExpirationDetails._shared_content_link_validator), + ('new_value', SharedLinkSettingsAddExpirationDetails._new_value_validator), +] + +SharedLinkSettingsAddExpirationType._description_validator = bv.String() +SharedLinkSettingsAddExpirationType._all_field_names_ = set(['description']) +SharedLinkSettingsAddExpirationType._all_fields_ = [('description', SharedLinkSettingsAddExpirationType._description_validator)] + +SharedLinkSettingsAddPasswordDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsAddPasswordDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsAddPasswordDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', +]) +SharedLinkSettingsAddPasswordDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsAddPasswordDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsAddPasswordDetails._shared_content_link_validator), +] + +SharedLinkSettingsAddPasswordType._description_validator = bv.String() +SharedLinkSettingsAddPasswordType._all_field_names_ = set(['description']) +SharedLinkSettingsAddPasswordType._all_fields_ = [('description', SharedLinkSettingsAddPasswordType._description_validator)] + +SharedLinkSettingsAllowDownloadDisabledDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsAllowDownloadDisabledDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsAllowDownloadDisabledDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', +]) +SharedLinkSettingsAllowDownloadDisabledDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsAllowDownloadDisabledDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsAllowDownloadDisabledDetails._shared_content_link_validator), +] + +SharedLinkSettingsAllowDownloadDisabledType._description_validator = bv.String() +SharedLinkSettingsAllowDownloadDisabledType._all_field_names_ = set(['description']) +SharedLinkSettingsAllowDownloadDisabledType._all_fields_ = [('description', SharedLinkSettingsAllowDownloadDisabledType._description_validator)] + +SharedLinkSettingsAllowDownloadEnabledDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsAllowDownloadEnabledDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsAllowDownloadEnabledDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', +]) +SharedLinkSettingsAllowDownloadEnabledDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsAllowDownloadEnabledDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsAllowDownloadEnabledDetails._shared_content_link_validator), +] + +SharedLinkSettingsAllowDownloadEnabledType._description_validator = bv.String() +SharedLinkSettingsAllowDownloadEnabledType._all_field_names_ = set(['description']) +SharedLinkSettingsAllowDownloadEnabledType._all_fields_ = [('description', SharedLinkSettingsAllowDownloadEnabledType._description_validator)] + +SharedLinkSettingsChangeAudienceDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsChangeAudienceDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsChangeAudienceDetails._new_value_validator = sharing.LinkAudience_validator +SharedLinkSettingsChangeAudienceDetails._previous_value_validator = bv.Nullable(sharing.LinkAudience_validator) +SharedLinkSettingsChangeAudienceDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', + 'new_value', + 'previous_value', +]) +SharedLinkSettingsChangeAudienceDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsChangeAudienceDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsChangeAudienceDetails._shared_content_link_validator), + ('new_value', SharedLinkSettingsChangeAudienceDetails._new_value_validator), + ('previous_value', SharedLinkSettingsChangeAudienceDetails._previous_value_validator), +] + +SharedLinkSettingsChangeAudienceType._description_validator = bv.String() +SharedLinkSettingsChangeAudienceType._all_field_names_ = set(['description']) +SharedLinkSettingsChangeAudienceType._all_fields_ = [('description', SharedLinkSettingsChangeAudienceType._description_validator)] + +SharedLinkSettingsChangeExpirationDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsChangeExpirationDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsChangeExpirationDetails._new_value_validator = bv.Nullable(common.DropboxTimestamp_validator) +SharedLinkSettingsChangeExpirationDetails._previous_value_validator = bv.Nullable(common.DropboxTimestamp_validator) +SharedLinkSettingsChangeExpirationDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', + 'new_value', + 'previous_value', +]) +SharedLinkSettingsChangeExpirationDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsChangeExpirationDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsChangeExpirationDetails._shared_content_link_validator), + ('new_value', SharedLinkSettingsChangeExpirationDetails._new_value_validator), + ('previous_value', SharedLinkSettingsChangeExpirationDetails._previous_value_validator), +] + +SharedLinkSettingsChangeExpirationType._description_validator = bv.String() +SharedLinkSettingsChangeExpirationType._all_field_names_ = set(['description']) +SharedLinkSettingsChangeExpirationType._all_fields_ = [('description', SharedLinkSettingsChangeExpirationType._description_validator)] + +SharedLinkSettingsChangePasswordDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsChangePasswordDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsChangePasswordDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', +]) +SharedLinkSettingsChangePasswordDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsChangePasswordDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsChangePasswordDetails._shared_content_link_validator), +] + +SharedLinkSettingsChangePasswordType._description_validator = bv.String() +SharedLinkSettingsChangePasswordType._all_field_names_ = set(['description']) +SharedLinkSettingsChangePasswordType._all_fields_ = [('description', SharedLinkSettingsChangePasswordType._description_validator)] + +SharedLinkSettingsRemoveExpirationDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsRemoveExpirationDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsRemoveExpirationDetails._previous_value_validator = bv.Nullable(common.DropboxTimestamp_validator) +SharedLinkSettingsRemoveExpirationDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', + 'previous_value', +]) +SharedLinkSettingsRemoveExpirationDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsRemoveExpirationDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsRemoveExpirationDetails._shared_content_link_validator), + ('previous_value', SharedLinkSettingsRemoveExpirationDetails._previous_value_validator), +] + +SharedLinkSettingsRemoveExpirationType._description_validator = bv.String() +SharedLinkSettingsRemoveExpirationType._all_field_names_ = set(['description']) +SharedLinkSettingsRemoveExpirationType._all_fields_ = [('description', SharedLinkSettingsRemoveExpirationType._description_validator)] + +SharedLinkSettingsRemovePasswordDetails._shared_content_access_level_validator = sharing.AccessLevel_validator +SharedLinkSettingsRemovePasswordDetails._shared_content_link_validator = bv.Nullable(bv.String()) +SharedLinkSettingsRemovePasswordDetails._all_field_names_ = set([ + 'shared_content_access_level', + 'shared_content_link', +]) +SharedLinkSettingsRemovePasswordDetails._all_fields_ = [ + ('shared_content_access_level', SharedLinkSettingsRemovePasswordDetails._shared_content_access_level_validator), + ('shared_content_link', SharedLinkSettingsRemovePasswordDetails._shared_content_link_validator), +] + +SharedLinkSettingsRemovePasswordType._description_validator = bv.String() +SharedLinkSettingsRemovePasswordType._all_field_names_ = set(['description']) +SharedLinkSettingsRemovePasswordType._all_fields_ = [('description', SharedLinkSettingsRemovePasswordType._description_validator)] + SharedLinkShareDetails._shared_link_owner_validator = bv.Nullable(UserLogInfo_validator) SharedLinkShareDetails._external_users_validator = bv.Nullable(bv.List(ExternalUserLogInfo_validator)) SharedLinkShareDetails._all_field_names_ = set([ @@ -77400,15 +102446,18 @@ def __repr__(self): SharingMemberPolicy._allow_validator = bv.Void() SharingMemberPolicy._forbid_validator = bv.Void() +SharingMemberPolicy._forbid_with_exclusions_validator = bv.Void() SharingMemberPolicy._other_validator = bv.Void() SharingMemberPolicy._tagmap = { 'allow': SharingMemberPolicy._allow_validator, 'forbid': SharingMemberPolicy._forbid_validator, + 'forbid_with_exclusions': SharingMemberPolicy._forbid_with_exclusions_validator, 'other': SharingMemberPolicy._other_validator, } SharingMemberPolicy.allow = SharingMemberPolicy('allow') SharingMemberPolicy.forbid = SharingMemberPolicy('forbid') +SharingMemberPolicy.forbid_with_exclusions = SharingMemberPolicy('forbid_with_exclusions') SharingMemberPolicy.other = SharingMemberPolicy('other') ShmodelGroupShareDetails._all_field_names_ = set([]) @@ -77826,6 +102875,21 @@ def __repr__(self): SmartSyncOptOutType._all_field_names_ = set(['description']) SmartSyncOptOutType._all_fields_ = [('description', SmartSyncOptOutType._description_validator)] +SmarterSmartSyncPolicyChangedDetails._previous_value_validator = team_policies.SmarterSmartSyncPolicyState_validator +SmarterSmartSyncPolicyChangedDetails._new_value_validator = team_policies.SmarterSmartSyncPolicyState_validator +SmarterSmartSyncPolicyChangedDetails._all_field_names_ = set([ + 'previous_value', + 'new_value', +]) +SmarterSmartSyncPolicyChangedDetails._all_fields_ = [ + ('previous_value', SmarterSmartSyncPolicyChangedDetails._previous_value_validator), + ('new_value', SmarterSmartSyncPolicyChangedDetails._new_value_validator), +] + +SmarterSmartSyncPolicyChangedType._description_validator = bv.String() +SmarterSmartSyncPolicyChangedType._all_field_names_ = set(['description']) +SmarterSmartSyncPolicyChangedType._all_fields_ = [('description', SmarterSmartSyncPolicyChangedType._description_validator)] + SpaceCapsType._hard_validator = bv.Void() SpaceCapsType._off_validator = bv.Void() SpaceCapsType._soft_validator = bv.Void() @@ -77988,6 +103052,14 @@ def __repr__(self): SsoRemoveLogoutUrlType._all_field_names_ = set(['description']) SsoRemoveLogoutUrlType._all_fields_ = [('description', SsoRemoveLogoutUrlType._description_validator)] +StartedEnterpriseAdminSessionDetails._federation_extra_details_validator = FedExtraDetails_validator +StartedEnterpriseAdminSessionDetails._all_field_names_ = set(['federation_extra_details']) +StartedEnterpriseAdminSessionDetails._all_fields_ = [('federation_extra_details', StartedEnterpriseAdminSessionDetails._federation_extra_details_validator)] + +StartedEnterpriseAdminSessionType._description_validator = bv.String() +StartedEnterpriseAdminSessionType._all_field_names_ = set(['description']) +StartedEnterpriseAdminSessionType._all_fields_ = [('description', StartedEnterpriseAdminSessionType._description_validator)] + TeamActivityCreateReportDetails._start_date_validator = common.DropboxTimestamp_validator TeamActivityCreateReportDetails._end_date_validator = common.DropboxTimestamp_validator TeamActivityCreateReportDetails._all_field_names_ = set([ @@ -78011,6 +103083,10 @@ def __repr__(self): TeamActivityCreateReportType._all_field_names_ = set(['description']) TeamActivityCreateReportType._all_fields_ = [('description', TeamActivityCreateReportType._description_validator)] +TeamDetails._team_validator = bv.String() +TeamDetails._all_field_names_ = set(['team']) +TeamDetails._all_fields_ = [('team', TeamDetails._team_validator)] + TeamEvent._timestamp_validator = common.DropboxTimestamp_validator TeamEvent._event_category_validator = EventCategory_validator TeamEvent._actor_validator = bv.Nullable(ActorLogInfo_validator) @@ -78126,35 +103202,46 @@ def __repr__(self): TeamFolderRenameType._all_field_names_ = set(['description']) TeamFolderRenameType._all_fields_ = [('description', TeamFolderRenameType._description_validator)] +TeamInviteDetails._invite_method_validator = InviteMethod_validator +TeamInviteDetails._all_field_names_ = set(['invite_method']) +TeamInviteDetails._all_fields_ = [('invite_method', TeamInviteDetails._invite_method_validator)] + TeamLinkedAppLogInfo._field_names_ = set([]) TeamLinkedAppLogInfo._all_field_names_ = AppLogInfo._all_field_names_.union(TeamLinkedAppLogInfo._field_names_) TeamLinkedAppLogInfo._fields_ = [] TeamLinkedAppLogInfo._all_fields_ = AppLogInfo._all_fields_ + TeamLinkedAppLogInfo._fields_ +TeamLogInfo._display_name_validator = bv.String() +TeamLogInfo._all_field_names_ = set(['display_name']) +TeamLogInfo._all_fields_ = [('display_name', TeamLogInfo._display_name_validator)] + TeamMemberLogInfo._team_member_id_validator = bv.Nullable(team_common.TeamMemberId_validator) TeamMemberLogInfo._member_external_id_validator = bv.Nullable(team_common.MemberExternalId_validator) +TeamMemberLogInfo._team_validator = bv.Nullable(TeamLogInfo_validator) TeamMemberLogInfo._field_names_ = set([ 'team_member_id', 'member_external_id', + 'team', ]) TeamMemberLogInfo._all_field_names_ = UserLogInfo._all_field_names_.union(TeamMemberLogInfo._field_names_) TeamMemberLogInfo._fields_ = [ ('team_member_id', TeamMemberLogInfo._team_member_id_validator), ('member_external_id', TeamMemberLogInfo._member_external_id_validator), + ('team', TeamMemberLogInfo._team_validator), ] TeamMemberLogInfo._all_fields_ = UserLogInfo._all_fields_ + TeamMemberLogInfo._fields_ -TeamMembershipType._free_validator = bv.Void() TeamMembershipType._full_validator = bv.Void() +TeamMembershipType._free_validator = bv.Void() TeamMembershipType._other_validator = bv.Void() TeamMembershipType._tagmap = { - 'free': TeamMembershipType._free_validator, 'full': TeamMembershipType._full_validator, + 'free': TeamMembershipType._free_validator, 'other': TeamMembershipType._other_validator, } -TeamMembershipType.free = TeamMembershipType('free') TeamMembershipType.full = TeamMembershipType('full') +TeamMembershipType.free = TeamMembershipType('free') TeamMembershipType.other = TeamMembershipType('other') TeamMergeFromDetails._team_name_validator = bv.String() @@ -78522,6 +103609,21 @@ def __repr__(self): TeamSelectiveSyncSettingsChangedType._all_field_names_ = set(['description']) TeamSelectiveSyncSettingsChangedType._all_fields_ = [('description', TeamSelectiveSyncSettingsChangedType._description_validator)] +TeamSharingWhitelistSubjectsChangedDetails._added_whitelist_subjects_validator = bv.List(bv.String()) +TeamSharingWhitelistSubjectsChangedDetails._removed_whitelist_subjects_validator = bv.List(bv.String()) +TeamSharingWhitelistSubjectsChangedDetails._all_field_names_ = set([ + 'added_whitelist_subjects', + 'removed_whitelist_subjects', +]) +TeamSharingWhitelistSubjectsChangedDetails._all_fields_ = [ + ('added_whitelist_subjects', TeamSharingWhitelistSubjectsChangedDetails._added_whitelist_subjects_validator), + ('removed_whitelist_subjects', TeamSharingWhitelistSubjectsChangedDetails._removed_whitelist_subjects_validator), +] + +TeamSharingWhitelistSubjectsChangedType._description_validator = bv.String() +TeamSharingWhitelistSubjectsChangedType._all_field_names_ = set(['description']) +TeamSharingWhitelistSubjectsChangedType._all_fields_ = [('description', TeamSharingWhitelistSubjectsChangedType._description_validator)] + TfaAddBackupPhoneDetails._all_field_names_ = set([]) TfaAddBackupPhoneDetails._all_fields_ = [] @@ -78529,6 +103631,13 @@ def __repr__(self): TfaAddBackupPhoneType._all_field_names_ = set(['description']) TfaAddBackupPhoneType._all_fields_ = [('description', TfaAddBackupPhoneType._description_validator)] +TfaAddExceptionDetails._all_field_names_ = set([]) +TfaAddExceptionDetails._all_fields_ = [] + +TfaAddExceptionType._description_validator = bv.String() +TfaAddExceptionType._all_field_names_ = set(['description']) +TfaAddExceptionType._all_fields_ = [('description', TfaAddExceptionType._description_validator)] + TfaAddSecurityKeyDetails._all_field_names_ = set([]) TfaAddSecurityKeyDetails._all_fields_ = [] @@ -78602,6 +103711,13 @@ def __repr__(self): TfaRemoveBackupPhoneType._all_field_names_ = set(['description']) TfaRemoveBackupPhoneType._all_fields_ = [('description', TfaRemoveBackupPhoneType._description_validator)] +TfaRemoveExceptionDetails._all_field_names_ = set([]) +TfaRemoveExceptionDetails._all_fields_ = [] + +TfaRemoveExceptionType._description_validator = bv.String() +TfaRemoveExceptionType._all_field_names_ = set(['description']) +TfaRemoveExceptionType._all_fields_ = [('description', TfaRemoveExceptionType._description_validator)] + TfaRemoveSecurityKeyDetails._all_field_names_ = set([]) TfaRemoveSecurityKeyDetails._all_fields_ = [] @@ -78648,19 +103764,29 @@ def __repr__(self): TimeUnit.other = TimeUnit('other') TrustedNonTeamMemberLogInfo._trusted_non_team_member_type_validator = TrustedNonTeamMemberType_validator -TrustedNonTeamMemberLogInfo._field_names_ = set(['trusted_non_team_member_type']) +TrustedNonTeamMemberLogInfo._team_validator = bv.Nullable(TeamLogInfo_validator) +TrustedNonTeamMemberLogInfo._field_names_ = set([ + 'trusted_non_team_member_type', + 'team', +]) TrustedNonTeamMemberLogInfo._all_field_names_ = UserLogInfo._all_field_names_.union(TrustedNonTeamMemberLogInfo._field_names_) -TrustedNonTeamMemberLogInfo._fields_ = [('trusted_non_team_member_type', TrustedNonTeamMemberLogInfo._trusted_non_team_member_type_validator)] +TrustedNonTeamMemberLogInfo._fields_ = [ + ('trusted_non_team_member_type', TrustedNonTeamMemberLogInfo._trusted_non_team_member_type_validator), + ('team', TrustedNonTeamMemberLogInfo._team_validator), +] TrustedNonTeamMemberLogInfo._all_fields_ = UserLogInfo._all_fields_ + TrustedNonTeamMemberLogInfo._fields_ TrustedNonTeamMemberType._multi_instance_admin_validator = bv.Void() +TrustedNonTeamMemberType._enterprise_admin_validator = bv.Void() TrustedNonTeamMemberType._other_validator = bv.Void() TrustedNonTeamMemberType._tagmap = { 'multi_instance_admin': TrustedNonTeamMemberType._multi_instance_admin_validator, + 'enterprise_admin': TrustedNonTeamMemberType._enterprise_admin_validator, 'other': TrustedNonTeamMemberType._other_validator, } TrustedNonTeamMemberType.multi_instance_admin = TrustedNonTeamMemberType('multi_instance_admin') +TrustedNonTeamMemberType.enterprise_admin = TrustedNonTeamMemberType('enterprise_admin') TrustedNonTeamMemberType.other = TrustedNonTeamMemberType('other') TrustedTeamsRequestAction._invited_validator = bv.Void() @@ -78768,6 +103894,34 @@ def __repr__(self): ViewerInfoPolicyChangedType._all_field_names_ = set(['description']) ViewerInfoPolicyChangedType._all_fields_ = [('description', ViewerInfoPolicyChangedType._description_validator)] +WatermarkingPolicy._disabled_validator = bv.Void() +WatermarkingPolicy._enabled_validator = bv.Void() +WatermarkingPolicy._other_validator = bv.Void() +WatermarkingPolicy._tagmap = { + 'disabled': WatermarkingPolicy._disabled_validator, + 'enabled': WatermarkingPolicy._enabled_validator, + 'other': WatermarkingPolicy._other_validator, +} + +WatermarkingPolicy.disabled = WatermarkingPolicy('disabled') +WatermarkingPolicy.enabled = WatermarkingPolicy('enabled') +WatermarkingPolicy.other = WatermarkingPolicy('other') + +WatermarkingPolicyChangedDetails._new_value_validator = WatermarkingPolicy_validator +WatermarkingPolicyChangedDetails._previous_value_validator = WatermarkingPolicy_validator +WatermarkingPolicyChangedDetails._all_field_names_ = set([ + 'new_value', + 'previous_value', +]) +WatermarkingPolicyChangedDetails._all_fields_ = [ + ('new_value', WatermarkingPolicyChangedDetails._new_value_validator), + ('previous_value', WatermarkingPolicyChangedDetails._previous_value_validator), +] + +WatermarkingPolicyChangedType._description_validator = bv.String() +WatermarkingPolicyChangedType._all_field_names_ = set(['description']) +WatermarkingPolicyChangedType._all_fields_ = [('description', WatermarkingPolicyChangedType._description_validator)] + WebDeviceSessionLogInfo._session_info_validator = bv.Nullable(WebSessionLogInfo_validator) WebDeviceSessionLogInfo._user_agent_validator = bv.String() WebDeviceSessionLogInfo._os_validator = bv.String() @@ -78792,6 +103946,21 @@ def __repr__(self): WebSessionLogInfo._fields_ = [] WebSessionLogInfo._all_fields_ = SessionLogInfo._all_fields_ + WebSessionLogInfo._fields_ +WebSessionsChangeActiveSessionLimitDetails._previous_value_validator = bv.String() +WebSessionsChangeActiveSessionLimitDetails._new_value_validator = bv.String() +WebSessionsChangeActiveSessionLimitDetails._all_field_names_ = set([ + 'previous_value', + 'new_value', +]) +WebSessionsChangeActiveSessionLimitDetails._all_fields_ = [ + ('previous_value', WebSessionsChangeActiveSessionLimitDetails._previous_value_validator), + ('new_value', WebSessionsChangeActiveSessionLimitDetails._new_value_validator), +] + +WebSessionsChangeActiveSessionLimitType._description_validator = bv.String() +WebSessionsChangeActiveSessionLimitType._all_field_names_ = set(['description']) +WebSessionsChangeActiveSessionLimitType._all_fields_ = [('description', WebSessionsChangeActiveSessionLimitType._description_validator)] + WebSessionsChangeFixedLengthPolicyDetails._new_value_validator = bv.Nullable(WebSessionsFixedLengthPolicy_validator) WebSessionsChangeFixedLengthPolicyDetails._previous_value_validator = bv.Nullable(WebSessionsFixedLengthPolicy_validator) WebSessionsChangeFixedLengthPolicyDetails._all_field_names_ = set([ diff --git a/script.module.dropbox/lib/dropbox/team_policies.py b/script.module.dropbox/lib/dropbox/team_policies.py index 136fa2983..9d219d5b2 100644 --- a/script.module.dropbox/lib/dropbox/team_policies.py +++ b/script.module.dropbox/lib/dropbox/team_policies.py @@ -125,6 +125,58 @@ def __repr__(self): EmmState_validator = bv.Union(EmmState) +class FileLockingPolicyState(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team_policies.FileLockingPolicyState.disabled: File locking feature is + disabled. + :ivar team_policies.FileLockingPolicyState.enabled: File locking feature is + allowed. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockingPolicyState, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileLockingPolicyState(%r, %r)' % (self._tag, self._value) + +FileLockingPolicyState_validator = bv.Union(FileLockingPolicyState) + class GroupCreation(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will @@ -435,6 +487,56 @@ def __repr__(self): PaperEnabledPolicy_validator = bv.Union(PaperEnabledPolicy) +class PasswordControlMode(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team_policies.PasswordControlMode.disabled: Password is disabled. + :ivar team_policies.PasswordControlMode.enabled: Password is enabled. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PasswordControlMode, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PasswordControlMode(%r, %r)' % (self._tag, self._value) + +PasswordControlMode_validator = bv.Union(PasswordControlMode) + class PasswordStrengthPolicy(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will @@ -937,6 +1039,58 @@ def __repr__(self): SmartSyncPolicy_validator = bv.Union(SmartSyncPolicy) +class SmarterSmartSyncPolicyState(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar team_policies.SmarterSmartSyncPolicyState.disabled: Smarter Smart Sync + feature is disabled. + :ivar team_policies.SmarterSmartSyncPolicyState.enabled: Smarter Smart Sync + feature is enabled. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition + enabled = None + # Attribute is overwritten below the class definition + other = None + + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(SmarterSmartSyncPolicyState, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'SmarterSmartSyncPolicyState(%r, %r)' % (self._tag, self._value) + +SmarterSmartSyncPolicyState_validator = bv.Union(SmarterSmartSyncPolicyState) + class SsoPolicy(bb.Union): """ This class acts as a tagged union. Only one of the ``is_*`` methods will @@ -1314,6 +1468,8 @@ class TwoStepVerificationState(bb.Union): factor authorization. :ivar team_policies.TwoStepVerificationState.optional: Optional require two factor authorization. + :ivar team_policies.TwoStepVerificationState.disabled: Disabled require two + factor authorization. """ _catch_all = 'other' @@ -1322,6 +1478,8 @@ class TwoStepVerificationState(bb.Union): # Attribute is overwritten below the class definition optional = None # Attribute is overwritten below the class definition + disabled = None + # Attribute is overwritten below the class definition other = None def is_required(self): @@ -1340,6 +1498,14 @@ def is_optional(self): """ return self._tag == 'optional' + def is_disabled(self): + """ + Check if the union tag is ``disabled``. + + :rtype: bool + """ + return self._tag == 'disabled' + def is_other(self): """ Check if the union tag is ``other``. @@ -1385,6 +1551,19 @@ def __repr__(self): EmmState.required = EmmState('required') EmmState.other = EmmState('other') +FileLockingPolicyState._disabled_validator = bv.Void() +FileLockingPolicyState._enabled_validator = bv.Void() +FileLockingPolicyState._other_validator = bv.Void() +FileLockingPolicyState._tagmap = { + 'disabled': FileLockingPolicyState._disabled_validator, + 'enabled': FileLockingPolicyState._enabled_validator, + 'other': FileLockingPolicyState._other_validator, +} + +FileLockingPolicyState.disabled = FileLockingPolicyState('disabled') +FileLockingPolicyState.enabled = FileLockingPolicyState('enabled') +FileLockingPolicyState.other = FileLockingPolicyState('other') + GroupCreation._admins_and_members_validator = bv.Void() GroupCreation._admins_only_validator = bv.Void() GroupCreation._tagmap = { @@ -1463,6 +1642,19 @@ def __repr__(self): PaperEnabledPolicy.unspecified = PaperEnabledPolicy('unspecified') PaperEnabledPolicy.other = PaperEnabledPolicy('other') +PasswordControlMode._disabled_validator = bv.Void() +PasswordControlMode._enabled_validator = bv.Void() +PasswordControlMode._other_validator = bv.Void() +PasswordControlMode._tagmap = { + 'disabled': PasswordControlMode._disabled_validator, + 'enabled': PasswordControlMode._enabled_validator, + 'other': PasswordControlMode._other_validator, +} + +PasswordControlMode.disabled = PasswordControlMode('disabled') +PasswordControlMode.enabled = PasswordControlMode('enabled') +PasswordControlMode.other = PasswordControlMode('other') + PasswordStrengthPolicy._minimal_requirements_validator = bv.Void() PasswordStrengthPolicy._moderate_password_validator = bv.Void() PasswordStrengthPolicy._strong_password_validator = bv.Void() @@ -1586,6 +1778,19 @@ def __repr__(self): SmartSyncPolicy.on_demand = SmartSyncPolicy('on_demand') SmartSyncPolicy.other = SmartSyncPolicy('other') +SmarterSmartSyncPolicyState._disabled_validator = bv.Void() +SmarterSmartSyncPolicyState._enabled_validator = bv.Void() +SmarterSmartSyncPolicyState._other_validator = bv.Void() +SmarterSmartSyncPolicyState._tagmap = { + 'disabled': SmarterSmartSyncPolicyState._disabled_validator, + 'enabled': SmarterSmartSyncPolicyState._enabled_validator, + 'other': SmarterSmartSyncPolicyState._other_validator, +} + +SmarterSmartSyncPolicyState.disabled = SmarterSmartSyncPolicyState('disabled') +SmarterSmartSyncPolicyState.enabled = SmarterSmartSyncPolicyState('enabled') +SmarterSmartSyncPolicyState.other = SmarterSmartSyncPolicyState('other') + SsoPolicy._disabled_validator = bv.Void() SsoPolicy._optional_validator = bv.Void() SsoPolicy._required_validator = bv.Void() @@ -1645,15 +1850,18 @@ def __repr__(self): TwoStepVerificationState._required_validator = bv.Void() TwoStepVerificationState._optional_validator = bv.Void() +TwoStepVerificationState._disabled_validator = bv.Void() TwoStepVerificationState._other_validator = bv.Void() TwoStepVerificationState._tagmap = { 'required': TwoStepVerificationState._required_validator, 'optional': TwoStepVerificationState._optional_validator, + 'disabled': TwoStepVerificationState._disabled_validator, 'other': TwoStepVerificationState._other_validator, } TwoStepVerificationState.required = TwoStepVerificationState('required') TwoStepVerificationState.optional = TwoStepVerificationState('optional') +TwoStepVerificationState.disabled = TwoStepVerificationState('disabled') TwoStepVerificationState.other = TwoStepVerificationState('other') ROUTES = { diff --git a/script.module.dropbox/lib/dropbox/users.py b/script.module.dropbox/lib/dropbox/users.py index 5dcc6da0e..9634e232d 100644 --- a/script.module.dropbox/lib/dropbox/users.py +++ b/script.module.dropbox/lib/dropbox/users.py @@ -366,6 +366,73 @@ def __repr__(self): BasicAccount_validator = bv.Struct(BasicAccount) +class FileLockingValue(bb.Union): + """ + The value for ``UserFeature.file_locking``. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar bool users.FileLockingValue.enabled: When this value is True, the user + can lock files in shared directories. When the value is False the user + can unlock the files they have locked or request to unlock files locked + by others. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def enabled(cls, val): + """ + Create an instance of this class set to the ``enabled`` tag with value + ``val``. + + :param bool val: + :rtype: FileLockingValue + """ + return cls('enabled', val) + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_enabled(self): + """ + When this value is True, the user can lock files in shared directories. + When the value is False the user can unlock the files they have locked + or request to unlock files locked by others. + + Only call this if :meth:`is_enabled` is true. + + :rtype: bool + """ + if not self.is_enabled(): + raise AttributeError("tag 'enabled' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(FileLockingValue, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'FileLockingValue(%r, %r)' % (self._tag, self._value) + +FileLockingValue_validator = bv.Union(FileLockingValue) + class FullAccount(Account): """ Detailed information about the current user's account. @@ -1316,6 +1383,76 @@ def __repr__(self): Name_validator = bv.Struct(Name) +class PaperAsFilesValue(bb.Union): + """ + The value for ``UserFeature.paper_as_files``. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar bool users.PaperAsFilesValue.enabled: When this value is true, the + user's Paper docs are accessible in Dropbox with the .paper extension + and must be accessed via the /files endpoints. When this value is + false, the user's Paper docs are stored separate from Dropbox files and + folders and should be accessed via the /paper endpoints. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def enabled(cls, val): + """ + Create an instance of this class set to the ``enabled`` tag with value + ``val``. + + :param bool val: + :rtype: PaperAsFilesValue + """ + return cls('enabled', val) + + def is_enabled(self): + """ + Check if the union tag is ``enabled``. + + :rtype: bool + """ + return self._tag == 'enabled' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_enabled(self): + """ + When this value is true, the user's Paper docs are accessible in Dropbox + with the .paper extension and must be accessed via the /files endpoints. + When this value is false, the user's Paper docs are stored separate from + Dropbox files and folders and should be accessed via the /paper + endpoints. + + Only call this if :meth:`is_enabled` is true. + + :rtype: bool + """ + if not self.is_enabled(): + raise AttributeError("tag 'enabled' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(PaperAsFilesValue, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'PaperAsFilesValue(%r, %r)' % (self._tag, self._value) + +PaperAsFilesValue_validator = bv.Union(PaperAsFilesValue) + class SpaceAllocation(bb.Union): """ Space is allocated differently based on the type of account. @@ -1510,6 +1647,9 @@ class TeamSpaceAllocation(bb.Struct): :ivar users.TeamSpaceAllocation.user_within_team_space_limit_type: The type of the space limit imposed on the team member (off, alert_only, stop_sync). + :ivar users.TeamSpaceAllocation.user_within_team_space_used_cached: An + accurate cached calculation of a team member's total space usage + (bytes). """ __slots__ = [ @@ -1521,6 +1661,8 @@ class TeamSpaceAllocation(bb.Struct): '_user_within_team_space_allocated_present', '_user_within_team_space_limit_type_value', '_user_within_team_space_limit_type_present', + '_user_within_team_space_used_cached_value', + '_user_within_team_space_used_cached_present', ] _has_required_fields = True @@ -1529,7 +1671,8 @@ def __init__(self, used=None, allocated=None, user_within_team_space_allocated=None, - user_within_team_space_limit_type=None): + user_within_team_space_limit_type=None, + user_within_team_space_used_cached=None): self._used_value = None self._used_present = False self._allocated_value = None @@ -1538,6 +1681,8 @@ def __init__(self, self._user_within_team_space_allocated_present = False self._user_within_team_space_limit_type_value = None self._user_within_team_space_limit_type_present = False + self._user_within_team_space_used_cached_value = None + self._user_within_team_space_used_cached_present = False if used is not None: self.used = used if allocated is not None: @@ -1546,6 +1691,8 @@ def __init__(self, self.user_within_team_space_allocated = user_within_team_space_allocated if user_within_team_space_limit_type is not None: self.user_within_team_space_limit_type = user_within_team_space_limit_type + if user_within_team_space_used_cached is not None: + self.user_within_team_space_used_cached = user_within_team_space_used_cached @property def used(self): @@ -1642,19 +1789,328 @@ def user_within_team_space_limit_type(self): self._user_within_team_space_limit_type_value = None self._user_within_team_space_limit_type_present = False + @property + def user_within_team_space_used_cached(self): + """ + An accurate cached calculation of a team member's total space usage + (bytes). + + :rtype: int + """ + if self._user_within_team_space_used_cached_present: + return self._user_within_team_space_used_cached_value + else: + raise AttributeError("missing required field 'user_within_team_space_used_cached'") + + @user_within_team_space_used_cached.setter + def user_within_team_space_used_cached(self, val): + val = self._user_within_team_space_used_cached_validator.validate(val) + self._user_within_team_space_used_cached_value = val + self._user_within_team_space_used_cached_present = True + + @user_within_team_space_used_cached.deleter + def user_within_team_space_used_cached(self): + self._user_within_team_space_used_cached_value = None + self._user_within_team_space_used_cached_present = False + def _process_custom_annotations(self, annotation_type, field_path, processor): super(TeamSpaceAllocation, self)._process_custom_annotations(annotation_type, field_path, processor) def __repr__(self): - return 'TeamSpaceAllocation(used={!r}, allocated={!r}, user_within_team_space_allocated={!r}, user_within_team_space_limit_type={!r})'.format( + return 'TeamSpaceAllocation(used={!r}, allocated={!r}, user_within_team_space_allocated={!r}, user_within_team_space_limit_type={!r}, user_within_team_space_used_cached={!r})'.format( self._used_value, self._allocated_value, self._user_within_team_space_allocated_value, self._user_within_team_space_limit_type_value, + self._user_within_team_space_used_cached_value, ) TeamSpaceAllocation_validator = bv.Struct(TeamSpaceAllocation) +class UserFeature(bb.Union): + """ + A set of features that a Dropbox User account may have configured. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar users.UserFeature.paper_as_files: This feature contains information + about how the user's Paper files are stored. + :ivar users.UserFeature.file_locking: This feature allows users to lock + files in order to restrict other users from editing them. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + paper_as_files = None + # Attribute is overwritten below the class definition + file_locking = None + # Attribute is overwritten below the class definition + other = None + + def is_paper_as_files(self): + """ + Check if the union tag is ``paper_as_files``. + + :rtype: bool + """ + return self._tag == 'paper_as_files' + + def is_file_locking(self): + """ + Check if the union tag is ``file_locking``. + + :rtype: bool + """ + return self._tag == 'file_locking' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserFeature, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserFeature(%r, %r)' % (self._tag, self._value) + +UserFeature_validator = bv.Union(UserFeature) + +class UserFeatureValue(bb.Union): + """ + Values that correspond to entries in :class:`UserFeature`. + + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + other = None + + @classmethod + def paper_as_files(cls, val): + """ + Create an instance of this class set to the ``paper_as_files`` tag with + value ``val``. + + :param PaperAsFilesValue val: + :rtype: UserFeatureValue + """ + return cls('paper_as_files', val) + + @classmethod + def file_locking(cls, val): + """ + Create an instance of this class set to the ``file_locking`` tag with + value ``val``. + + :param FileLockingValue val: + :rtype: UserFeatureValue + """ + return cls('file_locking', val) + + def is_paper_as_files(self): + """ + Check if the union tag is ``paper_as_files``. + + :rtype: bool + """ + return self._tag == 'paper_as_files' + + def is_file_locking(self): + """ + Check if the union tag is ``file_locking``. + + :rtype: bool + """ + return self._tag == 'file_locking' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def get_paper_as_files(self): + """ + Only call this if :meth:`is_paper_as_files` is true. + + :rtype: PaperAsFilesValue + """ + if not self.is_paper_as_files(): + raise AttributeError("tag 'paper_as_files' not set") + return self._value + + def get_file_locking(self): + """ + Only call this if :meth:`is_file_locking` is true. + + :rtype: FileLockingValue + """ + if not self.is_file_locking(): + raise AttributeError("tag 'file_locking' not set") + return self._value + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserFeatureValue, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserFeatureValue(%r, %r)' % (self._tag, self._value) + +UserFeatureValue_validator = bv.Union(UserFeatureValue) + +class UserFeaturesGetValuesBatchArg(bb.Struct): + """ + :ivar users.UserFeaturesGetValuesBatchArg.features: A list of features in + :class:`UserFeature`. If the list is empty, this route will return + :class:`UserFeaturesGetValuesBatchError`. + """ + + __slots__ = [ + '_features_value', + '_features_present', + ] + + _has_required_fields = True + + def __init__(self, + features=None): + self._features_value = None + self._features_present = False + if features is not None: + self.features = features + + @property + def features(self): + """ + A list of features in :class:`UserFeature`. If the list is empty, this + route will return :class:`UserFeaturesGetValuesBatchError`. + + :rtype: list of [UserFeature] + """ + if self._features_present: + return self._features_value + else: + raise AttributeError("missing required field 'features'") + + @features.setter + def features(self, val): + val = self._features_validator.validate(val) + self._features_value = val + self._features_present = True + + @features.deleter + def features(self): + self._features_value = None + self._features_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserFeaturesGetValuesBatchArg, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserFeaturesGetValuesBatchArg(features={!r})'.format( + self._features_value, + ) + +UserFeaturesGetValuesBatchArg_validator = bv.Struct(UserFeaturesGetValuesBatchArg) + +class UserFeaturesGetValuesBatchError(bb.Union): + """ + This class acts as a tagged union. Only one of the ``is_*`` methods will + return true. To get the associated value of a tag (if one exists), use the + corresponding ``get_*`` method. + + :ivar users.UserFeaturesGetValuesBatchError.empty_features_list: At least + one :class:`UserFeature` must be included in the + :class:`UserFeaturesGetValuesBatchArg`.features list. + """ + + _catch_all = 'other' + # Attribute is overwritten below the class definition + empty_features_list = None + # Attribute is overwritten below the class definition + other = None + + def is_empty_features_list(self): + """ + Check if the union tag is ``empty_features_list``. + + :rtype: bool + """ + return self._tag == 'empty_features_list' + + def is_other(self): + """ + Check if the union tag is ``other``. + + :rtype: bool + """ + return self._tag == 'other' + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserFeaturesGetValuesBatchError, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserFeaturesGetValuesBatchError(%r, %r)' % (self._tag, self._value) + +UserFeaturesGetValuesBatchError_validator = bv.Union(UserFeaturesGetValuesBatchError) + +class UserFeaturesGetValuesBatchResult(bb.Struct): + + __slots__ = [ + '_values_value', + '_values_present', + ] + + _has_required_fields = True + + def __init__(self, + values=None): + self._values_value = None + self._values_present = False + if values is not None: + self.values = values + + @property + def values(self): + """ + :rtype: list of [UserFeatureValue] + """ + if self._values_present: + return self._values_value + else: + raise AttributeError("missing required field 'values'") + + @values.setter + def values(self, val): + val = self._values_validator.validate(val) + self._values_value = val + self._values_present = True + + @values.deleter + def values(self): + self._values_value = None + self._values_present = False + + def _process_custom_annotations(self, annotation_type, field_path, processor): + super(UserFeaturesGetValuesBatchResult, self)._process_custom_annotations(annotation_type, field_path, processor) + + def __repr__(self): + return 'UserFeaturesGetValuesBatchResult(values={!r})'.format( + self._values_value, + ) + +UserFeaturesGetValuesBatchResult_validator = bv.Struct(UserFeaturesGetValuesBatchResult) + GetAccountBatchResult_validator = bv.List(BasicAccount_validator) Account._account_id_validator = users_common.AccountId_validator Account._name_validator = Name_validator @@ -1690,6 +2146,15 @@ def __repr__(self): ('team_member_id', BasicAccount._team_member_id_validator), ] +FileLockingValue._enabled_validator = bv.Boolean() +FileLockingValue._other_validator = bv.Void() +FileLockingValue._tagmap = { + 'enabled': FileLockingValue._enabled_validator, + 'other': FileLockingValue._other_validator, +} + +FileLockingValue.other = FileLockingValue('other') + FullAccount._country_validator = bv.Nullable(bv.String(min_length=2, max_length=2)) FullAccount._locale_validator = bv.String(min_length=2) FullAccount._referral_link_validator = bv.String() @@ -1792,6 +2257,15 @@ def __repr__(self): ('abbreviated_name', Name._abbreviated_name_validator), ] +PaperAsFilesValue._enabled_validator = bv.Boolean() +PaperAsFilesValue._other_validator = bv.Void() +PaperAsFilesValue._tagmap = { + 'enabled': PaperAsFilesValue._enabled_validator, + 'other': PaperAsFilesValue._other_validator, +} + +PaperAsFilesValue.other = PaperAsFilesValue('other') + SpaceAllocation._individual_validator = IndividualSpaceAllocation_validator SpaceAllocation._team_validator = TeamSpaceAllocation_validator SpaceAllocation._other_validator = bv.Void() @@ -1818,19 +2292,74 @@ def __repr__(self): TeamSpaceAllocation._allocated_validator = bv.UInt64() TeamSpaceAllocation._user_within_team_space_allocated_validator = bv.UInt64() TeamSpaceAllocation._user_within_team_space_limit_type_validator = team_common.MemberSpaceLimitType_validator +TeamSpaceAllocation._user_within_team_space_used_cached_validator = bv.UInt64() TeamSpaceAllocation._all_field_names_ = set([ 'used', 'allocated', 'user_within_team_space_allocated', 'user_within_team_space_limit_type', + 'user_within_team_space_used_cached', ]) TeamSpaceAllocation._all_fields_ = [ ('used', TeamSpaceAllocation._used_validator), ('allocated', TeamSpaceAllocation._allocated_validator), ('user_within_team_space_allocated', TeamSpaceAllocation._user_within_team_space_allocated_validator), ('user_within_team_space_limit_type', TeamSpaceAllocation._user_within_team_space_limit_type_validator), + ('user_within_team_space_used_cached', TeamSpaceAllocation._user_within_team_space_used_cached_validator), ] +UserFeature._paper_as_files_validator = bv.Void() +UserFeature._file_locking_validator = bv.Void() +UserFeature._other_validator = bv.Void() +UserFeature._tagmap = { + 'paper_as_files': UserFeature._paper_as_files_validator, + 'file_locking': UserFeature._file_locking_validator, + 'other': UserFeature._other_validator, +} + +UserFeature.paper_as_files = UserFeature('paper_as_files') +UserFeature.file_locking = UserFeature('file_locking') +UserFeature.other = UserFeature('other') + +UserFeatureValue._paper_as_files_validator = PaperAsFilesValue_validator +UserFeatureValue._file_locking_validator = FileLockingValue_validator +UserFeatureValue._other_validator = bv.Void() +UserFeatureValue._tagmap = { + 'paper_as_files': UserFeatureValue._paper_as_files_validator, + 'file_locking': UserFeatureValue._file_locking_validator, + 'other': UserFeatureValue._other_validator, +} + +UserFeatureValue.other = UserFeatureValue('other') + +UserFeaturesGetValuesBatchArg._features_validator = bv.List(UserFeature_validator) +UserFeaturesGetValuesBatchArg._all_field_names_ = set(['features']) +UserFeaturesGetValuesBatchArg._all_fields_ = [('features', UserFeaturesGetValuesBatchArg._features_validator)] + +UserFeaturesGetValuesBatchError._empty_features_list_validator = bv.Void() +UserFeaturesGetValuesBatchError._other_validator = bv.Void() +UserFeaturesGetValuesBatchError._tagmap = { + 'empty_features_list': UserFeaturesGetValuesBatchError._empty_features_list_validator, + 'other': UserFeaturesGetValuesBatchError._other_validator, +} + +UserFeaturesGetValuesBatchError.empty_features_list = UserFeaturesGetValuesBatchError('empty_features_list') +UserFeaturesGetValuesBatchError.other = UserFeaturesGetValuesBatchError('other') + +UserFeaturesGetValuesBatchResult._values_validator = bv.List(UserFeatureValue_validator) +UserFeaturesGetValuesBatchResult._all_field_names_ = set(['values']) +UserFeaturesGetValuesBatchResult._all_fields_ = [('values', UserFeaturesGetValuesBatchResult._values_validator)] + +features_get_values = bb.Route( + 'features/get_values', + 1, + False, + UserFeaturesGetValuesBatchArg_validator, + UserFeaturesGetValuesBatchResult_validator, + UserFeaturesGetValuesBatchError_validator, + {'host': u'api', + 'style': u'rpc'}, +) get_account = bb.Route( 'get_account', 1, @@ -1873,6 +2402,7 @@ def __repr__(self): ) ROUTES = { + 'features/get_values': features_get_values, 'get_account': get_account, 'get_account_batch': get_account_batch, 'get_current_account': get_current_account, From 517b420be0c2e085356002016c1969842f0acf5b Mon Sep 17 00:00:00 2001 From: Adam Fontenot Date: Sun, 9 Apr 2023 19:07:49 -0400 Subject: [PATCH 022/145] [service.libraryautoupdate] 1.2.4 libraryautoupdate performs a connectivity check before scanning the library. Previously, this check fetched www.google.com, which is inappropriate for a connection check. This commit fixes the problem by fetching a static connectivity check page, which returns a 204 status code with an empty response. --- service.libraryautoupdate/addon.xml | 6 +++--- service.libraryautoupdate/resources/lib/service.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/service.libraryautoupdate/addon.xml b/service.libraryautoupdate/addon.xml index 8ff42d5f6..302f918c7 100644 --- a/service.libraryautoupdate/addon.xml +++ b/service.libraryautoupdate/addon.xml @@ -1,6 +1,6 @@  + name="Library Auto Update" version="1.2.4" provider-name="robweber"> @@ -78,7 +78,7 @@ resources/media/icon.png - Version 1.2.3 -- fix for hourly timer settings not working + Version 1.2.4 +- use a connection check URL instead of google.com
diff --git a/service.libraryautoupdate/resources/lib/service.py b/service.libraryautoupdate/resources/lib/service.py index 9fe1f215c..a17686196 100644 --- a/service.libraryautoupdate/resources/lib/service.py +++ b/service.libraryautoupdate/resources/lib/service.py @@ -337,7 +337,7 @@ def databaseUpdated(self, database): def _networkUp(self): try: - urlopen('http://www.google.com', timeout=1) + urlopen('http://connectivitycheck.gstatic.com/generate_204', timeout=1) return True except Exception: pass From ed8d3cc86399547ba7809b916c30ffb02178a092 Mon Sep 17 00:00:00 2001 From: Birger Jesch Date: Mon, 10 Apr 2023 09:19:35 +0200 Subject: [PATCH 023/145] Fix deprecated xbmc.translatePath by transferring translatePath to xbmcvfs, correct spelling for german language, bump version. (#2425) --- script.metadata.editor/addon.xml | 2 +- .../language/resource.language.de_DE/strings.po | 12 ++++++------ script.metadata.editor/resources/lib/helper.py | 2 +- script.metadata.editor/resources/lib/nfo_updater.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/script.metadata.editor/addon.xml b/script.metadata.editor/addon.xml index 214073ca8..62f571883 100644 --- a/script.metadata.editor/addon.xml +++ b/script.metadata.editor/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/script.metadata.editor/resources/language/resource.language.de_DE/strings.po b/script.metadata.editor/resources/language/resource.language.de_DE/strings.po index c0ad55dcd..13da79841 100644 --- a/script.metadata.editor/resources/language/resource.language.de_DE/strings.po +++ b/script.metadata.editor/resources/language/resource.language.de_DE/strings.po @@ -125,7 +125,7 @@ msgstr "Als Standard setzen?" #: /resources/settings.xml msgctxt "#32021" msgid "Enable .nfo updating for movies, TV shows and music videos" -msgstr "Aktiviere .nfo Updating für Filme, Serien und Musikvideos" +msgstr "Aktiviere .nfo Aktualisierung für Filme, Serien und Musikvideos" #: /resources/lib/editor.py msgctxt "#32022" @@ -155,7 +155,7 @@ msgstr "Hohe Serverlast. Bitte warten." #: /resources/settings.xml msgctxt "#32027" msgid "TV show library is based on informations of" -msgstr "Serien-Datenbank ist basierend auf Informationen von" +msgstr "Serien-Datenbank basiert auf Informationen von" #: /resources/settings.xml msgctxt "#32029" @@ -170,7 +170,7 @@ msgstr "Bewertungs-Updater" #: /resources/settings.xml msgctxt "#32028" msgid "Run updating process in the background" -msgstr "Führe das Updaten im Hintergrund aus" +msgstr "Führe die Aktualisierung im Hintergrund aus" #: /resources/settings.xml msgctxt "#32031" @@ -204,7 +204,7 @@ msgstr "" #: /default.py msgctxt "#32036" msgid "Update TV show ratings" -msgstr "Aktutalisiere Serienbewertungen" +msgstr "Aktualisiere Serienbewertungen" #: /resources/lib/rating_updater.py msgctxt "#32033" @@ -223,7 +223,7 @@ msgstr "Erstelle .nfo Datei, falls diese fehlt" #: /default.py msgctxt "#32037" msgid "Update movie ratings" -msgstr "Aktutalisiere Filmbewertungen" +msgstr "Aktualisiere Filmbewertungen" #: /default.py msgctxt "#32038" @@ -300,7 +300,7 @@ msgctxt "#32052" msgid "Fallback to US MPAA if configured country has no certification stored" msgstr "" "Nutze US MPAA als Fallback, falls keine Zertifizierung der konfigurierten " -"Region gefunden wurde" +"Region gefunden wird" #: /resources/settings.xml msgctxt "#32053" diff --git a/script.metadata.editor/resources/lib/helper.py b/script.metadata.editor/resources/lib/helper.py index 99e8ee1b1..45694dcbb 100644 --- a/script.metadata.editor/resources/lib/helper.py +++ b/script.metadata.editor/resources/lib/helper.py @@ -24,7 +24,7 @@ ADDON = xbmcaddon.Addon() ADDON_ID = ADDON.getAddonInfo('id') -ADDON_DATA_PATH = os.path.join(xbmc.translatePath("special://profile/addon_data/%s" % ADDON_ID)) +ADDON_DATA_PATH = os.path.join(xbmcvfs.translatePath("special://profile/addon_data/%s" % ADDON_ID)) NOTICE = xbmc.LOGINFO WARNING = xbmc.LOGWARNING diff --git a/script.metadata.editor/resources/lib/nfo_updater.py b/script.metadata.editor/resources/lib/nfo_updater.py index c93428814..66e6c9dbc 100644 --- a/script.metadata.editor/resources/lib/nfo_updater.py +++ b/script.metadata.editor/resources/lib/nfo_updater.py @@ -108,7 +108,7 @@ def write_file(self): xml_prettyprint(self.root) - content = ET.tostring(self.root, encoding='UTF-8', method='xml', xml_declaration=True).decode() + content = ET.tostring(self.root, encoding='UTF8', method='xml').decode() with xbmcvfs.File(self.targetfile, 'w') as f: result = f.write(content) From 42dcb31df2e5a91b967d027201357e7e335e0d60 Mon Sep 17 00:00:00 2001 From: zim514 Date: Wed, 12 Apr 2023 02:03:45 +0000 Subject: [PATCH 024/145] [script.service.hue] 1.4.15 --- script.service.hue/addon.xml | 23 +- .../resource.language.da_dk/strings.po | 6 +- .../resource.language.es_es/strings.po | 262 ++++++++--------- .../resource.language.fr_fr/strings.po | 8 +- .../resource.language.it_it/strings.po | 48 ++-- .../resource.language.sk_sk/strings.po | 266 +++++++++--------- .../resource.language.zh_cn/strings.po | 8 +- script.service.hue/resources/lib/__init__.py | 3 +- script.service.hue/resources/lib/ambigroup.py | 41 ++- script.service.hue/resources/lib/core.py | 18 +- .../resources/lib/hueconnection.py | 17 +- .../resources/lib/imageprocess.py | 2 +- script.service.hue/resources/lib/kodiutils.py | 6 +- script.service.hue/resources/lib/language.py | 2 +- .../resources/lib/lightgroup.py | 50 ++-- script.service.hue/resources/lib/menu.py | 6 +- script.service.hue/resources/lib/reporting.py | 13 +- 17 files changed, 394 insertions(+), 385 deletions(-) diff --git a/script.service.hue/addon.xml b/script.service.hue/addon.xml index fa31c365e..3a20be1de 100644 --- a/script.service.hue/addon.xml +++ b/script.service.hue/addon.xml @@ -1,4 +1,5 @@ - + + @@ -20,43 +21,49 @@
https://github.com/zim514/script.service.hue https://forum.kodi.tv/showthread.php?tid=344886 - -Remove dependency with SimpleCache -Fix service not disabling correctly -Fix reconnection -Improved Hue error handling - + v1.4.15 +- Fix 'disable during daylight' option +- Localisation updates from Weblate +- Improved connection error handling +- Fix crash on ambilight initialization and settings changes + Automatitza les llums Hue amb la reproducció de Kodi Automatizace Hue světel s přehráváním Kodi Automatiser Hue-lys sammen med afspilning i Kodi Hue-Licht mit der Kodi-Wiedergabe automatisieren Automate Hue lights with Kodi playback + Automatiza las luces Hue con la reproducción de Kodi Ohjaa Hue-valoja automaattisesti Kodin toistolla Automatiser les lumières Hue V2 (Philips) avec la lecture Kodi Automatski Hue svjetla s Kodi reprodukcijom Automatizza le luci Hue con la riproduzione di Kodi Kodi 재생으로 Hue 조명 자동화 + Automatizácia svetiel Hue s prehrávaním v Kodi Kodi 播放时自动调整 Hue 灯光 Automatitza les teves llums Hue amb Kodi. Creeu escenes en diverses habitacions que s'executen al reproduir, posar en pausa o aturar la reproducció multimèdia. Crea i suprimeix escenes de diverses habitacions des de la configuració del complement i, a continuació, selecciona quina vols aplicar als diferents esdeveniments de reproducció. Pots utilitzar les hores de sortida i posta del sol de Hue per desactivar automàticament el servei durant el dia i encendre els llums al capvespre durant la reproducció. Inclou suport d'Ambilight. Ovládejte Hue světla automaticky pomocí Kodi. Vytvořte scény pro začátek, přestávku i ukončení přehrávání a nechte Kodi reagovat automaticky na Vaše akce. Je možné využít východ i západ slunce. Obsahuje podporu pro Ambilight. Automatiser dine Hue-lys med Kodi. Opret scener i flere rum, der kører, når du afspiller, sætter på pause eller stopper medieafspilning. Opret og slet multirumsscener fra indstillinger og vælg derefter, hvilke der skal anvendes til forskellige afspilningstyper. Kan bruge Hues tider for solopgang og solnedgang til automatisk at deaktivere tjenesten i dagtimerne og tænde lysene ved solnedgang under afspilning. Inkluderer understøttelse af Ambilight. Hue-Licht mit Kodi automatisieren. Mehrraumszenen erstellen, die während der Wiedergabe, beim Pausieren oder Stoppen der Medienwiedergabe aktiv sind. Mehrraumszenen aus den Addon-Einstellungen heraus erstellen und löschen, dann auswählen, welche für verschiedene Wiedergabeereignisse genutzt werden sollen. Kann Hues Sonnenaufgangs- und -untergangszeiten zum automatischen Deaktivieren des Dienstes während der Tageszeit nutzen und die Lampen während der Wiedergabe bei Sonnenuntergang einschalten. Beinhaltet Ambilight-Unterstützung. Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support. + Automatiza tus luces Hue con Kodi. Crea escenas multihabitación que se ejecutan al Reproducir, Pausar o Detener la reproducción multimedia. Cree y elimine escenas multihabitación desde los ajustes del add-on y, a continuación, seleccionar cuáles se aplicarán a los diferentes eventos de reproducción. Puede usar las horas de salida y puesta del sol de Hue para desactivar automáticamente el servicio durante el día y encender las luces al atardecer durante la reproducción. Incluye compatibilidad con Ambilight. Automatisoi Hue-valosi Kodilla. Luo monihuonevalaistusasetuksia, jotka suoritetaan median toiston alkaessa, tauotessa tai päättyessä. Luo ja poista valaistusasetuksia lisäosan asetuksista ja valitse niiden käyttö ei toistotapahtumissa. Huen auringonnousu- ja -laskuaikoja voidaan hyödyntää palvelun automaattiseen käytöstä poistoon päiväsaikaan ja valojen sytytykseen auringon laskiessa toiston aikana. Sisältää myös Ambilight-tuen. Automatiser vos lumières Hue V2 (Philips) avec Kodi. Créez des scènes multi-pièces qui s'exécutent lorsque vous lisez, mettez en pause ou arrêtez la lecture multimédia. Créer et supprimer des scènes multi-pièces à partir des paramètres complémentaires, puis sélectionner celle à appliquer pour différents événements de lecture. Peut utiliser les heures de lever et de coucher du soleil de Hue pour désactiver automatiquement le service pendant la journée et allumer les lumières au coucher du soleil pendant la lecture. Inclut la prise en charge Ambilight. Automatizirajte svoja Hue svjetla s Kodijem. Stvorite višesobnu scenu koja se pokreće kada Reproducirate, Pauzirate ili Zaustavite medijsku reprodukciju. Stvorite i obrišite višesobne scene iz postavki dodatka tada odaberite koju primijeniti za drugačiji događaj reprodukcije. Može se koristiti zasićenje vremena izlaska i zalaska sunca za automatsko onemogućavanje usluge tijekom dana i uključivanje svjetla pri zalasku sunca tijekom reprodukcije. - Automatizza le tue luci Hue con Kodi. Crea scene multi-stanza che vengono eseguite quando riproduci, metti in pausa o interrompi la riproduzione multimediale. Crea ed elimina scene multi-room dalle impostazioni del componente aggiuntivo, quindi seleziona quali applicare per diversi eventi di riproduzione. Può utilizzare gli orari di alba e tramonto di Hue per disabilitare automaticamente il servizio durante il giorno e accendere le luci al tramonto durante la riproduzione. Include il supporto Ambilight. + Automatizza le tue luci Hue con Kodi. Crea scene multi-room che vengono eseguite quando riproduci, metti in pausa o interrompi la riproduzione multimediale. Crea ed elimina scene multi-room dalle impostazioni dell'add-on, quindi seleziona quale applicare per diversi eventi di riproduzione. Può utilizzare gli orari di alba e tramonto di Hue per disattivare automaticamente il servizio durante il giorno e accendere le luci al tramonto durante la riproduzione. Include il supporto Ambilight. Kodi로 Hue 조명을 자동화하세요. 미디어 재생을 재생, 일시 중지 또는 중지할 때 실행되는 멀티룸 장면을 만듭니다. 애드온 설정에서 멀티룸 장면을 만들거나 삭제하고 다른 재생 이벤트에 적용할 장면을 선택합니다. Hue의 일출 및 일몰 시간을 사용하여 주간에는 서비스를 자동으로 비활성화하고 재생 중에 일몰 시 조명을 켤 수 있습니다. Ambilight 지원이 포함됩니다. + Automatizácia svetiel Hue pomocou Kodi. Vytvorte scény pre viacero miestností, ktoré sa spustia pri prehrávaní, pozastavení alebo ukončení prehrávania médií. Vytvárajte a odstraňujte scény z viacerých miestností v nastaveniach doplnku a potom vyberte, ktoré sa majú použiť pre rôzne udalosti prehrávania. Môžete využiť časy východu a západu slnka zariadenia Hue na automatické vypnutie služby počas dňa a zapnutie svetiel pri západe slnka počas prehrávania. Obsahuje podporu funkcie Ambilight. 使用 Kodi 自动化 Hue 灯光。创建播放、暂停或停止媒体播放时运行的多房间场景。从插件设置中创建和删除多房间场景,然后选择要应用于不同播放事件的场景。可以使用 Hue 灯的日出和日落时间在白天自动禁用服务,并在日落后播放期间打开灯光。包括 Ambilight 支持。 Vyžaduje Hue Bridge V2 (čtvercový). Ambilight není podporován na všech zařízeních. Kræver en Hue Bridge V2 (firkant). Ambilight er ikke tilgængelig på al hardware. Erfordert eine Hue Bridge V2 (quadratisch). Ambilight-Unterstützung nicht mit jeder Hardware verfügbar. Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware. + Requiere un Hue Bridge V2 (cuadrado). Ambilight no está disponible en todos los equipos. Vaatii Hue Silta V2 (nelikulmainen) -laitteen. Ambilight ei ole käytettävissä kaikilla laitteilla. Nécessite un bridge Hue V2 (carré). Ambilight n'est pas disponible sur tous les matériels. Zahtijeva Hue Bridge V2 (Square). Ambijetalno svijtlo nije dostupno na svim hardverima. Richiede un Bridge Hue V2 (quadrato). Ambilight non disponibile su tutto l'hardware. Hue Bridge V2(정사각형)가 필요합니다. 모든 하드웨어에서 Ambilight를 사용할 수 있는 것은 아닙니다. + Vyžaduje Hue Bridge V2 (štvorcový). Ambilight nie je k dispozícii na všetkých zariadeniach. 需要 Hue Bridge V2 桥接器(正方形)。并非所有硬件都支持环境光。
diff --git a/script.service.hue/resources/language/resource.language.da_dk/strings.po b/script.service.hue/resources/language/resource.language.da_dk/strings.po index 222c7eb8e..69e986663 100644 --- a/script.service.hue/resources/language/resource.language.da_dk/strings.po +++ b/script.service.hue/resources/language/resource.language.da_dk/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-01-21 23:15+0000\n" +"PO-Revision-Date: 2023-02-23 22:15+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Danish \n" "Language: da_dk\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15.1\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -558,7 +558,7 @@ msgstr "FEJL: Scene eller lys blev ikke fundet, den kan være ændret eller blev msgctxt "#30033" msgid "Reconnected" -msgstr "" +msgstr "Forbundet igen" #~ msgctxt "#30501" #~ msgid "Discover Hue Bridge" diff --git a/script.service.hue/resources/language/resource.language.es_es/strings.po b/script.service.hue/resources/language/resource.language.es_es/strings.po index e5e5f2f28..1ea48c4d0 100644 --- a/script.service.hue/resources/language/resource.language.es_es/strings.po +++ b/script.service.hue/resources/language/resource.language.es_es/strings.po @@ -6,39 +6,39 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-01-03 23:15+0000\n" -"Last-Translator: Christian Gade \n" +"PO-Revision-Date: 2023-03-02 11:15+0000\n" +"Last-Translator: José Antonio Alvarado \n" "Language-Team: Spanish (Spain) \n" "Language: es_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" -msgstr "" +msgstr "Automatiza las luces Hue con la reproducción de Kodi" msgctxt "Addon Description" msgid "Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support." -msgstr "" +msgstr "Automatiza tus luces Hue con Kodi. Crea escenas multihabitación que se ejecutan al Reproducir, Pausar o Detener la reproducción multimedia. Cree y elimine escenas multihabitación desde los ajustes del add-on y, a continuación, seleccionar cuáles se aplicarán a los diferentes eventos de reproducción. Puede usar las horas de salida y puesta del sol de Hue para desactivar automáticamente el servicio durante el día y encender las luces al atardecer durante la reproducción. Incluye compatibilidad con Ambilight." msgctxt "Addon Disclaimer" msgid "Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware." -msgstr "" +msgstr "Requiere un Hue Bridge V2 (cuadrado). Ambilight no está disponible en todos los equipos." msgctxt "#32100" msgid "Video Actions" -msgstr "" +msgstr "Acciones de vídeo" msgctxt "#32102" msgid "Audio Actions" -msgstr "" +msgstr "Acciones de audio" msgctxt "#32201" msgid "Start/Resume" -msgstr "" +msgstr "Iniciar/Reanudar" msgctxt "#32202" msgid "Pause" @@ -50,51 +50,51 @@ msgstr "Parar" msgctxt "#32510" msgid "Scene Name:" -msgstr "" +msgstr "Nombre de la escena:" msgctxt "#32511" msgid "Scene ID" -msgstr "" +msgstr "ID de escena" msgctxt "#32512" msgid "Select..." -msgstr "" +msgstr "Seleccionar..." msgctxt "#30500" msgid "Bridge" -msgstr "" +msgstr "Bridge" msgctxt "#30501" msgid "Discover Hue Bridge / Enter IP" -msgstr "Discover Hue Bridge / Enter IP" +msgstr "Descubrir Hue Bridge / Introducir IP" msgctxt "#30502" msgid "Bridge IP" -msgstr "" +msgstr "IP Bridge" msgctxt "#30503" msgid "Bridge User" -msgstr "" +msgstr "Usuario de Bridge" msgctxt "#30505" msgid "Enable Schedule (24h format)" -msgstr "" +msgstr "Activar horario (formato 24h)" msgctxt "#30506" msgid "Start time:" -msgstr "" +msgstr "Hora de inicio:" msgctxt "#30507" msgid "End time:" -msgstr "" +msgstr "Hora de fin:" msgctxt "#30508" msgid "Disable during daylight" -msgstr "" +msgstr "Desactivar con luz diurna" msgctxt "#30509" msgid "Activate during playback at sunset" -msgstr "" +msgstr "Activar durante la reproducción al atardecer" msgctxt "#30510" msgid "General" @@ -106,39 +106,39 @@ msgstr "Planificador" msgctxt "#30512" msgid "Scenes" -msgstr "" +msgstr "Escenas" msgctxt "#30513" msgid "Play Scene Enabled" -msgstr "" +msgstr "Reproducción de escena activada" msgctxt "#30514" msgid "Pause Scene Enabled" -msgstr "" +msgstr "Pausa de escena activada" msgctxt "#30515" msgid "Stop Scene Enabled" -msgstr "" +msgstr "Detener escena activado" msgctxt "#30516" msgid "Disable time check if any light already on" -msgstr "" +msgstr "Desactivar comprobar la hora si alguna luz ya está encendida" msgctxt "#30517" msgid "Don't enable scene if any light is off" -msgstr "" +msgstr "No activar la escena si alguna luz está apagada" msgctxt "#30521" msgid "[B][I]Warning: Not supported on all hardware[/B][/I]" -msgstr "" +msgstr "[B][I]Advertencia: No compatible con todo el hardware[/B][/I]" msgctxt "#30522" msgid "CPU & Hue performance" -msgstr "" +msgstr "Rendimiento de CPU y Hue" msgctxt "#30523" msgid "Ambilight" -msgstr "" +msgstr "Ambilight" msgctxt "#32101" msgid "Advanced" @@ -146,115 +146,115 @@ msgstr "Avanzado" msgctxt "#32106" msgid "Video Activation" -msgstr "" +msgstr "Activación de vídeo" msgctxt "#6101" msgid "Select Lights" -msgstr "" +msgstr "Seleccionar luces" msgctxt "#30520" msgid "Enabled" -msgstr "" +msgstr "Activado" msgctxt "#9001" msgid "Press connect button on Hue bridge" -msgstr "" +msgstr "Pulsa el botón de conexión del Hue bridge" msgctxt "#9007" msgid "Create Scene" -msgstr "" +msgstr "Crear escena" msgctxt "#9008" msgid "Delete Scene" -msgstr "" +msgstr "Borrar escena" msgctxt "#30000" msgid "Hue Service" -msgstr "" +msgstr "Servicio Hue" msgctxt "#30004" msgid "Check your bridge and network" -msgstr "" +msgstr "Comprobar el bridge y la red" msgctxt "#30006" msgid "Hue connected" -msgstr "" +msgstr "Hue conectado" msgctxt "#30008" msgid "Bridge not found" -msgstr "" +msgstr "No se encuentra el bridge" msgctxt "#30010" msgid "User not found" -msgstr "" +msgstr "Usuario no encontrado" msgctxt "#30011" msgid "Complete!" -msgstr "" +msgstr "¡Completo!" msgctxt "#30013" msgid "Cancelled" -msgstr "" +msgstr "Cancelado" msgctxt "#30015" msgid "Select Hue Lights..." -msgstr "" +msgstr "Seleccionar luces Hue..." msgctxt "#30017" msgid "Found bridge: " -msgstr "" +msgstr "Bridge encontrado: " msgctxt "#30018" msgid "Discover bridge..." -msgstr "" +msgstr "Descubrir el bridge..." msgctxt "#30021" msgid "Bridge connection failed" -msgstr "" +msgstr "Fallo en la conexión del bridge" msgctxt "#30022" msgid "Discovery started" -msgstr "" +msgstr "Descubrimiento iniciado" msgctxt "#30023" msgid "Bridge not configured" -msgstr "" +msgstr "Bridge no configurado" msgctxt "#30024" msgid "Check Hue Bridge configuration" -msgstr "" +msgstr "Comprobar la configuración del Hue Bridge" msgctxt "#30025" msgid "ERROR: Scene not deleted" -msgstr "" +msgstr "ERROR: Escena no eliminada" msgctxt "#30026" msgid "Scene Created" -msgstr "" +msgstr "Escena creada" msgctxt "#30028" msgid "Delete Hue Scene" -msgstr "" +msgstr "Borrar Escena Hue" msgctxt "#30030" msgid "Enter Scene Name" -msgstr "" +msgstr "Introducir nombre de escena" msgctxt "#30031" msgid "Transition Time:" -msgstr "" +msgstr "Hora de transición:" msgctxt "#30034" msgid "Cancel" -msgstr "" +msgstr "Cancelar" msgctxt "#30035" msgid "Lights:" -msgstr "" +msgstr "Luces:" msgctxt "#30036" msgid "Scene Name:" -msgstr "" +msgstr "Nombre de la escena:" msgctxt "#30037" msgid "Save" @@ -262,27 +262,27 @@ msgstr "Guardar" msgctxt "#30038" msgid "Create Hue Scene" -msgstr "" +msgstr "Crear escena Hue" msgctxt "#30002" msgid "ERROR: Scene not created" -msgstr "ERROR: Scene not created" +msgstr "ERROR: Escena no creada" msgctxt "#30039" msgid "Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Ajustar un tiempo de atenuación en segundos, o 0 para una transición instantánea." msgctxt "#30040" msgid "Scene deleted" -msgstr "" +msgstr "Escena eliminada" msgctxt "#30041" msgid "You may now assign your Scene to player actions." -msgstr "" +msgstr "Ahora puedes asignar tu Escena a las acciones de los reproductores." msgctxt "#30042" msgid "Fade Time (Seconds)" -msgstr "" +msgstr "Tiempo de atenuación (segundos)" msgctxt "#30043" msgid "Error" @@ -290,139 +290,139 @@ msgstr "Error" msgctxt "#30044" msgid "Create New Scene" -msgstr "" +msgstr "Crear nueva escena" msgctxt "#30045" msgid "Scene successfully created!" -msgstr "" +msgstr "¡Escena creada con éxito!" msgctxt "#30046" msgid "Adjust lights to desired state in the Hue App to save as new scene." -msgstr "" +msgstr "Ajustar las luces al estado deseado en la App Hue para guardar como nueva escena." msgctxt "#30047" msgid "Connection lost. Check settings. Shutting down" -msgstr "" +msgstr "Conexión perdida. Comprobar los ajustes. Apagando" msgctxt "#30048" msgid "Connection lost. Trying again in 2 minutes" -msgstr "" +msgstr "Conexión perdida. Nuevo intento en 2 minutos" msgctxt "#30049" msgid "Scene Name" -msgstr "" +msgstr "Nombre de la escena" msgctxt "#30050" msgid "N-UPnP discovery..." -msgstr "" +msgstr "Descubrimiento N-UPnP..." msgctxt "#30051" msgid "UPnP discovery..." -msgstr "" +msgstr "Descubrimiento UPnP..." msgctxt "#30005" msgid "Searching for bridge..." -msgstr "" +msgstr "Buscando el bridge..." msgctxt "#30052" msgid "Invalid start or end time, schedule disabled" -msgstr "" +msgstr "Hora de inicio o fin no válida, programación desactivada" msgctxt "#30056" msgid "Set brightness on start" -msgstr "" +msgstr "Ajustar el brillo al encender" msgctxt "#30057" msgid "Force on" -msgstr "" +msgstr "Fuerza sobre" msgctxt "#30058" msgid "Light Names:" -msgstr "" +msgstr "Nombres de luz:" msgctxt "#30065" msgid "Update interval (ms)" -msgstr "" +msgstr "Intervalo de actualización (ms)" msgctxt "#30066" msgid "Hue transition time (ms)" -msgstr "" +msgstr "Tiempo de transición del Hue (ms)" msgctxt "#30067" msgid "Frame capture size" -msgstr "" +msgstr "Tamaño de captura del fotograma" msgctxt "#30068" msgid "Show Hue bridge capacity errors" -msgstr "" +msgstr "Mostrar errores de capacidad del Hue bridge" msgctxt "#30800" msgid "Minimum duration (Minutes)" -msgstr "" +msgstr "Duración mínima (minutos)" msgctxt "#30801" msgid "Enable for Movies" -msgstr "" +msgstr "Activar para películas" msgctxt "#30802" msgid "Enable for TV episodes" -msgstr "" +msgstr "Activar para episodios de TV" msgctxt "#30803" msgid "Enable for music videos" -msgstr "" +msgstr "Activar para vídeos musicales" msgctxt "#30804" msgid "Enable for other videos (Discs)" -msgstr "" +msgstr "Activar para otros vídeos (Discos)" msgctxt "#30805" msgid "Enable for live TV" -msgstr "" +msgstr "Activar para TV en directo" msgctxt "#30809" msgid "Saturation" -msgstr "" +msgstr "Saturación" msgctxt "#30810" msgid "Minimum Brightness" -msgstr "" +msgstr "Brillo mínimo" msgctxt "#30811" msgid "Maximum Brightness" -msgstr "" +msgstr "Brillo máximo" msgctxt "#30812" msgid "Disable connection message" -msgstr "" +msgstr "Desactivar mensaje de conexión" msgctxt "#30813" msgid "Average image processing time:" -msgstr "" +msgstr "Tiempo medio de procesamiento de la imagen:" msgctxt "#30814" msgid "On playback stop" -msgstr "" +msgstr "Al detener la reproducción" msgctxt "#30815" msgid "Resume light state" -msgstr "" +msgstr "Reanudar estado de luz" msgctxt "#30816" msgid "Resume transition time (secs.)" -msgstr "" +msgstr "Tiempo de transición de reanudación (seg.)" msgctxt "#30071" msgid "Only colour lights are supported" -msgstr "" +msgstr "Sólo se admiten luces de color" msgctxt "#30072" msgid "Unsupported Hue Bridge" -msgstr "" +msgstr "Hue Bridge no compatible" msgctxt "#30055" msgid "Disabled" -msgstr "" +msgstr "Desactivado" msgctxt "#30060" msgid "Play" @@ -430,132 +430,132 @@ msgstr "Reproducir" msgctxt "#30061" msgid "Hue Status: " -msgstr "" +msgstr "Estado Hue: " msgctxt "#30062" msgid "Settings" -msgstr "" +msgstr "Ajustes" msgctxt "#30063" msgid "Disabled by daylight" -msgstr "" +msgstr "Desactivado por la luz del día" msgctxt "#30064" msgid "ERROR: Scene not found" -msgstr "" +msgstr "ERROR: Escena no encontrada" msgctxt "#30080" msgid "The following error occurred:" -msgstr "" +msgstr "Se ha producido el siguiente error:" msgctxt "#30081" msgid "Automatically report this error?" -msgstr "" +msgstr "¿Informar automáticamente de este error?" msgctxt "#30069" msgid "No lights selected for Ambilight." -msgstr "" +msgstr "No hay luces seleccionadas para Ambilight." msgctxt "#30070" msgid "Ok" -msgstr "" +msgstr "Ok" msgctxt "#30075" msgid "Hue Bridge over capacity" -msgstr "" +msgstr "El Hue Bridge supera su capacidad" msgctxt "#30076" msgid "Network not ready" -msgstr "" +msgstr "Red no preparada" msgctxt "#30077" msgid "The Hue Bridge is over capacity. Increase refresh rate or reduce the number of Ambilights." -msgstr "" +msgstr "El Hue Bridge está por encima de su capacidad. Aumentar la frecuencia de actualización o reducir el número de Ambilights." msgctxt "#30078" msgid "Bridge not found[CR]Check your bridge and network." -msgstr "" +msgstr "Puente no encontrado[CR]Comprobar el bridge y la red." msgctxt "#30082" msgid "Press link button on bridge. Waiting for 90 seconds..." -msgstr "" +msgstr "Pulse el botón de enlace en el bridge. Esperando 90 segundos..." msgctxt "#30083" msgid "Unknown" -msgstr "" +msgstr "Desconocido" msgctxt "#30084" msgid "User Found![CR]Saving settings..." -msgstr "" +msgstr "¡Usuario encontrado![CR]Guardando ajustes..." msgctxt "#30085" msgid "Adjust lights to desired state in the Hue App to save as new scene.[CR]Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Ajustar las luces al estado deseado en la aplicación Hue para guardar como nueva escena.[CR]Ajustar un tiempo de atenuación en segundos, o 0 para una transición instantánea." msgctxt "#30086" msgid "User not found[CR]Check your bridge and network." -msgstr "" +msgstr "Usuario no encontrado[CR]Comprobar el bridge y la red." msgctxt "#30087" msgid "Scene successfully created![CR]You may now assign your scene to player actions." -msgstr "" +msgstr "¡Escena creada con éxito![CR]Ahora puedes asignar tu escena a las acciones de los reproductores." msgctxt "#30073" msgid "Do not show again" -msgstr "" +msgstr "No volver a mostrar" msgctxt "#30074" msgid "Disable Hue Labs during playback" -msgstr "" +msgstr "Desactivar Hue Labs durante la reproducción" msgctxt "#30001" msgid "Hue Bridge V1 (Round) is unsupported. Hue Bridge V2 (Square) is required." -msgstr "" +msgstr "Hue Bridge V1 (Redondo) no es compatible. Se requiere Hue Bridge V2 (Cuadrado)." msgctxt "#30012" msgid "Unknown colour gamut for light:" -msgstr "" +msgstr "Gama de colores desconocida para la luz:" msgctxt "#30016" msgid "Report errors" -msgstr "" +msgstr "Informar de errores" msgctxt "#30020" msgid "Never report errors" -msgstr "" +msgstr "No informar nunca de los errores" msgctxt "#30032" msgid "Hue Service Error" -msgstr "" +msgstr "Error del servicio Hue" msgctxt "#30029" msgid "Connection Error" -msgstr "" +msgstr "Error de conexión" msgctxt "#30014" msgid "Error: Lights incompatible with Ambilight" -msgstr "" +msgstr "Error: Luces incompatibles con Ambilight" msgctxt "#30007" msgid "Bridge not found automatically. Please make sure your bridge is up to date and has access to the internet. [CR]Would you like to enter your bridge IP manually?" -msgstr "" +msgstr "Bridge no encontrado automáticamente. Por favor, asegúrese de que su bridge está actualizado y tiene acceso a internet. [CR]¿Desea introducir manualmente la IP de su bridge?" msgctxt "#30009" msgid "Connecting..." -msgstr "" +msgstr "Conectando..." msgctxt "#30027" msgid "Are you sure you want to delete this scene:" -msgstr "" +msgstr "Estás seguro de que quieres borrar esta escena:" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." -msgstr "" +msgstr "Bridge obsoleto. Por favor, actualice su bridge." msgctxt "#30003" msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." -msgstr "" +msgstr "ERROR: Escena o Luz no encontrada, puede que haya cambiado o se haya borrado. Comprobar la configuración." msgctxt "#30033" msgid "Reconnected" -msgstr "" +msgstr "Reconectado" diff --git a/script.service.hue/resources/language/resource.language.fr_fr/strings.po b/script.service.hue/resources/language/resource.language.fr_fr/strings.po index 6d4d31bc6..60be5dc47 100644 --- a/script.service.hue/resources/language/resource.language.fr_fr/strings.po +++ b/script.service.hue/resources/language/resource.language.fr_fr/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-01-15 23:20+0000\n" +"PO-Revision-Date: 2023-04-01 16:21+0000\n" "Last-Translator: skypichat \n" "Language-Team: French (France) \n" "Language: fr_fr\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.15\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -554,8 +554,8 @@ msgstr "Bridge obsolète. Veuillez mettre à jour votre bridge." msgctxt "#30003" msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." -msgstr "" +msgstr "ERREUR : Scène ou lumière introuvable, elle a peut-être été modifiée ou supprimée. Vérifiez votre configuration." msgctxt "#30033" msgid "Reconnected" -msgstr "" +msgstr "Reconnecté" diff --git a/script.service.hue/resources/language/resource.language.it_it/strings.po b/script.service.hue/resources/language/resource.language.it_it/strings.po index 5f0d49170..e88fb3374 100644 --- a/script.service.hue/resources/language/resource.language.it_it/strings.po +++ b/script.service.hue/resources/language/resource.language.it_it/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-02-05 08:15+0000\n" +"PO-Revision-Date: 2023-04-01 16:21+0000\n" "Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" @@ -22,7 +22,7 @@ msgstr "Automatizza le luci Hue con la riproduzione di Kodi" msgctxt "Addon Description" msgid "Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support." -msgstr "Automatizza le tue luci Hue con Kodi. Crea scene multi-stanza che vengono eseguite quando riproduci, metti in pausa o interrompi la riproduzione multimediale. Crea ed elimina scene multi-room dalle impostazioni del componente aggiuntivo, quindi seleziona quali applicare per diversi eventi di riproduzione. Può utilizzare gli orari di alba e tramonto di Hue per disabilitare automaticamente il servizio durante il giorno e accendere le luci al tramonto durante la riproduzione. Include il supporto Ambilight." +msgstr "Automatizza le tue luci Hue con Kodi. Crea scene multi-room che vengono eseguite quando riproduci, metti in pausa o interrompi la riproduzione multimediale. Crea ed elimina scene multi-room dalle impostazioni dell'add-on, quindi seleziona quale applicare per diversi eventi di riproduzione. Può utilizzare gli orari di alba e tramonto di Hue per disattivare automaticamente il servizio durante il giorno e accendere le luci al tramonto durante la riproduzione. Include il supporto Ambilight." msgctxt "Addon Disclaimer" msgid "Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware." @@ -66,7 +66,7 @@ msgstr "Bridge" msgctxt "#30501" msgid "Discover Hue Bridge / Enter IP" -msgstr "Scopri Hue Bridge / Inserisci IP" +msgstr "Rileva Bridge Hue / Inserisci IP" msgctxt "#30502" msgid "Bridge IP" @@ -90,7 +90,7 @@ msgstr "Ora di fine:" msgctxt "#30508" msgid "Disable during daylight" -msgstr "Disattiva durante il giorno" +msgstr "Disabilita durante il giorno" msgctxt "#30509" msgid "Activate during playback at sunset" @@ -102,7 +102,7 @@ msgstr "Generale" msgctxt "#30511" msgid "Schedule" -msgstr "Programmazione" +msgstr "Pianificazione" msgctxt "#30512" msgid "Scenes" @@ -118,15 +118,15 @@ msgstr "Pausa scena abilitata" msgctxt "#30515" msgid "Stop Scene Enabled" -msgstr "Interrompi scena abilitato" +msgstr "Interrompi scena abilitata" msgctxt "#30516" msgid "Disable time check if any light already on" -msgstr "Disattiva controllo tempo se qualche luce è già accesa" +msgstr "Disabilita controllo tempo se qualche luce è già accesa" msgctxt "#30517" msgid "Don't enable scene if any light is off" -msgstr "Non abilitare scena se una luce è spenta" +msgstr "Non abilitare scena se qualche luce è spenta" msgctxt "#30521" msgid "[B][I]Warning: Not supported on all hardware[/B][/I]" @@ -158,7 +158,7 @@ msgstr "Abilitato" msgctxt "#9001" msgid "Press connect button on Hue bridge" -msgstr "Premi il pulsante di connessione sul bridge Hue" +msgstr "Premi il pulsante di connessione sul Bridge Hue" msgctxt "#9007" msgid "Create Scene" @@ -222,7 +222,7 @@ msgstr "Bridge non configurato" msgctxt "#30024" msgid "Check Hue Bridge configuration" -msgstr "Controlla la configurazione di Hue Bridge" +msgstr "Controlla la configurazione del Bridge Hue" msgctxt "#30025" msgid "ERROR: Scene not deleted" @@ -234,7 +234,7 @@ msgstr "Scena creata" msgctxt "#30028" msgid "Delete Hue Scene" -msgstr "Elimina Hue Scene" +msgstr "Elimina scena Hue" msgctxt "#30030" msgid "Enter Scene Name" @@ -278,7 +278,7 @@ msgstr "Scena eliminata" msgctxt "#30041" msgid "You may now assign your Scene to player actions." -msgstr "Assegnare scena alle azioni del riproduttore." +msgstr "Ora puoi assegnare la tua scena alle azioni del lettore." msgctxt "#30042" msgid "Fade Time (Seconds)" @@ -302,11 +302,11 @@ msgstr "Regola le luci allo stato desiderato nell'app Hue per salvarle come nuov msgctxt "#30047" msgid "Connection lost. Check settings. Shutting down" -msgstr "Collegamento perso. Controlla le impostazioni. Spegnere" +msgstr "Collegamento perso. Controlla le impostazioni. Spegnimento in corso" msgctxt "#30048" msgid "Connection lost. Trying again in 2 minutes" -msgstr "Collegamento perso. Riprova tra 2 minuti" +msgstr "Connessione persa. Riprova tra 2 minuti" msgctxt "#30049" msgid "Scene Name" @@ -350,11 +350,11 @@ msgstr "Tempo di transizione Hue (ms)" msgctxt "#30067" msgid "Frame capture size" -msgstr "Dimensioni acquisizione frame" +msgstr "Dimensione cattura fotogramma" msgctxt "#30068" msgid "Show Hue bridge capacity errors" -msgstr "Mostra errori di capacità del bridge Hue" +msgstr "Mostra errori di capienza del Bridge Hue" msgctxt "#30800" msgid "Minimum duration (Minutes)" @@ -378,7 +378,7 @@ msgstr "Abilita per altri video (dischi)" msgctxt "#30805" msgid "Enable for live TV" -msgstr "Abilita per la TV in diretta" +msgstr "Abilita per la Live TV" msgctxt "#30809" msgid "Saturation" @@ -394,7 +394,7 @@ msgstr "Luminosità massima" msgctxt "#30812" msgid "Disable connection message" -msgstr "Disattiva messaggio di connessione" +msgstr "Disabilita messaggio di connessione" msgctxt "#30813" msgid "Average image processing time:" @@ -406,7 +406,7 @@ msgstr "All'arresto della riproduzione" msgctxt "#30815" msgid "Resume light state" -msgstr "Ripristina lo stato luminoso" +msgstr "Ripristina lo stato della luce" msgctxt "#30816" msgid "Resume transition time (secs.)" @@ -462,7 +462,7 @@ msgstr "Ok" msgctxt "#30075" msgid "Hue Bridge over capacity" -msgstr "Hue Bridge oltre la capacità" +msgstr "Bridge Hue oltre la capienza" msgctxt "#30076" msgid "Network not ready" @@ -470,7 +470,7 @@ msgstr "Rete non pronta" msgctxt "#30077" msgid "The Hue Bridge is over capacity. Increase refresh rate or reduce the number of Ambilights." -msgstr "L'Hue Bridge è al di sopra della capacità. Aumenta la frequenza di aggiornamento o riduci il numero di Ambilight." +msgstr "Il Bridge Hue è al di sopra della capienza. Aumenta la frequenza di aggiornamento o riduci il numero di Ambilight." msgctxt "#30078" msgid "Bridge not found[CR]Check your bridge and network." @@ -478,7 +478,7 @@ msgstr "Bridge non trovato[CR]Controlla il tuo bridge e la tua rete." msgctxt "#30082" msgid "Press link button on bridge. Waiting for 90 seconds..." -msgstr "Premi il pulsante di collegamento sul Bridge. Aspetta 90 secondi..." +msgstr "Premi il pulsante di collegamento sul bridge. Aspetta 90 secondi..." msgctxt "#30083" msgid "Unknown" @@ -510,7 +510,7 @@ msgstr "Disattiva Hue Labs durante la riproduzione" msgctxt "#30001" msgid "Hue Bridge V1 (Round) is unsupported. Hue Bridge V2 (Square) is required." -msgstr "Hue Bridge V1 (Round) non è supportato. È richiesto Hue Bridge V2 (quadrato)." +msgstr "Il Bridge Hue V1 (rotondo) non è supportato. È richiesto il Bridge l'Hue V2 (quadrato)." msgctxt "#30012" msgid "Unknown colour gamut for light:" @@ -542,7 +542,7 @@ msgstr "Bridge non trovato automaticamente. Assicurati che il tuo bridge sia agg msgctxt "#30009" msgid "Connecting..." -msgstr "Collegamento..." +msgstr "Connessione in corso..." msgctxt "#30027" msgid "Are you sure you want to delete this scene:" diff --git a/script.service.hue/resources/language/resource.language.sk_sk/strings.po b/script.service.hue/resources/language/resource.language.sk_sk/strings.po index 32f416a76..32af9b76a 100644 --- a/script.service.hue/resources/language/resource.language.sk_sk/strings.po +++ b/script.service.hue/resources/language/resource.language.sk_sk/strings.po @@ -6,95 +6,95 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-04-05 16:16+0000\n" -"Last-Translator: Christian Gade \n" +"PO-Revision-Date: 2023-03-13 17:16+0000\n" +"Last-Translator: Patrik Špaňo \n" "Language-Team: Slovak \n" "Language: sk_sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 4.11.2\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" -msgstr "" +msgstr "Automatizácia svetiel Hue s prehrávaním v Kodi" msgctxt "Addon Description" msgid "Automate your Hue lights with Kodi. Create multi-room scenes that run when you Play, Pause or Stop media playback. Create and delete multi-room scenes from add-on settings then select which to apply for different Playback events. Can use Hue's sunrise and sunset times to automatically disable the service during daytime and turn on the lights at sunset during playback. Includes Ambilight support." -msgstr "" +msgstr "Automatizácia svetiel Hue pomocou Kodi. Vytvorte scény pre viacero miestností, ktoré sa spustia pri prehrávaní, pozastavení alebo ukončení prehrávania médií. Vytvárajte a odstraňujte scény z viacerých miestností v nastaveniach doplnku a potom vyberte, ktoré sa majú použiť pre rôzne udalosti prehrávania. Môžete využiť časy východu a západu slnka zariadenia Hue na automatické vypnutie služby počas dňa a zapnutie svetiel pri západe slnka počas prehrávania. Obsahuje podporu funkcie Ambilight." msgctxt "Addon Disclaimer" msgid "Requires a Hue Bridge V2 (Square). Ambilight not available on all hardware." -msgstr "" +msgstr "Vyžaduje Hue Bridge V2 (štvorcový). Ambilight nie je k dispozícii na všetkých zariadeniach." msgctxt "#32100" msgid "Video Actions" -msgstr "" +msgstr "Akcie Videa" msgctxt "#32102" msgid "Audio Actions" -msgstr "" +msgstr "Akcie Audia" msgctxt "#32201" msgid "Start/Resume" -msgstr "" +msgstr "Spustiť/Pokračovať" msgctxt "#32202" msgid "Pause" -msgstr "" +msgstr "Pauza" msgctxt "#32203" msgid "Stop" -msgstr "" +msgstr "Ukončiť" msgctxt "#32510" msgid "Scene Name:" -msgstr "" +msgstr "Názov Scény:" msgctxt "#32511" msgid "Scene ID" -msgstr "" +msgstr "ID Scény" msgctxt "#32512" msgid "Select..." -msgstr "" +msgstr "Vybrať..." msgctxt "#30500" msgid "Bridge" -msgstr "" +msgstr "Bridge (most)" msgctxt "#30501" msgid "Discover Hue Bridge / Enter IP" -msgstr "Discover Hue Bridge / Enter IP" +msgstr "Vyhľadať Hue Bridge / Zadať IP" msgctxt "#30502" msgid "Bridge IP" -msgstr "" +msgstr "Bridge IP adresa" msgctxt "#30503" msgid "Bridge User" -msgstr "" +msgstr "Bridge užívateľ" msgctxt "#30505" msgid "Enable Schedule (24h format)" -msgstr "" +msgstr "Povolenie Harmonogramu (24 hodínový formát)" msgctxt "#30506" msgid "Start time:" -msgstr "" +msgstr "Čas spustenia:" msgctxt "#30507" msgid "End time:" -msgstr "" +msgstr "Čas ukončenia:" msgctxt "#30508" msgid "Disable during daylight" -msgstr "" +msgstr "Zakázať počas denného svetla" msgctxt "#30509" msgid "Activate during playback at sunset" -msgstr "" +msgstr "Aktivovať počas prehrávania pri západe slnka" msgctxt "#30510" msgid "General" @@ -106,183 +106,183 @@ msgstr "Plán" msgctxt "#30512" msgid "Scenes" -msgstr "" +msgstr "Scény" msgctxt "#30513" msgid "Play Scene Enabled" -msgstr "" +msgstr "Povolená Scéna Prehrávania" msgctxt "#30514" msgid "Pause Scene Enabled" -msgstr "" +msgstr "Povolená Scéna Pauzy" msgctxt "#30515" msgid "Stop Scene Enabled" -msgstr "" +msgstr "Povolená Scéna Zastavenia" msgctxt "#30516" msgid "Disable time check if any light already on" -msgstr "" +msgstr "Vypnúť kontrolu času, ak už niektoré svetlo svieti" msgctxt "#30517" msgid "Don't enable scene if any light is off" -msgstr "" +msgstr "Nepovoliť scénu, ak je niektoré svetlo zhasnuté" msgctxt "#30521" msgid "[B][I]Warning: Not supported on all hardware[/B][/I]" -msgstr "" +msgstr "[B][I]Upozornenie: Nie je podporované na všetkých zariadeniach[/B][/I]" msgctxt "#30522" msgid "CPU & Hue performance" -msgstr "" +msgstr "Výkon CPU & Hue" msgctxt "#30523" msgid "Ambilight" -msgstr "" +msgstr "Ambilight" msgctxt "#32101" msgid "Advanced" -msgstr "" +msgstr "Pokročilé" msgctxt "#32106" msgid "Video Activation" -msgstr "" +msgstr "Aktivovanie Videa" msgctxt "#6101" msgid "Select Lights" -msgstr "" +msgstr "Vyberte Svetlá" msgctxt "#30520" msgid "Enabled" -msgstr "" +msgstr "Aktivované" msgctxt "#9001" msgid "Press connect button on Hue bridge" -msgstr "" +msgstr "Stlačte tlačidlo pripojenia na Hue Bridge" msgctxt "#9007" msgid "Create Scene" -msgstr "" +msgstr "Vytvoriť Scénu" msgctxt "#9008" msgid "Delete Scene" -msgstr "" +msgstr "Zmazať Scénu" msgctxt "#30000" msgid "Hue Service" -msgstr "" +msgstr "Služba Hue" msgctxt "#30004" msgid "Check your bridge and network" -msgstr "" +msgstr "Skontrolujte bridge a sieť" msgctxt "#30006" msgid "Hue connected" -msgstr "" +msgstr "Hue pripojený" msgctxt "#30008" msgid "Bridge not found" -msgstr "" +msgstr "Bridge nebol nájdený" msgctxt "#30010" msgid "User not found" -msgstr "" +msgstr "Používateľ nebol nájdený" msgctxt "#30011" msgid "Complete!" -msgstr "" +msgstr "Hotovo!" msgctxt "#30013" msgid "Cancelled" -msgstr "" +msgstr "Zrušené" msgctxt "#30015" msgid "Select Hue Lights..." -msgstr "" +msgstr "Vyberte Hue Svetlá..." msgctxt "#30017" msgid "Found bridge: " -msgstr "" +msgstr "Nájdený bridge: " msgctxt "#30018" msgid "Discover bridge..." -msgstr "" +msgstr "Hľadať Bridge..." msgctxt "#30021" msgid "Bridge connection failed" -msgstr "" +msgstr "Pripojenie k Bridge zlyhalo" msgctxt "#30022" msgid "Discovery started" -msgstr "" +msgstr "Hľadanie sa začalo" msgctxt "#30023" msgid "Bridge not configured" -msgstr "" +msgstr "Bridge nie je nakonfigurovaný" msgctxt "#30024" msgid "Check Hue Bridge configuration" -msgstr "" +msgstr "Skontrolujte konfiguráciu Hue Bridge" msgctxt "#30025" msgid "ERROR: Scene not deleted" -msgstr "" +msgstr "CHYBA: Scéna nebola vymazaná" msgctxt "#30026" msgid "Scene Created" -msgstr "" +msgstr "Scéna Vytvorená" msgctxt "#30028" msgid "Delete Hue Scene" -msgstr "" +msgstr "Zmazať Hue scénu" msgctxt "#30030" msgid "Enter Scene Name" -msgstr "" +msgstr "Zadajte názov scény" msgctxt "#30031" msgid "Transition Time:" -msgstr "" +msgstr "Čas prechodu:" msgctxt "#30034" msgid "Cancel" -msgstr "" +msgstr "Zrušiť" msgctxt "#30035" msgid "Lights:" -msgstr "" +msgstr "Svetlá:" msgctxt "#30036" msgid "Scene Name:" -msgstr "" +msgstr "Názov Scény:" msgctxt "#30037" msgid "Save" -msgstr "" +msgstr "Uložiť" msgctxt "#30038" msgid "Create Hue Scene" -msgstr "" +msgstr "Vytvoriť Hue Scénu" msgctxt "#30002" msgid "ERROR: Scene not created" -msgstr "ERROR: Scene not created" +msgstr "CHYBA: Scéna nebola vytvorená" msgctxt "#30039" msgid "Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Nastavte čas trvania prechodu v sekundách alebo 0 pre okamžitý prechod." msgctxt "#30040" msgid "Scene deleted" -msgstr "" +msgstr "Scéna zmazaná" msgctxt "#30041" msgid "You may now assign your Scene to player actions." -msgstr "" +msgstr "Teraz môžete priradiť Scénu k akciám prehrávača." msgctxt "#30042" msgid "Fade Time (Seconds)" -msgstr "" +msgstr "Čas Prechodu (v sekundách)" msgctxt "#30043" msgid "Error" @@ -290,63 +290,63 @@ msgstr "Chyba" msgctxt "#30044" msgid "Create New Scene" -msgstr "" +msgstr "Vytvoriť Novú Scénu" msgctxt "#30045" msgid "Scene successfully created!" -msgstr "" +msgstr "Scéna úspešne vytvorená!" msgctxt "#30046" msgid "Adjust lights to desired state in the Hue App to save as new scene." -msgstr "" +msgstr "Nastavte svetlá na požadovaný stav v aplikácii Hue a uložte ich ako novú scénu." msgctxt "#30047" msgid "Connection lost. Check settings. Shutting down" -msgstr "" +msgstr "Strata spojenia. Skontrolujte nastavenia. Vypínam" msgctxt "#30048" msgid "Connection lost. Trying again in 2 minutes" -msgstr "" +msgstr "Spojenie prerušené. Ďalší pokus o 2 minuty" msgctxt "#30049" msgid "Scene Name" -msgstr "" +msgstr "Názov Scény" msgctxt "#30050" msgid "N-UPnP discovery..." -msgstr "" +msgstr "Vyhľadávanie N-UPnP..." msgctxt "#30051" msgid "UPnP discovery..." -msgstr "" +msgstr "Vyhľadávanie UPnP..." msgctxt "#30005" msgid "Searching for bridge..." -msgstr "" +msgstr "Hľadám Bridge..." msgctxt "#30052" msgid "Invalid start or end time, schedule disabled" -msgstr "" +msgstr "Chybný čas spustenia alebo ukončenia. Harmonogram deaktivovaný" msgctxt "#30056" msgid "Set brightness on start" -msgstr "" +msgstr "Nastavenie jasu pri spustení" msgctxt "#30057" msgid "Force on" -msgstr "" +msgstr "Vynútiť zapnutie" msgctxt "#30058" msgid "Light Names:" -msgstr "" +msgstr "Názvy Svetiel:" msgctxt "#30065" msgid "Update interval (ms)" -msgstr "" +msgstr "Interval aktualizácie (ms)" msgctxt "#30066" msgid "Hue transition time (ms)" -msgstr "" +msgstr "Čau prechodu Hue (ms)" msgctxt "#30067" msgid "Frame capture size" @@ -354,59 +354,59 @@ msgstr "" msgctxt "#30068" msgid "Show Hue bridge capacity errors" -msgstr "" +msgstr "Zobrazenie chýb kapacity Hue bridge" msgctxt "#30800" msgid "Minimum duration (Minutes)" -msgstr "" +msgstr "Minimálne trvanie (v minutách)" msgctxt "#30801" msgid "Enable for Movies" -msgstr "" +msgstr "Povoliť pre Filmy" msgctxt "#30802" msgid "Enable for TV episodes" -msgstr "" +msgstr "Povoliť pre Seriály" msgctxt "#30803" msgid "Enable for music videos" -msgstr "" +msgstr "Povoliť pre hudobné videa" msgctxt "#30804" msgid "Enable for other videos (Discs)" -msgstr "" +msgstr "Povoliť pre ostatné videa (CD/DVD)" msgctxt "#30805" msgid "Enable for live TV" -msgstr "" +msgstr "Povoliť pre živú TV" msgctxt "#30809" msgid "Saturation" -msgstr "" +msgstr "Saturácia" msgctxt "#30810" msgid "Minimum Brightness" -msgstr "" +msgstr "Minimálny Jas" msgctxt "#30811" msgid "Maximum Brightness" -msgstr "" +msgstr "Maximálny Jas" msgctxt "#30812" msgid "Disable connection message" -msgstr "" +msgstr "Vypnúť spravu o pripojení" msgctxt "#30813" msgid "Average image processing time:" -msgstr "" +msgstr "Priemerný čas spracovania obrázku:" msgctxt "#30814" msgid "On playback stop" -msgstr "" +msgstr "Pri ukončení prehrávania" msgctxt "#30815" msgid "Resume light state" -msgstr "" +msgstr "Obnoviť stav svetiel" msgctxt "#30816" msgid "Resume transition time (secs.)" @@ -414,15 +414,15 @@ msgstr "" msgctxt "#30071" msgid "Only colour lights are supported" -msgstr "" +msgstr "Sú podporované len farebné svetlá" msgctxt "#30072" msgid "Unsupported Hue Bridge" -msgstr "" +msgstr "Nepodporovaný Hue Bridge" msgctxt "#30055" msgid "Disabled" -msgstr "" +msgstr "Deaktivované" msgctxt "#30060" msgid "Play" @@ -430,132 +430,132 @@ msgstr "Prehrať" msgctxt "#30061" msgid "Hue Status: " -msgstr "" +msgstr "Stav Hue: " msgctxt "#30062" msgid "Settings" -msgstr "" +msgstr "Nastavenia" msgctxt "#30063" msgid "Disabled by daylight" -msgstr "" +msgstr "Deaktivované počas dňa" msgctxt "#30064" msgid "ERROR: Scene not found" -msgstr "" +msgstr "CHYBA: Scéna nebola nájdená" msgctxt "#30080" msgid "The following error occurred:" -msgstr "" +msgstr "Vyskytla sa nasledujúca chyba:" msgctxt "#30081" msgid "Automatically report this error?" -msgstr "" +msgstr "Automaticky nahlásiť túto chybu?" msgctxt "#30069" msgid "No lights selected for Ambilight." -msgstr "" +msgstr "Neboli vybraté vybrané žiadne svetlá pre Ambilight." msgctxt "#30070" msgid "Ok" -msgstr "" +msgstr "Ok" msgctxt "#30075" msgid "Hue Bridge over capacity" -msgstr "" +msgstr "Hue Bridge kapacita vyčerpaná" msgctxt "#30076" msgid "Network not ready" -msgstr "" +msgstr "Sieť nie je pripravená" msgctxt "#30077" msgid "The Hue Bridge is over capacity. Increase refresh rate or reduce the number of Ambilights." -msgstr "" +msgstr "Hue Bridge kapacita vyčerpaná. Zvýšte obnovovaciu frekvenciu alebo znížte počet Ambilight svetiel." msgctxt "#30078" msgid "Bridge not found[CR]Check your bridge and network." -msgstr "" +msgstr "Bridge nebol nájdený[CR]Skontrolujte bridge a sieť." msgctxt "#30082" msgid "Press link button on bridge. Waiting for 90 seconds..." -msgstr "" +msgstr "Stlačte tlačidlo prepojenia na bridge. Čakám 90 sekúnd..." msgctxt "#30083" msgid "Unknown" -msgstr "" +msgstr "Neznáme" msgctxt "#30084" msgid "User Found![CR]Saving settings..." -msgstr "" +msgstr "Používateľ nájdený![CR]Ukladanie nastavení..." msgctxt "#30085" msgid "Adjust lights to desired state in the Hue App to save as new scene.[CR]Set a fade time in seconds, or 0 for an instant transition." -msgstr "" +msgstr "Nastavte svetlá na požadovaný stav v aplikácii Hue a uložte ich ako novú scénu.[CR]Nastavte čas prechodu v sekundách alebo 0 pre okamžitý prechod." msgctxt "#30086" msgid "User not found[CR]Check your bridge and network." -msgstr "" +msgstr "Používateľ nebol nájdený[CR]Skontrolujte bridge a sieť." msgctxt "#30087" msgid "Scene successfully created![CR]You may now assign your scene to player actions." -msgstr "" +msgstr "Scéna bola úspešne vytvorená![CR]Teraz môžete priradiť scénu k akciám prehrávača." msgctxt "#30073" msgid "Do not show again" -msgstr "" +msgstr "Nezobrazovať znovu" msgctxt "#30074" msgid "Disable Hue Labs during playback" -msgstr "" +msgstr "Zakázať Hue Labs počas prehrávania" msgctxt "#30001" msgid "Hue Bridge V1 (Round) is unsupported. Hue Bridge V2 (Square) is required." -msgstr "" +msgstr "Hue Bridge V1 (Round) nie je podporovaný. Vyžaduje sa Hue Bridge V2 (Square)." msgctxt "#30012" msgid "Unknown colour gamut for light:" -msgstr "" +msgstr "Neznámy farebný gamut pre svetlo:" msgctxt "#30016" msgid "Report errors" -msgstr "" +msgstr "Hlásenie chýb" msgctxt "#30020" msgid "Never report errors" -msgstr "" +msgstr "Nikdy nehlásiť chyby" msgctxt "#30032" msgid "Hue Service Error" -msgstr "" +msgstr "Chyba služby Hue" msgctxt "#30029" msgid "Connection Error" -msgstr "" +msgstr "Chyba spojenia" msgctxt "#30014" msgid "Error: Lights incompatible with Ambilight" -msgstr "" +msgstr "Chyba: Svetlá nekompatibilné s Ambilight" msgctxt "#30007" msgid "Bridge not found automatically. Please make sure your bridge is up to date and has access to the internet. [CR]Would you like to enter your bridge IP manually?" -msgstr "" +msgstr "Bridge nebol nájdený automaticky. Uistite sa, že váš Bridge je aktualizovaný a má prístup na internet. [CR]Chcete zadať IP adresu pre bridge ručne?" msgctxt "#30009" msgid "Connecting..." -msgstr "" +msgstr "Pripájanie..." msgctxt "#30027" msgid "Are you sure you want to delete this scene:" -msgstr "" +msgstr "Ste si istí, že chcete túto scénu vymazať:" msgctxt "#30019" msgid "Bridge outdated. Please update your bridge." -msgstr "" +msgstr "Bridge je zastaralý. Prosím, aktualizujte svoj bridge." msgctxt "#30003" msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." -msgstr "" +msgstr "CHYBA: Scéna alebo svetlo sa nenašli, možno sa zmenili alebo boli odstránené. Skontrolujte svoju konfiguráciu." msgctxt "#30033" msgid "Reconnected" -msgstr "" +msgstr "Znovu pripojené" diff --git a/script.service.hue/resources/language/resource.language.zh_cn/strings.po b/script.service.hue/resources/language/resource.language.zh_cn/strings.po index 3bb6cfcb1..fcc0983d0 100644 --- a/script.service.hue/resources/language/resource.language.zh_cn/strings.po +++ b/script.service.hue/resources/language/resource.language.zh_cn/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-08-06 02:14+0000\n" +"PO-Revision-Date: 2023-03-25 05:16+0000\n" "Last-Translator: taxigps \n" "Language-Team: Chinese (China) \n" "Language: zh_cn\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Automate Hue lights with Kodi playback" @@ -554,11 +554,11 @@ msgstr "桥接器已过时。请更新您的桥接器。" msgctxt "#30003" msgid "ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration." -msgstr "" +msgstr "错误:找不到场景或灯,可能已更改或删除。请检查您的配置。" msgctxt "#30033" msgid "Reconnected" -msgstr "" +msgstr "重新连接" #~ msgctxt "#30501" #~ msgid "Discover Hue Bridge" diff --git a/script.service.hue/resources/lib/__init__.py b/script.service.hue/resources/lib/__init__.py index e30b5b3a4..1b7e4260c 100644 --- a/script.service.hue/resources/lib/__init__.py +++ b/script.service.hue/resources/lib/__init__.py @@ -8,8 +8,6 @@ from collections import deque from threading import Event - - import xbmc import xbmcaddon import xbmcvfs @@ -41,4 +39,5 @@ def wrapper_timer(*args, **kwargs): run_time = end_time - start_time # 3 PROCESS_TIMES.append(run_time) return value + return wrapper_timer diff --git a/script.service.hue/resources/lib/ambigroup.py b/script.service.hue/resources/lib/ambigroup.py index d7496974d..670e9b631 100644 --- a/script.service.hue/resources/lib/ambigroup.py +++ b/script.service.hue/resources/lib/ambigroup.py @@ -12,28 +12,27 @@ from PIL import Image from qhue import QhueException -from resources.lib import ADDON, MINIMUM_COLOR_DISTANCE, imageprocess, lightgroup -from resources.lib import PROCESS_TIMES, reporting, AMBI_RUNNING -from resources.lib.language import get_string as _ +from . import ADDON, MINIMUM_COLOR_DISTANCE, imageprocess, lightgroup +from . import PROCESS_TIMES, reporting, AMBI_RUNNING from .kodiutils import notification +from .language import get_string as _ from .lightgroup import STATE_STOPPED, STATE_PAUSED, STATE_PLAYING from .rgbxy import Converter, ColorHelper # https://github.com/benknight/hue-python-rgb-converter from .rgbxy import XYPoint, GamutA, GamutB, GamutC class AmbiGroup(lightgroup.LightGroup): - def __init__(self, light_group_id, hue_connection, initial_state=STATE_STOPPED, video_info_tag=xbmc.InfoTagVideo): - self.hue_connection = hue_connection - self.light_group_id = light_group_id + def __init__(self, light_group_id, hue_connection, media_type=lightgroup.VIDEO, initial_state=STATE_STOPPED, video_info_tag=xbmc.InfoTagVideo): + self.bridge = hue_connection.bridge + self.light_group_id = light_group_id + self.enabled = ADDON.getSettingBool(f"group{self.light_group_id}_enabled") self.monitor = hue_connection.monitor - self.group0 = self.bridge.groups[0] - self.bridge_error500 = 0 self.state = initial_state - self.enabled = ADDON.getSettingBool(f"group{self.light_group_id}_enabled") + self.video_info_tag = video_info_tag + self.bridge_error500 = 0 self.saved_light_states = {} - self.video_info_tag = video_info_tag self.image_process = imageprocess.ImageProcess() @@ -42,8 +41,6 @@ def __init__(self, light_group_id, hue_connection, initial_state=STATE_STOPPED, self.converterC = Converter(GamutC) self.helper = ColorHelper(GamutC) # Gamut doesn't matter for this usage - self.enabled = ADDON.getSettingBool(f"group{self.light_group_id}_enabled") - self.transition_time = int(ADDON.getSettingInt(f"group{self.light_group_id}_TransitionTime") / 100) # This is given as a multiple of 100ms and defaults to 4 (400ms). transition_time:10 will make the transition last 1 second. self.force_on = ADDON.getSettingBool(f"group{self.light_group_id}_forceOn") self.disable_labs = ADDON.getSettingBool(f"group{self.light_group_id}_disableLabs") @@ -60,7 +57,7 @@ def __init__(self, light_group_id, hue_connection, initial_state=STATE_STOPPED, if self.enabled: self.ambi_lights = {} - light_ids = ADDON.getSetting(f"group{self.light_group_id}_Lights").split(",") + light_ids = ADDON.getSetting(f"group{light_group_id}_Lights").split(",") index = 0 if len(light_ids) > 0: @@ -70,7 +67,7 @@ def __init__(self, light_group_id, hue_connection, initial_state=STATE_STOPPED, self.ambi_lights.update(light) index = index + 1 - super(xbmc.Player).__init__() + super().__init__(light_group_id, hue_connection, media_type, initial_state, video_info_tag) @staticmethod def _force_on(ambi_lights, bridge, saved_light_states): @@ -148,6 +145,7 @@ def _resume_light_state(self): def _ambi_loop(self): AMBI_RUNNING.set() cap = xbmc.RenderCapture() + cap_image = bytes xbmc.log("[script.service.hue] _ambiLoop started") aspect_ratio = cap.getAspectRatio() @@ -264,8 +262,8 @@ def _get_effect_sensors(self): # Find all sensor IDs for active Hue Labs effects all_sensors = self.bridge.sensors() - effects = [id - for id, sensor in list(all_sensors.items()) + effects = [effect_id + for effect_id, sensor in list(all_sensors.items()) if sensor['modelid'] == 'HUELABSVTOGGLE' and 'status' in sensor['state'] and sensor['state']['status'] == 1 ] @@ -279,6 +277,7 @@ def _get_effect_sensors(self): ] for link in sensor_links: + i = link.split('/')[-1] if link.startswith('/lights/'): lights.setdefault(i, set()) @@ -302,11 +301,11 @@ def _get_effect_sensors(self): # an effect will also power on its lights. try: sensors = set([sensor - for id in list(self.ambi_lights.keys()) - for sensor in lights[id] - if id in lights - and id in self.saved_light_states - and self.saved_light_states[id]['state']['on'] + for sensor_id in list(self.ambi_lights.keys()) + for sensor in lights[sensor_id] + if sensor_id in lights + and sensor_id in self.saved_light_states + and self.saved_light_states[sensor_id]['state']['on'] ]) return sensors except KeyError: diff --git a/script.service.hue/resources/lib/core.py b/script.service.hue/resources/lib/core.py index 1b70d5fbe..a2c91b15e 100644 --- a/script.service.hue/resources/lib/core.py +++ b/script.service.hue/resources/lib/core.py @@ -5,16 +5,15 @@ import json import sys -from datetime import timedelta import requests import xbmc -from resources.lib import ADDON, SETTINGS_CHANGED, ADDONID, AMBI_RUNNING -from resources.lib import ambigroup, lightgroup, kodiutils, hueconnection -from resources.lib.hueconnection import HueConnection -from resources.lib.language import get_string as _ -from resources.lib.kodiutils import validate_settings, notification, cache_set, cache_get +from . import ADDON, SETTINGS_CHANGED, ADDONID, AMBI_RUNNING +from . import ambigroup, lightgroup, kodiutils, hueconnection +from .hueconnection import HueConnection +from .kodiutils import validate_settings, notification, cache_set, cache_get +from .language import get_string as _ def core(): @@ -93,8 +92,7 @@ def _service(monitor): ambigroup.AmbiGroup(3, hue_connection)] timer = 60 - daylight = hue_connection.get_daylight() - new_daylight = daylight + daylight = new_daylight = hue_connection.get_daylight() cache_set("daylight", daylight) cache_set("service_enabled", True) @@ -131,7 +129,7 @@ def _service(monitor): # fetch daylight status, reconnect to Hue if it fails try: new_daylight = hue_connection.get_daylight() - except requests.exceptions.RequestException as error: + except requests.exceptions.RequestException: if hue_connection.reconnect(monitor): new_daylight = hue_connection.get_daylight() else: @@ -192,7 +190,7 @@ def onNotification(self, sender, method, data): light_group_id = json_loads['group'] action = json_loads['command'] xbmc.log(f"[script.service.hue] Action Notification: group: {light_group_id}, command: {action}") - cache_set("script.service.hue.action", (action, light_group_id), expiration=(timedelta(seconds=5))) + cache_set("script.service.hue.action", (action, light_group_id)) def activate(light_groups): diff --git a/script.service.hue/resources/lib/hueconnection.py b/script.service.hue/resources/lib/hueconnection.py index f2020fc65..a1e671408 100644 --- a/script.service.hue/resources/lib/hueconnection.py +++ b/script.service.hue/resources/lib/hueconnection.py @@ -14,8 +14,8 @@ import xbmcgui from qhue import QhueException -from resources.lib import ADDON, QHUE_TIMEOUT, reporting -from resources.lib.kodiutils import notification +from . import ADDON, QHUE_TIMEOUT, reporting +from .kodiutils import notification from .language import get_string as _ @@ -147,7 +147,6 @@ def discover(self): elif progress_bar.iscanceled(): xbmc.log("[script.service.hue] Cancelled 2") - complete = True progress_bar.update(percent=100, message=_("Cancelled")) progress_bar.close() @@ -155,19 +154,17 @@ def discover(self): xbmc.log(f"[script.service.hue] User not created, received: {self.bridge_user}") progress_bar.update(percent=100, message=_("User not found[CR]Check your bridge and network.")) self.monitor.waitForAbort(5) - complete = True progress_bar.close() return elif progress_bar.iscanceled(): xbmc.log("[script.service.hue] Cancelled 3") - complete = True + progress_bar.update(percent=100, message=_("Cancelled")) progress_bar.close() else: progress_bar.update(percent=100, message=_("Bridge not found[CR]Check your bridge and network.")) xbmc.log("[script.service.hue] Bridge not found, check your bridge and network") self.monitor.waitForAbort(5) - complete = True progress_bar.close() xbmc.log("[script.service.hue] Cancelled 4") @@ -193,6 +190,7 @@ def _discover_bridge_ip(self): def _discover_nupnp(self): xbmc.log("[script.service.hue] In kodiHue discover_nupnp()") + req = "" try: req = requests.get('https://discovery.meethue.com/') result = req.json() @@ -215,7 +213,7 @@ def _discover_nupnp(self): def _check_bridge_model(self): bridge = qhue.Bridge(self.bridge_ip, None, timeout=QHUE_TIMEOUT) - model = "" + model = "" # variable is used try: bridge_config = bridge.config() @@ -236,6 +234,7 @@ def _check_bridge_model(self): return None def _check_version(self): + api_version = "" b = qhue.Bridge(self.bridge_ip, None, timeout=QHUE_TIMEOUT) try: api_version = b.config()['apiversion'] @@ -352,6 +351,7 @@ def create_hue_scene(self): scene_name = xbmcgui.Dialog().input(_("Scene Name")) if scene_name: + result = "" try: transition_time = int(xbmcgui.Dialog().numeric(0, _("Fade Time (Seconds)"), defaultt="10")) * 10 # yes, default with two ts. *10 to convert secs to msecs except ValueError: @@ -381,6 +381,7 @@ def create_hue_scene(self): xbmcgui.Dialog().ok(_("Error"), _("ERROR: Scene not created")) def delete_hue_scene(self): + result = "" xbmc.log("[script.service.hue] In kodiHue deleteHueScene") scene = self.select_hue_scene() if scene is not None: @@ -442,6 +443,8 @@ def select_hue_lights(self): return None def select_hue_scene(self): + hue_scenes = "" + h_scene_name = "" xbmc.log("[script.service.hue] In selectHueScene{}") try: diff --git a/script.service.hue/resources/lib/imageprocess.py b/script.service.hue/resources/lib/imageprocess.py index a53a1af03..29082a7db 100644 --- a/script.service.hue/resources/lib/imageprocess.py +++ b/script.service.hue/resources/lib/imageprocess.py @@ -9,7 +9,7 @@ from PIL import ImageEnhance -from resources.lib import timer +from . import timer class ImageProcess(object): diff --git a/script.service.hue/resources/lib/kodiutils.py b/script.service.hue/resources/lib/kodiutils.py index 8d43e6d85..c1cd08b65 100644 --- a/script.service.hue/resources/lib/kodiutils.py +++ b/script.service.hue/resources/lib/kodiutils.py @@ -10,8 +10,8 @@ import xbmc import xbmcgui -from resources.lib import ADDON, ADDONID -from resources.lib.language import get_string as _ +from . import ADDON, ADDONID +from .language import get_string as _ cache_window = xbmcgui.Window(10000) @@ -63,7 +63,7 @@ def cache_get(key: str): return data except JSONDecodeError: # Occurs when Cache is empty or unreadable (Eg. Old SimpleCache data still in memory because Kodi hasn't restarted) - #xbmc.log(f"[script.service.hue] cache_get JSONDecodeError: {key}: {data_str}") + # xbmc.log(f"[script.service.hue] cache_get JSONDecodeError: {key}: {data_str}") return None diff --git a/script.service.hue/resources/lib/language.py b/script.service.hue/resources/lib/language.py index cb226dc44..79a73fd32 100644 --- a/script.service.hue/resources/lib/language.py +++ b/script.service.hue/resources/lib/language.py @@ -8,7 +8,7 @@ # generated by language_gen.py -from resources.lib import STRDEBUG, ADDON, xbmc +from . import STRDEBUG, ADDON, xbmc _strings = {} diff --git a/script.service.hue/resources/lib/lightgroup.py b/script.service.hue/resources/lib/lightgroup.py index 90c5c1432..31236a86e 100644 --- a/script.service.hue/resources/lib/lightgroup.py +++ b/script.service.hue/resources/lib/lightgroup.py @@ -4,15 +4,13 @@ # See LICENSE.TXT for more information. import datetime -import traceback import requests import xbmc import xbmcgui - -from resources.lib import ADDON, reporting, ADDONID -from resources.lib.kodiutils import convert_time, notification, cache_get +from . import ADDON, reporting, ambigroup +from .kodiutils import convert_time, notification, cache_get from .language import get_string as _ STATE_STOPPED = 0 @@ -24,20 +22,10 @@ class LightGroup(xbmc.Player): - def __init__(self, light_group_id, hue_connection, media_type, initial_state=STATE_STOPPED, video_info_tag=xbmc.InfoTagVideo): + def __init__(self, light_group_id, hue_connection, media_type=VIDEO, initial_state=STATE_STOPPED, video_info_tag=xbmc.InfoTagVideo): self.light_group_id = light_group_id self.bridge = hue_connection.bridge - self.enabled = ADDON.getSettingBool(f"group{self.light_group_id}_enabled") - - self.start_behavior = ADDON.getSettingBool(f"group{self.light_group_id}_startBehavior") - self.start_scene = ADDON.getSettingString(f"group{self.light_group_id}_startSceneID") - - self.pause_behavior = ADDON.getSettingBool(f"group{self.light_group_id}_pauseBehavior") - self.pause_scene = ADDON.getSettingString(f"group{self.light_group_id}_pauseSceneID") - - self.stop_behavior = ADDON.getSettingBool(f"group{self.light_group_id}_stopBehavior") - self.stop_scene = ADDON.getSettingString(f"group{self.light_group_id}_stopSceneID") - + self.hue_connection = hue_connection self.state = initial_state self.media_type = media_type self.video_info_tag = video_info_tag @@ -45,6 +33,18 @@ def __init__(self, light_group_id, hue_connection, media_type, initial_state=STA self.lights = self.bridge.lights self.group0 = self.bridge.groups[0] + self.enabled = ADDON.getSettingBool(f"group{self.light_group_id}_enabled") + + if not isinstance(self, ambigroup.AmbiGroup): + self.start_behavior = ADDON.getSettingBool(f"group{self.light_group_id}_startBehavior") + self.start_scene = ADDON.getSettingString(f"group{self.light_group_id}_startSceneID") + + self.pause_behavior = ADDON.getSettingBool(f"group{self.light_group_id}_pauseBehavior") + self.pause_scene = ADDON.getSettingString(f"group{self.light_group_id}_pauseSceneID") + + self.stop_behavior = ADDON.getSettingBool(f"group{self.light_group_id}_stopBehavior") + self.stop_scene = ADDON.getSettingString(f"group{self.light_group_id}_stopSceneID") + if self.enabled: super().__init__() @@ -53,7 +53,8 @@ def __repr__(self): def onAVStarted(self): if self.enabled: - xbmc.log(f"[script.service.hue] In LightGroup[{self.light_group_id}], onPlaybackStarted. Group enabled: {self.enabled},startBehavior: {self.start_behavior} , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}, self.mediaType: {self.media_type},self.playbackType(): {self.playback_type()}") + xbmc.log( + f"[script.service.hue] In LightGroup[{self.light_group_id}], onPlaybackStarted. Group enabled: {self.enabled},startBehavior: {self.start_behavior} , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}, self.mediaType: {self.media_type},self.playbackType(): {self.playback_type()}") self.state = STATE_PLAYING self.last_media_type = self.playback_type() @@ -152,8 +153,8 @@ def playback_type(self): @staticmethod def check_active_time(): - service_enabled = cache_get("service_enabled") - daylight = cache_get("script.service.hue.daylight") + + daylight = cache_get("daylight") xbmc.log("[script.service.hue] Schedule: {}, daylightDisable: {}, daylight: {}, startTime: {}, endTime: {}".format(ADDON.getSettingBool("enableSchedule"), ADDON.getSettingBool("daylightDisable"), daylight, ADDON.getSettingString("startTime"), ADDON.getSettingString("endTime"))) @@ -187,7 +188,7 @@ def check_video_activation(self, info_tag): # previousFileName = fileName # xbmc.log("[script.service.hue] InfoTag contents: duration: {}, mediaType: {}, file: {}".format(duration, mediaType, fileName)) - except (AttributeError, TypeError) as exc: + except (AttributeError, TypeError): xbmc.log("[script.service.hue] Can't read infoTag {exc}") return False # xbmc.log("Video Activation settings({}): minDuration: {}, Movie: {}, Episode: {}, MusicVideo: {}, PVR : {}, Other: {}".format(self.light_group_id, settings_storage['videoMinimumDuration'], settings_storage['video_enableMovie'], @@ -213,8 +214,8 @@ def check_already_active(self, scene): try: scene_data = self.bridge.scenes[scene]() for light in scene_data["lights"]: - l = self.bridge.lights[light]() - if l["state"]["on"]: # one light is on, the scene can be applied + states = self.bridge.lights[light]() + if states["state"]["on"]: # one light is on, the scene can be applied # xbmc.log("[script.service.hue] Check if scene light already active: True") return True # xbmc.log("[script.service.hue] Check if scene light already active: False") @@ -234,8 +235,8 @@ def check_keep_lights_off_rule(self, scene): try: scene_data = self.bridge.scenes[scene]() for light in scene_data["lights"]: - l = self.bridge.lights[light]() - if l["state"]["on"] is False: # one light is off, the scene should not be applied + states = self.bridge.lights[light]() + if states["state"]["on"] is False: # one light is off, the scene should not be applied xbmc.log("[script.service.hue] Check if lights should stay off: True") return False xbmc.log("[script.service.hue] Check if lights should stay off: False") @@ -245,5 +246,4 @@ def check_keep_lights_off_rule(self, scene): except Exception as exc: reporting.process_exception(exc) - return True diff --git a/script.service.hue/resources/lib/menu.py b/script.service.hue/resources/lib/menu.py index 2c9cd479e..1e6bd1982 100644 --- a/script.service.hue/resources/lib/menu.py +++ b/script.service.hue/resources/lib/menu.py @@ -4,7 +4,6 @@ # See LICENSE.TXT for more information. import sys -from datetime import timedelta from urllib.parse import parse_qs import xbmc @@ -12,9 +11,8 @@ import xbmcvfs from xbmcgui import ListItem -import resources.lib.kodiutils -from resources.lib import ADDON, ADDONID, ADDONPATH -from resources.lib.kodiutils import cache_set, cache_get +from . import ADDON, ADDONID, ADDONPATH +from .kodiutils import cache_set, cache_get from .language import get_string as _ diff --git a/script.service.hue/resources/lib/reporting.py b/script.service.hue/resources/lib/reporting.py index ec4bec591..79e978109 100644 --- a/script.service.hue/resources/lib/reporting.py +++ b/script.service.hue/resources/lib/reporting.py @@ -7,14 +7,16 @@ import sys import traceback + import rollbar import xbmc import xbmcgui from qhue import QhueException +from requests import RequestException -from resources.lib import ADDONVERSION, ROLLBAR_API_KEY, KODIVERSION, ADDONPATH, ADDON -from resources.lib.kodiutils import notification -from resources.lib.language import get_string as _ +from . import ADDONVERSION, ROLLBAR_API_KEY, KODIVERSION, ADDONPATH, ADDON +from .kodiutils import notification +from .language import get_string as _ def process_exception(exc, level="critical", error=""): @@ -23,6 +25,9 @@ def process_exception(exc, level="critical", error=""): if type(exc) == QhueException and exc.type_id in ["3", "7"]: # 3: resource not found, 7: invalid value for parameter xbmc.log("[script.service.hue] Qhue resource not found, not reporting to rollbar") notification(_("Hue Service"), _("ERROR: Scene or Light not found, it may have changed or been deleted. Check your configuration."), icon=xbmcgui.NOTIFICATION_ERROR) + elif type(exc) == RequestException: + xbmc.log("[script.service.hue] RequestException, not reporting to rollbar") + notification(_("Hue Service"), _("Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) else: if ADDON.getSettingBool("error_reporting"): if _error_report_dialog(exc): @@ -51,5 +56,5 @@ def _report_error(level="critical", error="", exc=""): 'error': error, 'exc': exc } - rollbar.init(ROLLBAR_API_KEY, capture_ip=False, code_version="v" + ADDONVERSION, root=ADDONPATH, scrub_fields='bridgeUser, bridgeIP, bridge_user, bridge_ip', environment=env) + rollbar.init(ROLLBAR_API_KEY, capture_ip=False, code_version="v" + ADDONVERSION, root=ADDONPATH, scrub_fields='bridgeUser, bridgeIP, bridge_user, bridge_ip, server.host', environment=env) rollbar.report_exc_info(sys.exc_info(), extra_data=data, level=level) From 9e47ba563ad46a09fb009b2b0e0e7b9e753b23cf Mon Sep 17 00:00:00 2001 From: Max Hadjinlian Date: Wed, 12 Apr 2023 18:42:25 -0700 Subject: [PATCH 025/145] [script.myepisodes] 3.2.0 --- script.myepisodes/addon.xml | 2 +- script.myepisodes/changelog.txt | 2 + script.myepisodes/default.py | 245 +++++++++++++---------- script.myepisodes/kodilogging.py | 10 +- script.myepisodes/myepisodes.py | 96 ++++++--- script.myepisodes/resources/settings.xml | 2 +- script.myepisodes/utils.py | 34 ++-- 7 files changed, 226 insertions(+), 165 deletions(-) diff --git a/script.myepisodes/addon.xml b/script.myepisodes/addon.xml index 8df1baa65..6f9020cae 100644 --- a/script.myepisodes/addon.xml +++ b/script.myepisodes/addon.xml @@ -1,7 +1,7 @@ diff --git a/script.myepisodes/changelog.txt b/script.myepisodes/changelog.txt index ac1f3eaa2..4bd4fa723 100644 --- a/script.myepisodes/changelog.txt +++ b/script.myepisodes/changelog.txt @@ -1,3 +1,5 @@ +3.2.0 ++ Important refactor and bug fixes. 3.0.2 + Use "is_alive" instead of "is_Alive" that doesn't exists 3.0.1 diff --git a/script.myepisodes/default.py b/script.myepisodes/default.py index 1dc3a0aba..d21b7ae07 100644 --- a/script.myepisodes/default.py +++ b/script.myepisodes/default.py @@ -4,6 +4,7 @@ import sys import threading import logging +from typing import Callable import xbmc import xbmcvfs @@ -12,7 +13,7 @@ import utils import kodilogging -from myepisodes import MyEpisodes +from myepisodes import MyEpisodes, SHOW_ID_ERR _addon = xbmcaddon.Addon() _kodiversion = float(xbmcaddon.Addon("xbmc.addon").getAddonInfo("version")[0:4]) @@ -25,90 +26,85 @@ logger = logging.getLogger(__name__) -class MyeMonitor(xbmc.Monitor): - def __init__(self, *args, **kwargs): +class MEMonitor(xbmc.Monitor): + def __init__(self, *args: int, **kwargs: Callable) -> None: xbmc.Monitor.__init__(self) self.action = kwargs["action"] - def onSettingsChanged(self): + def onSettingsChanged(self) -> None: logger.debug("User changed settings") self.action() -def _initMyEpisodes(): - username = utils.getSetting("Username") - password = utils.getSetting("Password") - - login_notif = _language(32912) - if not username or not password: - utils.notif(login_notif, time=2500) - return None - - mye = MyEpisodes(username, password) - mye.login() - if mye.is_logged: - login_notif = f"{username} {_language(32911)}" - utils.notif(login_notif, time=2500) - - if mye.is_logged and (not mye.populate_shows()): - utils.notif(_language(32927), time=2500) - return mye +class MEProperties: + def __init__(self) -> None: + self.showid = self.episode = self.season = 0 + self.title = "" + self.is_excluded = False + self.total_time = sys.maxsize + self.last_pos = 0 -class MyePlayer(xbmc.Player): - def __init__(self): +class MEPlayer(xbmc.Player): + def __init__(self) -> None: xbmc.Player.__init__(self) - logger.debug("MyePlayer - init") + logger.debug("MEPlayer - init") + self._tracker = threading.Thread(target=self._track_position) + self._reset() - self.mye = _initMyEpisodes() + def _reset(self) -> None: + logger.debug("_reset called") + self.resetTracker() + if hasattr(self, "mye"): + del self.mye + self.monitor = MEMonitor(action=self._reset) + self.props = MEProperties() + self._playback_lock = threading.Event() + self.mye: MyEpisodes = MEPlayer.initMyEpisodes() if not self.mye.is_logged: return - logger.debug("MyePlayer - account is logged successfully.") - self.showid = self.episode = self.title = self.season = None - self.is_excluded = False - self._total_time = sys.maxsize - self._last_pos = 0 - self._min_percent = utils.getSettingAsInt("watched-percent") - self._tracker = None - self._playback_lock = threading.Event() - self.monitor = MyeMonitor(action=self._reset) - - def _reset(self): - logger.debug("_reset called") - self.tearDown() - if self.mye: - del self.mye - self.__init__() - - def _trackPosition(self): - while self._playback_lock.isSet() and not self.monitor.abortRequested(): - try: - self._last_pos = self.getTime() - except: - self._playback_lock.clear() - logger.debug(f"Tracker time = {self._last_pos}") - xbmc.sleep(250) - logger.debug(f"Tracker time (ended) = {self._last_pos}") - - def setUp(self): - self._playback_lock.set() - self._tracker = threading.Thread(target=self._trackPosition) - - def tearDown(self): + def resetTracker(self) -> None: if hasattr(self, "_playback_lock"): self._playback_lock.clear() if not hasattr(self, "_tracker"): return - if self._tracker is None: - return if self._tracker.is_alive(): self._tracker.join() - self._tracker = None + self._tracker = threading.Thread(target=self._track_position) + + @classmethod + def initMyEpisodes(cls) -> MyEpisodes: + username = utils.getSetting("Username") + password = utils.getSetting("Password") + + login_notif = _language(32912) + if not username or not password: + utils.notif(login_notif, time=2500) + return MyEpisodes("", "") + + mye = MyEpisodes(username, password) + mye.login() + if mye.is_logged: + login_notif = f"{username} {_language(32911)}" + utils.notif(login_notif, time=2500) - def _addShow(self): + if mye.is_logged and (not mye.populate_shows()): + utils.notif(_language(32927), time=2500) + return mye + def _track_position(self) -> None: + while self._playback_lock.is_set() and not self.monitor.abortRequested(): + try: + self.props.last_pos = self.getTime() + except: + self._playback_lock.clear() + logger.debug("Tracker time = %d", self.props.last_pos) + xbmc.sleep(250) + logger.debug("Tracker time (ended) = %d", self.props.last_pos) + + def _add_show(self) -> None: if not utils.getSettingAsBool("auto-add"): logger.debug("Auto-add function disabled.") return @@ -117,112 +113,143 @@ def _addShow(self): self.mye.populate_shows() # Add the show if it's not already in our account - if self.showid in list(self.mye.shows.values()): + if self.props.showid in list(self.mye.shows.values()): logger.debug("Show is already in the account.") return - was_added = self.mye.add_show(self.showid) + was_added = self.mye.add_show(self.props.showid) added = 32926 if was_added: added = 32925 - utils.notif(f"{self.title} {_language(added)}") + utils.notif(f"{self.props.title} {_language(added)}") # For backward compatibility - def onPlayBackStarted(self): + def onPlayBackStarted(self) -> None: if _kodiversion >= 17.9: return # This call is only for Krypton and below self.onAVStarted() # Only available in Leia (18) and up - def onAVStarted(self): - self.setUp() - self._total_time = self.getTotalTime() + def onAVStarted(self) -> None: + self._playback_lock.set() + self.props.total_time = self.getTotalTime() self._tracker.start() filename_full_path = self.getPlayingFile() # We don't want to take care of any URL because we can't really gain # information from it. - self.is_excluded = False + self.props.is_excluded = False if utils.is_excluded(filename_full_path): - self.is_excluded = True - self.tearDown() + self.props.is_excluded = True + self.resetTracker() return # Try to find the title with the help of Kodi (Theses came from # Kodi.Subtitles add-ons) - self.season = str(xbmc.getInfoLabel("VideoPlayer.Season")) - logger.debug("Player - Season: {self.season}") - self.episode = str(xbmc.getInfoLabel("VideoPlayer.Episode")) - logger.debug("Player - Episode: {self.episode}") - self.title = xbmc.getInfoLabel("VideoPlayer.TVshowtitle") - logger.debug("Player - TVShow: {self.title}") - if self.title == "": + try: + self.props.season = int(xbmc.getInfoLabel("VideoPlayer.Season")) + except ValueError: + self.props.season = 0 + logger.debug("Player - Season: %02d", self.props.season) + + try: + self.props.episode = int(xbmc.getInfoLabel("VideoPlayer.Episode")) + except ValueError: + self.props.episode = 0 + logger.debug("Player - Episode: %02d", self.props.episode) + + self.props.title = xbmc.getInfoLabel("VideoPlayer.TVshowtitle") + logger.debug("Player - TVShow: %s", self.props.title) + + if self.props.title == "": filename = os.path.basename(filename_full_path) - logger.debug("Player - Filename: {filename}") - self.title, self.season, self.episode = self.mye.get_info(filename) - logger.debug("Player - TVShow: {self.title}") + logger.debug("Player - Filename: '%s'", filename) + self.props.title, self.props.season, self.props.episode = self.mye.get_info( + filename + ) + logger.debug("Player - TVShow: '%s'", self.props.title) logger.debug( - f"Title: {self.title} - Season: {self.season} - Ep: {self.episode}" + "Title: '%s' - Season: %02d - Ep: %02d ", + self.props.title, + self.props.season, + self.props.episode, ) - if not self.season and not self.episode: + if not self.props.season and not self.props.episode: # It's not a show. If it should be recognised as one. Send a bug. - self.tearDown() + self.resetTracker() return - self.showid = self.mye.find_show_id(self.title) - if self.showid is None: - utils.notif(f"{self.title} {_language(32923)}", time=3000) - self.tearDown() + self.props.showid = self.mye.find_show_id(self.props.title) + if self.props.showid == SHOW_ID_ERR: + utils.notif(f"{self.props.title} {_language(32923)}", time=3000) + self.resetTracker() return logger.debug( - f"Player - Found : {self.title} - {self.showid} (S{self.season} E{self.episode}" + "Player - Found : '%s' - %02d (S%02d E%02d", + self.props.title, + self.props.showid, + self.props.season, + self.props.episode, ) - utils.notif(self.title, time=2000) - self._addShow() + utils.notif(self.props.title, time=2000) + self._add_show() - def onPlayBackStopped(self): + def onPlayBackStopped(self) -> None: # User stopped the playback self.onPlayBackEnded() - def onPlayBackEnded(self): - self.tearDown() + def onPlayBackEnded(self) -> None: + self.resetTracker() - logger.debug(f"onPlayBackEnded: is_exluded: {self.is_excluded}") - if self.is_excluded: + logger.debug("onPlayBackEnded: is_exluded: %r", self.props.is_excluded) + if self.props.is_excluded: return - logger.debug(f"last_pos / total_time : {self._last_pos} / {self._total_time}") - - actual_percent = (self._last_pos / self._total_time) * 100 logger.debug( - f"last_pos / total_time : {self._last_pos} / {self._total_time} = {actual_percent} %%", + "last_pos / total_time : %d / %d", + self.props.last_pos, + self.props.total_time, ) - logger.debug(f"min_percent: {self._min_percent}") + actual_percent = (self.props.last_pos / self.props.total_time) * 100 + logger.debug( + "last_pos / total_time : %d / %d = %d%%", + self.props.last_pos, + self.props.total_time, + actual_percent, + ) - if actual_percent < self._min_percent: + min_percent = min(utils.getSettingAsInt("watched-percent"), 95) + logger.debug("min_percent: %d%%", min_percent) + if actual_percent < min_percent: return # In case it was deleted or whatever happened during playback - self._addShow() + self._add_show() # Playback is finished, set the items to watched found = 32923 - if self.mye.set_episode_watched(self.showid, self.season, self.episode): + if self.mye.set_episode_watched( + self.props.showid, self.props.season, self.props.episode + ): found = 32924 - utils.notif(f"{self.title} ({self.season} - {self.episode}) {_language(found)}") + utils.notif( + f"{self.props.title} ({self.props.season:02} - {self.props.episode:02}) {_language(found)}" + ) if __name__ == "__main__": - player = MyePlayer() + player = MEPlayer() if not player.mye.is_logged: sys.exit(0) logger.debug( - f"[{_addon.getAddonInfo('name')}] - Version: {_addon.getAddonInfo('version')} Started" + "[%s] - Version: %s Started", + _addon.getAddonInfo("name"), + _addon.getAddonInfo("version"), ) while not player.monitor.abortRequested(): @@ -230,5 +257,5 @@ def onPlayBackEnded(self): # Abort was requested while waiting. We should exit break - player.tearDown() + player.resetTracker() sys.exit(0) diff --git a/script.myepisodes/kodilogging.py b/script.myepisodes/kodilogging.py index 41b144614..1c6dbff98 100644 --- a/script.myepisodes/kodilogging.py +++ b/script.myepisodes/kodilogging.py @@ -23,14 +23,14 @@ class KodiLogHandler(logging.StreamHandler): - def __init__(self): + def __init__(self) -> None: logging.StreamHandler.__init__(self) addon_id = xbmcaddon.Addon().getAddonInfo("id") - format = f"### [addon_id] - [%(filename)s:%(lineno)s - %(funcName)20s() ] %(name)s: %(message)s" + format = f"### [{addon_id}] - [%(filename)s:%(lineno)s - %(funcName)20s() ] %(name)s: %(message)s" formatter = logging.Formatter(format) self.setFormatter(formatter) - def emit(self, record): + def emit(self, record: logging.LogRecord) -> None: levels = { logging.CRITICAL: xbmc.LOGFATAL, logging.ERROR: xbmc.LOGERROR, @@ -42,11 +42,11 @@ def emit(self, record): xbmc.log(self.format(record), levels[record.levelno]) - def flush(self): + def flush(self) -> None: pass -def config(): +def config() -> None: logger = logging.getLogger() logger.addHandler(KodiLogHandler()) logger.setLevel(logging.DEBUG) diff --git a/script.myepisodes/myepisodes.py b/script.myepisodes/myepisodes.py index 165256b66..0b4b2a0f3 100644 --- a/script.myepisodes/myepisodes.py +++ b/script.myepisodes/myepisodes.py @@ -1,9 +1,15 @@ # -*- coding: utf-8 -*- +from __future__ import annotations +from typing import final, TypeVar, Any, Callable, Optional, cast + import re import requests +from urllib3.util.retry import Retry from bs4 import BeautifulSoup +SHOW_ID_ERR = -1 + # This is totally stolen from script.xbmc.subtitles plugin ! REGEX_EXPRESSIONS = [ r"[Ss]([0-9]+)[][._-]*[Ee]([0-9]+)([^\\\\/]*)$", @@ -22,42 +28,64 @@ ] MYEPISODE_URL = "https://www.myepisodes.com" -MAX_LOGIN_ATTEMPTS = 3 +MAX_RETRY_ATTEMPTS = 5 -def sanitize(title, replace): +def sanitize(title: str, replace: str) -> str: for char in ["[", "]", "_", "(", ")", ".", "-"]: title = title.replace(char, replace) return title -def logged(func): - def wrapper(*args, **kwargs): +F = TypeVar("F", bound=Callable[..., Any]) + + +def logged(func: F) -> F: + def wrapper(*args: MyEpisodes, **kwargs: str) -> F: mye = args[0] if not mye.is_logged: mye.login() return func(*args, **kwargs) - return wrapper + return cast(F, wrapper) + +def retry_session(retries, backoff_factor=0.5): + session = requests.Session() + retry = Retry( + total=retries, + read=retries, + connect=retries, + backoff_factor=backoff_factor, + allowed_methods=None, + raise_on_status=False, + raise_on_redirect=False, + ) -class MyEpisodes(object): - def __init__(self, userid, password): + adapter = requests.adapters.HTTPAdapter(max_retries=retry) + session.mount("http://", adapter) + session.mount("https://", adapter) + return session + + +@final +class MyEpisodes: + def __init__(self, userid: str, password: str) -> None: self.userid = userid self.password = password - self.req = requests.Session() + self.req = retry_session(retries=MAX_RETRY_ATTEMPTS) self.title_is_filename = False self.is_logged = False - self.shows = {} + self.shows: dict[str, int] = {} - def __del__(self): + def __del__(self) -> None: self.req.close() - def __repr__(self): + def __repr__(self) -> str: return f"MyEpisodes('{self.userid}', '{self.password}')" - def login(self): - login_attempts = MAX_LOGIN_ATTEMPTS + def login(self) -> None: + login_attempts = MAX_RETRY_ATTEMPTS login_data = { "username": self.userid, "password": self.password, @@ -74,7 +102,7 @@ def login(self): login_attempts -= 1 @logged - def populate_shows(self): + def populate_shows(self) -> bool: self.shows.clear() # Populate shows with the list of show_ids in our account @@ -104,7 +132,9 @@ def populate_shows(self): return True - def find_show_link(self, data, show_name, strict=False): + def find_show_link( + self, data: bytes, show_name: str, strict: bool = False + ) -> Optional[str]: if data is None: return None @@ -133,7 +163,7 @@ def find_show_link(self, data, show_name, strict=False): return show_href @logged - def find_show_id(self, show_name): + def find_show_id(self, show_name: str) -> int: # Try to find the ID of the show in our account first name = show_name.lower() @@ -173,30 +203,30 @@ def find_show_id(self, show_name): # Really did not find anything :'( if show_href is None: - return None + return SHOW_ID_ERR try: show_id = int(show_href.split("/")[2]) except IndexError: - return None + return SHOW_ID_ERR if show_id is None: - return None + return SHOW_ID_ERR return show_id # This is totally stolen from script.xbmc.subtitles plugin ! - def get_info(self, file_name): - title = None - episode = None - season = None + def get_info(self, file_name: str) -> tuple[str, int, int]: + title = "" + season = SHOW_ID_ERR + episode = SHOW_ID_ERR self.title_is_filename = False for regex in REGEX_EXPRESSIONS: response_file = re.findall(regex, file_name) if response_file: - season = response_file[0][0] - episode = response_file[0][1] + season = int(response_file[0][0]) + episode = int(response_file[0][1]) else: continue title = re.split(regex, file_name)[0] @@ -205,16 +235,16 @@ def get_info(self, file_name): self.title_is_filename = True return title.title(), season, episode - return None, None, None + return title, season, episode - def add_show(self, show_id): + def add_show(self, show_id: int) -> bool: return self._add_del_show(show_id) - def del_show(self, show_id): + def del_show(self, show_id: int) -> bool: return self._add_del_show(show_id, mode="del") @logged - def _add_del_show(self, show_id, mode="add"): + def _add_del_show(self, show_id: int, mode: str = "add") -> bool: add_del_data = {"action": mode, "showid": show_id} data = self.req.post( f"{MYEPISODE_URL}/ajax/service.php", @@ -229,14 +259,16 @@ def _add_del_show(self, show_id, mode="add"): return True - def set_episode_watched(self, show_id, season, episode): + def set_episode_watched(self, show_id: int, season: int, episode: int) -> bool: return self._set_episode_un_watched(show_id, season, episode) - def set_episode_unwatched(self, show_id, season, episode): + def set_episode_unwatched(self, show_id: int, season: int, episode: int) -> bool: return self._set_episode_un_watched(show_id, season, episode, watched=False) @logged - def _set_episode_un_watched(self, show_id, season, episode, watched=True): + def _set_episode_un_watched( + self, show_id: int, season: int, episode: int, watched: bool = True + ) -> bool: key = f"V{show_id}-{season}-{episode}" # If you are wondering why the lower and conversion to str, it's # because the backend of MyEpisodes is so smart that it doesn't diff --git a/script.myepisodes/resources/settings.xml b/script.myepisodes/resources/settings.xml index 6bd9d4c0c..69d53ec24 100644 --- a/script.myepisodes/resources/settings.xml +++ b/script.myepisodes/resources/settings.xml @@ -3,7 +3,7 @@ - + diff --git a/script.myepisodes/utils.py b/script.myepisodes/utils.py index d0a9f99af..8f1ca3312 100644 --- a/script.myepisodes/utils.py +++ b/script.myepisodes/utils.py @@ -14,47 +14,47 @@ _scriptname = _addon.getAddonInfo("name") -def getSettingAsBool(setting): +def getSettingAsBool(setting: str) -> bool: return _addon.getSetting(setting).lower() == "true" -def getSetting(setting): +def getSetting(setting: str) -> str: return _addon.getSetting(setting).strip() -def getSettingAsInt(setting): +def getSettingAsInt(setting: str) -> int: try: return int(getSetting(setting)) except ValueError: return 0 -def notif(msg, time=5000): - xbmcgui.Dialog().notification(f"MyEpisodes", msg, _icon, time) +def notif(msg: str, time: int = 5000) -> None: + xbmcgui.Dialog().notification("MyEpisodes", msg, _icon, time) -def is_excluded(filename): - logger.debug(f"_is_excluded(): Check if '{filename}' is a URL.") +def is_excluded(filename: str) -> bool: + logger.debug("_is_excluded(): Check if '%s' is a URL.", filename) excluded_protocols = ["pvr://", "http://", "https://"] if any(protocol in filename for protocol in excluded_protocols): - logger.debug(f"_is_excluded(): '{filename}' is a URL; it's excluded.") + logger.debug("_is_excluded(): '%s' is a URL; it's excluded.", filename) return True - logger.debug(f"_is_excluded(): Check if '{filename}' is in an excluded path.") + logger.debug("_is_excluded(): Check if '%s' is in an excluded path.", filename) for index in range(1, 4): - if index == 1: - index = "" - exclude_option = getSettingAsBool(f"ExcludePathOption{index}") - logger.debug(f"ExcludePathOption{index}") - logger.debug(f"testing with {exclude_option}") + index_str = "" if index == 1 else str(index) + exclude_option = getSettingAsBool(f"ExcludePathOption{index_str}") + logger.debug("ExcludePathOption%s", index_str) if not exclude_option: continue - exclude_path = getSetting(f"ExcludePath{index}") - logger.debug(f"testing with {exclude_path}") + exclude_path = getSetting(f"ExcludePath{index_str}") + logger.debug("testing with '%s'", exclude_path) if exclude_path == "": continue if exclude_path in filename: - logger.debug(f"_is_excluded(): Video is excluded (ExcludePath{index}).") + logger.debug( + "_is_excluded(): Video is excluded (ExcludePath%s).", index_str + ) return True return False From fed6e036513dd0200b3b2b8cc2b1f35006ed4aea Mon Sep 17 00:00:00 2001 From: Randall Spicher Date: Sat, 15 Apr 2023 17:10:39 -0400 Subject: [PATCH 026/145] [weather.noaa] 2.0.11 --- weather.noaa/addon.xml | 2 +- weather.noaa/changelog.txt | 8 + weather.noaa/default.py | 1685 ++++++++++++++------------- weather.noaa/resources/lib/utils.py | 1153 +++++++++--------- weather.noaa/resources/settings.xml | 75 ++ 5 files changed, 1574 insertions(+), 1349 deletions(-) diff --git a/weather.noaa/addon.xml b/weather.noaa/addon.xml index ee867b538..ba4caf2ab 100644 --- a/weather.noaa/addon.xml +++ b/weather.noaa/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/weather.noaa/changelog.txt b/weather.noaa/changelog.txt index d298b000a..2801fb5f8 100644 --- a/weather.noaa/changelog.txt +++ b/weather.noaa/changelog.txt @@ -1,3 +1,11 @@ +v2.0.11 +- fix wind-chill calculation +- if we have a direct windchill or headindex value from the api, use that instead of calculating it +- refresh the gridpoint and forecast urls from the lattitude/longitude every couple of days to handle grid changes in the api +- only reset location descriptive name when lat,long is entered +- retry after a minute if there is an error from the api +- fixes when using forecast.weather.gov as the source + v2.0.10 - radar images url path changed - cleanup on alerts diff --git a/weather.noaa/default.py b/weather.noaa/default.py index a0bc51952..130849be1 100644 --- a/weather.noaa/default.py +++ b/weather.noaa/default.py @@ -4,213 +4,255 @@ #from future import standard_library #standard_library.install_aliases() -import os, glob, sys, time +import os, glob, sys, time, re import xbmc, xbmcgui, xbmcvfs, xbmcaddon +import datetime from resources.lib.utils import FtoC, CtoF, log, ADDON, LANGUAGE, MAPSECTORS, LOOPSECTORS, MAPTYPES from resources.lib.utils import WEATHER_CODES, FORECAST, FEELS_LIKE, SPEED, WIND_DIR, SPEEDUNIT, zip_x from resources.lib.utils import get_url_JSON, get_url_image from resources.lib.utils import get_month, get_timestamp, get_weekday, get_time - +from dateutil.parser import parse WEATHER_WINDOW = xbmcgui.Window(12600) -WEATHER_ICON = xbmcvfs.translatePath('%s.png') -DATEFORMAT = xbmc.getRegion('dateshort') -TIMEFORMAT = xbmc.getRegion('meridiem') -MAXDAYS = 10 -TEMPUNIT = xbmc.getRegion('tempunit') -SOURCEPREF = ADDON.getSetting("DataSourcePreference") +WEATHER_ICON = xbmcvfs.translatePath('%s.png') +DATEFORMAT = xbmc.getRegion('dateshort') +TIMEFORMAT = xbmc.getRegion('meridiem') +MAXDAYS = 10 +TEMPUNIT = xbmc.getRegion('tempunit') +SOURCEPREF = ADDON.getSetting("DataSourcePreference") def set_property(name, value): - WEATHER_WINDOW.setProperty(name, value) + WEATHER_WINDOW.setProperty(name, value) def clear_property(name): - WEATHER_WINDOW.clearProperty(name) + WEATHER_WINDOW.clearProperty(name) def clear(): - set_property('Current.Condition' , 'N/A') - set_property('Current.Temperature' , '0') - set_property('Current.Wind' , '0') - set_property('Current.WindDirection' , 'N/A') - set_property('Current.Humidity' , '0') - set_property('Current.FeelsLike' , '0') - set_property('Current.UVIndex' , '0') - set_property('Current.DewPoint' , '0') - set_property('Current.OutlookIcon' , 'na.png') - set_property('Current.FanartCode' , 'na') - for count in range (0, MAXDAYS+1): - set_property('Day%i.Title' % count, 'N/A') - set_property('Day%i.HighTemp' % count, '0') - set_property('Day%i.LowTemp' % count, '0') - set_property('Day%i.Outlook' % count, 'N/A') - set_property('Day%i.OutlookIcon' % count, 'na.png') - set_property('Day%i.FanartCode' % count, 'na') + set_property('Current.Condition' , 'N/A') + set_property('Current.Temperature' , '0') + set_property('Current.Wind' , '0') + set_property('Current.WindDirection' , 'N/A') + set_property('Current.Humidity' , '0') + set_property('Current.FeelsLike' , '0') + set_property('Current.UVIndex' , '0') + set_property('Current.DewPoint' , '0') + set_property('Current.OutlookIcon' , 'na.png') + set_property('Current.FanartCode' , 'na') + for count in range (0, MAXDAYS+1): + set_property('Day%i.Title' % count, 'N/A') + set_property('Day%i.HighTemp' % count, '0') + set_property('Day%i.LowTemp' % count, '0') + set_property('Day%i.Outlook' % count, 'N/A') + set_property('Day%i.OutlookIcon' % count, 'na.png') + set_property('Day%i.FanartCode' % count, 'na') def refresh_locations(): - locations = 0 - for count in range(1, 6): - LatLong = ADDON.getSetting('Location%sLatLong' % count) - loc_name = ADDON.getSetting('Location%s' % count) - if LatLong: - locations += 1 - if not loc_name: - loc_name = 'Location %s' % count - set_property('Location%s' % count, loc_name) - - else: - set_property('Location%s' % count, '') - - #set_property('Location%s' % count, loc_name) - - set_property('Locations', str(locations)) - log('available locations: %s' % str(locations)) - -def get_initial(loc): - url = 'https://api.weather.gov/points/%s' % loc - log("url:"+url) - responsedata=get_url_JSON(url) - return responsedata - + locations = 0 + for count in range(1, 6): + LatLong = ADDON.getSetting('Location%sLatLong' % count) + loc_name = ADDON.getSetting('Location%s' % count) + if LatLong: + locations += 1 + if not loc_name: + loc_name = 'Location %s' % count + set_property('Location%s' % count, loc_name) + + else: + set_property('Location%s' % count, '') + + #set_property('Location%s' % count, loc_name) + + set_property('Locations', str(locations)) + log('available locations: %s' % str(locations)) + + def code_from_icon(icon): - if icon: - #xbmc.log('icon: %s' % (icon) ,level=xbmc.LOGDEBUG) - if '?' in icon: - icon=icon.rsplit('?', 1)[0] - - sun="day" -# if "/day/" in icon: -# sun="day" - if "/night/" in icon: - sun="night" - - rain = None - code = None - # loop though our "split" icon paths, and get max rain percent - # take last icon code in the process - for checkcode in icon.rsplit('/'): - thing=checkcode.split(",") - code="%s/%s" % (sun,thing[0]) - if len(thing) > 1: - train=thing[1] - if rain is None or train > rain: - rain=train - - return code, rain - + if icon: + #xbmc.log('icon: %s' % (icon) ,level=xbmc.LOGDEBUG) + + + daynight="day" + + #special handling of forecast.weather.gov "dualimage" icon generator urls + #https://forecast.weather.gov/DualImage.php?i=bkn&j=shra&jp=30 + #https://forecast.weather.gov/DualImage.php?i=shra&j=bkn&ip=30 + if 'DualImage' in icon: + params = icon.split("?")[1].split("&") + code="day" + rain=None + for param in params: + thing=param.split("=") + p=thing[0] + v=thing[1] + if p == "i": + code="%s/%s" % ("day",v) + if p == "ip" or p == "jp": + if rain is None or v > rain: + rain=v + + return code, rain + + + if '?' in icon: + icon=icon.rsplit('?', 1)[0] + + # strip off file extension if we have one + icon=icon.replace(".png","") + icon=icon.replace(".jpg","") + + if "/day/" in icon: + daynight="day" + elif "/night/" in icon: + daynight="night" + + rain = None + code = None + # loop though our "split" icon paths, and get max rain percent + # take last icon code in the process + for checkcode in icon.rsplit('/'): + thing=checkcode.split(",") + code="%s/%s" % (daynight,thing[0]) + if len(thing) > 1: + train=thing[1] + if rain is None or train > rain: + rain=train + + return code, rain + ######################################################################################## ## Dialog for getting Latitude and Longitude ######################################################################################## -def enterLocation(num): -## log("argument: %s" % (sys.argv[1])) - text = ADDON.getSetting("Location"+num+"LatLong") - Latitude="" - Longitude="" - if text and "," in text: - thing=text.split(",") - Latitude=thing[0] - Longitude=thing[1] - - dialog = xbmcgui.Dialog() - - Latitude=dialog.input(LANGUAGE(32341),defaultt=Latitude,type=xbmcgui.INPUT_ALPHANUM) - -# xbmc.Keyboard(line, heading, hidden) -# keyboard = xbmc.Keyboard(Latitude, 32341, False) -# keyboard.doModal() -# if (keyboard.isConfirmed()): -# Latitude= keyboard.getText() - if not Latitude: - ADDON.setSetting("Location"+num+"LatLong","") - return False - - Longitude=dialog.input(heading=LANGUAGE(32342),defaultt=Longitude,type=xbmcgui.INPUT_ALPHANUM) - -# keyboard = xbmc.Keyboard(Longitude, 32342, False) -# keyboard.doModal() -# if (keyboard.isConfirmed()): -# Longitude= keyboard.getText() - if not Longitude: - ADDON.setSetting("Location"+num+"LatLong","") - return False - LatLong=Latitude+","+Longitude - ADDON.setSetting("Location"+num+"LatLong",LatLong) - fetchLocation(num,LatLong) - return + + +def enterLocation(num): +## log("argument: %s" % (sys.argv[1])) + + text = ADDON.getSetting("Location"+num+"LatLong") + Latitude="" + Longitude="" + if text and "," in text: + thing=text.split(",") + Latitude=thing[0] + Longitude=thing[1] + + dialog = xbmcgui.Dialog() + + Latitude=dialog.input(LANGUAGE(32341),defaultt=Latitude,type=xbmcgui.INPUT_ALPHANUM) + + if not Latitude: + ADDON.setSetting("Location"+num+"LatLong","") + return False + + Longitude=dialog.input(heading=LANGUAGE(32342),defaultt=Longitude,type=xbmcgui.INPUT_ALPHANUM) + + if not Longitude: + ADDON.setSetting("Location"+num+"LatLong","") + return False + LatLong=Latitude+","+Longitude + ADDON.setSetting("Location"+num+"LatLong",LatLong) + get_Stations(num,LatLong,True) + return + ######################################################################################## ## fetches location data (weather grid point, station, etc, for lattitude,logngitude +## returns url for fetching local weather stations ######################################################################################## -def fetchLocation(num,LatLong): - prefix="Location"+num - log('searching for location: %s' % LatLong) - data = get_initial(LatLong) - log('location data: %s' % data) - if not data: - log('failed to retrieve location data') - return None - if data and 'properties' in data: - - city = data['properties']['relativeLocation']['properties']['city'] - state = data['properties']['relativeLocation']['properties']['state'] - locationName= city+", "+state - ADDON.setSetting(prefix, locationName) - - gridX=data['properties']['gridX'] - ADDON.setSetting(prefix+'gridX',str(gridX)) - - gridY=data['properties']['gridY'] - ADDON.setSetting(prefix+'gridY',str(gridY)) - - cwa=data['properties']['cwa'] - ADDON.setSetting(prefix+'cwa', cwa) - - forecastZone=data['properties']['forecastZone'] - zone=forecastZone.rsplit('/',1)[1] - ADDON.setSetting(prefix+'Zone', zone) - - forecastCounty=data['properties']['county'] - county=forecastCounty.rsplit('/',1)[1] - ADDON.setSetting(prefix+'County', county) - - forecastGridData_url = data['properties']['forecastGridData'] - ADDON.setSetting(prefix+'forecastGrid_url', forecastGridData_url) - - forecastHourly_url = data['properties']['forecastHourly'] - ADDON.setSetting(prefix+'forecastHourly_url', forecastHourly_url) - - forecast_url = data['properties']['forecast'] - ADDON.setSetting(prefix+'forecast_url', forecast_url) - - radarStation = data['properties']['radarStation'] - ADDON.setSetting(prefix+'radarStation', radarStation) - - - stations_url = data['properties']['observationStations'] - odata = get_url_JSON(stations_url) - - if odata and 'features' in odata: - stations={} - stationlist=[] - - for count,item in enumerate(odata['features']): - stationId=item['properties']['stationIdentifier'] - stationName=item['properties']['name'] - stationlist.append(stationName) - stations[stationName]=stationId - - dialog = xbmcgui.Dialog() - i=dialog.select(LANGUAGE(32331),stationlist) - # clean up reference to dialog object - del dialog - - - ADDON.setSetting(prefix+'Station',stations[stationlist[i]]) - ADDON.setSetting(prefix+'StationName',stationlist[i]) - - + + +def get_Points(num,LatLong,resetName=False): + + prefix="Location"+num + log('searching for location: %s' % LatLong) + url = 'https://api.weather.gov/points/%s' % LatLong + log("url:"+url) + data=get_url_JSON(url) + log('location data: %s' % data) + if not data: + log('failed to retrieve location data') + return None + if data and 'properties' in data: + + if resetName: + city = data['properties']['relativeLocation']['properties']['city'] + state = data['properties']['relativeLocation']['properties']['state'] + locationName= city+", "+state + ADDON.setSetting(prefix, locationName) + + gridX=data['properties']['gridX'] + ADDON.setSetting(prefix+'gridX',str(gridX)) + + gridY=data['properties']['gridY'] + ADDON.setSetting(prefix+'gridY',str(gridY)) + + cwa=data['properties']['cwa'] + ADDON.setSetting(prefix+'cwa', cwa) + + forecastZone=data['properties']['forecastZone'] + zone=forecastZone.rsplit('/',1)[1] + ADDON.setSetting(prefix+'Zone', zone) + + forecastCounty=data['properties']['county'] + county=forecastCounty.rsplit('/',1)[1] + ADDON.setSetting(prefix+'County', county) + + forecastGridData_url = data['properties']['forecastGridData'] + ADDON.setSetting(prefix+'forecastGrid_url', forecastGridData_url) + + forecastHourly_url = data['properties']['forecastHourly'] + ADDON.setSetting(prefix+'forecastHourly_url', forecastHourly_url) + + forecast_url = data['properties']['forecast'] + ADDON.setSetting(prefix+'forecast_url', forecast_url) + + radarStation = data['properties']['radarStation'] + ADDON.setSetting(prefix+'radarStation', radarStation) + + + #current_datetime = parse("now") + current_datetime = datetime.datetime.now() + ADDON.setSetting(prefix+'lastPointsCheck', str(current_datetime)) + + + stations_url = data['properties']['observationStations'] + return stations_url + +######################################################################################## +## fetches location data (weather grid point, station, etc, for lattitude,logngitude +######################################################################################## + +def get_Stations(num,LatLong,resetName=False): + + prefix="Location"+num + odata=None + stations_url=get_Points(num,LatLong,resetName) + if stations_url: + odata = get_url_JSON(stations_url) + + if odata and 'features' in odata: + stations={} + stationlist=[] + + for count,item in enumerate(odata['features']): + stationId=item['properties']['stationIdentifier'] + stationName=item['properties']['name'] + stationlist.append(stationName) + stations[stationName]=stationId + + dialog = xbmcgui.Dialog() + i=dialog.select(LANGUAGE(32331),stationlist) + # clean up reference to dialog object + del dialog + + + ADDON.setSetting(prefix+'Station',stations[stationlist[i]]) + ADDON.setSetting(prefix+'StationName',stationlist[i]) + + ######################################################################################## @@ -219,116 +261,117 @@ def fetchLocation(num,LatLong): def fetchDaily(num): - log("SOURCEPREF: %s" % SOURCEPREF) - url=ADDON.getSetting('Location'+str(num)+'forecast_url') - if "preview-api.weather.gov" == SOURCEPREF: - url=url.replace("https://api.weather.gov","https://preview-api.weather.gov") - - if 'F' in TEMPUNIT: - url="%s?units=us" % url - elif 'C' in TEMPUNIT: - url="%s?units=si" % url - - log('forecast url: %s' % url) - - daily_weather = get_url_JSON(url) - - if daily_weather and 'properties' in daily_weather: - data=daily_weather['properties'] - else: - #api.weather.gov is acting up, so fall back to alternate api - xbmc.log('failed to find weather data from : %s' % url,level=xbmc.LOGERROR) - xbmc.log('%s' % daily_weather,level=xbmc.LOGERROR) - return fetchAltDaily(num) - - for count, item in enumerate(data['periods'], start=0): - icon = item['icon'] - #https://api.weather.gov/icons/land/night/ovc?size=small - if icon and '?' in icon: - icon=icon.rsplit('?', 1)[0] - code, rain=code_from_icon(icon) - - weathercode = WEATHER_CODES.get(code) - starttime=item['startTime'] - startstamp=get_timestamp(starttime) - set_property('Day%i.isDaytime' % (count),str(item['isDaytime'])) - set_property('Day%i.Title' % (count), item['name']) - - if item['isDaytime'] == True: - ##Since we passed units into api, we may need to convert to C, or may not - if 'F' in TEMPUNIT: - set_property('Day%i.HighTemp' % (count), str(FtoC(item['temperature']))) - set_property('Day%i.LowTemp' % (count), str(FtoC(item['temperature']))) - elif 'C' in TEMPUNIT: - set_property('Day%i.HighTemp' % (count), str(item['temperature'])) - set_property('Day%i.LowTemp' % (count), str(item['temperature'])) - if item['isDaytime'] == False: - if 'F' in TEMPUNIT: - set_property('Day%i.HighTemp' % (count), str(FtoC(item['temperature']))) - set_property('Day%i.LowTemp' % (count), str(FtoC(item['temperature']))) - elif 'C' in TEMPUNIT: - set_property('Day%i.HighTemp' % (count), str(item['temperature'])) - set_property('Day%i.LowTemp' % (count), str(item['temperature'])) - set_property('Day%i.Outlook' % (count), item['shortForecast']) - set_property('Day%i.FanartCode' % (count), weathercode) - set_property('Day%i.OutlookIcon'% (count), WEATHER_ICON % weathercode) - set_property('Day%i.RemoteIcon' % (count), icon) - - # NOTE: Day props are 0 based, but Daily/Hourly are 1 based - set_property('Daily.%i.isDaytime' % (count+1),str(item['isDaytime'])) - set_property('Daily.%i.Outlook' % (count+1), item['shortForecast']) - set_property('Daily.%i.ShortOutlook' % (count+1), item['shortForecast']) - set_property('Daily.%i.DetailedOutlook' % (count+1), item['detailedForecast']) - - set_property('Daily.%i.RemoteIcon' % (count+1), icon) - set_property('Daily.%i.OutlookIcon' % (count+1), WEATHER_ICON % weathercode) - set_property('Daily.%i.FanartCode' % (count+1), weathercode) - set_property('Daily.%i.WindDirection' % (count+1), item['windDirection']) - set_property('Daily.%i.WindSpeed' % (count+1), item['windSpeed']) - - if item['isDaytime'] == True: - set_property('Daily.%i.LongDay' % (count+1), item['name']) - set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (d)") - #set_property('Daily.%i.TempDay' % (count+1), u'%i\N{DEGREE SIGN}%s' % (item['temperature'], item['temperatureUnit'])) - #set_property('Daily.%i.HighTemperature' % (count+1), u'%i\N{DEGREE SIGN}%s' % (item['temperature'], item['temperatureUnit'])) - - ## we passed units to api, so we got back C or F, so don't need to convert - set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - #if 'F' in TEMPUNIT: - # set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - # set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - #elif 'C' in TEMPUNIT: - # set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - # set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - set_property('Daily.%i.TempNight' % (count+1), '') - set_property('Daily.%i.LowTemperature' % (count+1), '') - - if item['isDaytime'] == False: - set_property('Daily.%i.LongDay' % (count+1), item['name']) - set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (n)") - - set_property('Daily.%i.TempDay' % (count+1), '') - set_property('Daily.%i.HighTemperature' % (count+1), '') - ## we passed units to api, so we got back C or F, so don't need to convert - #if 'F' in TEMPUNIT: - set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - #elif 'C' in TEMPUNIT: - # set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - # set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - - if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': - set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) - set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) - else: - set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) - set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) - - if rain: - set_property('Daily.%i.ChancePrecipitation' % (count+1), str(rain) + '%') - else: - set_property('Daily.%i.ChancePrecipitation' % (count+1), '') + log("SOURCEPREF: %s" % SOURCEPREF) + url=ADDON.getSetting('Location'+str(num)+'forecast_url') + if "preview-api.weather.gov" == SOURCEPREF: + url=url.replace("https://api.weather.gov","https://preview-api.weather.gov") + + if 'F' in TEMPUNIT: + url="%s?units=us" % url + elif 'C' in TEMPUNIT: + url="%s?units=si" % url + + log('forecast url: %s' % url) + + daily_weather = get_url_JSON(url) + + if daily_weather and 'properties' in daily_weather: + data=daily_weather['properties'] + else: + #api.weather.gov is acting up, so fall back to alternate api + xbmc.log('failed to find weather data from : %s' % url,level=xbmc.LOGERROR) + xbmc.log('%s' % daily_weather,level=xbmc.LOGERROR) + return fetchAltDaily(num) + + for count, item in enumerate(data['periods'], start=0): + icon = item['icon'] + #https://api.weather.gov/icons/land/night/ovc?size=small + if icon and '?' in icon: + icon=icon.rsplit('?', 1)[0] + code, rain=code_from_icon(icon) + + weathercode = WEATHER_CODES.get(code) + starttime=item['startTime'] + startstamp=get_timestamp(starttime) + set_property('Day%i.isDaytime' % (count),str(item['isDaytime'])) + set_property('Day%i.Title' % (count), item['name']) + + if item['isDaytime'] == True: + ##Since we passed units into api, we may need to convert to C, or may not + if 'F' in TEMPUNIT: + set_property('Day%i.HighTemp' % (count), str(FtoC(item['temperature']))) + set_property('Day%i.LowTemp' % (count), str(FtoC(item['temperature']))) + elif 'C' in TEMPUNIT: + set_property('Day%i.HighTemp' % (count), str(item['temperature'])) + set_property('Day%i.LowTemp' % (count), str(item['temperature'])) + if item['isDaytime'] == False: + if 'F' in TEMPUNIT: + set_property('Day%i.HighTemp' % (count), str(FtoC(item['temperature']))) + set_property('Day%i.LowTemp' % (count), str(FtoC(item['temperature']))) + elif 'C' in TEMPUNIT: + set_property('Day%i.HighTemp' % (count), str(item['temperature'])) + set_property('Day%i.LowTemp' % (count), str(item['temperature'])) + set_property('Day%i.Outlook' % (count), item['shortForecast']) + set_property('Day%i.FanartCode' % (count), weathercode) + set_property('Day%i.OutlookIcon'% (count), WEATHER_ICON % weathercode) + set_property('Day%i.RemoteIcon' % (count), icon) + + # NOTE: Day props are 0 based, but Daily/Hourly are 1 based + set_property('Daily.%i.isDaytime' % (count+1),str(item['isDaytime'])) + set_property('Daily.%i.Outlook' % (count+1), item['shortForecast']) + set_property('Daily.%i.ShortOutlook' % (count+1), item['shortForecast']) + set_property('Daily.%i.DetailedOutlook' % (count+1), item['detailedForecast']) + + set_property('Daily.%i.RemoteIcon' % (count+1), icon) + set_property('Daily.%i.OutlookIcon' % (count+1), WEATHER_ICON % weathercode) + set_property('Daily.%i.FanartCode' % (count+1), weathercode) + set_property('Daily.%i.WindDirection' % (count+1), item['windDirection']) + set_property('Daily.%i.WindSpeed' % (count+1), item['windSpeed']) + + if item['isDaytime'] == True: + set_property('Daily.%i.LongDay' % (count+1), item['name']) + set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (d)") + #set_property('Daily.%i.TempDay' % (count+1), u'%i\N{DEGREE SIGN}%s' % (item['temperature'], item['temperatureUnit'])) + #set_property('Daily.%i.HighTemperature' % (count+1), u'%i\N{DEGREE SIGN}%s' % (item['temperature'], item['temperatureUnit'])) + + ## we passed units to api, so we got back C or F, so don't need to convert + set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + #if 'F' in TEMPUNIT: + # set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + # set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + #elif 'C' in TEMPUNIT: + # set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + # set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + set_property('Daily.%i.TempNight' % (count+1), '') + set_property('Daily.%i.LowTemperature' % (count+1), '') + + if item['isDaytime'] == False: + set_property('Daily.%i.LongDay' % (count+1), item['name']) + set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (n)") + + set_property('Daily.%i.TempDay' % (count+1), '') + set_property('Daily.%i.HighTemperature' % (count+1), '') + ## we passed units to api, so we got back C or F, so don't need to convert + #if 'F' in TEMPUNIT: + set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + #elif 'C' in TEMPUNIT: + # set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + # set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + + if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': + set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) + set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) + else: + set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) + set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) + + if rain and str(rain) and not "0" == str(rain): + set_property('Daily.%i.ChancePrecipitation' % (count+1), str(rain) + '%') + else: + ##set_property('Daily.%i.ChancePrecipitation' % (count+1), '') + clear_property('Daily.%i.ChancePrecipitation' % (count+1)) @@ -339,164 +382,179 @@ def fetchDaily(num): def fetchAltDaily(num): - latlong=ADDON.getSetting('Location'+str(num)+"LatLong") - latitude =latlong.rsplit(',',1)[0] - longitude=latlong.rsplit(',',1)[1] - - url="https://forecast.weather.gov/MapClick.php?lon="+longitude+"&lat="+latitude+"&FcstType=json" - log('forecast url: %s' % url) - - daily_weather = get_url_JSON(url) - - if daily_weather and 'data' in daily_weather: - - dailydata=[ - {"startPeriodName": a, - "startValidTime": b, - "tempLabel": c, - "temperature": d, - "pop": e, - "weather": f, - "iconLink": g, - "hazard": h, - "hazardUrl": i, - "text": j - } - for a,b,c,d,e,f,g,h,i,j in zip_x(None, - daily_weather['time']['startPeriodName'], - daily_weather['time']['startValidTime'], - daily_weather['time']['tempLabel'], - daily_weather['data']['temperature'], - daily_weather['data']['pop'], - daily_weather['data']['weather'], - daily_weather['data']['iconLink'], - daily_weather['data']['hazard'], - daily_weather['data']['hazardUrl'], - daily_weather['data']['text'] - )] - - else: - xbmc.log('failed to retrieve weather data from : %s' % url,level=xbmc.LOGERROR) - xbmc.log('%s' % daily_weather,level=xbmc.LOGERROR) - return None - - for count, item in enumerate(dailydata, start=0): - icon = item['iconLink'] - - #https://api.weather.gov/icons/land/night/ovc?size=small - code, ignoreme = code_from_icon(icon) - weathercode = WEATHER_CODES.get(code) - - starttime=item['startValidTime'] - startstamp=get_timestamp(starttime) - set_property('Day%i.Title' % (count), item['startPeriodName']) - - set_property('Day%i.Outlook' % (count), item['weather']) - set_property('Day%i.Details' % (count), item['text']) - - set_property('Day%i.OutlookIcon' % (count), WEATHER_ICON % weathercode) - set_property('Day%i.RemoteIcon' % (count), icon) - set_property('Day%i.FanartCode' % (count), weathercode) - - # NOTE: Day props are 0 based, but Daily/Hourly are 1 based - set_property('Daily.%i.DetailedOutlook' % (count+1), item['text']) - set_property('Daily.%i.Outlook' % (count+1), item['weather']) - set_property('Daily.%i.ShortOutlook' % (count+1), item['weather']) - - set_property('Daily.%i.OutlookIcon' % (count+1), WEATHER_ICON % weathercode) - set_property('Daily.%i.RemoteIcon' % (count+1), icon) - set_property('Daily.%i.FanartCode' % (count+1), weathercode) - - if item['tempLabel'] == 'High': - set_property('Daily.%i.LongDay' % (count+1), item['startPeriodName']) - set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (d)") - - if 'F' in TEMPUNIT: - set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - elif 'C' in TEMPUNIT: - set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) -# set_property('Daily.%i.TempDay' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) -# set_property('Daily.%i.HighTemperature' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) - set_property('Daily.%i.TempNight' % (count+1), '') - set_property('Daily.%i.LowTemperature' % (count+1), '') - - if item['tempLabel'] == 'Low': - set_property('Daily.%i.LongDay' % (count+1), item['startPeriodName']) - set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (n)") - set_property('Daily.%i.TempDay' % (count+1), '') - set_property('Daily.%i.HighTemperature' % (count+1), '') - if 'F' in TEMPUNIT: - set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - elif 'C' in TEMPUNIT: - set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - #set_property('Daily.%i.TempNight' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) - #set_property('Daily.%i.LowTemperature' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) - if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': - set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) - set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) - else: - set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) - set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) - - rain = item['pop'] - if rain: - set_property('Daily.%i.ChancePrecipitation' % (count+1), str(rain) + '%') - else: - set_property('Daily.%i.ChancePrecipitation' % (count+1), '') - - - - - if daily_weather and 'currentobservation' in daily_weather: - data=daily_weather['currentobservation'] - icon = "http://forecast.weather.gov/newimages/large/%s" % data.get('Weatherimage') - code, rain = code_from_icon(icon) - weathercode = WEATHER_CODES.get(code) - set_property('Current.Location', data.get('name')) - set_property('Current.RemoteIcon',icon) - set_property('Current.OutlookIcon', '%s.png' % weathercode) # xbmc translates it to Current.ConditionIcon - set_property('Current.FanartCode', weathercode) - set_property('Current.Condition', FORECAST.get(data.get('Weather'), data.get('Weather'))) - set_property('Current.Humidity' , str(data.get('Relh'))) - set_property('Current.DewPoint', str(FtoC(data.get('Dewp')))) - - try: - temp=data.get('Temp') - set_property('Current.Temperature',str(FtoC(temp))) # api values are in C - except: - set_property('Current.Temperature','') - - try: - set_property('Current.Wind', str(round(float(data.get('Winds'))*1.609298167))) - except: - set_property('Current.Wind','') - - try: - set_property('Current.WindDirection', xbmc.getLocalizedString(WIND_DIR(int(data.get('Windd'))))) - except: - set_property('Current.WindDirection', '') - - try: - set_property('Current.WindGust' , str(SPEED(float(data.get('Gust'))/2.237)) + SPEEDUNIT) - except: - set_property('Current.WindGust' , '') - - if rain: - set_property('Current.ChancePrecipitation', str(rain)+'%'); - else : - set_property('Current.ChancePrecipitation', ''); - - try: - set_property('Current.FeelsLike', FEELS_LIKE( FtoC(data.get('Temp')), float(data.get('Winds'))/2.237, int(data.get('Relh')), False)) - except: - set_property('Current.FeelsLike', '') - - - + latlong=ADDON.getSetting('Location'+str(num)+"LatLong") + latitude =latlong.rsplit(',',1)[0] + longitude=latlong.rsplit(',',1)[1] + + url="https://forecast.weather.gov/MapClick.php?lon="+longitude+"&lat="+latitude+"&FcstType=json" + log('forecast url: %s' % url) + + daily_weather = get_url_JSON(url) + + if daily_weather and 'data' in daily_weather: + + dailydata=[ + {"startPeriodName": a, + "startValidTime": b, + "tempLabel": c, + "temperature": d, + "pop": e, + "weather": f, + "iconLink": g, + "hazard": h, + "hazardUrl": i, + "text": j + } + for a,b,c,d,e,f,g,h,i,j in zip_x(None, + daily_weather['time']['startPeriodName'], + daily_weather['time']['startValidTime'], + daily_weather['time']['tempLabel'], + daily_weather['data']['temperature'], + daily_weather['data']['pop'], + daily_weather['data']['weather'], + daily_weather['data']['iconLink'], + daily_weather['data']['hazard'], + daily_weather['data']['hazardUrl'], + daily_weather['data']['text'] + )] + + else: + xbmc.log('failed to retrieve weather data from : %s' % url,level=xbmc.LOGERROR) + xbmc.log('%s' % daily_weather,level=xbmc.LOGERROR) + return None + + for count, item in enumerate(dailydata, start=0): + icon = item['iconLink'] + + #https://api.weather.gov/icons/land/night/ovc?size=small + code, ignoreme = code_from_icon(icon) + weathercode = WEATHER_CODES.get(code) + + starttime=item['startValidTime'] + startstamp=get_timestamp(starttime) + set_property('Day%i.Title' % (count), item['startPeriodName']) + + set_property('Day%i.Outlook' % (count), item['weather']) + set_property('Day%i.Details' % (count), item['text']) + + set_property('Day%i.OutlookIcon' % (count), WEATHER_ICON % weathercode) + set_property('Day%i.RemoteIcon' % (count), icon) + set_property('Day%i.FanartCode' % (count), weathercode) + + # NOTE: Day props are 0 based, but Daily/Hourly are 1 based + set_property('Daily.%i.DetailedOutlook' % (count+1), item['text']) + set_property('Daily.%i.Outlook' % (count+1), item['weather']) + set_property('Daily.%i.ShortOutlook' % (count+1), item['weather']) + + set_property('Daily.%i.OutlookIcon' % (count+1), WEATHER_ICON % weathercode) + set_property('Daily.%i.RemoteIcon' % (count+1), icon) + set_property('Daily.%i.FanartCode' % (count+1), weathercode) + + if item['tempLabel'] == 'High': + set_property('Daily.%i.LongDay' % (count+1), item['startPeriodName']) + set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (d)") + + if 'F' in TEMPUNIT: + set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + elif 'C' in TEMPUNIT: + set_property('Daily.%i.TempDay' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + set_property('Daily.%i.HighTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) +# set_property('Daily.%i.TempDay' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) +# set_property('Daily.%i.HighTemperature' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) + set_property('Daily.%i.TempNight' % (count+1), '') + set_property('Daily.%i.LowTemperature' % (count+1), '') + + if item['tempLabel'] == 'Low': + set_property('Daily.%i.LongDay' % (count+1), item['startPeriodName']) + set_property('Daily.%i.ShortDay' % (count+1), get_weekday(startstamp,'s')+" (n)") + set_property('Daily.%i.TempDay' % (count+1), '') + set_property('Daily.%i.HighTemperature' % (count+1), '') + if 'F' in TEMPUNIT: + set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + elif 'C' in TEMPUNIT: + set_property('Daily.%i.TempNight' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + set_property('Daily.%i.LowTemperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + #set_property('Daily.%i.TempNight' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) + #set_property('Daily.%i.LowTemperature' % (count+1), u'%s\N{DEGREE SIGN}%s' % (item['temperature'], "F")) + if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': + set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) + set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) + else: + set_property('Daily.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) + set_property('Daily.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) + + rain = item['pop'] + if rain and str(rain) and not "0" == str(rain): + set_property('Daily.%i.ChancePrecipitation' % (count+1), str(rain) + '%') + else: + ##set_property('Daily.%i.ChancePrecipitation' % (count+1), '') + clear_property('Daily.%i.ChancePrecipitation' % (count+1)) + + + + + if daily_weather and 'currentobservation' in daily_weather: + data=daily_weather['currentobservation'] + icon = "http://forecast.weather.gov/newimages/large/%s" % data.get('Weatherimage') + code, rain = code_from_icon(icon) + weathercode = WEATHER_CODES.get(code) + + set_property('Current.Location', data.get('name')) + set_property('Current.RemoteIcon',icon) + set_property('Current.OutlookIcon', '%s.png' % weathercode) # xbmc translates it to Current.ConditionIcon + set_property('Current.FanartCode', weathercode) + set_property('Current.Condition', FORECAST.get(data.get('Weather'), data.get('Weather'))) + set_property('Current.Humidity' , str(data.get('Relh'))) + set_property('Current.DewPoint', str(FtoC(data.get('Dewp')))) + + try: + temp=data.get('Temp') + set_property('Current.Temperature',str(FtoC(temp))) # api values are in C + except: + #set_property('Current.Temperature','') + clear_property('Current.Temperature') + + try: + set_property('Current.Wind', str(round(float(data.get('Winds'))*1.609298167))) + except: + #set_property('Current.Wind','') + clear_property('Current.Wind') + + try: + set_property('Current.WindDirection', xbmc.getLocalizedString(WIND_DIR(int(data.get('Windd'))))) + except: + #set_property('Current.WindDirection', '') + clear_property('Current.WindDirection') + + try: + set_property('Current.WindGust' , str(SPEED(float(data.get('Gust'))/2.237)) + SPEEDUNIT) + except: + clear_property('Current.WindGust') + ##set_property('Current.WindGust' , '') + + if rain and str(rain) and not "0" == str(rain): + set_property('Current.ChancePrecipitation', str(rain)+'%') + else : + clear_property('Current.ChancePrecipitation') + + # calculate feels like + clear_property('Current.FeelsLike') + try: + feels = FEELS_LIKE( FtoC(data.get('Temp')), float(data.get('Winds'))/2.237, int(data.get('Relh')), False) + set_property('Current.FeelsLike', str(feels)) + except: + clear_property('Current.FeelsLike') + #set_property('Current.FeelsLike', '') + + # if we have windchill or heatindex directly, then use that instead + if data.get('WindChill') and not "NA" == data.get('WindChill'): + set_property('Current.FeelsLike', str(FtoC(data.get('WindChill'))) ) + if data.get('HeatIndex') and not "NA" == data.get('HeatIndex'): + set_property('Current.FeelsLike', str(FtoC(data.get('HeatIndex'))) ) + + ######################################################################################## @@ -504,84 +562,101 @@ def fetchAltDaily(num): ######################################################################################## def fetchCurrent(num): - station=ADDON.getSetting('Location'+str(num)+'Station') - url="https://api.weather.gov/stations/%s/observations/latest" %station - current=get_url_JSON(url) - if current and 'properties' in current: - data=current['properties'] - else: - xbmc.log('failed to find weather data from : %s' % url,level=xbmc.LOGERROR) - xbmc.log('%s' % current,level=xbmc.LOGERROR) - return - - icon = data['icon'] - #https://api.weather.gov/icons/land/night/ovc?size=small - code = None - rain = None - if icon: - if '?' in icon: - icon=icon.rsplit('?', 1)[0] - code, rain = code_from_icon(icon) - weathercode = WEATHER_CODES.get(code) - set_property('Current.RemoteIcon',icon) - set_property('Current.OutlookIcon', '%s.png' % weathercode) # xbmc translates it to Current.ConditionIcon - set_property('Current.FanartCode', weathercode) - - set_property('Current.Condition', FORECAST.get(data.get('textDescription'), data.get('textDescription'))) - try: - set_property('Current.Humidity' , str(round(data.get('relativeHumidity').get('value')))) - except: - set_property('Current.Humidity' , '') - - try: - temp=int(round(data.get('temperature').get('value'))) - set_property('Current.Temperature',str(temp)) # api values are in C - except: - set_property('Current.Temperature','') - try: - set_property('Current.Wind', str(int(round(data.get('windSpeed').get('value'))))) - except: - set_property('Current.Wind','') - - try: - set_property('Current.WindDirection', xbmc.getLocalizedString(WIND_DIR(int(round(data.get('windDirection').get('value')))))) - except: - set_property('Current.WindDirection', '') - - if rain: - set_property('Current.ChancePrecipitation', str(rain)+'%'); - else : - set_property('Current.ChancePrecipitation', ''); - - try: - set_property('Current.FeelsLike', FEELS_LIKE(data.get('temperature').get('value'), float(data.get('windSpeed').get('value'))/3.6, data.get('relativeHumidity').get('value'), False)) - except: - set_property('Current.FeelsLike', '') - - try: - temp=int(round(data.get('dewpoint').get('value',0))) - set_property('Current.DewPoint', str(temp)) # api values are in C - except: - set_property('Current.DewPoint', '') + station=ADDON.getSetting('Location'+str(num)+'Station') + url="https://api.weather.gov/stations/%s/observations/latest" %station + current=get_url_JSON(url) + if current and 'properties' in current: + data=current['properties'] + else: + xbmc.log('failed to find weather data from : %s' % url,level=xbmc.LOGERROR) + xbmc.log('%s' % current,level=xbmc.LOGERROR) + return + + icon = data['icon'] + #https://api.weather.gov/icons/land/night/ovc?size=small + code = None + rain = None + if icon: + if '?' in icon: + icon=icon.rsplit('?', 1)[0] + code, rain = code_from_icon(icon) + weathercode = WEATHER_CODES.get(code) + set_property('Current.RemoteIcon',icon) + set_property('Current.OutlookIcon', '%s.png' % weathercode) # xbmc translates it to Current.ConditionIcon + set_property('Current.FanartCode', weathercode) + + set_property('Current.Condition', FORECAST.get(data.get('textDescription'), data.get('textDescription'))) + try: + set_property('Current.Humidity' , str(round(data.get('relativeHumidity').get('value')))) + except: + ##set_property('Current.Humidity' , '') + clear_property('Current.Humidity') + + try: + temp=int(round(data.get('temperature').get('value'))) + set_property('Current.Temperature',str(temp)) # api values are in C + except: + ##set_property('Current.Temperature','') + clear_property('Current.Temperature') + try: + set_property('Current.Wind', str(int(round(data.get('windSpeed').get('value'))))) + except: + ##set_property('Current.Wind','') + clear_property('Current.Wind') + + try: + set_property('Current.WindDirection', xbmc.getLocalizedString(WIND_DIR(int(round(data.get('windDirection').get('value')))))) + except: + #set_property('Current.WindDirection', '') + clear_property('Current.WindDirection') + + if rain and str(rain) and not "0" == str(rain): + set_property('Current.ChancePrecipitation', str(rain)+'%') + else : + #set_property('Current.ChancePrecipitation', '') + clear_property('Current.ChancePrecipitation') + + clear_property('Current.FeelsLike') + #calculate feels like + windspeed=data.get('windSpeed').get('value') + if not windspeed: + windspeed=0 + + try: + set_property('Current.FeelsLike', FEELS_LIKE(data.get('temperature').get('value'), float(windspeed)/3.6, data.get('relativeHumidity').get('value'), False)) + except: + clear_property('Current.FeelsLike') + + # if we have windchill or heat index directly, then use that instead + if data.get('windChill').get('value'): + set_property('Current.FeelsLike', str(data.get('windChill').get('value')) ) + if data.get('heatIndex').get('value'): + set_property('Current.FeelsLike', str(data.get('heatIndex').get('value')) ) + + try: + temp=int(round(data.get('dewpoint').get('value',0))) + set_property('Current.DewPoint', str(temp)) # api values are in C + except: + set_property('Current.DewPoint', '') ## extended properties - try: - set_property('Current.WindGust' , SPEED(float(data.get('windGust').get('value',0))/3.6) + SPEEDUNIT) - except: - set_property('Current.WindGust' , '') + try: + set_property('Current.WindGust' , SPEED(float(data.get('windGust').get('value',0))/3.6) + SPEEDUNIT) + except: + set_property('Current.WindGust' , '') - try: - set_property('Current.SeaLevel' , str(data.get('seaLevelPressure').get('value',0))) - except: - set_property('Current.SeaLevel' , '') + try: + set_property('Current.SeaLevel' , str(data.get('seaLevelPressure').get('value',0))) + except: + set_property('Current.SeaLevel' , '') - try: - set_property('Current.GroundLevel' ,str(data.get('barometricPressure').get('value',0))) - except: - set_property('Current.GroundLevel' , '') + try: + set_property('Current.GroundLevel' ,str(data.get('barometricPressure').get('value',0))) + except: + set_property('Current.GroundLevel' , '') @@ -594,52 +669,52 @@ def fetchCurrent(num): def fetchWeatherAlerts(num): - ### we could fetch alerts for either 'County', or 'Zone' - #https://api.weather.gov/alerts/active/zone/CTZ006 - #https://api.weather.gov/alerts/active/zone/CTC009 - ##https://api.weather.gov/alerts/active?status=actual&point=%7Blat%7D,%7Blong%7D - - #for now, lets use the point alert lookup, as suggested by the weather api team - - ##a_zone=ADDON.getSetting('Location'+str(num)+'County') - ##url="https://api.weather.gov/alerts/active/zone/%s" %a_zone - - # we are storing lat,long as comma separated already, so that is convienent for us and we can just drop it into the url - latlong=ADDON.getSetting('Location'+str(num)+'LatLong') - url="https://api.weather.gov/alerts/active?status=actual&point=%s" % (latlong) - - alerts=get_url_JSON(url) - # if we have a valid response then clear our current alerts - if alerts and 'features' in alerts: - for count in range (1, 10): - clear_property('Alerts.%i.event' % (count)) - else: - xbmc.log('failed to get proper alert response %s' % url,level=xbmc.LOGERROR) - xbmc.log('%s' % alerts,level=xbmc.LOGDEBUG) - return - - if 'features' in alerts and alerts['features']: - data=alerts['features'] - set_property('Alerts.IsFetched' , 'true') - else: - clear_property('Alerts.IsFetched') - xbmc.log('No current weather alerts from %s' % url,level=xbmc.LOGDEBUG) - return - - for count, item in enumerate(data, start=1): - - thisdata=item['properties'] - set_property('Alerts.%i.status' % (count), str(thisdata['status'])) - set_property('Alerts.%i.messageType' % (count), str(thisdata['messageType'])) - set_property('Alerts.%i.category' % (count), str(thisdata['category'])) - set_property('Alerts.%i.severity' % (count), str(thisdata['severity'])) - set_property('Alerts.%i.certainty' % (count), str(thisdata['certainty'])) - set_property('Alerts.%i.urgency' % (count), str(thisdata['urgency'])) - set_property('Alerts.%i.event' % (count), str(thisdata['event'])) - set_property('Alerts.%i.headline' % (count), str(thisdata['headline'])) - set_property('Alerts.%i.description' % (count), str(thisdata['description'])) - set_property('Alerts.%i.instruction' % (count), str(thisdata['instruction'])) - set_property('Alerts.%i.response' % (count), str(thisdata['response'])) + ### we could fetch alerts for either 'County', or 'Zone' + #https://api.weather.gov/alerts/active/zone/CTZ006 + #https://api.weather.gov/alerts/active/zone/CTC009 + ##https://api.weather.gov/alerts/active?status=actual&point=%7Blat%7D,%7Blong%7D + + #for now, lets use the point alert lookup, as suggested by the weather api team + + ##a_zone=ADDON.getSetting('Location'+str(num)+'County') + ##url="https://api.weather.gov/alerts/active/zone/%s" %a_zone + + # we are storing lat,long as comma separated already, so that is convienent for us and we can just drop it into the url + latlong=ADDON.getSetting('Location'+str(num)+'LatLong') + url="https://api.weather.gov/alerts/active?status=actual&point=%s" % (latlong) + + alerts=get_url_JSON(url) + # if we have a valid response then clear our current alerts + if alerts and 'features' in alerts: + for count in range (1, 10): + clear_property('Alerts.%i.event' % (count)) + else: + xbmc.log('failed to get proper alert response %s' % url,level=xbmc.LOGERROR) + xbmc.log('%s' % alerts,level=xbmc.LOGDEBUG) + return + + if 'features' in alerts and alerts['features']: + data=alerts['features'] + set_property('Alerts.IsFetched' , 'true') + else: + clear_property('Alerts.IsFetched') + xbmc.log('No current weather alerts from %s' % url,level=xbmc.LOGDEBUG) + return + + for count, item in enumerate(data, start=1): + + thisdata=item['properties'] + set_property('Alerts.%i.status' % (count), str(thisdata['status'])) + set_property('Alerts.%i.messageType' % (count), str(thisdata['messageType'])) + set_property('Alerts.%i.category' % (count), str(thisdata['category'])) + set_property('Alerts.%i.severity' % (count), str(thisdata['severity'])) + set_property('Alerts.%i.certainty' % (count), str(thisdata['certainty'])) + set_property('Alerts.%i.urgency' % (count), str(thisdata['urgency'])) + set_property('Alerts.%i.event' % (count), str(thisdata['event'])) + set_property('Alerts.%i.headline' % (count), str(thisdata['headline'])) + set_property('Alerts.%i.description' % (count), str(thisdata['description'])) + set_property('Alerts.%i.instruction' % (count), str(thisdata['instruction'])) + set_property('Alerts.%i.response' % (count), str(thisdata['response'])) @@ -649,79 +724,83 @@ def fetchWeatherAlerts(num): def fetchHourly(num): - log("SOURCEPREF: %s" % SOURCEPREF) - - url=ADDON.getSetting('Location'+str(num)+'forecastHourly_url') - if "preview-api.weather.gov" == SOURCEPREF: - url=url.replace("https://api.weather.gov","https://preview-api.weather.gov") - log("url-x: %s" % url) - - if 'F' in TEMPUNIT: - url="%s?units=us" % url - elif 'C' in TEMPUNIT: - url="%s?units=si" % url - - - - hourly_weather = get_url_JSON(url) - if hourly_weather and 'properties' in hourly_weather: - data=hourly_weather['properties'] - else: - xbmc.log('failed to find proper hourly weather from %s' % url,level=xbmc.LOGERROR) - return + log("SOURCEPREF: %s" % SOURCEPREF) + + url=ADDON.getSetting('Location'+str(num)+'forecastHourly_url') + if "preview-api.weather.gov" == SOURCEPREF: + url=url.replace("https://api.weather.gov","https://preview-api.weather.gov") + log("url-x: %s" % url) + + if 'F' in TEMPUNIT: + url="%s?units=us" % url + elif 'C' in TEMPUNIT: + url="%s?units=si" % url + + + + hourly_weather = get_url_JSON(url) + if hourly_weather and 'properties' in hourly_weather: + data=hourly_weather['properties'] + else: + xbmc.log('failed to find proper hourly weather from %s' % url,level=xbmc.LOGERROR) + return + #api is currently returning a 0 % rain icon url, which is not valid, so need to clean it + iconreplacepattern1 = re.compile(r"[,]0$") # extended properties - for count, item in enumerate(data['periods'], start = 0): - - icon=item['icon'] - #https://api.weather.gov/icons/land/night/ovc?size=small - if icon: - if '?' in icon: - icon=icon.rsplit('?', 1)[0] - code, rain=code_from_icon(icon) - set_property('Hourly.%i.RemoteIcon' % (count+1), icon) - - weathercode = WEATHER_CODES.get(code) - starttime=item['startTime'] - startstamp=get_timestamp(starttime) - if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': - set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) - set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) - else: - set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) - set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) - - set_property('Hourly.%i.Time' % (count+1), get_time(startstamp)) - if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': - set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) - set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) - else: - set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) - set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) - - set_property('Hourly.%i.Outlook' % (count+1), FORECAST.get(item['shortForecast'], item['shortForecast'])) - set_property('Hourly.%i.ShortOutlook' % (count+1), FORECAST.get(item['shortForecast'], item['shortForecast'])) - set_property('Hourly.%i.OutlookIcon' % (count+1), WEATHER_ICON % weathercode) - set_property('Hourly.%i.FanartCode' % (count+1), weathercode) - #set_property('Hourly.%i.Humidity' % (count+1), str(item['main'].get('humidity','')) + '%') - set_property('Hourly.%i.WindDirection' % (count+1), item['windDirection']) - set_property('Hourly.%i.WindSpeed' % (count+1), item['windSpeed']) - - #set_property('Hourly.%i.Temperature' % (count+1), str(item['temperature'])+u'\N{DEGREE SIGN}'+item['temperatureUnit']) - - ## we passed units to api, so we got back C or F, so don't need to convert - set_property('Hourly.%i.Temperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - ##if 'F' in TEMPUNIT: - ## set_property('Hourly.%i.Temperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) - ##elif 'C' in TEMPUNIT: - ## set_property('Hourly.%i.Temperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) - - - if rain: - set_property('Hourly.%i.ChancePrecipitation' % (count+1), str(rain) + '%') - else: - set_property('Hourly.%i.ChancePrecipitation' % (count+1), '') - count = 1 + for count, item in enumerate(data['periods'], start = 0): + + icon=item['icon'] + #https://api.weather.gov/icons/land/night/ovc?size=small + if icon: + if '?' in icon: + icon=icon.rsplit('?', 1)[0] + code, rain=code_from_icon(icon) + icon=iconreplacepattern1.sub("",icon) + set_property('Hourly.%i.RemoteIcon' % (count+1), icon) + + weathercode = WEATHER_CODES.get(code) + starttime=item['startTime'] + startstamp=get_timestamp(starttime) + if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': + set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) + set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) + else: + set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) + set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) + + set_property('Hourly.%i.Time' % (count+1), get_time(startstamp)) + if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': + set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'dl')) + set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ds')) + else: + set_property('Hourly.%i.LongDate' % (count+1), get_month(startstamp, 'ml')) + set_property('Hourly.%i.ShortDate' % (count+1), get_month(startstamp, 'ms')) + + set_property('Hourly.%i.Outlook' % (count+1), FORECAST.get(item['shortForecast'], item['shortForecast'])) + set_property('Hourly.%i.ShortOutlook' % (count+1), FORECAST.get(item['shortForecast'], item['shortForecast'])) + set_property('Hourly.%i.OutlookIcon' % (count+1), WEATHER_ICON % weathercode) + set_property('Hourly.%i.FanartCode' % (count+1), weathercode) + #set_property('Hourly.%i.Humidity' % (count+1), str(item['main'].get('humidity','')) + '%') + set_property('Hourly.%i.WindDirection' % (count+1), item['windDirection']) + set_property('Hourly.%i.WindSpeed' % (count+1), item['windSpeed']) + + #set_property('Hourly.%i.Temperature' % (count+1), str(item['temperature'])+u'\N{DEGREE SIGN}'+item['temperatureUnit']) + + ## we passed units to api, so we got back C or F, so don't need to convert + set_property('Hourly.%i.Temperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + ##if 'F' in TEMPUNIT: + ## set_property('Hourly.%i.Temperature' % (count+1), u'%s%s' % (item['temperature'], TEMPUNIT)) + ##elif 'C' in TEMPUNIT: + ## set_property('Hourly.%i.Temperature' % (count+1), u'%s%s' % (FtoC(item['temperature']), TEMPUNIT)) + + + if rain and str(rain) and not "0" == str(rain): + set_property('Hourly.%i.ChancePrecipitation' % (count+1), str(rain) + '%') + else: + ##set_property('Hourly.%i.ChancePrecipitation' % (count+1), '') + clear_property('Hourly.%i.ChancePrecipitation' % (count+1)) + count = 1 ######################################################################################## @@ -729,72 +808,72 @@ def fetchHourly(num): ######################################################################################## def mapSettings(mapid): - s_sel = ADDON.getSetting(mapid+"Sector") - t_sel = ADDON.getSetting(mapid+"Type") + s_sel = ADDON.getSetting(mapid+"Sector") + t_sel = ADDON.getSetting(mapid+"Type") - t_keys = [] - t_values= [] + t_keys = [] + t_values= [] - #1st option is blank for removing map - t_keys.append("") - t_values.append("") + #1st option is blank for removing map + t_keys.append("") + t_values.append("") - for key,value in MAPTYPES.items(): - t_keys.append(key) - t_values.append(value) + for key,value in MAPTYPES.items(): + t_keys.append(key) + t_values.append(value) - dialog = xbmcgui.Dialog() + dialog = xbmcgui.Dialog() - ti=0 - try: - ti=t_keys.index(t_sel) - except: - ti=0 - ti=dialog.select(LANGUAGE(32350), t_values,0,ti) - t_sel=t_keys[ti] - ADDON.setSetting(mapid+"Type",t_keys[ti]) + ti=0 + try: + ti=t_keys.index(t_sel) + except: + ti=0 + ti=dialog.select(LANGUAGE(32350), t_values,0,ti) + t_sel=t_keys[ti] + ADDON.setSetting(mapid+"Type",t_keys[ti]) - if ti > 0: + if ti > 0: - if ("LOOP" == t_sel): - Sectors=LOOPSECTORS - else: - Sectors=MAPSECTORS + if ("LOOP" == t_sel): + Sectors=LOOPSECTORS + else: + Sectors=MAPSECTORS - # convert our map data into matching arrays to pass into dialog - s_keys = [] - s_values= [] + # convert our map data into matching arrays to pass into dialog + s_keys = [] + s_values= [] - for key,value in Sectors.items(): - s_keys.append(key) - s_values.append(value['name']) + for key,value in Sectors.items(): + s_keys.append(key) + s_values.append(value['name']) - # grab index of current region, and pass in as default to dialog - si=0 - try: - si=s_keys.index(s_sel.lower()) - except: - #ignore if we did not find - si=0 - si=dialog.select(LANGUAGE(32349),s_values,0,si) - s_sel=s_keys[si] - ADDON.setSetting(mapid+"Sector",s_sel) - ADDON.setSetting(mapid+"Label",Sectors[s_sel]['name']+":"+MAPTYPES[t_sel]) - ADDON.setSetting(mapid+"Select",Sectors[s_sel]['name']+":"+MAPTYPES[t_sel]) - else: - ADDON.setSetting(mapid+"Label","") - ADDON.setSetting(mapid+"Select","") + # grab index of current region, and pass in as default to dialog + si=0 + try: + si=s_keys.index(s_sel.lower()) + except: + #ignore if we did not find + si=0 + si=dialog.select(LANGUAGE(32349),s_values,0,si) + s_sel=s_keys[si] + ADDON.setSetting(mapid+"Sector",s_sel) + ADDON.setSetting(mapid+"Label",Sectors[s_sel]['name']+":"+MAPTYPES[t_sel]) + ADDON.setSetting(mapid+"Select",Sectors[s_sel]['name']+":"+MAPTYPES[t_sel]) + else: + ADDON.setSetting(mapid+"Label","") + ADDON.setSetting(mapid+"Select","") - - # clean up referenced dialog object - del dialog - + + # clean up referenced dialog object + del dialog + ######################################################################################## @@ -802,135 +881,145 @@ def mapSettings(mapid): ######################################################################################## class MyMonitor(xbmc.Monitor): - def __init__(self, *args, **kwargs): - xbmc.Monitor.__init__(self) + def __init__(self, *args, **kwargs): + xbmc.Monitor.__init__(self) log('version %s started with argv: %s' % (ADDON.getAddonInfo('version'), sys.argv[1])) MONITOR = MyMonitor() -set_property('Forecast.IsFetched' , 'true') -set_property('Current.IsFetched' , 'true') -set_property('Today.IsFetched' , '') -set_property('Daily.IsFetched' , 'true') -set_property('Detailed.IsFetched' , 'true') -set_property('Weekend.IsFetched' , '') -set_property('36Hour.IsFetched' , '') -set_property('Hourly.IsFetched' , 'true') -set_property('NOAA.IsFetched' , 'true') -set_property('WeatherProvider' , 'NOAA') +set_property('Forecast.IsFetched' , 'true') +set_property('Current.IsFetched' , 'true') +set_property('Today.IsFetched' , '') +set_property('Daily.IsFetched' , 'true') +set_property('Detailed.IsFetched' , 'true') +set_property('Weekend.IsFetched' , '') +set_property('36Hour.IsFetched' , '') +set_property('Hourly.IsFetched' , 'true') +set_property('NOAA.IsFetched' , 'true') +set_property('WeatherProvider' , 'NOAA') set_property('WeatherProviderLogo', xbmcvfs.translatePath(os.path.join(ADDON.getAddonInfo('path'), 'resources', 'media', 'skin-banner.png'))) if sys.argv[1].startswith('EnterLocation'): - num=sys.argv[2] - enterLocation(num) + num=sys.argv[2] + enterLocation(num) if sys.argv[1].startswith('FetchLocation'): - num=sys.argv[2] - LatLong = ADDON.getSetting("Location"+num+"LatLong") - if not LatLong: - enterLocation(num) - elif LatLong: - fetchLocation(num,LatLong) + num=sys.argv[2] + LatLong = ADDON.getSetting("Location"+num+"LatLong") + if not LatLong: + enterLocation(num) + elif LatLong: + get_Stations(num,LatLong) elif sys.argv[1].startswith('Map'): - mapSettings(sys.argv[1]) + mapSettings(sys.argv[1]) else: - num=sys.argv[1] - LatLong = ADDON.getSetting('Location%sLatLong' % num) - - station=ADDON.getSetting('Location'+str(num)+'Station') - if station == '' : - log("calling location with %s" % (LatLong)) - fetchLocation(str(num),LatLong) - - refresh_locations() - - LatLong = ADDON.getSetting('Location%s' % num) - - if LatLong: - fetchWeatherAlerts(num) - if "forecast.weather.gov" == SOURCEPREF: - fetchAltDaily(num) - else: - fetchCurrent(num) - fetchDaily(num) - fetchHourly(num) - Station=ADDON.getSetting('Location%sradarStation' % num) - - set_property('Map.IsFetched', 'true') - #KODI will cache and not re-fetch the weather image, so inject a dummy time-stamp into the url to trick kodi because we want the new image - nowtime=str(time.time()) - #Radar - radarLoop=ADDON.getSetting('RadarLoop') - - #clean up previously fetched radar loop images - imagepath=xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile')) - for f in glob.glob(imagepath+"radar*.gif"): - os.remove(f) - - if ("true" == radarLoop): - #kodi will not loop gifs from a url, we have to actually - #download to a local file to get it to loop - - #xbmc.log('Option To Loop Radar Selected',level=xbmc.LOGDEBUG) - xbmc.log('Option To Loop Radar Selected',level=xbmc.LOGDEBUG) - url="https://radar.weather.gov/ridge/standard/%s_loop.gif" % (Station) - radarfilename="radar_%s_%s.gif" % (Station,nowtime) - dest=imagepath+radarfilename - loop_image=get_url_image(url, dest) - set_property('Map.%i.Area' % 1, loop_image) - else: - url="https://radar.weather.gov/ridge/standard/%s_0.gif?%s" % (Station,nowtime) - set_property('Map.%i.Area' % 1, url) - #clear_property('Map.%i.Area' % 1) - #set_property('Map.%i.Layer' % 1, url) - - clear_property('Map.%i.Layer' % 1) - set_property('Map.%i.Heading' % 1, LANGUAGE(32334)) - - - # add satellite maps if we configured any - for count in range (1, 5): - mcount=count+1 - mapsector = ADDON.getSetting('Map%iSector' % (mcount)) - maptype = ADDON.getSetting('Map%iType' % (mcount)) - maplabel = ADDON.getSetting('Map%iLabel' % (mcount)) - - if (mapsector and maptype): - - if ("LOOP" == maptype): - # want looping radar gifs - path=LOOPSECTORS.get(mapsector)['path'] - imagepath=xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile')) - url="https://radar.weather.gov/%s" % (path) - radarfilename="radar_%s_%s.gif" % (mapsector,nowtime) - dest=imagepath+radarfilename - loop_image=get_url_image(url, dest) - - set_property('Map.%i.Area' % (mcount), loop_image) - set_property('Map.%i.Heading' % (mcount), "%s" % (maplabel) ) - clear_property('Map.%i.Layer' % (mcount)) - else: - # want normal satellite images - path=MAPSECTORS.get(mapsector)['path'] - if mapsector != 'glm-e' and mapsector != 'glm-w': - path=path.replace("%s",maptype) - url="https://cdn.star.nesdis.noaa.gov/%s?%s" % (path,nowtime) - - set_property('Map.%i.Area' % (mcount), url) - set_property('Map.%i.Heading' % (mcount), "%s" % (maplabel) ) - clear_property('Map.%i.Layer' % (mcount)) - else: - clear_property('Map.%i.Area' % (mcount)) - clear_property('Map.%i.Heading' % (mcount)) - clear_property('Map.%i.Layer' % (mcount)) - else: - log('no location provided') - clear() + num=sys.argv[1] + LatLong = ADDON.getSetting('Location%sLatLong' % num) + + station=ADDON.getSetting('Location'+str(num)+'Station') + if station == '' : + log("calling location with %s" % (LatLong)) + get_Stations(str(num),LatLong) + + try: + lastPointsCheck=ADDON.getSetting('Location'+str(num)+'lastPointsCheck') + last_check=parse(lastPointsCheck) + current_datetime = datetime.datetime.now() + next_check=last_check+datetime.timedelta(days=2) + if (next_check < current_datetime): + get_Points(str(num),LatLong) + except: + get_Points(str(num),LatLong) + + refresh_locations() + + LatLong = ADDON.getSetting('Location%s' % num) + + if LatLong: + fetchWeatherAlerts(num) + if "forecast.weather.gov" == SOURCEPREF: + fetchAltDaily(num) + else: + fetchCurrent(num) + fetchDaily(num) + fetchHourly(num) + Station=ADDON.getSetting('Location%sradarStation' % num) + + set_property('Map.IsFetched', 'true') + #KODI will cache and not re-fetch the weather image, so inject a dummy time-stamp into the url to trick kodi because we want the new image + nowtime=str(time.time()) + #Radar + radarLoop=ADDON.getSetting('RadarLoop') + + #clean up previously fetched radar loop images + imagepath=xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile')) + for f in glob.glob(imagepath+"radar*.gif"): + os.remove(f) + + if ("true" == radarLoop): + #kodi will not loop gifs from a url, we have to actually + #download to a local file to get it to loop + + #xbmc.log('Option To Loop Radar Selected',level=xbmc.LOGDEBUG) + xbmc.log('Option To Loop Radar Selected',level=xbmc.LOGDEBUG) + url="https://radar.weather.gov/ridge/standard/%s_loop.gif" % (Station) + radarfilename="radar_%s_%s.gif" % (Station,nowtime) + dest=imagepath+radarfilename + loop_image=get_url_image(url, dest) + set_property('Map.%i.Area' % 1, loop_image) + else: + url="https://radar.weather.gov/ridge/standard/%s_0.gif?%s" % (Station,nowtime) + set_property('Map.%i.Area' % 1, url) + #clear_property('Map.%i.Area' % 1) + #set_property('Map.%i.Layer' % 1, url) + + clear_property('Map.%i.Layer' % 1) + set_property('Map.%i.Heading' % 1, LANGUAGE(32334)) + + + # add satellite maps if we configured any + for count in range (1, 5): + mcount=count+1 + mapsector = ADDON.getSetting('Map%iSector' % (mcount)) + maptype = ADDON.getSetting('Map%iType' % (mcount)) + maplabel = ADDON.getSetting('Map%iLabel' % (mcount)) + + if (mapsector and maptype): + + if ("LOOP" == maptype): + # want looping radar gifs + path=LOOPSECTORS.get(mapsector)['path'] + imagepath=xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile')) + url="https://radar.weather.gov/%s" % (path) + radarfilename="radar_%s_%s.gif" % (mapsector,nowtime) + dest=imagepath+radarfilename + loop_image=get_url_image(url, dest) + + set_property('Map.%i.Area' % (mcount), loop_image) + set_property('Map.%i.Heading' % (mcount), "%s" % (maplabel) ) + clear_property('Map.%i.Layer' % (mcount)) + else: + # want normal satellite images + path=MAPSECTORS.get(mapsector)['path'] + if mapsector != 'glm-e' and mapsector != 'glm-w': + path=path.replace("%s",maptype) + url="https://cdn.star.nesdis.noaa.gov/%s?%s" % (path,nowtime) + + set_property('Map.%i.Area' % (mcount), url) + set_property('Map.%i.Heading' % (mcount), "%s" % (maplabel) ) + clear_property('Map.%i.Layer' % (mcount)) + else: + clear_property('Map.%i.Area' % (mcount)) + clear_property('Map.%i.Heading' % (mcount)) + clear_property('Map.%i.Layer' % (mcount)) + else: + log('no location provided') + clear() # clean up references to classes that we used del MONITOR, xbmc, xbmcgui, xbmcvfs, xbmcaddon, WEATHER_WINDOW diff --git a/weather.noaa/resources/lib/utils.py b/weather.noaa/resources/lib/utils.py index 4eadd6dea..c939ef406 100644 --- a/weather.noaa/resources/lib/utils.py +++ b/weather.noaa/resources/lib/utils.py @@ -14,629 +14,682 @@ #standard_library.install_aliases() -ADDON = xbmcaddon.Addon() -ADDONID = ADDON.getAddonInfo('id') -LANGUAGE = ADDON.getLocalizedString +ADDON = xbmcaddon.Addon() +ADDONID = ADDON.getAddonInfo('id') +LANGUAGE = ADDON.getLocalizedString -DEBUG = ADDON.getSetting('Debug') -TEMPUNIT = xbmc.getRegion('tempunit') -SPEEDUNIT = xbmc.getRegion('speedunit') -DATEFORMAT = xbmc.getRegion('dateshort') -TIMEFORMAT = xbmc.getRegion('meridiem') +DEBUG = ADDON.getSetting('Debug') +TEMPUNIT = xbmc.getRegion('tempunit') +SPEEDUNIT = xbmc.getRegion('speedunit') +DATEFORMAT = xbmc.getRegion('dateshort') +TIMEFORMAT = xbmc.getRegion('meridiem') def log(txt): - if DEBUG == 'true': - message = u'%s: %s' % (ADDONID, txt) - xbmc.log(msg=message, level=xbmc.LOGDEBUG) + if DEBUG == 'true': + message = u'%s: %s' % (ADDONID, txt) + xbmc.log(msg=message, level=xbmc.LOGDEBUG) def get_url_JSON(url): - try: - xbmc.log('fetching url: %s' % url,level=xbmc.LOGDEBUG) - try: - timeout = 10 - socket.setdefaulttimeout(timeout) - # this call to urllib.request.urlopen now uses the default timeout - # we have set in the socket module - req = urllib.request.Request(url) - req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3') - response = urllib.request.urlopen(req) - - #responsedata = decode_utf8(urlopen(url, timeout=25).read()) - responsedata = response.read() - data = json.loads(responsedata) - log('data: %s' % data) - # Happy path, we found and parsed data - return data - except: - xbmc.log('failed to parse json: %s' % url,level=xbmc.LOGERROR) - xbmc.log('data: %s' % data,level=xbmc.LOGERROR) - except: - xbmc.log('failed to fetch : %s' % url,level=xbmc.LOGERROR) - return None + try: + xbmc.log('fetching url: %s' % url,level=xbmc.LOGDEBUG) + try: + timeout = 30 + socket.setdefaulttimeout(timeout) + # this call to urllib.request.urlopen now uses the default timeout + # we have set in the socket module + req = urllib.request.Request(url) + req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3') + try: + response = urllib.request.urlopen(req) + except: + time.sleep(60) + response = urllib.request.urlopen(req) + + responsedata = response.read() + data = json.loads(responsedata) + log('data: %s' % data) + # Happy path, we found and parsed data + return data + except: + xbmc.log('failed to parse json: %s' % url,level=xbmc.LOGERROR) + xbmc.log('data: %s' % data,level=xbmc.LOGERROR) + except: + xbmc.log('failed to fetch : %s' % url,level=xbmc.LOGERROR) + return None def get_url_response(url): - try: - xbmc.log('fetching url: %s' % url,level=xbmc.LOGDEBUG) - timeout = 10 - socket.setdefaulttimeout(timeout) - # this call to urllib.request.urlopen now uses the default timeout - # we have set in the socket module - req = urllib.request.Request(url) - req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3') - response = urllib.request.urlopen(req) - - responsedata = response.read() - log('data: %s' % responsedata) - # Happy path, we found and parsed data - return responsedata - except: - xbmc.log('failed to fetch : %s' % url,level=xbmc.LOGERROR) - return None + try: + xbmc.log('fetching url: %s' % url,level=xbmc.LOGDEBUG) + timeout = 30 + socket.setdefaulttimeout(timeout) + # this call to urllib.request.urlopen now uses the default timeout + # we have set in the socket module + req = urllib.request.Request(url) + req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3') + + try: + response = urllib.request.urlopen(req) + except: + time.sleep(60) + response = urllib.request.urlopen(req) + + responsedata = response.read() + log('data: %s' % responsedata) + # Happy path, we found and parsed data + return responsedata + except: + xbmc.log('failed to fetch : %s' % url,level=xbmc.LOGERROR) + return None def get_url_image(url,destination): - try: - urllib.request.urlretrieve(url, destination) - return destination - except: - xbmc.log('failed to fetch : %s' % url,level=xbmc.LOGERROR) - return None + try: + urllib.request.urlretrieve(url, destination) + return destination + except: + xbmc.log('failed to fetch : %s' % url,level=xbmc.LOGERROR) + return None WEATHER_CODES = { - 'day/skc': '32', #'Fair/clear' - 'day/few': '30', #'A few clouds' - 'day/sct': '30', #'Partly cloudy' - 'day/bkn': '28', #'Mostly cloudy' - 'day/ovc': '26', #'Overcast' - 'day/wind_skc': '24', #'Fair/clear and windy' - 'day/wind_few': '30', #'A few clouds and windy' - 'day/wind_sct': '30', #'Partly cloudy and windy' - 'day/wind_bkn': '28', #'Mostly cloudy and windy' - 'day/wind_ovc': '26', #'Overcast and windy' - 'day/snow': '16', #'Snow' - 'day/rain_snow': '5', #'Rain/snow' - 'day/rain_sleet': '6', #'Rain/sleet' - 'day/snow_sleet': '7', #'Snow/sleet' - 'day/fzra': '10', #'Freezing rain' - 'day/rain_fzra': '10', #'Rain/freezing rain' - 'day/snow_fzra': '10', #'Freezing rain/snow' - 'day/sleet': '18', #'Sleet' - 'day/rain': '40', #'Rain' - 'day/rain_showers': '11', #'Rain showers (high cloud cover)' - 'day/rain_showers_hi': '12', #'Rain showers (low cloud cover)' - 'day/tsra': '37', #'Thunderstorm (high cloud cover)' - 'day/tsra_sct': '38', #'Thunderstorm (medium cloud cover)' - 'day/tsra_hi': '39', #'Thunderstorm (low cloud cover)' - 'day/tornado': '0', #'Tornado' - 'day/hurricane': '2', #'Hurricane conditions' - 'day/tropical_storm': '1', #'Tropical storm conditions' - 'day/dust': '19', #'Dust' - 'day/smoke': '22', #'Smoke' - 'day/haze': '21', #'Haze' - 'day/hot': '36', #'Hot' - 'day/cold': '25', #'Cold' - 'day/blizzard': '15', #'Blizzard' - 'day/fog': '20', #'Fog/mist' - - - 'night/skc': '31', #'Fair/clear' - 'night/few': '29', #'A few clouds' - 'night/sct': '29', #'Partly cloudy' - 'night/bkn': '27', #'Mostly cloudy' - 'night/ovc': '26', #'Overcast' - 'night/wind_skc': '24', #'Fair/clear and windy' - 'night/wind_few': '29', #'A few clouds and windy' - 'night/wind_sct': '29', #'Partly cloudy and windy' - 'night/wind_bkn': '27', #'Mostly cloudy and windy' - 'night/wind_ovc': '26', #'Overcast and windy' - 'night/snow': '16', #'Snow' - 'night/rain_snow': '5', #'Rain/snow' - 'night/rain_sleet': '6', #'Rain/sleet' - 'night/snow_sleet': '7', #'Rain/sleet' - 'night/fzra': '10', #'Freezing rain' - 'night/rain_fzra': '10', #'Rain/freezing rain' - 'night/snow_fzra': '10', #'Freezing rain/snow' - 'night/sleet': '18', #'Sleet' - 'night/rain': '40', #'Rain' - 'night/rain_showers': '11', #'Rain showers (high cloud cover)' - 'night/rain_showers_hi':'12', #'Rain showers (low cloud cover)' - 'night/tsra': '37', #'Thunderstorm (high cloud cover)' - 'night/tsra_sct': '38', #'Thunderstorm (medium cloud cover)' - 'night/tsra_hi': '39', #'Thunderstorm (low cloud cover)' - 'night/tornado': '0', #'Tornado' - 'night/hurricane': '2', #'Hurricane conditions' - 'night/tropical_storm': '1', #'Tropical storm conditions' - 'night/dust': '19', #'Dust' - 'night/smoke': '22', #'Smoke' - 'night/haze': '21', #'Haze' - 'night/hot': '36', #'Hot' - 'night/cold': '25', #'Cold' - 'night/blizzard': '15', #'Blizzard' - 'night/fog': '20', #'Fog/mist' - - '': 'na' - } + 'day/skc': '32', #'Fair/clear' + 'day/few': '30', #'A few clouds' + 'day/sct': '30', #'Partly cloudy' + 'day/bkn': '28', #'Mostly cloudy' + 'day/ovc': '26', #'Overcast' + 'day/wind_skc': '24', #'Fair/clear and windy' + 'day/wind_few': '30', #'A few clouds and windy' + 'day/wind_sct': '30', #'Partly cloudy and windy' + 'day/wind_bkn': '28', #'Mostly cloudy and windy' + 'day/wind_ovc': '26', #'Overcast and windy' + 'day/snow': '16', #'Snow' + 'day/rain_snow': '5', #'Rain/snow' + 'day/rain_sleet': '6', #'Rain/sleet' + 'day/snow_sleet': '7', #'Snow/sleet' + 'day/fzra': '10', #'Freezing rain' + 'day/rain_fzra': '10', #'Rain/freezing rain' + 'day/snow_fzra': '10', #'Freezing rain/snow' + 'day/sleet': '18', #'Sleet' + 'day/rain': '40', #'Rain' + 'day/rain_showers': '11', #'Rain showers (high cloud cover)' + 'day/rain_showers_hi': '12', #'Rain showers (low cloud cover)' + 'day/tsra': '37', #'Thunderstorm (high cloud cover)' + 'day/tsra_sct': '38', #'Thunderstorm (medium cloud cover)' + 'day/tsra_hi': '39', #'Thunderstorm (low cloud cover)' + 'day/tornado': '0', #'Tornado' + 'day/hurricane': '2', #'Hurricane conditions' + 'day/tropical_storm': '1', #'Tropical storm conditions' + 'day/dust': '19', #'Dust' + 'day/smoke': '22', #'Smoke' + 'day/haze': '21', #'Haze' + 'day/hot': '36', #'Hot' + 'day/cold': '25', #'Cold' + 'day/blizzard': '15', #'Blizzard' + 'day/fog': '20', #'Fog/mist' + + + 'night/skc': '31', #'Fair/clear' + 'night/few': '29', #'A few clouds' + 'night/sct': '29', #'Partly cloudy' + 'night/bkn': '27', #'Mostly cloudy' + 'night/ovc': '26', #'Overcast' + 'night/wind_skc': '24', #'Fair/clear and windy' + 'night/wind_few': '29', #'A few clouds and windy' + 'night/wind_sct': '29', #'Partly cloudy and windy' + 'night/wind_bkn': '27', #'Mostly cloudy and windy' + 'night/wind_ovc': '26', #'Overcast and windy' + 'night/snow': '16', #'Snow' + 'night/rain_snow': '5', #'Rain/snow' + 'night/rain_sleet': '6', #'Rain/sleet' + 'night/snow_sleet': '7', #'Rain/sleet' + 'night/fzra': '10', #'Freezing rain' + 'night/rain_fzra': '10', #'Rain/freezing rain' + 'night/snow_fzra': '10', #'Freezing rain/snow' + 'night/sleet': '18', #'Sleet' + 'night/rain': '40', #'Rain' + 'night/rain_showers': '11', #'Rain showers (high cloud cover)' + 'night/rain_showers_hi':'12', #'Rain showers (low cloud cover)' + 'night/tsra': '37', #'Thunderstorm (high cloud cover)' + 'night/tsra_sct': '38', #'Thunderstorm (medium cloud cover)' + 'night/tsra_hi': '39', #'Thunderstorm (low cloud cover)' + 'night/tornado': '0', #'Tornado' + 'night/hurricane': '2', #'Hurricane conditions' + 'night/tropical_storm': '1', #'Tropical storm conditions' + 'night/dust': '19', #'Dust' + 'night/smoke': '22', #'Smoke' + 'night/haze': '21', #'Haze' + 'night/hot': '36', #'Hot' + 'night/cold': '25', #'Cold' + 'night/blizzard': '15', #'Blizzard' + 'night/fog': '20', #'Fog/mist' + + # special hanlding of forecast.weather.com url patterns that use "nxyz" pattersn for night + 'day/nskc': '31', #'Fair/clear' + 'day/nfew': '29', #'A few clouds' + 'day/nsct': '29', #'Partly cloudy' + 'day/nbkn': '27', #'Mostly cloudy' + 'day/novc': '26', #'Overcast' + 'day/nwind_skc': '24', #'Fair/clear and windy' + 'day/nwind_few': '29', #'A few clouds and windy' + 'day/nwind_sct': '29', #'Partly cloudy and windy' + 'day/nwind_bkn': '27', #'Mostly cloudy and windy' + 'day/nwind_ovc': '26', #'Overcast and windy' + 'day/nsnow': '16', #'Snow' + 'day/nrain_snow': '5', #'Rain/snow' + 'day/nrain_sleet': '6', #'Rain/sleet' + 'day/nsnow_sleet': '7', #'Rain/sleet' + 'day/nfzra': '10', #'Freezing rain' + 'day/nrain_fzra': '10', #'Rain/freezing rain' + 'day/nsnow_fzra': '10', #'Freezing rain/snow' + 'day/nsleet': '18', #'Sleet' + 'day/nrain': '40', #'Rain' + 'day/nrain_showers': '11', #'Rain showers (high cloud cover)' + 'day/nrain_showers_hi':'12', #'Rain showers (low cloud cover)' + 'day/ntsra': '37', #'Thunderstorm (high cloud cover)' + 'day/ntsra_sct': '38', #'Thunderstorm (medium cloud cover)' + 'day/ntsra_hi': '39', #'Thunderstorm (low cloud cover)' + 'day/ntornado': '0', #'Tornado' + 'day/nhurricane': '2', #'Hurricane conditions' + 'day/ntropical_storm': '1', #'Tropical storm conditions' + 'day/ndust': '19', #'Dust' + 'day/nsmoke': '22', #'Smoke' + 'day/nhaze': '21', #'Haze' + 'day/nhot': '36', #'Hot' + 'day/ncold': '25', #'Cold' + 'day/nblizzard': '15', #'Blizzard' + 'day/nfog': '20', #'Fog/mist' + + + + + + '': 'na' + } MONTH_NAME_LONG = { '01' : 21, - '02' : 22, - '03' : 23, - '04' : 24, - '05' : 25, - '06' : 26, - '07' : 27, - '08' : 28, - '09' : 29, - '10' : 30, - '11' : 31, - '12' : 32 - } + '02' : 22, + '03' : 23, + '04' : 24, + '05' : 25, + '06' : 26, + '07' : 27, + '08' : 28, + '09' : 29, + '10' : 30, + '11' : 31, + '12' : 32 + } MONTH_NAME_SHORT = { '01' : 51, - '02' : 52, - '03' : 53, - '04' : 54, - '05' : 55, - '06' : 56, - '07' : 57, - '08' : 58, - '09' : 59, - '10' : 60, - '11' : 61, - '12' : 62 - } + '02' : 52, + '03' : 53, + '04' : 54, + '05' : 55, + '06' : 56, + '07' : 57, + '08' : 58, + '09' : 59, + '10' : 60, + '11' : 61, + '12' : 62 + } WEEK_DAY_LONG = { '0' : 17, - '1' : 11, - '2' : 12, - '3' : 13, - '4' : 14, - '5' : 15, - '6' : 16 - } + '1' : 11, + '2' : 12, + '3' : 13, + '4' : 14, + '5' : 15, + '6' : 16 + } WEEK_DAY_SHORT = { '0' : 47, - '1' : 41, - '2' : 42, - '3' : 43, - '4' : 44, - '5' : 45, - '6' : 46 - } + '1' : 41, + '2' : 42, + '3' : 43, + '4' : 44, + '5' : 45, + '6' : 46 + } FORECAST = { 'thunderstorm with light rain': LANGUAGE(32201), - 'thunderstorm with rain': LANGUAGE(32202), - 'thunderstorm with heavy rain': LANGUAGE(32203), - 'light thunderstorm': LANGUAGE(32204), - 'thunderstorm': LANGUAGE(32205), - 'heavy thunderstorm': LANGUAGE(32206), - 'ragged thunderstorm': LANGUAGE(32207), - 'thunderstorm with light drizzle': LANGUAGE(32208), - 'thunderstorm with drizzle': LANGUAGE(32209), - 'thunderstorm with heavy drizzle': LANGUAGE(32210), - 'light intensity drizzle': LANGUAGE(32211), - 'drizzle': LANGUAGE(32212), - 'heavy intensity drizzle': LANGUAGE(32213), - 'light intensity drizzle rain': LANGUAGE(32214), - 'drizzle rain': LANGUAGE(32215), - 'heavy intensity drizzle rain': LANGUAGE(32216), - 'shower rain And drizzle': LANGUAGE(32217), - 'heavy shower rain and drizzle': LANGUAGE(32218), - 'shower drizzle': LANGUAGE(32219), - 'light rain': LANGUAGE(32220), - 'moderate rain': LANGUAGE(32221), - 'heavy intensity rain': LANGUAGE(32222), - 'very heavy rain': LANGUAGE(32223), - 'extreme rain': LANGUAGE(32224), - 'freezing rain': LANGUAGE(32225), - 'light intensity shower rain': LANGUAGE(32226), - 'shower rain': LANGUAGE(32227), - 'heavy intensity shower rain': LANGUAGE(32228), - 'ragged shower rain': LANGUAGE(32229), - 'light snow': LANGUAGE(32230), - 'snow': LANGUAGE(32231), - 'heavy snow': LANGUAGE(32232), - 'sleet': LANGUAGE(32233), - 'shower sleet': LANGUAGE(32234), - 'light rain and snow': LANGUAGE(32235), - 'rain and snow': LANGUAGE(32236), - 'light shower snow': LANGUAGE(32237), - 'shower snow': LANGUAGE(32238), - 'heavy shower snow': LANGUAGE(32239), - 'mist': LANGUAGE(32240), - 'smoke': LANGUAGE(32241), - 'haze': LANGUAGE(32242), - 'sand, dust whirls': LANGUAGE(32243), - 'fog': LANGUAGE(32244), - 'sand': LANGUAGE(32245), - 'dust': LANGUAGE(32246), - 'volcanic ash': LANGUAGE(32247), - 'squalls': LANGUAGE(32248), - 'tornado': LANGUAGE(32249), - 'clear sky': LANGUAGE(32250), - 'few clouds': LANGUAGE(32251), - 'scattered clouds': LANGUAGE(32252), - 'broken clouds': LANGUAGE(32253), - 'overcast clouds': LANGUAGE(32254), - 'tornado': LANGUAGE(32255), - 'tropical storm': LANGUAGE(32256), - 'hurricane': LANGUAGE(32257), - 'cold': LANGUAGE(32258), - 'hot': LANGUAGE(32259), - 'windy': LANGUAGE(32260), - 'hail': LANGUAGE(32261), - 'calm': LANGUAGE(32262), - 'light breeze': LANGUAGE(32263), - 'gentle breeze': LANGUAGE(32264), - 'moderate breeze': LANGUAGE(32265), - 'fresh breeze': LANGUAGE(32266), - 'strong breeze': LANGUAGE(32267), - 'high wind, near gale': LANGUAGE(32268), - 'gale': LANGUAGE(32269), - 'severe gale': LANGUAGE(32270), - 'storm': LANGUAGE(32271), - 'violent storm': LANGUAGE(32272), - 'hurricane': LANGUAGE(32273), - 'clear': LANGUAGE(32274), - 'clouds': LANGUAGE(32275), - 'rain': LANGUAGE(32276) - } + 'thunderstorm with rain': LANGUAGE(32202), + 'thunderstorm with heavy rain': LANGUAGE(32203), + 'light thunderstorm': LANGUAGE(32204), + 'thunderstorm': LANGUAGE(32205), + 'heavy thunderstorm': LANGUAGE(32206), + 'ragged thunderstorm': LANGUAGE(32207), + 'thunderstorm with light drizzle': LANGUAGE(32208), + 'thunderstorm with drizzle': LANGUAGE(32209), + 'thunderstorm with heavy drizzle': LANGUAGE(32210), + 'light intensity drizzle': LANGUAGE(32211), + 'drizzle': LANGUAGE(32212), + 'heavy intensity drizzle': LANGUAGE(32213), + 'light intensity drizzle rain': LANGUAGE(32214), + 'drizzle rain': LANGUAGE(32215), + 'heavy intensity drizzle rain': LANGUAGE(32216), + 'shower rain And drizzle': LANGUAGE(32217), + 'heavy shower rain and drizzle': LANGUAGE(32218), + 'shower drizzle': LANGUAGE(32219), + 'light rain': LANGUAGE(32220), + 'moderate rain': LANGUAGE(32221), + 'heavy intensity rain': LANGUAGE(32222), + 'very heavy rain': LANGUAGE(32223), + 'extreme rain': LANGUAGE(32224), + 'freezing rain': LANGUAGE(32225), + 'light intensity shower rain': LANGUAGE(32226), + 'shower rain': LANGUAGE(32227), + 'heavy intensity shower rain': LANGUAGE(32228), + 'ragged shower rain': LANGUAGE(32229), + 'light snow': LANGUAGE(32230), + 'snow': LANGUAGE(32231), + 'heavy snow': LANGUAGE(32232), + 'sleet': LANGUAGE(32233), + 'shower sleet': LANGUAGE(32234), + 'light rain and snow': LANGUAGE(32235), + 'rain and snow': LANGUAGE(32236), + 'light shower snow': LANGUAGE(32237), + 'shower snow': LANGUAGE(32238), + 'heavy shower snow': LANGUAGE(32239), + 'mist': LANGUAGE(32240), + 'smoke': LANGUAGE(32241), + 'haze': LANGUAGE(32242), + 'sand, dust whirls': LANGUAGE(32243), + 'fog': LANGUAGE(32244), + 'sand': LANGUAGE(32245), + 'dust': LANGUAGE(32246), + 'volcanic ash': LANGUAGE(32247), + 'squalls': LANGUAGE(32248), + 'tornado': LANGUAGE(32249), + 'clear sky': LANGUAGE(32250), + 'few clouds': LANGUAGE(32251), + 'scattered clouds': LANGUAGE(32252), + 'broken clouds': LANGUAGE(32253), + 'overcast clouds': LANGUAGE(32254), + 'tornado': LANGUAGE(32255), + 'tropical storm': LANGUAGE(32256), + 'hurricane': LANGUAGE(32257), + 'cold': LANGUAGE(32258), + 'hot': LANGUAGE(32259), + 'windy': LANGUAGE(32260), + 'hail': LANGUAGE(32261), + 'calm': LANGUAGE(32262), + 'light breeze': LANGUAGE(32263), + 'gentle breeze': LANGUAGE(32264), + 'moderate breeze': LANGUAGE(32265), + 'fresh breeze': LANGUAGE(32266), + 'strong breeze': LANGUAGE(32267), + 'high wind, near gale': LANGUAGE(32268), + 'gale': LANGUAGE(32269), + 'severe gale': LANGUAGE(32270), + 'storm': LANGUAGE(32271), + 'violent storm': LANGUAGE(32272), + 'hurricane': LANGUAGE(32273), + 'clear': LANGUAGE(32274), + 'clouds': LANGUAGE(32275), + 'rain': LANGUAGE(32276) + } def SPEED(mps): - try: - val = float(mps) - except: - return '' - - if SPEEDUNIT == 'km/h': - speed = mps * 3.6 - elif SPEEDUNIT == 'm/min': - speed = mps * 60 - elif SPEEDUNIT == 'ft/h': - speed = mps * 11810.88 - elif SPEEDUNIT == 'ft/min': - speed = mps * 196.84 - elif SPEEDUNIT == 'ft/s': - speed = mps * 3.281 - elif SPEEDUNIT == 'mph': - speed = mps * 2.237 - elif SPEEDUNIT == 'knots': - speed = mps * 1.944 - elif SPEEDUNIT == 'Beaufort': - speed = KPHTOBFT(mps* 3.6) - elif SPEEDUNIT == 'inch/s': - speed = mps * 39.37 - elif SPEEDUNIT == 'yard/s': - speed = mps * 1.094 - elif SPEEDUNIT == 'Furlong/Fortnight': - speed = mps * 6012.886 - else: - speed = mps - return str(int(round(speed))) + try: + val = float(mps) + except: + return '' + + if SPEEDUNIT == 'km/h': + speed = mps * 3.6 + elif SPEEDUNIT == 'm/min': + speed = mps * 60 + elif SPEEDUNIT == 'ft/h': + speed = mps * 11810.88 + elif SPEEDUNIT == 'ft/min': + speed = mps * 196.84 + elif SPEEDUNIT == 'ft/s': + speed = mps * 3.281 + elif SPEEDUNIT == 'mph': + speed = mps * 2.237 + elif SPEEDUNIT == 'knots': + speed = mps * 1.944 + elif SPEEDUNIT == 'Beaufort': + speed = KPHTOBFT(mps* 3.6) + elif SPEEDUNIT == 'inch/s': + speed = mps * 39.37 + elif SPEEDUNIT == 'yard/s': + speed = mps * 1.094 + elif SPEEDUNIT == 'Furlong/Fortnight': + speed = mps * 6012.886 + else: + speed = mps + return str(int(round(speed))) def FtoC(Fahrenheit): - try: - Celsius = (float(Fahrenheit) - 32.0) * 5.0/9.0 - return str(int(round(Celsius))) - except: - return - + try: + Celsius = (float(Fahrenheit) - 32.0) * 5.0/9.0 + return str(int(round(Celsius))) + except: + return + def CtoF(Celsius): - try: - Fahrenheit = (float(Celsius) * 9.0/5.0) + 32.0 - return str(int(round(Fahrenheit))) - except: - return + try: + Fahrenheit = (float(Celsius) * 9.0/5.0) + 32.0 + return str(int(round(Fahrenheit))) + except: + return def TEMP(deg): - if TEMPUNIT == u'\N{DEGREE SIGN}'+'F': - temp = deg * 1.8 + 32 - elif TEMPUNIT == u'K': - temp = deg + 273.15 - elif TEMPUNIT == u'°Ré': - temp = deg * 0.8 - elif TEMPUNIT == u'°Ra': - temp = deg * 1.8 + 491.67 - elif TEMPUNIT == u'°Rø': - temp = deg * 0.525 + 7.5 - elif TEMPUNIT == u'°D': - temp = deg / -0.667 + 150 - elif TEMPUNIT == u'°N': - temp = deg * 0.33 - else: - temp = deg - return str(int(round(temp))) + if TEMPUNIT == u'\N{DEGREE SIGN}'+'F': + temp = deg * 1.8 + 32 + elif TEMPUNIT == u'K': + temp = deg + 273.15 + elif TEMPUNIT == u'°Ré': + temp = deg * 0.8 + elif TEMPUNIT == u'°Ra': + temp = deg * 1.8 + 491.67 + elif TEMPUNIT == u'°Rø': + temp = deg * 0.525 + 7.5 + elif TEMPUNIT == u'°D': + temp = deg / -0.667 + 150 + elif TEMPUNIT == u'°N': + temp = deg * 0.33 + else: + temp = deg + return str(int(round(temp))) def WIND_DIR(deg): - if deg >= 349 or deg <= 11: - return 71 - elif deg >= 12 and deg <= 33: - return 72 - elif deg >= 34 and deg <= 56: - return 73 - elif deg >= 57 and deg <= 78: - return 74 - elif deg >= 79 and deg <= 101: - return 75 - elif deg >= 102 and deg <= 123: - return 76 - elif deg >= 124 and deg <= 146: - return 77 - elif deg >= 147 and deg <= 168: - return 78 - elif deg >= 169 and deg <= 191: - return 79 - elif deg >= 192 and deg <= 213: - return 80 - elif deg >= 214 and deg <= 236: - return 81 - elif deg >= 237 and deg <= 258: - return 82 - elif deg >= 259 and deg <= 281: - return 83 - elif deg >= 282 and deg <= 303: - return 84 - elif deg >= 304 and deg <= 326: - return 85 - elif deg >= 327 and deg <= 348: - return 86 + if deg >= 349 or deg <= 11: + return 71 + elif deg >= 12 and deg <= 33: + return 72 + elif deg >= 34 and deg <= 56: + return 73 + elif deg >= 57 and deg <= 78: + return 74 + elif deg >= 79 and deg <= 101: + return 75 + elif deg >= 102 and deg <= 123: + return 76 + elif deg >= 124 and deg <= 146: + return 77 + elif deg >= 147 and deg <= 168: + return 78 + elif deg >= 169 and deg <= 191: + return 79 + elif deg >= 192 and deg <= 213: + return 80 + elif deg >= 214 and deg <= 236: + return 81 + elif deg >= 237 and deg <= 258: + return 82 + elif deg >= 259 and deg <= 281: + return 83 + elif deg >= 282 and deg <= 303: + return 84 + elif deg >= 304 and deg <= 326: + return 85 + elif deg >= 327 and deg <= 348: + return 86 def KPHTOBFT(spd): - if (spd < 1.0): - bft = '0' - elif (spd >= 1.0) and (spd < 5.6): - bft = '1' - elif (spd >= 5.6) and (spd < 12.0): - bft = '2' - elif (spd >= 12.0) and (spd < 20.0): - bft = '3' - elif (spd >= 20.0) and (spd < 29.0): - bft = '4' - elif (spd >= 29.0) and (spd < 39.0): - bft = '5' - elif (spd >= 39.0) and (spd < 50.0): - bft = '6' - elif (spd >= 50.0) and (spd < 62.0): - bft = '7' - elif (spd >= 62.0) and (spd < 75.0): - bft = '8' - elif (spd >= 75.0) and (spd < 89.0): - bft = '9' - elif (spd >= 89.0) and (spd < 103.0): - bft = '10' - elif (spd >= 103.0) and (spd < 118.0): - bft = '11' - elif (spd >= 118.0): - bft = '12' - else: - bft = '' - return bft + if (spd < 1.0): + bft = '0' + elif (spd >= 1.0) and (spd < 5.6): + bft = '1' + elif (spd >= 5.6) and (spd < 12.0): + bft = '2' + elif (spd >= 12.0) and (spd < 20.0): + bft = '3' + elif (spd >= 20.0) and (spd < 29.0): + bft = '4' + elif (spd >= 29.0) and (spd < 39.0): + bft = '5' + elif (spd >= 39.0) and (spd < 50.0): + bft = '6' + elif (spd >= 50.0) and (spd < 62.0): + bft = '7' + elif (spd >= 62.0) and (spd < 75.0): + bft = '8' + elif (spd >= 75.0) and (spd < 89.0): + bft = '9' + elif (spd >= 89.0) and (spd < 103.0): + bft = '10' + elif (spd >= 103.0) and (spd < 118.0): + bft = '11' + elif (spd >= 118.0): + bft = '12' + else: + bft = '' + return bft def FEELS_LIKE(Ts, Vs=0, Rs=0, ext=True): - T=float(Ts) - V=float(Vs) - R=float(Rs) - - if T <= 10.0 and V >= 8.0: - FeelsLike = WIND_CHILL(T, V) - elif T >= 26.0: - FeelsLike = HEAT_INDEX(T, R) - else: - FeelsLike = T - if ext: - return TEMP( FeelsLike ) - else: - return str(int(round(FeelsLike))) + T=float(Ts) + V=float(Vs) + R=float(Rs) + + if T <= 10.0 and V >= 8.0: + FeelsLike = WIND_CHILL(T, V) + elif T >= 26.0: + FeelsLike = HEAT_INDEX(T, R) + else: + FeelsLike = T + if ext: + return TEMP( FeelsLike ) + else: + return str(int(round(FeelsLike))) -#### thanks to FrostBox @ http://forum.kodi.tv/showthread.php?tid=114637&pid=937168#pid937168 def WIND_CHILL(Ts, Vs): - T=float(Ts) - V=float(Vs) - - FeelsLike = ( 13.12 + ( 0.6215 * T ) - ( 11.37 * V**0.16 ) + ( 0.3965 * T * V**0.16 ) ) - return FeelsLike + T=float(Ts) + V=float(Vs) + FeelsLike= 13.12 + (0.6215 * T) - (11.37 * (V**0.16)) + (0.3965 * (V**0.16)) + return FeelsLike + + #Tf=(float(Ts) * 9.0/5.0) + 32.0 + #Vm=(float(Vs) * 0.6213711922 ) + #Ff=35.74 + ( 0.6215 * Tf ) - 35.75 (Vm**0.16) + 0.4275 Tf (Vm**0.16) + #return FtoC(FeelsLike) + + ### https://en.wikipedia.org/wiki/Heat_index def HEAT_INDEX(Ts, Rs): - T=float(Ts) - R=float(Rs) - T = T * 1.8 + 32.0 # calaculation is done in F - FeelsLike = -42.379 + (2.04901523 * T) + (10.14333127 * R) + (-0.22475541 * T * R) + (-0.00683783 * T**2) + (-0.05481717 * R**2) + (0.00122874 * T**2 * R) + (0.00085282 * T * R**2) + (-0.00000199 * T**2 * R**2) - FeelsLike = (FeelsLike - 32.0) / 1.8 # convert to C - return FeelsLike + T=float(Ts) + R=float(Rs) + T = T * 1.8 + 32.0 # calaculation is done in F + FeelsLike = -42.379 + (2.04901523 * T) + (10.14333127 * R) + (-0.22475541 * T * R) + (-0.00683783 * T**2) + (-0.05481717 * R**2) + (0.00122874 * T**2 * R) + (0.00085282 * T * R**2) + (-0.00000199 * T**2 * R**2) + FeelsLike = (FeelsLike - 32.0) / 1.8 # convert to C + return FeelsLike #### thanks to FrostBox @ http://forum.kodi.tv/showthread.php?tid=114637&pid=937168#pid937168 def DEW_POINT(Tc=0, RH=93.0, ext=True, minRH=( 0, 0.075 )[ 0 ]): - Es = 6.11 * 10.0**( 7.5 * Tc / ( 237.7 + Tc ) ) - RH = RH or minRH - E = ( RH * Es ) / 100 - try: - DewPoint = ( -430.22 + 237.7 * math.log( E ) ) / ( -math.log( E ) + 19.08 ) - except ValueError: - DewPoint = 0 - if ext: - return TEMP( DewPoint ) - else: - return str(int(round(DewPoint))) + Es = 6.11 * 10.0**( 7.5 * Tc / ( 237.7 + Tc ) ) + RH = RH or minRH + E = ( RH * Es ) / 100 + try: + DewPoint = ( -430.22 + 237.7 * math.log( E ) ) / ( -math.log( E ) + 19.08 ) + except ValueError: + DewPoint = 0 + if ext: + return TEMP( DewPoint ) + else: + return str(int(round(DewPoint))) ## a couple functions from itertools def repeat_x(object_x, times=None): - # repeat(10, 3) --> 10 10 10 - if times is None: - while True: - yield object_x - else: - for i in range(times): - yield object_x + # repeat(10, 3) --> 10 10 10 + if times is None: + while True: + yield object_x + else: + for i in range(times): + yield object_x def zip_x(fill, *args): - # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- - iterators = [iter(it) for it in args] - num_active = len(iterators) - if not num_active: - return - while True: - values = [] - for i, it in enumerate(iterators): - try: - value = next(it) - except StopIteration: - num_active -= 1 - if not num_active: - return - iterators[i] = repeat_x(fill) - value = fill - values.append(value) - yield tuple(values) + # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- + iterators = [iter(it) for it in args] + num_active = len(iterators) + if not num_active: + return + while True: + values = [] + for i, it in enumerate(iterators): + try: + value = next(it) + except StopIteration: + num_active -= 1 + if not num_active: + return + iterators[i] = repeat_x(fill) + value = fill + values.append(value) + yield tuple(values) def get_timestamp(datestr): - #"2019-04-29T16:00:00-04:00" - #iso_fmt = '%Y-%m-%dT%H:%M:%S%z' - datestamp=parse(datestr) - return time.mktime(datestamp.timetuple()) + #"2019-04-29T16:00:00-04:00" + #iso_fmt = '%Y-%m-%dT%H:%M:%S%z' + datestamp=parse(datestr) + return time.mktime(datestamp.timetuple()) def convert_date(stamp): - if str(stamp).startswith('-'): - return '' - date_time = time.localtime(stamp) - if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': - localdate = time.strftime('%d-%m-%Y', date_time) - elif DATEFORMAT[1] == 'm' or DATEFORMAT[0] == 'M': - localdate = time.strftime('%m-%d-%Y', date_time) - else: - localdate = time.strftime('%Y-%m-%d', date_time) - - if TIMEFORMAT != '/': - localtime = time.strftime('%I:%M%p', date_time) - else: - localtime = time.strftime('%H:%M', date_time) - return localtime + ' ' + localdate + if str(stamp).startswith('-'): + return '' + date_time = time.localtime(stamp) + if DATEFORMAT[1] == 'd' or DATEFORMAT[0] == 'D': + localdate = time.strftime('%d-%m-%Y', date_time) + elif DATEFORMAT[1] == 'm' or DATEFORMAT[0] == 'M': + localdate = time.strftime('%m-%d-%Y', date_time) + else: + localdate = time.strftime('%Y-%m-%d', date_time) + + if TIMEFORMAT != '/': + localtime = time.strftime('%I:%M%p', date_time) + else: + localtime = time.strftime('%H:%M', date_time) + return localtime + ' ' + localdate def get_time(stamp): - date_time = time.localtime(stamp) - if TIMEFORMAT != '/': - localtime = time.strftime('%I:%M%p', date_time) - else: - localtime = time.strftime('%H:%M', date_time) - return localtime + date_time = time.localtime(stamp) + if TIMEFORMAT != '/': + localtime = time.strftime('%I:%M%p', date_time) + else: + localtime = time.strftime('%H:%M', date_time) + return localtime def get_weekday(stamp, form): - date_time = time.localtime(stamp) - weekday = time.strftime('%w', date_time) - if form == 's': - return xbmc.getLocalizedString(WEEK_DAY_SHORT[weekday]) - elif form == 'l': - return xbmc.getLocalizedString(WEEK_DAY_LONG[weekday]) - else: - return int(weekday) + date_time = time.localtime(stamp) + weekday = time.strftime('%w', date_time) + if form == 's': + return xbmc.getLocalizedString(WEEK_DAY_SHORT[weekday]) + elif form == 'l': + return xbmc.getLocalizedString(WEEK_DAY_LONG[weekday]) + else: + return int(weekday) def get_month(stamp, form): - date_time = time.localtime(stamp) - month = time.strftime('%m', date_time) - day = time.strftime('%d', date_time) - if form == 'ds': - label = day + ' ' + xbmc.getLocalizedString(MONTH_NAME_SHORT[month]) - elif form == 'dl': - label = day + ' ' + xbmc.getLocalizedString(MONTH_NAME_LONG[month]) - elif form == 'ms': - label = xbmc.getLocalizedString(MONTH_NAME_SHORT[month]) + ' ' + day - elif form == 'ml': - label = xbmc.getLocalizedString(MONTH_NAME_LONG[month]) + ' ' + day - return label + date_time = time.localtime(stamp) + month = time.strftime('%m', date_time) + day = time.strftime('%d', date_time) + if form == 'ds': + label = day + ' ' + xbmc.getLocalizedString(MONTH_NAME_SHORT[month]) + elif form == 'dl': + label = day + ' ' + xbmc.getLocalizedString(MONTH_NAME_LONG[month]) + elif form == 'ms': + label = xbmc.getLocalizedString(MONTH_NAME_SHORT[month]) + ' ' + day + elif form == 'ml': + label = xbmc.getLocalizedString(MONTH_NAME_LONG[month]) + ' ' + day + return label # Satellite Imagery paths MAPSECTORS = { - "conus-e": {"name":LANGUAGE(32360),"path":"GOES16/ABI/CONUS/%s/1250x750.jpg"}, - "conus-w": {"name":LANGUAGE(32361),"path":"GOES17/ABI/CONUS/%s/1250x750.jpg"}, - "glm-e": {"name":LANGUAGE(32362),"path":"GOES16/GLM/CONUS/EXTENT/1250x750.jpg"}, - "glm-w": {"name":LANGUAGE(32363),"path":"GOES17/GLM/CONUS/EXTENT/1250x750.jpg"}, - "ak": {"name":LANGUAGE(32364),"path":"GOES17/ABI/SECTOR/ak/%s/1000x1000.jpg"}, - "cak": {"name":LANGUAGE(32365),"path":"GOES17/ABI/SECTOR/cak/%s/1200x1200.jpg"}, - "sea": {"name":LANGUAGE(32366),"path":"GOES17/ABI/SECTOR/sea/%s/1200x1200.jpg"}, - "np": {"name":LANGUAGE(32367),"path":"GOES17/ABI/SECTOR/np/%s/900x540.jpg"}, - "wus": {"name":LANGUAGE(32368),"path":"GOES17/ABI/SECTOR/wus/%s/1000x1000.jpg"}, - "pnw-w": {"name":LANGUAGE(32369),"path":"GOES17/ABI/SECTOR/pnw/%s/1200x1200.jpg"}, - "pnw-e": {"name":LANGUAGE(32370),"path":"GOES16/ABI/SECTOR/pnw/%s/1200x1200.jpg"}, - "psw-w": {"name":LANGUAGE(32371),"path":"GOES17/ABI/SECTOR/psw/%s/1200x1200.jpg"}, - "psw-e": {"name":LANGUAGE(32371),"path":"GOES16/ABI/SECTOR/psw/%s/1200x1200.jpg"}, - "nr": {"name":LANGUAGE(32373),"path":"GOES16/ABI/SECTOR/nr/%s/1200x1200.jpg"}, - "sr": {"name":LANGUAGE(32374),"path":"GOES16/ABI/SECTOR/sr/%s/1200x1200.jpg"}, - "sp": {"name":LANGUAGE(32375),"path":"GOES16/ABI/SECTOR/sp/%s/1200x1200.jpg"}, - "umv": {"name":LANGUAGE(32376),"path":"GOES16/ABI/SECTOR/umv/%s/1200x1200.jpg"}, - "smv": {"name":LANGUAGE(32377),"path":"GOES16/ABI/SECTOR/smv/%s/1200x1200.jpg"}, - "can": {"name":LANGUAGE(32378),"path":"GOES16/ABI/SECTOR/can/%s/1125x560.jpg"}, - "cgl": {"name":LANGUAGE(32379),"path":"GOES16/ABI/SECTOR/cgl/%s/1200x1200.jpg"}, - "eus": {"name":LANGUAGE(32380),"path":"GOES16/ABI/SECTOR/eus/%s/1000x1000.jpg"}, - "ne": {"name":LANGUAGE(32381),"path":"GOES16/ABI/SECTOR/ne/%s/1200x1200.jpg"}, - "na": {"name":LANGUAGE(32382),"path":"GOES16/ABI/SECTOR/na/%s/900x540.jpg"}, - "se": {"name":LANGUAGE(32383),"path":"GOES16/ABI/SECTOR/se/%s/1200x1200.jpg"}, - "car": {"name":LANGUAGE(32384),"path":"GOES16/ABI/SECTOR/car/%s/1000x1000.jpg"}, - "pr": {"name":LANGUAGE(32385),"path":"GOES16/ABI/SECTOR/pr/%s/1200x1200.jpg"}, - "gm": {"name":LANGUAGE(32386),"path":"GOES16/ABI/SECTOR/gm/%s/1000x1000.jpg"}, - "taw": {"name":LANGUAGE(32387),"path":"GOES16/ABI/SECTOR/taw/%s/900x540.jpg"}, - "mex": {"name":LANGUAGE(32388),"path":"GOES16/ABI/SECTOR/mex/%s/1000x1000.jpg"}, - "hi": {"name":LANGUAGE(32389),"path":"GOES17/ABI/SECTOR/hi/%s/1200x1200.jpg"}, - "tpw": {"name":LANGUAGE(32390),"path":"GOES17/ABI/SECTOR/tpw/%s/900x540.jpg"}, - "tsp": {"name":LANGUAGE(32391),"path":"GOES17/ABI/SECTOR/tsp/%s/900x540.jpg"}, - "eep": {"name":LANGUAGE(32392),"path":"GOES16/ABI/SECTOR/eep/%s/900x540.jpg"}, - "cam": {"name":LANGUAGE(32393),"path":"GOES16/ABI/SECTOR/cam/%s/1000x1000.jpg"}, - "nsa": {"name":LANGUAGE(32394),"path":"GOES16/ABI/SECTOR/nsa/%s/900x540.jpg"}, - "ssa": {"name":LANGUAGE(32395),"path":"GOES16/ABI/SECTOR/ssa/%s/900x540.jpg"} - } + "conus-e": {"name":LANGUAGE(32360),"path":"GOES16/ABI/CONUS/%s/1250x750.jpg"}, + "conus-w": {"name":LANGUAGE(32361),"path":"GOES17/ABI/CONUS/%s/1250x750.jpg"}, + "glm-e": {"name":LANGUAGE(32362),"path":"GOES16/GLM/CONUS/EXTENT/1250x750.jpg"}, + "glm-w": {"name":LANGUAGE(32363),"path":"GOES17/GLM/CONUS/EXTENT/1250x750.jpg"}, + "ak": {"name":LANGUAGE(32364),"path":"GOES17/ABI/SECTOR/ak/%s/1000x1000.jpg"}, + "cak": {"name":LANGUAGE(32365),"path":"GOES17/ABI/SECTOR/cak/%s/1200x1200.jpg"}, + "sea": {"name":LANGUAGE(32366),"path":"GOES17/ABI/SECTOR/sea/%s/1200x1200.jpg"}, + "np": {"name":LANGUAGE(32367),"path":"GOES17/ABI/SECTOR/np/%s/900x540.jpg"}, + "wus": {"name":LANGUAGE(32368),"path":"GOES17/ABI/SECTOR/wus/%s/1000x1000.jpg"}, + "pnw-w": {"name":LANGUAGE(32369),"path":"GOES17/ABI/SECTOR/pnw/%s/1200x1200.jpg"}, + "pnw-e": {"name":LANGUAGE(32370),"path":"GOES16/ABI/SECTOR/pnw/%s/1200x1200.jpg"}, + "psw-w": {"name":LANGUAGE(32371),"path":"GOES17/ABI/SECTOR/psw/%s/1200x1200.jpg"}, + "psw-e": {"name":LANGUAGE(32371),"path":"GOES16/ABI/SECTOR/psw/%s/1200x1200.jpg"}, + "nr": {"name":LANGUAGE(32373),"path":"GOES16/ABI/SECTOR/nr/%s/1200x1200.jpg"}, + "sr": {"name":LANGUAGE(32374),"path":"GOES16/ABI/SECTOR/sr/%s/1200x1200.jpg"}, + "sp": {"name":LANGUAGE(32375),"path":"GOES16/ABI/SECTOR/sp/%s/1200x1200.jpg"}, + "umv": {"name":LANGUAGE(32376),"path":"GOES16/ABI/SECTOR/umv/%s/1200x1200.jpg"}, + "smv": {"name":LANGUAGE(32377),"path":"GOES16/ABI/SECTOR/smv/%s/1200x1200.jpg"}, + "can": {"name":LANGUAGE(32378),"path":"GOES16/ABI/SECTOR/can/%s/1125x560.jpg"}, + "cgl": {"name":LANGUAGE(32379),"path":"GOES16/ABI/SECTOR/cgl/%s/1200x1200.jpg"}, + "eus": {"name":LANGUAGE(32380),"path":"GOES16/ABI/SECTOR/eus/%s/1000x1000.jpg"}, + "ne": {"name":LANGUAGE(32381),"path":"GOES16/ABI/SECTOR/ne/%s/1200x1200.jpg"}, + "na": {"name":LANGUAGE(32382),"path":"GOES16/ABI/SECTOR/na/%s/900x540.jpg"}, + "se": {"name":LANGUAGE(32383),"path":"GOES16/ABI/SECTOR/se/%s/1200x1200.jpg"}, + "car": {"name":LANGUAGE(32384),"path":"GOES16/ABI/SECTOR/car/%s/1000x1000.jpg"}, + "pr": {"name":LANGUAGE(32385),"path":"GOES16/ABI/SECTOR/pr/%s/1200x1200.jpg"}, + "gm": {"name":LANGUAGE(32386),"path":"GOES16/ABI/SECTOR/gm/%s/1000x1000.jpg"}, + "taw": {"name":LANGUAGE(32387),"path":"GOES16/ABI/SECTOR/taw/%s/900x540.jpg"}, + "mex": {"name":LANGUAGE(32388),"path":"GOES16/ABI/SECTOR/mex/%s/1000x1000.jpg"}, + "hi": {"name":LANGUAGE(32389),"path":"GOES17/ABI/SECTOR/hi/%s/1200x1200.jpg"}, + "tpw": {"name":LANGUAGE(32390),"path":"GOES17/ABI/SECTOR/tpw/%s/900x540.jpg"}, + "tsp": {"name":LANGUAGE(32391),"path":"GOES17/ABI/SECTOR/tsp/%s/900x540.jpg"}, + "eep": {"name":LANGUAGE(32392),"path":"GOES16/ABI/SECTOR/eep/%s/900x540.jpg"}, + "cam": {"name":LANGUAGE(32393),"path":"GOES16/ABI/SECTOR/cam/%s/1000x1000.jpg"}, + "nsa": {"name":LANGUAGE(32394),"path":"GOES16/ABI/SECTOR/nsa/%s/900x540.jpg"}, + "ssa": {"name":LANGUAGE(32395),"path":"GOES16/ABI/SECTOR/ssa/%s/900x540.jpg"} + } MAPTYPES = { - "LOOP": LANGUAGE(32333), - "GEOCOLOR": LANGUAGE(32400), - "EXTENT": LANGUAGE(32401), - "Sandwich": LANGUAGE(32402), - "AirMass": LANGUAGE(32404), - "DayCloudPhase":LANGUAGE(32405), - "NightMicrophysics":LANGUAGE(32406), - "DMW": LANGUAGE(32407), - "Dust": LANGUAGE(32408), - "01": LANGUAGE(32409), - "02": LANGUAGE(32410), - "03": LANGUAGE(32411), - "04": LANGUAGE(32412), - "05": LANGUAGE(32413), - "06": LANGUAGE(32414), - "07": LANGUAGE(32415), - "08": LANGUAGE(32416), - "09": LANGUAGE(32417), - "10": LANGUAGE(32418), - "11": LANGUAGE(32419), - "12": LANGUAGE(32420), - "13": LANGUAGE(32421), - "14": LANGUAGE(32422), - "15": LANGUAGE(32423), - "16": LANGUAGE(32424) - } + "LOOP": LANGUAGE(32333), + "GEOCOLOR": LANGUAGE(32400), + "EXTENT": LANGUAGE(32401), + "Sandwich": LANGUAGE(32402), + "AirMass": LANGUAGE(32404), + "DayCloudPhase":LANGUAGE(32405), + "NightMicrophysics":LANGUAGE(32406), + "DMW": LANGUAGE(32407), + "Dust": LANGUAGE(32408), + "01": LANGUAGE(32409), + "02": LANGUAGE(32410), + "03": LANGUAGE(32411), + "04": LANGUAGE(32412), + "05": LANGUAGE(32413), + "06": LANGUAGE(32414), + "07": LANGUAGE(32415), + "08": LANGUAGE(32416), + "09": LANGUAGE(32417), + "10": LANGUAGE(32418), + "11": LANGUAGE(32419), + "12": LANGUAGE(32420), + "13": LANGUAGE(32421), + "14": LANGUAGE(32422), + "15": LANGUAGE(32423), + "16": LANGUAGE(32424) + } LOOPSECTORS = { - ##ridge/standard/CONUS_loop.gif - "us": {"name":LANGUAGE(32396),"path":"ridge/standard/CONUS-LARGE_loop.gif"}, - "pnw": {"name":LANGUAGE(32369),"path":"ridge/standard/PACNORTHWEST_loop.gif"}, - "psw": {"name":LANGUAGE(32371),"path":"ridge/standard/PACSOUTHWEST_loop.gif"}, - "nr": {"name":LANGUAGE(32373),"path":"ridge/standard/NORTHROCKIES_loop.gif"}, - "sr": {"name":LANGUAGE(32374),"path":"ridge/standard/SOUTHROCKIES_loop.gif"}, - "sp": {"name":LANGUAGE(32375),"path":"ridge/standard/SOUTHPLAINS_loop.gif"}, - "umv": {"name":LANGUAGE(32376),"path":"ridge/standard/UPPERMISSVLY_loop.gif"}, - "smv": {"name":LANGUAGE(32377),"path":"ridge/standard/SOUTHMISSVLY_loop.gif"}, - "cgl": {"name":LANGUAGE(32379),"path":"ridge/standard/CENTGRLAKES_loop.gif"}, - "ne": {"name":LANGUAGE(32381),"path":"ridge/standard/NORTHEAST_loop.gif"}, - "se": {"name":LANGUAGE(32383),"path":"ridge/standard/SOUTHEAST_loop.gif"}, - "car": {"name":LANGUAGE(32384),"path":"ridge/standard/CARIB_loop.gif"}, - "ak": {"name":LANGUAGE(32364),"path":"ridge/standard/ALASKA_loop.gif"}, - "hi": {"name":LANGUAGE(32389),"path":"ridge/standard/HAWAII_loop.gif"}, - "guam": {"name":LANGUAGE(32397),"path":"ridge/standard/GUAM_loop.gif"} - } + ##ridge/standard/CONUS_loop.gif + "us": {"name":LANGUAGE(32396),"path":"ridge/standard/CONUS-LARGE_loop.gif"}, + "pnw": {"name":LANGUAGE(32369),"path":"ridge/standard/PACNORTHWEST_loop.gif"}, + "psw": {"name":LANGUAGE(32371),"path":"ridge/standard/PACSOUTHWEST_loop.gif"}, + "nr": {"name":LANGUAGE(32373),"path":"ridge/standard/NORTHROCKIES_loop.gif"}, + "sr": {"name":LANGUAGE(32374),"path":"ridge/standard/SOUTHROCKIES_loop.gif"}, + "sp": {"name":LANGUAGE(32375),"path":"ridge/standard/SOUTHPLAINS_loop.gif"}, + "umv": {"name":LANGUAGE(32376),"path":"ridge/standard/UPPERMISSVLY_loop.gif"}, + "smv": {"name":LANGUAGE(32377),"path":"ridge/standard/SOUTHMISSVLY_loop.gif"}, + "cgl": {"name":LANGUAGE(32379),"path":"ridge/standard/CENTGRLAKES_loop.gif"}, + "ne": {"name":LANGUAGE(32381),"path":"ridge/standard/NORTHEAST_loop.gif"}, + "se": {"name":LANGUAGE(32383),"path":"ridge/standard/SOUTHEAST_loop.gif"}, + "car": {"name":LANGUAGE(32384),"path":"ridge/standard/CARIB_loop.gif"}, + "ak": {"name":LANGUAGE(32364),"path":"ridge/standard/ALASKA_loop.gif"}, + "hi": {"name":LANGUAGE(32389),"path":"ridge/standard/HAWAII_loop.gif"}, + "guam": {"name":LANGUAGE(32397),"path":"ridge/standard/GUAM_loop.gif"} + } diff --git a/weather.noaa/resources/settings.xml b/weather.noaa/resources/settings.xml index f1dc215b9..472793cf8 100644 --- a/weather.noaa/resources/settings.xml +++ b/weather.noaa/resources/settings.xml @@ -204,6 +204,21 @@ + + 3 + + + true + + + + false + + + + + + @@ -405,6 +420,21 @@ + + 3 + + + true + + + + false + + + + + + @@ -606,6 +636,21 @@ + + 3 + + + true + + + + false + + + + + + @@ -807,6 +852,21 @@ + + 3 + + + true + + + + false + + + + + + @@ -1008,6 +1068,21 @@ + + 3 + + + true + + + + false + + + + + + From 3e4fc35825bee0096ade53d8ffb335d6d708bb0d Mon Sep 17 00:00:00 2001 From: Heckie75 Date: Sun, 16 Apr 2023 19:45:06 +0200 Subject: [PATCH 027/145] [script.timers] 3.6.0 --- script.timers/addon.xml | 20 ++-- script.timers/resources/assets/icon_alarm.png | Bin 11293 -> 0 bytes .../{icon_sleep.png => icon_timers.png} | Bin .../resource.language.de_de/strings.po | 68 ++++++++++++- .../resource.language.en_gb/strings.po | 66 +++++++++++- .../lib/contextmenu/abstract_set_timer.py | 19 ++-- .../resources/lib/player/mediatype.py | 1 + script.timers/resources/lib/player/player.py | 17 +++- .../resources/lib/player/player_utils.py | 26 +++-- .../resources/lib/timer/concurrency.py | 14 +-- .../resources/lib/timer/scheduleraction.py | 53 +++++----- script.timers/resources/lib/timer/storage.py | 4 +- .../resources/lib/utils/datetime_utils.py | 4 +- .../resources/lib/utils/picture_utils.py | 54 ++++++++++ .../resources/lib/utils/settings_utils.py | 3 +- .../resources/lib/utils/vfs_utils.py | 18 ---- script.timers/resources/settings.xml | 94 ++++++++++++++---- 17 files changed, 357 insertions(+), 104 deletions(-) delete mode 100644 script.timers/resources/assets/icon_alarm.png rename script.timers/resources/assets/{icon_sleep.png => icon_timers.png} (100%) create mode 100644 script.timers/resources/lib/utils/picture_utils.py diff --git a/script.timers/addon.xml b/script.timers/addon.xml index 613e520af..6180c22b0 100644 --- a/script.timers/addon.xml +++ b/script.timers/addon.xml @@ -1,5 +1,5 @@ - + @@ -36,6 +36,7 @@ * Different schedule modes: once, everyday, Mon-Fri, Fri-Sat, Sat-Sun, Sun-Thu, Mon-Thu, specific weekday and many more * Date change is supported, e.g. from 23:30 (p.m.) until 1:30 (a.m.) * Shuffle, repeat, 2 end modes, i.e. duration or specific time +* Smart shuffle mode for slideshows that tries to find folder that fits into timeframe randomly * Actions related to media: start media and stop at end, just start media, start media at end, stop media immediately, stop media at end, power down system * Linear fading in timer period: fade-in, fade-out, no fading. Min and max volume can be set for each timer * Custom label for timer @@ -65,6 +66,12 @@ https://github.com/Heckie75/kodi-addon-timers https://github.com/Heckie75/kodi-addon-timers +v3.6.0 (2023-04-16) +- Smart shuffle mode for slideshows (try randomly to find folder that fits into timeframe) +- Fixed resuming slideshow at right position +- Fixed resuming of enclosing timers especially combination of concurrent media types like video, audio or slideshow +- Improved notifications and competitive behavior (introduced extra low priority) + v3.5.0 (2023-02-07) - New feature: priority of timers and competitive behavior - New feature: System action to put playing device on standby via a CEC peripheral @@ -84,17 +91,6 @@ v3.3.0 (2022-10-08) - Improved scheduler that enables scheduling to the second, reduces CPU load on idle and enables smoother fading - Added fields for start and end time in order to schedule to the second (expert only) - Fixed Zattoo PVR support and other audio/video addons - -v3.2.0 (2022-08-27) -- Unlimited amount of timers -- Added feature in order to pause timers for a certain period -- Set adequate label for playing items instead of internal path -- Added global configurable offset in order to perform timers ahead of time or later in time -- Changed context menu 'timers' for EPG -- Snooze timer can resume playing media and be started from any context menu -- Changed resume behaviour if there are two parallel ending timers so that non-resuming timer wins and stops media -- Added dialog in order to abort system action -- Added help texts for all settings resources/assets/icon.png diff --git a/script.timers/resources/assets/icon_alarm.png b/script.timers/resources/assets/icon_alarm.png deleted file mode 100644 index ccaf487d68bf37928e27d38ee1fd87b82b319d31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11293 zcmW++byQSe7o8b~PLU3&p&LOuL~7{nPHB+t86>1(2x*A{6_8G;p;OQyB}Y*ZsX;)H z{P=x;y|?bU_nf=defOPx_C87ay6U7v3`76`fE22sVh8{L?_Yrc0=)Z&^^13|001ih zs`Au0wD_PTET`0@WJj?>x1_kZSX(B0X2L;CdwRkdomK6gs?AV9qT{5bGTb=M)hrB} z+>RwqO?1c?PaFUIOC(DTY;5do_iULeQ%4j8Vpj=PCSgl}#35_?PR5Q*-x+Vz%wP3| zgq7|@DeTPi68z{ow>UhyJ@gHl4+JAV!oHxMpv3JdKOfwkXxh_bnXqD?w~F_sL}v>N z3zal}BgAdd4-kiWt!h@=!U!78O9b*g;$w%Lp^lCkBuI-v(7o<%JvTzPD@)u09fsIo z8mM4NK8LIexYr}UbRE4XFg{p)(Zwxdc>R(ECl!|qXAb@z6$5JjqqqhCnJ?4L6iR61 z`R44dZ&JEL;cU%_-JJ<5jS=53h$|!SB)wq32Igkq-^wzkL}|^z>2KfMt=v5#t-~<| z*1|jBJ55JkRd+2xE@5i%G=S)(0+MOGTf$`;*`ajbKZa4LTGT_-OO!k+V5Tegn`;pZ zbQM4g=*AHZuBk#v!uU%9rV}lW`fg=qN+ZrEhJ_UHT^lZ&`oj}q)-7poZy8bHS z-c5^}-M4|dX)@$q-C8|$UAs<3ZbEJid^i+6IC&&StRooFIoIWj7 z58aFSn>U~O`!#g|T&N1Q@0NyqXu@8ZkNm(HWr8Nw?7%V}$0A!eb*65#o7q;6cP41o zyXoyl?Kg4*Yqc49Psaq^tC4PE3bh@OPxo7CkDHbaERHdiroFYd%?d0>(s#WvFobyX z?|P(73zwvHaN0n4PrF12#6Ing_GD-v-hYWVc6S-8ly0Vbb>6H{^({=NxO^CL+ zET`d$Q3$6O@hGeH*`b>x9W+sMCG-5)>jyivfW1ch-W%RI!$}k#G-IOmyR!TgtH#R0 zroDl}ifgD5T9j`*B}@D%`shRfp<~YB{&sD)iUm3c5j2$UZ<9a>y{6(za5ArW1n5|C%F|=R`LOJb_O+ zx|bS&VaRp3oxNe5M;)H-1l@)-;dnLN3!dRBhqnf@PK^Iynk3})u-5|pgN~Lw8QI%} zU1_epPBX`4+Ar=F++s=&{L3;;CFUNXAn>mRHT%Al02xXX7iMjxxo+Z;l@}^wEHDpex;PK4k={U7cUlaCy<_(hAL|r+3(oj^ z#7@Dvyp7h#h7Bvym=WOPUQ7FYuY8y&aA#f9abX5hHx#~|+@c*LMCrXN);@()P~|(fy3!vL6xQa{8LT1@9jO-|#T>_qU-gfp^!BxR{o%Hfu$3b~W!JBxp|h zkKgXAbN3I}JZ+0E zeCzO_ph*#Pme2a@XrPnIllL~Fj(XA1KIrR5ynjd6Vl~-H^NCSAiu8vu3`v0el&+iR zr3hjaQF0c#TQ$;oNy^J$7IZssR|@sdaEvnd?RhKefThT5Z3aCgieIGaf!QbpS;u97 zx=G*SlJEnr)kCQlL=XaFhT*=G@>%6rpG98t?8)^;*LQQg9ax+ApcxyIHL`04b4z2= zf&Q0Aj#)u2w4f;S6>KKsMjjYNf)VxN=6gIP(lINjx)Oi=FN(kJ^NnN;OSPqS)Ar`TV&`q`_F z|3G({zK<{7sK`MgSf!J^^Fe42&xh7ticSLlFE*}hjbs-M_g8`8X6zdnCFON49I)9u zC=mUos1K)+oJLzBZN~caSrd)t*Jx52v}N3+@)n$!x1ZvoI^Zzo$tC#^AxzrbWwUuB z^zX<~+q(kPK)!FV%z{7xO`%IZaL)r%8cbx{s-+rtpSRQ*+|BOi6T{}5X872rnubdS z+@g;RS8%6p^Scn*yjl$R>5po)t$8t{JU@ZAbUm(bTXupzi}kQYLa}| zOkIZPL|nT(a`uCE9bR-&*YCr?nKL9q=MSO5RhS-`E$uTx7)K){Ni0ilaQ5he+ra{n z&9kX);JWD4gnI&gzQgO^_*oO9NY;)+5`@E&r1+++j>}=}kwwH|OA~hKv8Y{ifkFbG z2vIKYh6g9p<2p*1GDwFzW+1;H6!5Qs7c9u6 z-Uj+opE~cwmx%f-@wu3xFW9FNiAD-+jbA_doR(eMn7PVS}-f4}(@2PrFDM;L0k z=qj6<%`-GEBV{E{I^t+S>LA5xCT07UdUP6C$-qjF+!@yun^OJv3Xs`gKcJ7VuYQo5 z2F+hRRD-rSF%w4`&K>7eu3%q*QHz9JXtJrMoDCj4#s0mcxRL5NDb!!z@p9Xkvo0!Q zw2#^d(+K)gKTI>QDo=@@MHBEFFh`I2YVEVdqt(_a7bRNeg@kzUE`;LQG3Tbq5}Ml z?P}$;cVK~vBWI7?{%TPp_#P)S<)4ZTRr5G0IOof|vaBgzT+?_?brlSsK&|le&<3RY z@^?LiXde7lvwPM_mGvA@cu3uk>w|j1rT|-byq4gxsE`k^=5zPNtd{>KmD*Xx!au;UoT<$YD@ zolD3K9=~Hj@@-vTgtDzMy3~BOL#+E^(ZTYo@NwH|NkGy27dZYif?2IOjUfA$m7AF^ z7gWjZTgBW++3AtLqS_*tC^g)5l7^ zla(tu8s7Yh`f0`^6q6@j@o1Z4WcG>z>Z@KFp|ODoY(Yl3vlQbv^n}{hF_=!s4iLc9uc2Vj4 z5xe#_DKvr)t1j$bI@xq`XV89yd-IAxE+ZRf=AR($ye`9Zn-w}85siF75Zg^{OOTo! z`2ITqT)0i<{VaZ|M%_q%%D#qyb7@v!4ZH9)aMrnWFiM-8voPRwUAP`Scz_*Om)Deu z4O=KsU0y}#&AHm7OyPMv`$y8kcq22gTHr*49#PG|=KnnUdsoO5c;Jk$Jq_bw5gIlg zK`scMF{<^{<;v=(vZrjKxf73ns9zqY{+GS-_4`NPzXn1tRbf}5dho5SqRzxGVmjNR zBNB)<%?2bf^=&s9CwL=Aymx)Vi*xtfTbF(G`y0rvq_;vD-KpkBGc*&_B7h8XQ2$r4 zA|m%GjPzqhQghm`v?oWLc#QME=_4*84rxIL1bzRAjt?QsbKg}qau)1~doR?d=7%bd z^N@4YU+fo2JT^-h=WmwCZf)DM0xOf>lGYhu!0a)zP75C?LZRj19OK9@y*j$Aoo`}L zku#ph<--+bXl3Xs?}?8z-Pi7j#*qjaq4R5ej)%8n6Hi{VAGafIIM#gm{XxCWg|tt( zn`_m4jKi%Kq1;kpc6WtbkJP*t$Lp@*y{p;XJtcg3Y|3H@Tj1lV#T~Wgi~}s3xOx@Y zguPP|ek{h@QlNU#e%tMU%-+&hJ-XQ;90reF@X{*GVBs-ObF-8?lc$dl@fB z+6O))H_~e`RAmvu6}48_PA_h<^UJ<1OysA;B(FSHOK^TUjcZ(3qwJv|)`$g_u~^Li z)+)Dqk#edjqwZfJ+bz*UvCO(V|9Ok7bU4`Ky3tAK_DeIa8F(Yt0!du^h+OUOHvz9d z3gEI)cWQ1-*dAw4?G=}kxhtFNun<4Bx580J9`Wta7P0hjjLq|2d zNi^$yM$Gd+wp)jg2buKKj`4F(riha>6~7$?X z#yvj&ac%9x_|3KxdjRf}S_a{9`6JUT_q0U5{@O+}v>DZIC(m4{uE}?i6Ug|Cj2r(^ zLA_aCtsTQla}H;r7S}FQ&gK9TH7@YBW;o~C&Sy&B8dRZEmK~M}WBlh+6FL7xkk>mt z5qkF#D}!ne&7yC`dndWo>0sMWQn^r+G@nM`FMA?hfb&ju3*4Ig1Nj9#MID{9tEI(s z6%F7flnraakTa}1ZjB+J*01DSi@Sa%Lo^3?@frV`Nor!LwHCzu7DzHI9m3)#MJlre zsbIWd_?Fy?SLp`=ashf<08R)9zYR*FnDGlwO3l| z87|=lZyX@gWg$v%=(9YEex_?xEVTq-O8bHn7hvx82oqXIZ0f-UaC4yxc}&CxfC*=h zVb5`P))i0UL9zGA^ZfM2(oDp!Si@9^A3)f@y zELA#uF*^sxp(J0$i5!yduxL0XGGYO?Pj{h)lE#>Di}OOKb;dsciDVJE4zo2*)Cd_@n)NpIlXp!@B zBtN22_*=e{=s~z4*F>n(5W_DrWLFQ#EN*Ri zMV#A}mx(W;!%A&~Vw=oy@;Ga*DpwMKVkDRo(}?;29v+h_GH`2q5O- zOvGz^+!!@@oClx{Df_*t7X^L}d_x!fV3#D;2IU6f)Jd3P1CT*VJig*vn|~AN&(dcB zTJCTo7nnNm+qI-@ErFQFWfi#(d{K^=F~Tu^_5%V~dJ@j_`}`{H$F_@37{j@OFc51r z0QX}{f($?7SQ|H?Z9ia-Rxi4lBfxYhQsgJPHA$C&OlJ^^Tb@ZnW^2>PeBSQuTsm7r zr37I47fnxQ;DquV+?n~Ukq2N7&ipWK0ms_#=vGM(pzO!pUXHY<^7E?^7{~$H3+=Ms zm5zAyFSNSjjF;3~f_rHE=y&BnvOuUK2+?DGbhRlwV!o{Pagfo^W99tkk|oTadD~ET zfQm8<#}In{9vR>(Fhn9Lq1Fv5<9G?j+mcnei4(U}lEfZ^w;&GzvY#yjl1)3Oq?g{o4fNZ`M z=GM#TsCdX;)Sv(ocYWX<8|#V=4_FeUw7UO<|D0X@b4kp-e8kI^3X7q3WT*b2z#2d1 z4tmi0{0kUnW>tYNW^Wj35bHmwL2%Z4?*S!!F0(5Jb{qTXr%h_lgJ1$Mbqz6vc%y8}B~gVG>eD{Q&@>mi4ZJaQCV+ zH%W$qM}fB)r&}b%K8JXWH5Xv6x+8Jrl|b?DM;obq=p(4O?k*UG)L42nKG&CKq~rA4 z8g?O|D?SsG^o{TpCqOM*4Iua0KGpD^OLk~&oIs=#`IXc($BCZ-xgL}wqXmE>1>(G@ zlC?jc8j%!>E^!8o>Ofkk3=gWUMuWvPiSLO4SgDSS*@)dHM1=d2JV3&<*89WVj)}Pz zRuQKGL@v8yt1bSvE)-`!1Rh1mjTr;I*04M%-g{L@Y`eZemNIxXYp!v~qutG%Cco;R zpCU9O>JD<3_2@`P8ksPKbAHGQ>_ze<MR6qf z*5Jo(+4?JrB%7iKd)vt#(vR@1fyI@>QOiyo?tECC?_-CvAl)Q6wHJ_2sMyKBlk%_G z=$?VQE&YI)kR^8fj6k3rZu+=f#%Crynbj$O1mbT~M$+a#-{F}PRj!Ls1}z+(W&oi3 zh#2CX9l_3q?Y=7~Oe_X7mHPE8TWcVdicnN`IAwA!$Wh?ipQS3SuGvDTAK%DxR(bqo zAceMwTWE>~El00LJR$)#{ZoW|e!N8OVW3%n{mJqCe}TsXP$ z{0LJp9e3V^O1)3hJZbP?2~r#dCM%n_|wOR3LLIG$9XvVxeW5=1J!F0_qKHFck8Z zkSeJMp6cHg#@05@XmtGo%>e#ROC{!EN1SCoA|nNW`gua~Q@sE1F|zDc@3bVDoM5S3-iJgBPu;c zb1kq_6>-#40Q960t=aW!0P@drU+NE!-+c+wDnPTDml;S9%*3Otwrz;H=aAI{^pNzC z6D{lTo5s|!q`2MIH8L$Yxy+7fLeFynU?T@sKh=}``=foiJK8!vzq?tPjRvagkDJW0 zpqRf3cv7#$*9$s^TTt9n%L88(r;^MEKT~NFq&m&5r3lrjSnjv}*@4~P&R9m!OAhyB zw6T%=W|K-Cc!^?R?>BgZ*ZZL&YP|k4>o}22 zwc)28+q?U5XVg5NGblf8_O$A@V#+XJc%w?nvT;SVoj`HGy>4_zbS+u;{FnTXrWYX& z3&A^M%OhghzZtC=D#=~z(93%wo~NlAOGj?iNCO3?c2|O)rL71=^edCTbztpFk*sqg z#}L-Tu{BaA+#blT6}89j!Ww}U;-pc+m&lZd#VHW}-{x~%V%?uAz(;$`Q1u^uoBA4; z2C;5j1#W^;qU#KLYCV6Iwjm5}(V>FhlrV0?I_dN&xz3yN-|2V@O6*e=*njd5Qvvi; z@2B00ev!%@<5pu%|EV!d1$qe6GWoO3j%er7d7QPB~$l|Z4st?ta*51z@x!BD?V;D{FY4?1pSoi$-D*lf86zM4 z#DSP~x%|1d+&IMIJ)xwt%Tc9rp`6pOC6)lTZgRa z`bVH`oGbOtU=l<35&)E5F+r|+QzYEIHP@#zPdZBBX% zhKB?BS@j0Eun^v=8uRWJfsAf0_C5p}iVAtP#dgmUvGE4eg~{$eEet1)Qn6L!ov}Jc zjFO3DUD9QO?d-mJqP`9v>*)=}DH-5iDj+Rng&%e~`X?8KroU241*U=&O6-dno_K_8 z4z|MS+~&WcM)=JCmMv);j+Dr0{__T?Fv&03zm@{XDoY^LQ#Z@N$Cp67^ zkro?VmE;_$I;`9~3f(mk~?#43}3`jnLj+gTFc9jyh5&r08F}=zU-6{Ix?!se-Pi z1k5_#PE%K_Y)0H6aOaf#x|CpLHmK82*BdLPr5@ zZ@Kp8qm{Y?-GqvSkr|B}Z`LOwsFst&yYB2){@C#1X}Vi?y%gUa0JOX#j&~kn#MeVH zc*m`be1vZWJO^$NgbD113(DzLBvkR@qKuFyc&Wg2q5QMXO6=lZ%qWd6&wwKJo^o+v zK|UTLIl}O)S)*MkQX!zm39w9Dy9ah2jv%NX)=Z1%(b>=`1Tirl7ma^0|93=H2ddW* zH~nL(&YJ;z2oqjvhh39s@cKx82*Q2v&?&)Q7SkBFC9gYtx;cQP0i-}z$D;LqV=>B@ z;s~ZGuAa2Tw3oA4jb}X#dRWza=5!Ay+BmoUj5I4SA4!^}#Y6tXmIY;CbT9s9wkn|` zbo$0ZsNakK6$w~3F&&kojxk)=v(zZ$+07ti`Hg4tjx35gQ`{20B=P4kjwTfVAYT5j z7hq(8f0vK*6rjPtzx$WR?#E|q#P8c?_Fd~LZ_9tO(D$iQ5*$j4#wV=M2Jdg{XOlFJ z=n?}o(8E^CJuw6lq~@&!UDXWd|2A}xdrH0FGcd^J-j2jy2z_=hsQ%MrS`n13zUEpO z+YQs8_hA1xk29#YG%11VBTTfxi=3A3kouPYpMQzaC#J3u`~sAR9p;bcIGY}S$NN-8 zTpNH5Leoz~z_N=2HnqfUqag=Xt$caTcmsyHZ|b2bNSmBREO&v9fY#n=G2d|s+>->h6$l|+d`fD~Q@xuGOWwMbNU*1Xs{6A&C z#m{uI+<~uM!r6KeLIzzcM*l7JhTO2tb+oIYb-Ug?Wy=ybLGu^bPDdd6kTM$Y&>Dr1 zUD|>^QRqi=Q-@Ah5ivoG%1_Zr4YVDE`K={^F=avb(Msy(5^+sJF*2b=y2 zO7k-TP+YKVPmwar zKF7B-@5-e2nh%u|dG$Eol$&$xzFV8EMvp_H>$U64Lsf%Sc;_9nx&~Lg{hE|;Pol>W zqe5nVr^jkunPGLB0fBsii0yZDc^mK^?mat6`STNan(U7@;GySBBEyfGG;A_@=p&pp zGmUVU_xtgRVkUSNc3l;8xcGlkkiA{d~rFJ>|z_WTLY`DRcRc`)HJ564O zroiNCk1ze$jrC{}p%`p{m#gn8(yNHMxhE1O&Y~_N=!JKUEzXPC`}Q`q3X8YC2FitR zKGrwBWiQ&C9-eih25U|VxRv=x2aXM2K2-(Z| zQDI*Rklpbks^8zN;D~N`N_rnoH|O81bK2ncfUJqUjv8zNO%0ny$T=tQyl5;QV4X@COGeg^Z)$x$NA^PM%)E^f*~ zF^!GtdvJ~j1hwarRau`)6D=>?)q$dUcTF*5_FoC+f}99?h1AL_A`V;x8cDId)A=1X zNa-qjX}?HnTE!es2l04X5Vr&R>STG4k8umudp#>---NUShT!Nqowv(4%=~jz2lQjc z93I7%z+ynb;A+l7BW+u}K7EO{7}i`l5Q$3O_zM{?<#vbuE`l)Fw3qtT zgR(!~_P}k@e6mQ2)m=A7;=WYn_6JcYBUID>F*z4kE-k>mo~zDsI+DG!nMj4ax>=WX z#?db7A6mXD zD*bhF-wg!%*&he25^(V@z~_cyOB)rOGt|VPzAoP`eF@uv?KPgCt%=Nr zbJyuQc9+EE0bIWu`I-Zd?76lykJxG-#Y7t|B#h3VK?L6vL8}!)NJUC+P zTqTbW`DOz*f%zn!p}1>5|M5iLpLXV1XAI)+&7C4XnO8eQ!;x7dv+K)cVp*YibBR(r z;F4o6g)NIm2MZB&t}$fQC!{WcN@^;c?gwZ z?kxK>6*w(gmJLRgqki76e)F^V$_`#F?${IIZ&epMvUwR(np7nga`k3@uskN~+}`bC zr-{<4|GfVm^4RK0vDjCZ{1n~SSm4uwkp~U_-;N!bd6L~ISG-XhbSyJy8N0g*ufzSSd3R-k;k>&Fy1QBko;_ka9=s*8q)*}7Hlm!uHtR)_M{_fm9M4x0>32;Z7x^z!L}*?3TNzEQ zL+_0}e4Tai{g>i?Pv1(U)G^F-(Zc`b3%;e7>GRZg$qdXvlIoblHgf~@55tz?o}%fX zOOm^|7nK6xt=0SY5Ze74fn8(+QfnS4RHmzp)`kkFVj1sSCJnlFtRGT9t){O3Svh72 zyhm0$jyvLPJR10Z_fe+PO5Y_*To*0 None: timer.duration = duration timer.end = datetime_utils.format_from_seconds( (datetime_utils.parse_time(starttime) + datetime_utils.parse_time(duration)).seconds) - timer.end_type = END_TYPE_NO if timer.duration == datetime_utils.DEFAULT_TIME else END_TYPE_DURATION + + if is_epg: + timer.end_type = END_TYPE_TIME + elif timer.duration == datetime_utils.DEFAULT_TIME: + timer.end_type = END_TYPE_NO + else: + timer.end_type = END_TYPE_DURATION system_action, media_action = self.ask_action( timer.label, path, is_epg, timer) @@ -97,7 +104,7 @@ def __init__(self, label: str, path: str, timerid=-1) -> None: timer.init() overlappings = determine_overlappings( - timer, self.storage.load_timers_from_storage(), ignore_high_prio=True) + timer, self.storage.load_timers_from_storage(), ignore_extra_prio=True) if overlappings: answer = self.handle_overlapping_timers( timer, overlapping_timers=overlappings) @@ -187,7 +194,7 @@ def post_apply(self, timer: Timer, confirm: int) -> None: msg = ("$H\n%s: $P" % self.addon.getLocalizedString( 32081)) if timer.system_action else "$H" xbmcgui.Dialog().notification(heading=timer.label, - message=timer.format(msg), icon=vfs_utils.get_asset_path("icon.png")) + message=timer.format(msg), icon=vfs_utils.get_asset_path("icon_timers.png")) def _get_timer_preselection(self, timerid: int, label: str, path: str) -> 'tuple[Timer,bool]': @@ -242,7 +249,7 @@ def _get_timer_preselection(self, timerid: int, label: str, path: str) -> 'tuple (td_start + datetime_utils.parse_time(timer.duration)).seconds) if vfs_utils.is_script(timer.path): - timer.media_type = "script" + timer.media_type = SCRIPT else: timer.media_type = vfs_utils.get_media_type(timer.path) or VIDEO diff --git a/script.timers/resources/lib/player/mediatype.py b/script.timers/resources/lib/player/mediatype.py index dc2e8e29d..cf961e317 100644 --- a/script.timers/resources/lib/player/mediatype.py +++ b/script.timers/resources/lib/player/mediatype.py @@ -1,5 +1,6 @@ AUDIO = "audio" VIDEO = "video" PICTURE = "picture" +SCRIPT = "script" TYPES = [AUDIO, VIDEO, PICTURE] diff --git a/script.timers/resources/lib/player/player.py b/script.timers/resources/lib/player/player.py index 1397b1da0..32c13359f 100644 --- a/script.timers/resources/lib/player/player.py +++ b/script.timers/resources/lib/player/player.py @@ -81,10 +81,18 @@ def _get_delay_for_seektime(_timer: Timer, _dtd: datetime_utils.DateTimeDelta) - seektime = _get_delay_for_seektime(timer, dtd) if type == PICTURE: - beginSlide = files[(seektime // self._getSlideshowStaytime()) % + stayTime = self._getSlideshowStaytime() + beginSlide = files[(seektime // stayTime) % len(files)] if seektime else None + + if timer.is_stop_at_end_timer(): + amountOfSlides = datetime_utils.abs_time_diff( + timer.current_period.end, dtd.td) // stayTime + 1 + else: + amountOfSlides = 0 + self._playSlideShow(path=path, - shuffle=timer.shuffle, beginSlide=beginSlide) + shuffle=timer.shuffle, beginSlide=beginSlide, amount=amountOfSlides) else: playlist = self._buildPlaylist( @@ -114,10 +122,10 @@ def _playAV(self, playlist: PlayList, startpos=0, seektime=None, repeat=player_u xbmc.executebuiltin("CECActivateSource") self.play(playlist.directUrl or playlist, startpos=startpos) - def _playSlideShow(self, path: str, beginSlide=None, shuffle=False) -> None: + def _playSlideShow(self, path: str, beginSlide=None, shuffle=False, amount=0) -> None: player_utils.play_slideshow( - path=path, beginSlide=beginSlide, shuffle=shuffle) + path=path, beginSlide=beginSlide, shuffle=shuffle, amount=amount) def _isPlaying(self, files, type, repeat=player_utils.REPEAT_OFF) -> bool: @@ -198,7 +206,6 @@ def resumeFormerOrStop(self, timer: Timer) -> None: def _resumeFormer(self, type: str, keep=False) -> bool: resuming = False - for _type in player_utils.get_types_replaced_by_type(type): resumeState = self._getResumeStatus(_type) diff --git a/script.timers/resources/lib/player/player_utils.py b/script.timers/resources/lib/player/player_utils.py index f199a50b4..2ea152ee4 100644 --- a/script.timers/resources/lib/player/player_utils.py +++ b/script.timers/resources/lib/player/player_utils.py @@ -3,6 +3,7 @@ import xbmcgui from resources.lib.player.mediatype import AUDIO, PICTURE, TYPES, VIDEO from resources.lib.timer.storage import Storage +from resources.lib.utils import picture_utils from resources.lib.utils.jsonrpc_utils import json_rpc from resources.lib.utils.vfs_utils import (build_playlist, convert_to_playlist, get_asset_path, get_files_and_type, @@ -45,13 +46,18 @@ def preview(addon: xbmcaddon.Addon, timerid: int, player: 'xbmc.Player') -> None if timer.is_playing_media_timer(): xbmcgui.Dialog().notification(addon.getLocalizedString(32027), timer.label, - icon=get_asset_path("icon.png")) + icon=get_asset_path("icon_timers.png")) if is_script(timer.path): run_addon(timer.path) elif timer.media_type == PICTURE: - play_slideshow(timer.path, shuffle=timer.shuffle) + if timer.shuffle and timer.is_play_at_start_timer() and timer.is_stop_at_end_timer(): + amount = 1 + timer.duration_timedelta.total_seconds() // get_slideshow_staytime() + else: + amount = 0 + + play_slideshow(timer.path, shuffle=timer.shuffle, amount=amount) else: playlist = build_playlist(path=timer.path, label=timer.label) @@ -62,12 +68,18 @@ def preview(addon: xbmcaddon.Addon, timerid: int, player: 'xbmc.Player') -> None 32027), addon.getLocalizedString(32109)) -def play_slideshow(path: str, beginSlide=None, shuffle=False) -> None: +def play_slideshow(path: str, beginSlide: str = None, shuffle=False, amount=0) -> None: + + if shuffle and amount: + path, shuffle = picture_utils.get_good_matching_random_folder( + path=path, wanted_amount=amount) + beginSlide = None - xbmc.executebuiltin("SlideShow(%s,recursive,%srandom%s)" % - (path, - "" if shuffle else "not", - (",beginslide=\"%s\"" % beginSlide) if beginSlide else "")) + cmd = "SlideShow(\"%s\",recursive,%s%s)" % (path, + "random" if shuffle else "notrandom", + (",beginslide=%s" % beginSlide) if beginSlide and "," not in beginSlide else "") + xbmc.log("[script.timers] %s" % cmd, xbmc.LOGINFO) + xbmc.executebuiltin(cmd) def run_addon(path: str) -> None: diff --git a/script.timers/resources/lib/timer/concurrency.py b/script.timers/resources/lib/timer/concurrency.py index 9859dbf35..3fe2c6032 100644 --- a/script.timers/resources/lib/timer/concurrency.py +++ b/script.timers/resources/lib/timer/concurrency.py @@ -1,7 +1,7 @@ import xbmcaddon import xbmcgui from resources.lib.player.player_utils import get_types_replaced_by_type -from resources.lib.timer.period import Period, timedelta +from resources.lib.timer.period import Period from resources.lib.timer.timer import (MEDIA_ACTION_START, MEDIA_ACTION_START_AT_END, MEDIA_ACTION_START_STOP, @@ -12,16 +12,18 @@ from resources.lib.utils.settings_utils import (CONFIRM_CUSTOM, CONFIRM_NO, CONFIRM_YES) -MIN_PRIO = -10 +MIN_PRIO = -12 MAX_PRIO = 12 +LOW_PRIO_MARK = -10 HIGH_PRIO_MARK = 10 DEFAULT_PRIO = 0 def get_next_lower_prio(timers: 'list[Timer]') -> int: - _min = min(timers, key=lambda t: t.priority).priority - 1 - return max(_min, MIN_PRIO) + _min = min(timers, key=lambda t: t.priority if t.priority > + LOW_PRIO_MARK else DEFAULT_PRIO).priority + return _min - 1 if _min > LOW_PRIO_MARK + 1 else _min def get_next_higher_prio(timers: 'list[Timer]') -> int: @@ -31,7 +33,7 @@ def get_next_higher_prio(timers: 'list[Timer]') -> int: return _max + 1 if _max < HIGH_PRIO_MARK - 1 else _max -def determine_overlappings(timer: Timer, timers: 'list[Timer]', ignore_high_prio=False) -> 'list[Timer]': +def determine_overlappings(timer: Timer, timers: 'list[Timer]', ignore_extra_prio=False) -> 'list[Timer]': def _disturbs(types: 'list[str]', type2: str, media_action1: int, media_action2: int, period1: Period, period2: Period) -> bool: @@ -101,7 +103,7 @@ def _disturbs(types: 'list[str]', type2: str, media_action1: int, media_action2: overlapping_timers: 'list[Timer]' = list() for t in timers: - if t.id == timer.id or (ignore_high_prio and t.priority >= HIGH_PRIO_MARK): + if t.id == timer.id or (ignore_extra_prio and (t.priority <= LOW_PRIO_MARK or t.priority >= HIGH_PRIO_MARK)): continue t_replace_types = get_types_replaced_by_type(t.media_type) diff --git a/script.timers/resources/lib/timer/scheduleraction.py b/script.timers/resources/lib/timer/scheduleraction.py index e8a17ff25..a6e8e21db 100644 --- a/script.timers/resources/lib/timer/scheduleraction.py +++ b/script.timers/resources/lib/timer/scheduleraction.py @@ -129,7 +129,7 @@ def _reset_stop(): enclosingTimers = [t for t in self._runningTimers if (t.current_period.start < timerToStop.current_period.start and t.current_period.end > timerToStop.current_period.end) - and t.media_type in _stopMediatype] + and t.media_type in _types_replaced_by_type] if enclosingTimers and not [t for t in enclosingTimers if timerToStop.priority >= t.priority]: _reset_stop() @@ -289,27 +289,35 @@ def perform(self, now: DateTimeDelta) -> None: def _performPlayerAction(_now: DateTimeDelta) -> None: if self.timerToPlayAV: + _showNotification(self.timerToPlayAV, msg_id=32280) self._player.playTimer(self.timerToPlayAV, _now) elif self.timerToStopAV: + _showNotification(self.timerToStopAV, msg_id=32281) self._player.resumeFormerOrStop(self.timerToStopAV) elif self.timerToPauseAV and not self._player.isPaused(): + _showNotification(self.timerToPauseAV, msg_id=32282) self._player.pause() elif self.timerToUnpauseAV and self._player.isPaused(): + _showNotification(self.timerToUnpauseAV, msg_id=32283) self._player.pause() + elif self.fader: + _showNotification(self.fader, msg_id=32284) + for type in set(self._forceResumeResetTypes): self._player.resetResumeStatus(type) if not self.timerToPlayAV or self.timerToPlayAV.media_type != VIDEO: if self.timerToPlaySlideshow: + _showNotification(self.timerToPlaySlideshow, msg_id=32286) self._player.playTimer(self.timerToPlaySlideshow, _now) elif self.timerToStopSlideshow: - self._player.resumeFormerOrStop( - self.timerToStopSlideshow) + _showNotification(self.timerToStopSlideshow, msg_id=32287) + self._player.resumeFormerOrStop(self.timerToStopSlideshow) def _setVolume(dtd: DateTimeDelta) -> None: @@ -320,28 +328,19 @@ def _setVolume(dtd: DateTimeDelta) -> None: else: self.fade(dtd) - return_vols = [ - t.return_vol for t in self._endingTimers if t.is_fading_timer()] - if return_vols: - self._player.setVolume(max(return_vols)) - - def _showNotifications() -> None: - - addon = xbmcaddon.Addon() - - for timer in self._endingTimers: + ending_faders = [ + t for t in self._endingTimers if t.is_fading_timer()] + if ending_faders: + self._player.setVolume( + max(ending_faders, key=lambda t: t.return_vol).return_vol) - if timer.notify and timer.end_type != END_TYPE_NO: - icon = get_asset_path("icon_sleep.png") - xbmcgui.Dialog().notification(addon.getLocalizedString( - 32101), timer.label, icon) + def _showNotification(timer: Timer, msg_id: int, icon="icon_timers.png") -> None: - for timer in self._beginningTimers: - if timer.notify: - icon = get_asset_path( - "icon_alarm.png" if timer.end_type == END_TYPE_NO else "icon_sleep.png") - xbmcgui.Dialog().notification(addon.getLocalizedString( - 32100), timer.label, icon=icon) + if timer.notify: + addon = xbmcaddon.Addon() + icon_path = get_asset_path(icon) + xbmcgui.Dialog().notification( + timer.label, addon.getLocalizedString(msg_id), icon_path) def _consumeSingleRunTimers() -> None: @@ -364,6 +363,7 @@ def _reset(timers: 'list[Timer]') -> None: def _runScripts() -> None: for timer in self.timersToRunScript: + _showNotification(timer, msg_id=32288) run_addon(timer.path) def _performSystemAction() -> None: @@ -372,21 +372,27 @@ def _performSystemAction() -> None: pass elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_SHUTDOWN_KODI: + _showNotification(self.timerWithSystemAction, msg_id=32082) xbmc.shutdown() elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_QUIT_KODI: + _showNotification(self.timerWithSystemAction, msg_id=32083) xbmc.executebuiltin("Quit()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_STANDBY: + _showNotification(self.timerWithSystemAction, msg_id=32084) xbmc.executebuiltin("Suspend()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_HIBERNATE: + _showNotification(self.timerWithSystemAction, msg_id=32085) xbmc.executebuiltin("Hibernate()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_POWEROFF: + _showNotification(self.timerWithSystemAction, msg_id=32086) xbmc.executebuiltin("Powerdown()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_CEC_STANDBY: + _showNotification(self.timerWithSystemAction, msg_id=32093) xbmc.executebuiltin("CECStandby()") def _adjustState() -> None: @@ -404,7 +410,6 @@ def _adjustState() -> None: if self.hasEventToPerform: _runScripts() - _showNotifications() _consumeSingleRunTimers() _performSystemAction() _adjustState() diff --git a/script.timers/resources/lib/timer/storage.py b/script.timers/resources/lib/timer/storage.py index 8bd9cee0b..d09aa443d 100644 --- a/script.timers/resources/lib/timer/storage.py +++ b/script.timers/resources/lib/timer/storage.py @@ -44,7 +44,7 @@ def _wait_for_unlock(self) -> None: wait -= 1 if wait == 0: - xbmc.log("%s is locked. Unlock now with small risk of data loss." % + xbmc.log("[script.timers] %s is locked. Unlock now with small risk of data loss." % self._get_storage_path(), xbmc.LOGWARNING) self.release_lock() @@ -60,7 +60,7 @@ def _load_from_storage(self) -> 'list[dict]': _storage.extend(json.load(file)) except: # this should normally not be a problem, but it fails when running unit tests - xbmc.log("Can't read timers from storage.", + xbmc.log("[script.timers] Can't read timers from storage.", xbmc.LOGWARNING) return _storage diff --git a/script.timers/resources/lib/utils/datetime_utils.py b/script.timers/resources/lib/utils/datetime_utils.py index 75292b274..d2820ae59 100644 --- a/script.timers/resources/lib/utils/datetime_utils.py +++ b/script.timers/resources/lib/utils/datetime_utils.py @@ -135,12 +135,12 @@ def parse_time(s_time: str, i_day=0) -> datetime.timedelta: minutes=t_time.tm_min) -def abs_time_diff(td1: datetime.timedelta, td2: datetime.timedelta) -> datetime.timedelta: +def abs_time_diff(td1: datetime.timedelta, td2: datetime.timedelta) -> int: return abs(time_diff(td1, td2)) -def time_diff(td1: datetime.timedelta, td2: datetime.timedelta) -> datetime.timedelta: +def time_diff(td1: datetime.timedelta, td2: datetime.timedelta) -> int: s1 = td1.days * 86400 + td1.seconds s2 = td2.days * 86400 + td2.seconds diff --git a/script.timers/resources/lib/utils/picture_utils.py b/script.timers/resources/lib/utils/picture_utils.py new file mode 100644 index 000000000..ce388b902 --- /dev/null +++ b/script.timers/resources/lib/utils/picture_utils.py @@ -0,0 +1,54 @@ +import os +from random import uniform + +import xbmcvfs +from resources.lib.player.mediatype import PICTURE +from resources.lib.utils import vfs_utils + + +def get_good_matching_random_folder(path: str, wanted_amount: int) -> 'tuple[str,bool]': + + def _scan_dirs_with_filecount(path: str, wanted_amount: int) -> 'list[str,int]': + + def _scan(path: str) -> 'tuple[int, list[str,int]]': + + dirs, files = xbmcvfs.listdir(path) + files = [ + f for f in files if vfs_utils.get_media_type(f) == PICTURE] + + result = list() + files_count = len(files) + + for d in dirs: + sub_count, subs = _scan(os.path.join(path, d)) + files_count += sub_count + if sub_count * 2 >= wanted_amount: + result.extend(subs) + + result.append((path, files_count)) + return files_count, result + + return _scan(path)[1] + + scale = 0 + choices = list() + dirs_with_filecount = _scan_dirs_with_filecount(path, wanted_amount) + for dir_with_filecount in dirs_with_filecount: + if dir_with_filecount[1] > wanted_amount: + match_factor = wanted_amount / dir_with_filecount[1] + else: + match_factor = dir_with_filecount[1] / wanted_amount + + choices.append( + (match_factor, dir_with_filecount[0], dir_with_filecount[1], dir_with_filecount[1] > wanted_amount)) + + scale += match_factor + + pick = uniform(0, scale) + current = 0 + for t in choices: + current += t[0] + if current > pick: + return t[1], t[3] + + return path, True diff --git a/script.timers/resources/lib/utils/settings_utils.py b/script.timers/resources/lib/utils/settings_utils.py index 12380e0fd..7d53c6399 100644 --- a/script.timers/resources/lib/utils/settings_utils.py +++ b/script.timers/resources/lib/utils/settings_utils.py @@ -3,6 +3,7 @@ import xbmcaddon import xbmcgui from resources.lib.timer.storage import Storage +from resources.lib.player.mediatype import VIDEO from resources.lib.timer.timer import (DEFAULT_TIME, END_TYPE_NO, FADE_OFF, MEDIA_ACTION_NONE, SYSTEM_ACTION_NONE, Timer) @@ -67,7 +68,7 @@ def prepare_empty_timer_in_setting(timer_id=None) -> None: addon.setSettingInt("timer_system_action", SYSTEM_ACTION_NONE) addon.setSettingInt("timer_media_action", MEDIA_ACTION_NONE) addon.setSettingString("timer_path", "") - addon.setSettingString("timer_mediatype", "") + addon.setSettingString("timer_mediatype", VIDEO) addon.setSettingBool("timer_repeat", False) addon.setSettingBool("timer_shuffle", False) addon.setSettingBool("timer_resume", True) diff --git a/script.timers/resources/lib/utils/vfs_utils.py b/script.timers/resources/lib/utils/vfs_utils.py index a099354bb..ba7a2bed8 100644 --- a/script.timers/resources/lib/utils/vfs_utils.py +++ b/script.timers/resources/lib/utils/vfs_utils.py @@ -26,24 +26,6 @@ _EXTERNAL_PATHS = ["http://", "https://"] -def scan_dirs_with_filecount(path: str) -> 'tuple[int,list[tuple[str,int]]]': - - def _scan(path: str, result: 'list[tuple[str,int]]') -> 'tuple[int,list[tuple[str,int]]]': - - dirs, files = xbmcvfs.listdir(path) - files_count = len(files) - for d in dirs: - _files_count, result = _scan("%s%s/" % (path, d), result=result) - files_count += _files_count - - result.append((path, files_count)) - - return files_count, result - - result = list() - return _scan(path, result=result) - - def is_folder(path: str) -> bool: dirs, files = xbmcvfs.listdir(path) diff --git a/script.timers/resources/settings.xml b/script.timers/resources/settings.xml index 01eb2d69c..0e6c73df5 100644 --- a/script.timers/resources/settings.xml +++ b/script.timers/resources/settings.xml @@ -80,7 +80,7 @@ 3 0 - -10 + -12 1 12 @@ -91,7 +91,7 @@ -1 - + 0 @@ -110,6 +110,25 @@ + + 0 + + + true + + + 32338 + + false + + + + -1 + -9 + + + + -1 @@ -274,7 +293,12 @@ false - -1 + + + -1 + + + 0 @@ -288,7 +312,12 @@ false - -1 + + + -1 + + + 0 @@ -302,23 +331,39 @@ false - -1 + + + -1 + + + 1 - - 0 - + + 3 + video - true + + + + + + - - 32080 - - false + + r + + + -1 + + + + + - - 0 + + 3 true @@ -326,7 +371,15 @@ 32080 - false + false + + + + -1 + + + + 0 @@ -356,7 +409,12 @@ true - -1 + + + -1 + + + @@ -634,7 +692,7 @@ 3 - 6 + 7 32256 From e6a5cead2691f93a8e2c7ae06a92b7052d36852c Mon Sep 17 00:00:00 2001 From: Joseph Bushell Date: Mon, 24 Apr 2023 16:55:28 +0100 Subject: [PATCH 028/145] [script.module.t1mlib] 4.0.8 --- script.module.t1mlib/addon.xml | 4 ++-- script.module.t1mlib/lib/t1mlib.py | 22 +++++++++++----------- script.module.t1mlib/readme.txt | 3 ++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/script.module.t1mlib/addon.xml b/script.module.t1mlib/addon.xml index e0cc02ada..10c209edf 100644 --- a/script.module.t1mlib/addon.xml +++ b/script.module.t1mlib/addon.xml @@ -1,5 +1,5 @@ - + @@ -15,7 +15,7 @@ https://forum.kodi.tv/showthread.php?tid=247163 https://github.com/learningit/repo-scripts> en - v4.0.7 - fix tv listings for live stream addons + v4.0.8 - nexus support resources/icon.png diff --git a/script.module.t1mlib/lib/t1mlib.py b/script.module.t1mlib/lib/t1mlib.py index 038c009c1..a3fd3a625 100644 --- a/script.module.t1mlib/lib/t1mlib.py +++ b/script.module.t1mlib/lib/t1mlib.py @@ -36,8 +36,8 @@ def __init__(self, aname): self.addonName = self.addon.getAddonInfo('name') self.localLang = self.addon.getLocalizedString self.homeDir = self.addon.getAddonInfo('path') - self.addonIcon = xbmc.translatePath(os.path.join(self.homeDir, 'resources', 'icon.png')) - self.addonFanart = xbmc.translatePath(os.path.join(self.homeDir,'resources' 'fanart.jpg')) + self.addonIcon = xbmcvfs.translatePath(os.path.join(self.homeDir, 'resources', 'icon.png')) + self.addonFanart = xbmcvfs.translatePath(os.path.join(self.homeDir,'resources' 'fanart.jpg')) self.defaultHeaders = httpHeaders self.defaultVidStream = {'codec': 'h264', 'width': 1280, 'height': 720, 'aspect': 1.78} self.defaultAudStream = {'codec': 'aac', 'language': 'en'} @@ -175,8 +175,8 @@ def makeLibraryPath(self, ftype, name=None): if name is None: name = self.cleanFilename(xbmc.getInfoLabel('ListItem.Title').replace('(Series)','',1).strip()) profile = self.script.getAddonInfo('profile') - moviesDir = xbmc.translatePath(os.path.join(profile,str(ftype))) - movieDir = xbmc.translatePath(os.path.join(moviesDir, name)) + moviesDir = xbmcvfs.translatePath(os.path.join(profile,str(ftype))) + movieDir = xbmcvfs.translatePath(os.path.join(moviesDir, name)) if not os.path.isdir(movieDir): os.makedirs(movieDir) return movieDir @@ -189,20 +189,20 @@ def doScan(self,movieDir): def addMusicVideoToLibrary(self, url): from xml.etree.ElementTree import Element from xml.etree.ElementTree import tostring - import html.parser + import html from xml.dom import minidom - UNESCAPE = html.parser.HTMLParser().unescape + UNESCAPE = html.unescape url, infoList = urllib.parse.unquote_plus(url).split('||',1) infoList = eval(infoList) artist = infoList.get('artist') title = infoList.get('title') movieDir = self.makeLibraryPath('music_videos', name=self.cleanFilename(artist)) - strmFile = xbmc.translatePath(os.path.join(movieDir, ''.join([self.cleanFilename(title),'.strm']))) + strmFile = xbmcvfs.translatePath(os.path.join(movieDir, ''.join([self.cleanFilename(title),'.strm']))) url = ''.join([sys.argv[0],'?mode=GV&url=',url]) with open(strmFile, 'w') as outfile: outfile.write(url) - nfoFile = xbmc.translatePath(os.path.join(movieDir, ''.join([self.cleanFilename(title),'.nfo']))) + nfoFile = xbmcvfs.translatePath(os.path.join(movieDir, ''.join([self.cleanFilename(title),'.nfo']))) nfoData = Element('musicvideo') for key, val in infoList.items(): child = Element(key) @@ -219,7 +219,7 @@ def addMusicVideoToLibrary(self, url): def addMovieToLibrary(self, url): name = self.cleanFilename(''.join([xbmc.getInfoLabel('ListItem.Title'),'.strm'])) movieDir = self.makeLibraryPath('movies') - strmFile = xbmc.translatePath(os.path.join(movieDir, name)) + strmFile = xbmcvfs.translatePath(os.path.join(movieDir, name)) url = ''.join([sys.argv[0],'?mode=GV&url=',url]) with open(strmFile, 'w') as outfile: outfile.write(url) @@ -238,7 +238,7 @@ def addShowByDate(self,url): title = self.cleanFilename(str(liz.getVideoInfoTag().getTitle())) TVShowTitle = self.cleanFilename(str(liz.getVideoInfoTag().getTVShowTitle())) se = ''.join([TVShowTitle,' ',pdate,' [',title,'].strm']) - strmFile = xbmc.translatePath(os.path.join(movieDir, se)) + strmFile = xbmcvfs.translatePath(os.path.join(movieDir, se)) with open(strmFile, 'w') as outfile: outfile.write(url) self.doScan(movieDir) @@ -253,7 +253,7 @@ def addShowToLibrary(self,url): episode = str(liz.getVideoInfoTag().getEpisode()) title = self.cleanFilename(str(liz.getVideoInfoTag().getTitle())) se = ''.join(['S',season,'E',episode,' ',title,'.strm']) - strmFile = xbmc.translatePath(os.path.join(movieDir, se)) + strmFile = xbmcvfs.translatePath(os.path.join(movieDir, se)) with open(strmFile, 'w') as outfile: outfile.write(url) self.doScan(movieDir) diff --git a/script.module.t1mlib/readme.txt b/script.module.t1mlib/readme.txt index 9d3762a93..a4ae19d82 100644 --- a/script.module.t1mlib/readme.txt +++ b/script.module.t1mlib/readme.txt @@ -5,4 +5,5 @@ Library of support routines for t1m addons V4.0.4 Matrix version - added music video support V4.0.6 - fix for Android file write having a Type Error -v4.0.7 - fix tv listings for live stream addons \ No newline at end of file +v4.0.7 - fix tv listings for live stream addons +v4.0.8 - nexus support \ No newline at end of file From bf55b16aa626cd24845862d4ad44b23b34e82ad7 Mon Sep 17 00:00:00 2001 From: Connor McLeod Date: Tue, 25 Apr 2023 18:32:32 +0100 Subject: [PATCH 029/145] [service.subtitles.legendasdivx] 1.0.6 (#2444) Fix for Nexus --- service.subtitles.legendasdivx/README.md | 4 +- service.subtitles.legendasdivx/addon.xml | 8 +- service.subtitles.legendasdivx/changelog.txt | 83 +++++++++++++++ service.subtitles.legendasdivx/service.py | 100 +++++++++++-------- 4 files changed, 146 insertions(+), 49 deletions(-) create mode 100644 service.subtitles.legendasdivx/changelog.txt diff --git a/service.subtitles.legendasdivx/README.md b/service.subtitles.legendasdivx/README.md index 669f2db0e..d0feb6d77 100644 --- a/service.subtitles.legendasdivx/README.md +++ b/service.subtitles.legendasdivx/README.md @@ -1,4 +1,4 @@ -service.subtitles.legendasdivx +service.subtitles.legendasdivx (v1.0.6) ========================= LegendasDivx.com subtitle service plugin for XBMC 19 Matrix or newer.
@@ -6,4 +6,4 @@ Ported from the Gotham (python2) to Matrix (python3). HiGhLaNdeR -
mail me for bugs \ No newline at end of file +
mail me for bugs diff --git a/service.subtitles.legendasdivx/addon.xml b/service.subtitles.legendasdivx/addon.xml index 377f26fac..683f488cc 100644 --- a/service.subtitles.legendasdivx/addon.xml +++ b/service.subtitles.legendasdivx/addon.xml @@ -1,7 +1,7 @@ @@ -16,9 +16,9 @@ highlander@teknorage.com pt en - - v1.0.5 (2021-12-28) - Regex fix. Login Fix. - - v1.0.4 (2020-4-10) - Initial release. Fixed rar extraction thanks to Alwinus (vfs.rar) and Zach (extraction code). - + v1.0.6 (2023-4-24) - Fix for Nexus. Search speed up by TFOUTO. + v1.0.3 (2020-4-10) - Initial release. Fixed rar extraction thanks to Alwinus (vfs.rar) and Zach (extraction code). +
all icon.png diff --git a/service.subtitles.legendasdivx/changelog.txt b/service.subtitles.legendasdivx/changelog.txt new file mode 100644 index 000000000..2278cb75f --- /dev/null +++ b/service.subtitles.legendasdivx/changelog.txt @@ -0,0 +1,83 @@ +1.0.6 +- Code fix to work in Nexus +- Search speed up by TFOUTO +1.0.3 +- Forget the past and welcome Python3 +- Ported with too much coffee and cigars! +- Matrix Only! +0.2.9 +- Better search results. +0.2.8 +- Android\Linux crash solved. _temp variable not decoded to utf-8 by default. +0.2.7 +- BUGFix when DEBUG is on making the script to crash +0.2.6 +- _newtemp variable without decode utf-8 was causing issues with accents. +- code cleanup +0.2.5 +- RAR download\extraction bug hopefully fixed. +- REQUEST: added uploader to the display. +0.2.4 +- Changes to the new authorization system. +- Changed domain to legendasdivx.pt. +0.2.3 +- Missing endpoints updated. +0.2.2 +- Site changed to ssl enabled (https) +0.2.1 +- TEMP directory should now work properly in every OS variant. +- Code clean up. +0.2.0 +- Reworked search pattern for TVSHOWS removing the year. Now you get results in some shows that were broken! +- Added timeout message in the search URL and site down warning when you can't reach the website. +- No more hangs when downloading, a extraction bug could happen and the script would hang. Now it will open a browse window and you explore the rar file choosing the subtitle you want. +- That's all folks! +0.1.6 +- Reworked subtitle search pattern, faster search results. Found the wierd BUG!!! Awesome... :) +0.1.5 +- Reworked subtitle search pattern, faster search results. Wierd BUG in some movies. +0.1.4 +- Bug on the regex prevents ID to be fetch properly, fixed with a workaround (string.split). +0.1.3 +- Bug when the movie is in the movie library and was using filename instead. +- Added year for better searching when the movie is in the library. (Example: Sin City) +- Changes in DEBUG MODE description within the code +0.1.2 +- Release pattern tweak for releases with a "slash" in-between words. +- Added Debug Mode in configurations for better help to failures (Mafarricos) +- Code cleanup (Mafarricos) +0.1.1 +- Added a last resort option to search for filename or title, configure in advanced options of the add-on. +0.1.0 +- Fix the decoding BUG in Raspberry Pi (Linux and Windows have different behaviours). +- New pattern for the last resort search to check if it's a movie or tvshow. +0.0.9 +- Account verification added. +0.0.8 +- Fixed more Unicode issues. +0.0.7 +- Fixed a bug that prevents searching all chosen subtitle languages. +- Improved search algorithm for library TVSHOWS and MOVIES. +- Added Portuguese (Brazil) missing strings.xml. +0.0.6 +- Added new pattern to find releases with spaces instead of dots (please start using dots in the release description). +- If there's no match with the patterns when searching for releases it will put the full description. +- Fix unicode issue when searching and the interface was set to Portuguese. +- Last resort search will always be by title if filename and parent folder fails. +0.0.5 +- Improved SYNC matching REGEX. +- Fixed a missing string in all languages. +0.0.4 +- Added Parent Folder search and sync matching. Choose in addon settings AUTO or OFF. AUTO checks if parent folder is a release and if true it will be used for search and sync. +- Reviewed Release pattern for better Description display. +- Improved SYNC matching. +0.0.3 +- Added Release pattern for better Description display. Now you can choose Full Description or Release only Description (Default) on addon settings! +- Some fixes and changes on the code. +0.0.2 +- Improved search code, we always depend on the site search... +- Manual search fully working. +- Improved scrapping on the description. +- Improved Sync results. +0.0.1 +- Initial port to new Gotham structure. diff --git a/service.subtitles.legendasdivx/service.py b/service.subtitles.legendasdivx/service.py index 601c53486..f3659cdf9 100644 --- a/service.subtitles.legendasdivx/service.py +++ b/service.subtitles.legendasdivx/service.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Service LegendasDivx.com version 1.0.5 +# Service LegendasDivx.com version 1.0.6 # Code based on Undertext (FRODO) service # Coded by HiGhLaNdR@OLDSCHOOL # Ported to Gotham by HiGhLaNdR@OLDSCHOOL @@ -10,7 +10,6 @@ import os from os.path import join as pjoin -import re import fnmatch import shutil import sys @@ -27,6 +26,13 @@ import uuid import socket from urllib.parse import unquote, quote_plus +import http.cookiejar +import urllib.error +import urllib.parse +import urllib.request +import socket +import re + _addon = xbmcaddon.Addon() _author = _addon.getAddonInfo('author') @@ -36,10 +42,10 @@ _language = _addon.getLocalizedString _dialog = xbmcgui.Dialog() -_cwd = xbmc.translatePath(_addon.getAddonInfo('path')) -_profile = xbmc.translatePath(_addon.getAddonInfo('profile')) -_resource = xbmc.translatePath(os.path.join(_cwd, 'resources', 'lib' )) -_temp = xbmc.translatePath(os.path.join(_profile, 'temp')) +_cwd = xbmcvfs.translatePath(_addon.getAddonInfo('path')) +_profile = xbmcvfs.translatePath(_addon.getAddonInfo('profile')) +_resource = xbmcvfs.translatePath(os.path.join(_cwd, 'resources', 'lib' )) +_temp = xbmcvfs.translatePath(os.path.join(_profile, 'temp')) if os.path.isdir(_temp):shutil.rmtree(_temp) xbmcvfs.mkdirs(_temp) @@ -116,37 +122,34 @@ def _log(module, msg): def log(msg): if debug == 'true': _log(_scriptname, msg) -def recursive_glob(treeroot, pattern): +def recursive_glob(treeroot, extensions): + extensions = set(extensions) results = [] for base, dirs, files in os.walk(treeroot): - for extension in pattern: - for filename in fnmatch.filter(files, '*.' + extension): results.append(os.path.join(base, filename)) + for filename in files: + _, ext = os.path.splitext(filename) + if ext.lower() in extensions: + results.append(os.path.join(base, filename)) return results def xbmc_extract(SRC, DEST): dd_ext, ff_ext = xbmcvfs.listdir(SRC) + ff_ext = (ff for ff in ff_ext if os.path.splitext(ff)[1][1:].lower() in SUB_EXTS) + dest_path = xbmcvfs.translatePath(DEST) for ff in ff_ext: - ext = os.path.splitext(ff)[1][1:].lower() - if ext in SUB_EXTS: - src_file = pjoin(SRC,ff).replace('\\','/') - dst_file = pjoin(xbmc.translatePath(DEST),ff) - success = xbmcvfs.copy(src_file,dst_file) - if not success: - log("Error extracting: '%s' to '%s'" % (src_file,dst_file)) - else: - log("Extracting: '%s' to '%s'" % (src_file,dst_file)) + src_file = os.path.join(SRC, ff) + dst_file = os.path.join(dest_path, ff) + success = xbmcvfs.copy(src_file,dst_file) + if not success: + log("Error extracting: '%s' to '%s'" % (src_file,dst_file)) else: - log("NO FILES YET...") + log("Extracting: '%s' to '%s'" % (src_file,dst_file)) for dd in dd_ext: - dd_mk = pjoin(DEST,dd).replace('\\','/') - success_mk = xbmcvfs.mkdir(dd_mk) - if not success_mk: - log("Error creating directory: '%s'" % dd_mk) - else: - log("Created directory: '%s'" % dd_mk) - now_SRC = pjoin(SRC,dd,'').replace('\\','/') - now_DEST = pjoin(DEST,dd) - success_dd = xbmc_extract(now_SRC,now_DEST) + dd_mk = os.path.join(DEST, dd) + os.makedirs(dd_mk, exist_ok=True) + now_SRC = os.path.join(SRC, dd, '') + now_DEST = os.path.join(DEST, dd) + success_dd = xbmc_extract(now_SRC, now_DEST) if not success_dd: log("Error extracting inside dir: '%s' to '%s'" % (now_SRC,now_DEST)) else: @@ -164,14 +167,10 @@ def login(): return my_opener def urlpost(query, lang, page): - - my_opener=login() - - postdata = urllib.parse.urlencode({'query' : query, 'form_cat' : lang}).encode("utf-8") - - my_opener.addheaders = [('Referer', main_url + 'modules.php?name=Downloads&file=jz&d_op=search&op=_jz00&page='+ str(page))] - urllib.request.install_opener(my_opener) - request = urllib.request.Request(main_url + 'modules.php?name=Downloads&file=jz&d_op=search&op=_jz00&page='+ str(page), postdata) + my_opener = login() + postdata = urllib.parse.urlencode({'query': query, 'form_cat': lang}).encode("utf-8") + headers = {'Referer': main_url + 'modules.php?name=Downloads&file=jz&d_op=search&op=_jz00&page=' + str(page)} + request = urllib.request.Request(main_url + 'modules.php?name=Downloads&file=jz&d_op=search&op=_jz00&page=' + str(page), data=postdata, headers=headers) log("POST url page: %s" % page) log("POST url data: %s" % postdata) try: @@ -192,6 +191,7 @@ def getallsubs(searchstring, languageshort, languagelong, file_original_path, se log("getallsubs: Search String = '%s'" % searchstring) log("getallsubs: Search String Not Clean = '%s'" % searchstring_notclean) page = 1 + listsResult = 0 if languageshort == "pt": content = urlpost(searchstring, "28", page) elif languageshort == "pb": content = urlpost(searchstring, "29", page) elif languageshort == "es": content = urlpost(searchstring, "30", page) @@ -273,13 +273,21 @@ def getallsubs(searchstring, languageshort, languagelong, file_original_path, se else: filename = "From: " + uploader + " - " + filename + " " + "(" + movieyear + ")" + " " + "hits: " + hits + " - " + desc subtitles_list.append({'rating': str(downloads), 'filename': filename, 'uploader': uploader, 'desc': desc, 'sync': sync, 'hits' : hits, 'id': id, 'language_short': languageshort, 'language_name': languagelong}) log("getallsubs: SUBS LIST = '%s'" % subtitles_list) - page = page + 1 + listsResult = listsResult + 1 - if languageshort == "pt": content = urlpost(searchstring, "28", page) - elif languageshort == "pb": content = urlpost(searchstring, "29", page) - elif languageshort == "es": content = urlpost(searchstring, "30", page) - elif languageshort == "en": content = urlpost(searchstring, "31", page) - + + page = page + 1 + if listsResult == 5 and page < 6: + + if languageshort == "pt": content = urlpost(searchstring, "28", page) + elif languageshort == "pb": content = urlpost(searchstring, "29", page) + elif languageshort == "es": content = urlpost(searchstring, "30", page) + elif languageshort == "en": content = urlpost(searchstring, "31", page) + listsResult = 0 + + else: + page = 6 + # Bubble sort, to put syncs on top for n in range(0,len(subtitles_list)): for i in range(1, len(subtitles_list)): @@ -287,6 +295,7 @@ def getallsubs(searchstring, languageshort, languagelong, file_original_path, se if subtitles_list[i]["sync"] > subtitles_list[i-1]["sync"]: subtitles_list[i] = subtitles_list[i-1] subtitles_list[i-1] = temp + return subtitles_list def append_subtitle(item): @@ -351,6 +360,10 @@ def Search(item): israr = str.split(israr[-1], '.') israr = str.lower(israr[-1]) + ''' + imdb = xbmc.Player().getVideoInfoTag().getIMDBNumber() + log("imdb: = %s" % imdb) + ''' title = xbmc.getCleanMovieTitle(item['title'])[0] year = item['year'] @@ -431,6 +444,7 @@ def Search(item): if 'por' in item['languages'] and PT_ON == 'true': subtitles_list = getallsubs(searchstring, "pt", "Portuguese", file_original_path, searchstring_notclean) for sub in subtitles_list: append_subtitle(sub) + #if 'por' in item['languages'] and PTBR_ON == 'true' and len(subtitles_list) == 0: if 'por' in item['languages'] and PTBR_ON == 'true': subtitles_list = getallsubs(searchstring, "pb", "Brazilian", file_original_path, searchstring_notclean) for sub in subtitles_list: append_subtitle(sub) @@ -452,7 +466,7 @@ def Download(id, filename): if not os.path.isdir(_temp):xbmcvfs.mkdir(_temp) unpacked = 'ldivx-' + str(uuid.uuid4()).replace("-","")[0:6] xbmcvfs.mkdirs(pjoin(_temp,unpacked,'')) - _newtemp = os.path.join(_temp, xbmc.translatePath(unpacked).replace('\\','/')) + _newtemp = os.path.join(_temp, xbmcvfs.translatePath(unpacked).replace('\\','/')) subtitles_list = [] my_opener = login() From abfe5e3f0de4c65f5de1fdcaed4a257a740366a6 Mon Sep 17 00:00:00 2001 From: JavaWiz1 Date: Tue, 25 Apr 2023 13:33:00 -0400 Subject: [PATCH 030/145] [script.module.google-auth-library] 2.14.1 (#2361) --- script.module.google-auth-library/LICENSE.txt | 201 ++++ script.module.google-auth-library/README.rst | 81 ++ script.module.google-auth-library/addon.xml | 22 + script.module.google-auth-library/icon.png | Bin 0 -> 7237 bytes .../lib/google/__init__.py | 24 + .../lib/google/auth/__init__.py | 29 + .../lib/google/auth/_cloud_sdk.py | 159 ++++ .../lib/google/auth/_credentials_async.py | 176 ++++ .../lib/google/auth/_default.py | 653 +++++++++++++ .../lib/google/auth/_default_async.py | 284 ++++++ .../lib/google/auth/_exponential_backoff.py | 111 +++ .../lib/google/auth/_helpers.py | 245 +++++ .../lib/google/auth/_jwt_async.py | 164 ++++ .../lib/google/auth/_oauth2client.py | 169 ++++ .../lib/google/auth/_service_account_info.py | 81 ++ .../lib/google/auth/api_key.py | 75 ++ .../lib/google/auth/app_engine.py | 179 ++++ .../lib/google/auth/aws.py | 767 ++++++++++++++++ .../google/auth/compute_engine/__init__.py | 21 + .../google/auth/compute_engine/_metadata.py | 267 ++++++ .../google/auth/compute_engine/credentials.py | 438 +++++++++ .../lib/google/auth/credentials.py | 384 ++++++++ .../lib/google/auth/crypt/__init__.py | 100 ++ .../google/auth/crypt/_cryptography_rsa.py | 136 +++ .../lib/google/auth/crypt/_helpers.py | 0 .../lib/google/auth/crypt/_python_rsa.py | 173 ++++ .../lib/google/auth/crypt/base.py | 131 +++ .../lib/google/auth/crypt/es256.py | 160 ++++ .../lib/google/auth/crypt/rsa.py | 30 + .../lib/google/auth/downscoped.py | 501 ++++++++++ .../lib/google/auth/environment_vars.py | 84 ++ .../lib/google/auth/exceptions.py | 76 ++ .../lib/google/auth/external_account.py | 537 +++++++++++ .../auth/external_account_authorized_user.py | 343 +++++++ .../lib/google/auth/iam.py | 100 ++ .../lib/google/auth/identity_pool.py | 249 +++++ .../google/auth/impersonated_credentials.py | 439 +++++++++ .../lib/google/auth/jwt.py | 868 ++++++++++++++++++ .../lib/google/auth/pluggable.py | 412 +++++++++ .../lib/google/auth/py.typed | 2 + .../lib/google/auth/transport/__init__.py | 109 +++ .../auth/transport/_aiohttp_requests.py | 391 ++++++++ .../auth/transport/_custom_tls_signer.py | 235 +++++ .../lib/google/auth/transport/_http_client.py | 115 +++ .../lib/google/auth/transport/_mtls_helper.py | 254 +++++ .../lib/google/auth/transport/grpc.py | 349 +++++++ .../lib/google/auth/transport/mtls.py | 105 +++ .../lib/google/auth/transport/requests.py | 611 ++++++++++++ .../lib/google/auth/transport/urllib3.py | 442 +++++++++ .../lib/google/auth/version.py | 15 + .../lib/google/oauth2/__init__.py | 15 + .../lib/google/oauth2/_client.py | 438 +++++++++ .../lib/google/oauth2/_client_async.py | 294 ++++++ .../lib/google/oauth2/_credentials_async.py | 112 +++ .../lib/google/oauth2/_id_token_async.py | 287 ++++++ .../lib/google/oauth2/_reauth_async.py | 330 +++++++ .../google/oauth2/_service_account_async.py | 132 +++ .../lib/google/oauth2/challenges.py | 183 ++++ .../lib/google/oauth2/credentials.py | 507 ++++++++++ .../lib/google/oauth2/gdch_credentials.py | 251 +++++ .../lib/google/oauth2/id_token.py | 341 +++++++ .../lib/google/oauth2/py.typed | 2 + .../lib/google/oauth2/reauth.py | 352 +++++++ .../lib/google/oauth2/service_account.py | 721 +++++++++++++++ .../lib/google/oauth2/sts.py | 177 ++++ .../lib/google/oauth2/utils.py | 171 ++++ 66 files changed, 15810 insertions(+) create mode 100644 script.module.google-auth-library/LICENSE.txt create mode 100644 script.module.google-auth-library/README.rst create mode 100644 script.module.google-auth-library/addon.xml create mode 100644 script.module.google-auth-library/icon.png create mode 100644 script.module.google-auth-library/lib/google/__init__.py create mode 100644 script.module.google-auth-library/lib/google/auth/__init__.py create mode 100644 script.module.google-auth-library/lib/google/auth/_cloud_sdk.py create mode 100644 script.module.google-auth-library/lib/google/auth/_credentials_async.py create mode 100644 script.module.google-auth-library/lib/google/auth/_default.py create mode 100644 script.module.google-auth-library/lib/google/auth/_default_async.py create mode 100644 script.module.google-auth-library/lib/google/auth/_exponential_backoff.py create mode 100644 script.module.google-auth-library/lib/google/auth/_helpers.py create mode 100644 script.module.google-auth-library/lib/google/auth/_jwt_async.py create mode 100644 script.module.google-auth-library/lib/google/auth/_oauth2client.py create mode 100644 script.module.google-auth-library/lib/google/auth/_service_account_info.py create mode 100644 script.module.google-auth-library/lib/google/auth/api_key.py create mode 100644 script.module.google-auth-library/lib/google/auth/app_engine.py create mode 100644 script.module.google-auth-library/lib/google/auth/aws.py create mode 100644 script.module.google-auth-library/lib/google/auth/compute_engine/__init__.py create mode 100644 script.module.google-auth-library/lib/google/auth/compute_engine/_metadata.py create mode 100644 script.module.google-auth-library/lib/google/auth/compute_engine/credentials.py create mode 100644 script.module.google-auth-library/lib/google/auth/credentials.py create mode 100644 script.module.google-auth-library/lib/google/auth/crypt/__init__.py create mode 100644 script.module.google-auth-library/lib/google/auth/crypt/_cryptography_rsa.py create mode 100644 script.module.google-auth-library/lib/google/auth/crypt/_helpers.py create mode 100644 script.module.google-auth-library/lib/google/auth/crypt/_python_rsa.py create mode 100644 script.module.google-auth-library/lib/google/auth/crypt/base.py create mode 100644 script.module.google-auth-library/lib/google/auth/crypt/es256.py create mode 100644 script.module.google-auth-library/lib/google/auth/crypt/rsa.py create mode 100644 script.module.google-auth-library/lib/google/auth/downscoped.py create mode 100644 script.module.google-auth-library/lib/google/auth/environment_vars.py create mode 100644 script.module.google-auth-library/lib/google/auth/exceptions.py create mode 100644 script.module.google-auth-library/lib/google/auth/external_account.py create mode 100644 script.module.google-auth-library/lib/google/auth/external_account_authorized_user.py create mode 100644 script.module.google-auth-library/lib/google/auth/iam.py create mode 100644 script.module.google-auth-library/lib/google/auth/identity_pool.py create mode 100644 script.module.google-auth-library/lib/google/auth/impersonated_credentials.py create mode 100644 script.module.google-auth-library/lib/google/auth/jwt.py create mode 100644 script.module.google-auth-library/lib/google/auth/pluggable.py create mode 100644 script.module.google-auth-library/lib/google/auth/py.typed create mode 100644 script.module.google-auth-library/lib/google/auth/transport/__init__.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/_aiohttp_requests.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/_custom_tls_signer.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/_http_client.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/_mtls_helper.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/grpc.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/mtls.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/requests.py create mode 100644 script.module.google-auth-library/lib/google/auth/transport/urllib3.py create mode 100644 script.module.google-auth-library/lib/google/auth/version.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/__init__.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/_client.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/_client_async.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/_credentials_async.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/_id_token_async.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/_reauth_async.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/_service_account_async.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/challenges.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/credentials.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/gdch_credentials.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/id_token.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/py.typed create mode 100644 script.module.google-auth-library/lib/google/oauth2/reauth.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/service_account.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/sts.py create mode 100644 script.module.google-auth-library/lib/google/oauth2/utils.py diff --git a/script.module.google-auth-library/LICENSE.txt b/script.module.google-auth-library/LICENSE.txt new file mode 100644 index 000000000..f49a4e16e --- /dev/null +++ b/script.module.google-auth-library/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/script.module.google-auth-library/README.rst b/script.module.google-auth-library/README.rst new file mode 100644 index 000000000..4f9fd3554 --- /dev/null +++ b/script.module.google-auth-library/README.rst @@ -0,0 +1,81 @@ +script.module.google-auth-libarary-python +========================================= + +Google Auth Python Library +========================== + +|pypi| + +This library simplifies using Google's various server-to-server authentication +mechanisms to access Google APIs. + +.. |pypi| image:: https://img.shields.io/pypi/v/google-auth.svg + :target: https://pypi.python.org/pypi/google-auth + +Installing +---------- + +You can install using `pip`_:: + + $ pip install google-auth + +.. _pip: https://pip.pypa.io/en/stable/ + +For more information on setting up your Python development environment, please refer to `Python Development Environment Setup Guide`_ for Google Cloud Platform. + +.. _`Python Development Environment Setup Guide`: https://cloud.google.com/python/setup + +Extras +------ + +google-auth has few extras that you can install. For example:: + + $ pip install google-auth[pyopenssl] + +Note that the extras pyopenssl and enterprise_cert should not be used together because they use conflicting versions of `cryptography`_. + +.. _`cryptography`: https://cryptography.io/en/latest/ + +Supported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^ +Python >= 3.6 + +Unsupported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Python == 2.7: The last version of this library with support for Python 2.7 + was `google.auth == 1.34.0`. + +- Python 3.5: The last version of this library with support for Python 3.5 + was `google.auth == 1.23.0`. + +Documentation +------------- + +Google Auth Python Library has usage and reference documentation at https://googleapis.dev/python/google-auth/latest/index.html. + +Current Maintainers +------------------- +- `@busunkim96 `_ (Bu Sun Kim) + +Authors +------- + +- `@theacodes `_ (Thea Flowers) +- `@dhermes `_ (Danny Hermes) +- `@lukesneeringer `_ (Luke Sneeringer) + +Contributing +------------ + +Contributions to this library are always welcome and highly encouraged. + +See `CONTRIBUTING.rst`_ for more information on how to get started. + +.. _CONTRIBUTING.rst: https://github.com/googleapis/google-auth-library-python/blob/main/CONTRIBUTING.rst + +License +------- + +Apache 2.0 - See `the LICENSE`_ for more information. + +.. _the LICENSE: https://github.com/googleapis/google-auth-library-python/blob/main/LICENSE \ No newline at end of file diff --git a/script.module.google-auth-library/addon.xml b/script.module.google-auth-library/addon.xml new file mode 100644 index 000000000..3fe2a0d05 --- /dev/null +++ b/script.module.google-auth-library/addon.xml @@ -0,0 +1,22 @@ + + + + + + + + + This library simplifies using Google's various server-to-server authentication mechanisms to access Google APIs. + Packed for KODI from https://github.com/googleapis/google-auth-library-python + all + Apache 2.0 + https://github.com/googleapis/google-auth-library-python + + icon.png + + + diff --git a/script.module.google-auth-library/icon.png b/script.module.google-auth-library/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ca4c53adbfa8d06d0e282d45f9cad195e89d571e GIT binary patch literal 7237 zcmd6segn*PtcXta6B_iEY!_ZO!(hW*?NtZN|0+Q0*Idt6f zyPh}Ce{kQg_FmUH=epM3d#&~T?6X2um1UkhCVvb7z!N!HNp%1Kp{F1K8;l;tp(32< z;kk>Hu8W5K2N!n}CksH#+}_lJM$Xp6(n8(B#N5NN-{KtrP;AOcifMkH-81xZAku0) zJm@Fp#L>;2G$No%IAG+yoYp5GaFu%IUu+;swO88s1zP{pU;HSjZs%mSWk-t&_g@Ho ziEeH*(#E3>d+FdhBsqGE-7A^C1iw#lrA#WCUbnyt#(}cSyFtw7-zZ)*e;ZV!;=a29 zNvMo$PYqt&P;I6i3a&&XS3`gb7`- zv`0p^b-1;)MNL*O`QZBg`Z~2-O6{8@DySvw3zXooW6z-8C5dSQ;;G)FJNM2feEjLd zx3|rD)gR_v#+4k6R(Adtml_@39JU-R9bjWzy^THoA^I+voLSQK=;gxxv4pq1MZl+rfr(Ml0Vruz#l?pv_XVq#QTaK(c^5Me4-ZdI&yGWrnX0PAhx@y>dz3GRnFG*< zYl`Fy+VJgzX_ven;FEj6T&?FSBnn?11$Z5_-lSNU$-TqJSibGu zoT2eUntS50sOvoa84cbSIQicb75taglNv+5r1c8#NYx=&9}CZ2t$7j^JseA;(v z()sgS*PHN?KGWXruYc+jezzPsvjVzEPEhLLBP75pwe_xcrfz7`QwGJ!HK`&Ycx>ng z)V4=aBR=;GKHph7%DPVE-D2DC;tL>aCy`ZAd6+rhZ>ETI5s`cN=n?>?Y42KZ7r9+y z>QFgSYR8cG$l9cYRMZ^>fE@hPN!9XZDp>ee+3&*~xxX_@XA%WEnnK~`P9lM4DsjhC zqUys?TDw6~Frg?iTPidBGrbs}K66yr`+fpsd`!ge6C3}!1y7hVVf&#rQHQYz4XU{V z!ViEYN#qqgy{7%2%8!Elxs138BGO)T*B3kR(H8ki(v@dO`78n0Q0eO#h>G6OVZ7yF z8mIk2^9=ixE@M-d!<0SaM+n0HMIp4oQlaqVfGuA6~$k_n%8)9A?C1k3- zaw~RyQBhH4r5aJ-{#;!wE>R+eL&I4KA4TWn70}NEnVg;V+!|dDrzEwy>1WFHbolfA zawIu9nezz6=c!%E=KLs{AQ^JZ9*U5VFe{F^)~zksE6mSO?CW=SPT#ygV_M*ZOFTsa zp)wj8gjZXXl$7);M&(hZ7DYZ>-p5=;iexCp2@zVBy+L$!VK=B{jWGnBQ{iEP2ryk; zUv~%|;^E;PX_d_Ax0dkB;f)oNy{Czbj~8liTs_+!C-h!Cr@}?Q8-Poyf3bIk5!#x! zFU5EwolL-h8ABiH{?>5qhvf%zA|euY7%ZH74MP<9M_fWe0v)l6{jnKFnwpxrx=C+N zUikx}X=BE&$gYBlEQgB&!%%lMX~SDvL+b9yRiLPspnTIgyQnCPce2FjZX;DDR_QvZ ztc;!g?mWk@6vu(H6-B|aQ(97@Ibn3gR9A>{`-V>rf(VlKSMh+#j9SP?mfP<356g`1 zR?0d$BvHSkIMLb0^Q+Dk3O56P=^!=kl0h!sX+z`Yo7|bUNtaNb7!nTw052f|#YC!w z^M#ly$}-CrK2v2Ow|S9Dm5qZT&R`JM+WO~@Bg^?w-OqTNzVG~bt5Jd}Den}YVe_&R ze3HR!53y>y-`M^7m27qCYdGba5WTtdY<*UKe(%&|PupW%z-vtOQ>6ZTk)366^>8J_ z^i;Ogm(vvAB6E%J?plP6Z7e_9q8ND|eNvf_uhn^QbN7>!d+UDi-lo$;j_qxFdiv1N z(0BS@7*!~KfKE)q*;x?_w|_1G(OgS%k8cY2G&=1c&yuZ+SgC0k4*e9th8u5N5?!7Q zaG-UmdZe0K#At46YJ?Twhr5%?jybGt#oX63^)O(d6~gV{->(ev9cuRI58xMLe2d;U zhd1Yu6Ik-nOk3-eg4fqrTQS-9CLlaIQ6dNa*;$dR_2TlcuQ6r0whK#3g&tToS8$4#yjUJv2?a{0uKU$XiT zGrP8tn~ndK=EKP6Vtd(^oaD;QWIs0od5y9S1LcHss7Yx2DYJB1#8XV;)^L~*HXMHf zXCp`Et3qW7Vz*vG^xue3fsLW?FQ419enoH4zAV)Ay&5oH5x6~{JB$wIOZQ7H1UfIXT` zv@tWsIQ@HE-hJ*9PX)o_p?2^zc|EW45jxNFhfi;(FUM(~$ku zEAr~y`+<$2d=zKhZ;g= z{Io*u4`ikN=CI9ufUVBl(lTm{7_E^~Qr*eizLG{9rbrwjye+x7Pl_e9A|g>;H5FMj zemcjVEg{9lDjDyj#7EwUxS-Fik{?d%|Jc$_SxycI1M`?H5WS?v#zsOW<;&SwhESMK z+!+YONQDJfgm-FRFU6+4hY8h?5R!pcyek?OtJt&>=xYVU}OycPwp?x{g)7b8qwnbpx^XKNd$H?u7(4H zYPA@LscF#)4K}#uo*7&%Mp&u_HZ8Iv??+uf$OrnvK0L!uUjqK1g)$M7gbPotx$BH2 zkP0G8$@n^cB>YqI<3XJ0&(L=EO0o9SWx9T-C$ydM`v_iQsP2T_X793A`f(ZjO}PKVA)tH<}lf1OxXsZ(9BSu$PuQ^VN3yV zQ@{QdPVN+z*X#!d5p1uIWQzFy^2Z`!*FEa=+N{*FOcGEn(ZY)l)t?yUdT+TWw?DRH z#TzqRaYJ|#E`4;uGDsZxlQ%BsDxv1)>2=REnNg8)udIScL)3|9iRT*Ixh#^1;QjG8shTJ$uPc#8mh-7>;j3$JyDCuIbInV4&@1>;9G0vj4DnFfhF=Rf60K%A?T>63)VD7mGsjsiq{ z&Xz-{eb1J!qC`Azk6i=qe=&rUqHV0gSyxzY&KWM~&xQ3j5q|!UFOlbNs%HL!#F;Mw zp_R2^W%2L)P4_or*j9))=zlfG-Q7pSU?xd6d5-lGrb}&hcsyYX&LjBSf7er#%8Rwj z6jf9fD@=T#`^#VkKe_>550d!C_w4!O{i&7R67GBd{w^+-GY5N271EHBlG^LG-DijR zzR+}jskw;t_QnDRnlQ}>qZ!zn2>S~ZPz4(sn5p2o$>F(65R}m2yj8O>)PEH65x2G~ z?zy_<^;=)Ym83??fLrQ;pVPvhrsk%4=g!X0CpC4vS{C;9_B8h!m41=6k3QTtH#a95 zd$QQ5)9$mfu^HAon4tOJ;D+fRrE#Onb}&k%LV~C>2LCa^*2Ee?MVUa4$Ut48QuJ(&7u`%Im#e&#l$4d+b{tExzdlZJU5cv4{Gvz}W;*5tp434muPyl> zr{xaX$qdRBw<)cuiJH1PSXcmk@?yRniMaq1UkFvT=z#nx-{|<<+}iP|-_Q`73#dQ4 zjF%-z16o5>qGRM?u{oTMPTTOXF!i5;Z~hXP>Kd^>zw$*KG-wrTllzZp7#JAnY#!|G z3=aQh)Tr=u6^M1ZE~u#~xsm7Ft*~lw$jIC|7d(K&6u2v23lguU>dqjAeoll8yZsH4f?eB zT&IksFvY~gi1nm1Y^w)^MN()H7cg%GmD@MnJq-z_0Vk;-QfpNU%N*|zi2CvEZxJgD zdp%ps%1FM2&t^j@JTV#m{HmHY1-@`(ppx1=^Hr{|SInN)nI%)O{d}X+SP8Hj&Cop} zOiP_tdmcEoiMsM0esAe<^~(75<@S`X|mp+V!G@-8heL+leWD zexfZBx5x~unqHi0L)-h&x#2?c(lcXl-%P4wALtd-IYXR{fdAmebbgO9Jx|Jr%K+cPv>y zlAdStx)jASsc6K8+B6)<+mtS zoAv|zz`_16O$RLra~x;?)q5s`uf^s z)q>gSyu7qDQrKeXxBP&AM!@cgs2rP+c0zFHc3gS8MMz-Ml0R<5Q=C>&{%p$({1E`x zd;8n+SG_d6!omg?=IG_0H9I^1{yFF=CVyC5;K9yfXCu^i4iXWh3y}89+xP&g*tJo0 z#3mNPG)i7JPs-(%gu%R_KkDjwZ8|=$4K27n&$E%ehvkJo88^!1-Af`U#E<;irt_ij zjAVXlR4}|G88euL(96?H=0yd~vmssx_8`vsoo5924{VBDV>SNe+u-1NYGQ4e0o~RY z_2(^R1tfi6-{@mK+FJ%E!`$>SJ&A&%zMY?)CH+2!;05KDq*{%czxfRzBWZjt=<;mJ zQukDl0AjAw0mhR8d?x93Y48;@<17|>SB^iQHKzT7L|^5Y2;92JGJuIc59nfOHc`8B z!k=JZ1o;s(`8}Z6^3^`oRabMb2>^lw?QeK8hwe}}S7~tDIb*d-Kb7vn;$qzW!_?GF zj$Nz)gwIMPuaCYqt?MHUc6(?@rOcN|obT;8=zLX;S#JkJ^189N;yGS=pYQ3RaS<-o zGMAp2$XCDw!sEh>cCi0fA7ed4$fWY=F4QjuB(ANUkfH=lk`w9sdY;PFHn=l87!Wat zXJ@Io%6TFV)xU_=-E=!8ga7i!K=>|wHD5Khv$KQOx9^i+JYxhP*ht#>l$4#F&X5Fl z!<5+A*z(~RL_=O)FyC~gSxAmj3q9s2?_!(lZo+ND6}_qNL;B&`kXlS4pJnGYDt~u= zd7|x;uxI2#k`_#7+lsldQQQA3w6nY0R8=IB{%_N+0F(Q{znIk6AAcNFgKFbrGL&xw zVhdY7rdJ4*SkLg&)(-HC`UQ{PrPkS~CBAT#&Eb(#naZ>)C@r;!9qAK$Yq}!mq7y!p zQCL=Ha-~7Rr){n>BCO`+?^b&?>v`kJ#vbju@qRk}JFj$>?AXST!I#!O#Fu`X`?Qf= z=fQ>rSJq{1hFTMH!tqHRYyS0DqSbDY3=4~ z(}}K%w2Eodqi;_{^K&dfxP?3IAg45W1qFz!wzyTYbWTUp!P9gWqJ@3V{i(dzqE+o7 zwxOE~ohozS8!GajYqkHZs)8p8XH8zG>QvQfmgo*)R`Jd6;dH^|cY2y7yyOVRJ_a?Yl(1Gn^WUr#a5tMY;dULQokoa)BsUoiRNbr_mZ3%Q6VTTX>30 zW^;zVqobpeE6=Wb{#Nz2JF{j4Uj-uJ|?DRHZx?PF}Q+T6adf-kHGr* zef{Ci*`L{umUbu0(nTKb7Zw)GdJ(9dUjZ8uPEJnK`87)W#zL3mEh!YE zG84!YS66pxuTxzYj)$e?+q^Cg z=Fk2)(|@9OKu=#L8#NsqCnPvqPYFw_e@y5zv!~L+sXlPLo|~JKAsFmy&-Fdb5Hd8J zKVwOE?*G;;z&Mh@PP(==j#HgyA@vRM)vbDNDPD@ym# zEH7UcHWY8I<|9dALeYiExV45XC8olq z#l!|8@RPFp1_vwT&4b}ZL4zgZp9yy;pxF^eyh1>!#P4E|I-_Qd;h}3q7~T6nP;Iv zJwh0pvN_aX?N=S+YzV?*Bh?dwz-l literal 0 HcmV?d00001 diff --git a/script.module.google-auth-library/lib/google/__init__.py b/script.module.google-auth-library/lib/google/__init__.py new file mode 100644 index 000000000..70a7bd995 --- /dev/null +++ b/script.module.google-auth-library/lib/google/__init__.py @@ -0,0 +1,24 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google namespace package.""" + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) # type: ignore diff --git a/script.module.google-auth-library/lib/google/auth/__init__.py b/script.module.google-auth-library/lib/google/auth/__init__.py new file mode 100644 index 000000000..861abe7ea --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/__init__.py @@ -0,0 +1,29 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Auth Library for Python.""" + +import logging + +from google.auth import version as google_auth_version +from google.auth._default import default, load_credentials_from_file + + +__version__ = google_auth_version.__version__ + + +__all__ = ["default", "load_credentials_from_file"] + +# Set default logging handler to avoid "No handler found" warnings. +logging.getLogger(__name__).addHandler(logging.NullHandler()) diff --git a/script.module.google-auth-library/lib/google/auth/_cloud_sdk.py b/script.module.google-auth-library/lib/google/auth/_cloud_sdk.py new file mode 100644 index 000000000..40e6aec13 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_cloud_sdk.py @@ -0,0 +1,159 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for reading the Google Cloud SDK's configuration.""" + +import json +import os +import subprocess + +import six + +from google.auth import environment_vars +from google.auth import exceptions + + +# The ~/.config subdirectory containing gcloud credentials. +_CONFIG_DIRECTORY = "gcloud" +# Windows systems store config at %APPDATA%\gcloud +_WINDOWS_CONFIG_ROOT_ENV_VAR = "APPDATA" +# The name of the file in the Cloud SDK config that contains default +# credentials. +_CREDENTIALS_FILENAME = "application_default_credentials.json" +# The name of the Cloud SDK shell script +_CLOUD_SDK_POSIX_COMMAND = "gcloud" +_CLOUD_SDK_WINDOWS_COMMAND = "gcloud.cmd" +# The command to get the Cloud SDK configuration +_CLOUD_SDK_CONFIG_COMMAND = ("config", "config-helper", "--format", "json") +# The command to get google user access token +_CLOUD_SDK_USER_ACCESS_TOKEN_COMMAND = ("auth", "print-access-token") +# Cloud SDK's application-default client ID +CLOUD_SDK_CLIENT_ID = ( + "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com" +) + + +def get_config_path(): + """Returns the absolute path the the Cloud SDK's configuration directory. + + Returns: + str: The Cloud SDK config path. + """ + # If the path is explicitly set, return that. + try: + return os.environ[environment_vars.CLOUD_SDK_CONFIG_DIR] + except KeyError: + pass + + # Non-windows systems store this at ~/.config/gcloud + if os.name != "nt": + return os.path.join(os.path.expanduser("~"), ".config", _CONFIG_DIRECTORY) + # Windows systems store config at %APPDATA%\gcloud + else: + try: + return os.path.join( + os.environ[_WINDOWS_CONFIG_ROOT_ENV_VAR], _CONFIG_DIRECTORY + ) + except KeyError: + # This should never happen unless someone is really + # messing with things, but we'll cover the case anyway. + drive = os.environ.get("SystemDrive", "C:") + return os.path.join(drive, "\\", _CONFIG_DIRECTORY) + + +def get_application_default_credentials_path(): + """Gets the path to the application default credentials file. + + The path may or may not exist. + + Returns: + str: The full path to application default credentials. + """ + config_path = get_config_path() + return os.path.join(config_path, _CREDENTIALS_FILENAME) + + +def _run_subprocess_ignore_stderr(command): + """ Return subprocess.check_output with the given command and ignores stderr.""" + with open(os.devnull, "w") as devnull: + output = subprocess.check_output(command, stderr=devnull) + return output + + +def get_project_id(): + """Gets the project ID from the Cloud SDK. + + Returns: + Optional[str]: The project ID. + """ + if os.name == "nt": + command = _CLOUD_SDK_WINDOWS_COMMAND + else: + command = _CLOUD_SDK_POSIX_COMMAND + + try: + # Ignore the stderr coming from gcloud, so it won't be mixed into the output. + # https://github.com/googleapis/google-auth-library-python/issues/673 + output = _run_subprocess_ignore_stderr((command,) + _CLOUD_SDK_CONFIG_COMMAND) + except (subprocess.CalledProcessError, OSError, IOError): + return None + + try: + configuration = json.loads(output.decode("utf-8")) + except ValueError: + return None + + try: + return configuration["configuration"]["properties"]["core"]["project"] + except KeyError: + return None + + +def get_auth_access_token(account=None): + """Load user access token with the ``gcloud auth print-access-token`` command. + + Args: + account (Optional[str]): Account to get the access token for. If not + specified, the current active account will be used. + + Returns: + str: The user access token. + + Raises: + google.auth.exceptions.UserAccessTokenError: if failed to get access + token from gcloud. + """ + if os.name == "nt": + command = _CLOUD_SDK_WINDOWS_COMMAND + else: + command = _CLOUD_SDK_POSIX_COMMAND + + try: + if account: + command = ( + (command,) + + _CLOUD_SDK_USER_ACCESS_TOKEN_COMMAND + + ("--account=" + account,) + ) + else: + command = (command,) + _CLOUD_SDK_USER_ACCESS_TOKEN_COMMAND + + access_token = subprocess.check_output(command, stderr=subprocess.STDOUT) + # remove the trailing "\n" + return access_token.decode("utf-8").strip() + except (subprocess.CalledProcessError, OSError, IOError) as caught_exc: + new_exc = exceptions.UserAccessTokenError( + "Failed to obtain access token", caught_exc + ) + six.raise_from(new_exc, caught_exc) diff --git a/script.module.google-auth-library/lib/google/auth/_credentials_async.py b/script.module.google-auth-library/lib/google/auth/_credentials_async.py new file mode 100644 index 000000000..d4d4e2c0e --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_credentials_async.py @@ -0,0 +1,176 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +"""Interfaces for credentials.""" + +import abc +import inspect + +import six + +from google.auth import credentials + + +@six.add_metaclass(abc.ABCMeta) +class Credentials(credentials.Credentials): + """Async inherited credentials class from google.auth.credentials. + The added functionality is the before_request call which requires + async/await syntax. + All credentials have a :attr:`token` that is used for authentication and + may also optionally set an :attr:`expiry` to indicate when the token will + no longer be valid. + + Most credentials will be :attr:`invalid` until :meth:`refresh` is called. + Credentials can do this automatically before the first HTTP request in + :meth:`before_request`. + + Although the token and expiration will change as the credentials are + :meth:`refreshed ` and used, credentials should be considered + immutable. Various credentials will accept configuration such as private + keys, scopes, and other options. These options are not changeable after + construction. Some classes will provide mechanisms to copy the credentials + with modifications such as :meth:`ScopedCredentials.with_scopes`. + """ + + async def before_request(self, request, method, url, headers): + """Performs credential-specific before request logic. + + Refreshes the credentials if necessary, then calls :meth:`apply` to + apply the token to the authentication header. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + method (str): The request's HTTP method or the RPC method being + invoked. + url (str): The request's URI or the RPC service's URI. + headers (Mapping): The request's headers. + """ + # pylint: disable=unused-argument + # (Subclasses may use these arguments to ascertain information about + # the http request.) + + if not self.valid: + if inspect.iscoroutinefunction(self.refresh): + await self.refresh(request) + else: + self.refresh(request) + self.apply(headers) + + +class CredentialsWithQuotaProject(credentials.CredentialsWithQuotaProject): + """Abstract base for credentials supporting ``with_quota_project`` factory""" + + +class AnonymousCredentials(credentials.AnonymousCredentials, Credentials): + """Credentials that do not provide any authentication information. + + These are useful in the case of services that support anonymous access or + local service emulators that do not use credentials. This class inherits + from the sync anonymous credentials file, but is kept if async credentials + is initialized and we would like anonymous credentials. + """ + + +@six.add_metaclass(abc.ABCMeta) +class ReadOnlyScoped(credentials.ReadOnlyScoped): + """Interface for credentials whose scopes can be queried. + + OAuth 2.0-based credentials allow limiting access using scopes as described + in `RFC6749 Section 3.3`_. + If a credential class implements this interface then the credentials either + use scopes in their implementation. + + Some credentials require scopes in order to obtain a token. You can check + if scoping is necessary with :attr:`requires_scopes`:: + + if credentials.requires_scopes: + # Scoping is required. + credentials = _credentials_async.with_scopes(scopes=['one', 'two']) + + Credentials that require scopes must either be constructed with scopes:: + + credentials = SomeScopedCredentials(scopes=['one', 'two']) + + Or must copy an existing instance using :meth:`with_scopes`:: + + scoped_credentials = _credentials_async.with_scopes(scopes=['one', 'two']) + + Some credentials have scopes but do not allow or require scopes to be set, + these credentials can be used as-is. + + .. _RFC6749 Section 3.3: https://tools.ietf.org/html/rfc6749#section-3.3 + """ + + +class Scoped(credentials.Scoped): + """Interface for credentials whose scopes can be replaced while copying. + + OAuth 2.0-based credentials allow limiting access using scopes as described + in `RFC6749 Section 3.3`_. + If a credential class implements this interface then the credentials either + use scopes in their implementation. + + Some credentials require scopes in order to obtain a token. You can check + if scoping is necessary with :attr:`requires_scopes`:: + + if credentials.requires_scopes: + # Scoping is required. + credentials = _credentials_async.create_scoped(['one', 'two']) + + Credentials that require scopes must either be constructed with scopes:: + + credentials = SomeScopedCredentials(scopes=['one', 'two']) + + Or must copy an existing instance using :meth:`with_scopes`:: + + scoped_credentials = credentials.with_scopes(scopes=['one', 'two']) + + Some credentials have scopes but do not allow or require scopes to be set, + these credentials can be used as-is. + + .. _RFC6749 Section 3.3: https://tools.ietf.org/html/rfc6749#section-3.3 + """ + + +def with_scopes_if_required(credentials, scopes): + """Creates a copy of the credentials with scopes if scoping is required. + + This helper function is useful when you do not know (or care to know) the + specific type of credentials you are using (such as when you use + :func:`google.auth.default`). This function will call + :meth:`Scoped.with_scopes` if the credentials are scoped credentials and if + the credentials require scoping. Otherwise, it will return the credentials + as-is. + + Args: + credentials (google.auth.credentials.Credentials): The credentials to + scope if necessary. + scopes (Sequence[str]): The list of scopes to use. + + Returns: + google.auth._credentials_async.Credentials: Either a new set of scoped + credentials, or the passed in credentials instance if no scoping + was required. + """ + if isinstance(credentials, Scoped) and credentials.requires_scopes: + return credentials.with_scopes(scopes) + else: + return credentials + + +@six.add_metaclass(abc.ABCMeta) +class Signing(credentials.Signing): + """Interface for credentials that can cryptographically sign messages.""" diff --git a/script.module.google-auth-library/lib/google/auth/_default.py b/script.module.google-auth-library/lib/google/auth/_default.py new file mode 100644 index 000000000..0860c67fe --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_default.py @@ -0,0 +1,653 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Application default credentials. + +Implements application default credentials and project ID detection. +""" + +import io +import json +import logging +import os +import warnings + +import six + +from google.auth import environment_vars +from google.auth import exceptions +import google.auth.transport._http_client + +_LOGGER = logging.getLogger(__name__) + +# Valid types accepted for file-based credentials. +_AUTHORIZED_USER_TYPE = "authorized_user" +_SERVICE_ACCOUNT_TYPE = "service_account" +_EXTERNAL_ACCOUNT_TYPE = "external_account" +_EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE = "external_account_authorized_user" +_IMPERSONATED_SERVICE_ACCOUNT_TYPE = "impersonated_service_account" +_GDCH_SERVICE_ACCOUNT_TYPE = "gdch_service_account" +_VALID_TYPES = ( + _AUTHORIZED_USER_TYPE, + _SERVICE_ACCOUNT_TYPE, + _EXTERNAL_ACCOUNT_TYPE, + _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE, + _IMPERSONATED_SERVICE_ACCOUNT_TYPE, + _GDCH_SERVICE_ACCOUNT_TYPE, +) + +# Help message when no credentials can be found. +_HELP_MESSAGE = """\ +Could not automatically determine credentials. Please set {env} or \ +explicitly create credentials and re-run the application. For more \ +information, please see \ +https://cloud.google.com/docs/authentication/getting-started +""".format( + env=environment_vars.CREDENTIALS +).strip() + +# Warning when using Cloud SDK user credentials +_CLOUD_SDK_CREDENTIALS_WARNING = """\ +Your application has authenticated using end user credentials from Google \ +Cloud SDK without a quota project. You might receive a "quota exceeded" \ +or "API not enabled" error. We recommend you rerun \ +`gcloud auth application-default login` and make sure a quota project is \ +added. Or you can use service accounts instead. For more information \ +about service accounts, see https://cloud.google.com/docs/authentication/""" + +# The subject token type used for AWS external_account credentials. +_AWS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request" + + +def _warn_about_problematic_credentials(credentials): + """Determines if the credentials are problematic. + + Credentials from the Cloud SDK that are associated with Cloud SDK's project + are problematic because they may not have APIs enabled and have limited + quota. If this is the case, warn about it. + """ + from google.auth import _cloud_sdk + + if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID: + warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING) + + +def load_credentials_from_file( + filename, scopes=None, default_scopes=None, quota_project_id=None, request=None +): + """Loads Google credentials from a file. + + The credentials file must be a service account key, stored authorized + user credentials, external account credentials, or impersonated service + account credentials. + + Args: + filename (str): The full path to the credentials file. + scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If + specified, the credentials will automatically be scoped if + necessary + default_scopes (Optional[Sequence[str]]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + quota_project_id (Optional[str]): The project ID used for + quota and billing. + request (Optional[google.auth.transport.Request]): An object used to make + HTTP requests. This is used to determine the associated project ID + for a workload identity pool resource (external account credentials). + If not specified, then it will use a + google.auth.transport.requests.Request client to make requests. + + Returns: + Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded + credentials and the project ID. Authorized user credentials do not + have the project ID information. External account credentials project + IDs may not always be determined. + + Raises: + google.auth.exceptions.DefaultCredentialsError: if the file is in the + wrong format or is missing. + """ + if not os.path.exists(filename): + raise exceptions.DefaultCredentialsError( + "File {} was not found.".format(filename) + ) + + with io.open(filename, "r") as file_obj: + try: + info = json.load(file_obj) + except ValueError as caught_exc: + new_exc = exceptions.DefaultCredentialsError( + "File {} is not a valid json file.".format(filename), caught_exc + ) + six.raise_from(new_exc, caught_exc) + return _load_credentials_from_info( + filename, info, scopes, default_scopes, quota_project_id, request + ) + + +def _load_credentials_from_info( + filename, info, scopes, default_scopes, quota_project_id, request +): + from google.auth.credentials import CredentialsWithQuotaProject + + credential_type = info.get("type") + + if credential_type == _AUTHORIZED_USER_TYPE: + credentials, project_id = _get_authorized_user_credentials( + filename, info, scopes + ) + + elif credential_type == _SERVICE_ACCOUNT_TYPE: + credentials, project_id = _get_service_account_credentials( + filename, info, scopes, default_scopes + ) + + elif credential_type == _EXTERNAL_ACCOUNT_TYPE: + credentials, project_id = _get_external_account_credentials( + info, + filename, + scopes=scopes, + default_scopes=default_scopes, + request=request, + ) + + elif credential_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE: + credentials, project_id = _get_external_account_authorized_user_credentials( + filename, info, request + ) + + elif credential_type == _IMPERSONATED_SERVICE_ACCOUNT_TYPE: + credentials, project_id = _get_impersonated_service_account_credentials( + filename, info, scopes + ) + elif credential_type == _GDCH_SERVICE_ACCOUNT_TYPE: + credentials, project_id = _get_gdch_service_account_credentials(filename, info) + else: + raise exceptions.DefaultCredentialsError( + "The file {file} does not have a valid type. " + "Type is {type}, expected one of {valid_types}.".format( + file=filename, type=credential_type, valid_types=_VALID_TYPES + ) + ) + if isinstance(credentials, CredentialsWithQuotaProject): + credentials = _apply_quota_project_id(credentials, quota_project_id) + return credentials, project_id + + +def _get_gcloud_sdk_credentials(quota_project_id=None): + """Gets the credentials and project ID from the Cloud SDK.""" + from google.auth import _cloud_sdk + + _LOGGER.debug("Checking Cloud SDK credentials as part of auth process...") + + # Check if application default credentials exist. + credentials_filename = _cloud_sdk.get_application_default_credentials_path() + + if not os.path.isfile(credentials_filename): + _LOGGER.debug("Cloud SDK credentials not found on disk; not using them") + return None, None + + credentials, project_id = load_credentials_from_file( + credentials_filename, quota_project_id=quota_project_id + ) + + if not project_id: + project_id = _cloud_sdk.get_project_id() + + return credentials, project_id + + +def _get_explicit_environ_credentials(quota_project_id=None): + """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment + variable.""" + from google.auth import _cloud_sdk + + cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path() + explicit_file = os.environ.get(environment_vars.CREDENTIALS) + + _LOGGER.debug( + "Checking %s for explicit credentials as part of auth process...", explicit_file + ) + + if explicit_file is not None and explicit_file == cloud_sdk_adc_path: + # Cloud sdk flow calls gcloud to fetch project id, so if the explicit + # file path is cloud sdk credentials path, then we should fall back + # to cloud sdk flow, otherwise project id cannot be obtained. + _LOGGER.debug( + "Explicit credentials path %s is the same as Cloud SDK credentials path, fall back to Cloud SDK credentials flow...", + explicit_file, + ) + return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id) + + if explicit_file is not None: + credentials, project_id = load_credentials_from_file( + os.environ[environment_vars.CREDENTIALS], quota_project_id=quota_project_id + ) + + return credentials, project_id + + else: + return None, None + + +def _get_gae_credentials(): + """Gets Google App Engine App Identity credentials and project ID.""" + # If not GAE gen1, prefer the metadata service even if the GAE APIs are + # available as per https://google.aip.dev/auth/4115. + if os.environ.get(environment_vars.LEGACY_APPENGINE_RUNTIME) != "python27": + return None, None + + # While this library is normally bundled with app_engine, there are + # some cases where it's not available, so we tolerate ImportError. + try: + _LOGGER.debug("Checking for App Engine runtime as part of auth process...") + import google.auth.app_engine as app_engine + except ImportError: + _LOGGER.warning("Import of App Engine auth library failed.") + return None, None + + try: + credentials = app_engine.Credentials() + project_id = app_engine.get_project_id() + return credentials, project_id + except EnvironmentError: + _LOGGER.debug( + "No App Engine library was found so cannot authentication via App Engine Identity Credentials." + ) + return None, None + + +def _get_gce_credentials(request=None, quota_project_id=None): + """Gets credentials and project ID from the GCE Metadata Service.""" + # Ping requires a transport, but we want application default credentials + # to require no arguments. So, we'll use the _http_client transport which + # uses http.client. This is only acceptable because the metadata server + # doesn't do SSL and never requires proxies. + + # While this library is normally bundled with compute_engine, there are + # some cases where it's not available, so we tolerate ImportError. + try: + from google.auth import compute_engine + from google.auth.compute_engine import _metadata + except ImportError: + _LOGGER.warning("Import of Compute Engine auth library failed.") + return None, None + + if request is None: + request = google.auth.transport._http_client.Request() + + if _metadata.ping(request=request): + # Get the project ID. + try: + project_id = _metadata.get_project_id(request=request) + except exceptions.TransportError: + project_id = None + + cred = compute_engine.Credentials() + cred = _apply_quota_project_id(cred, quota_project_id) + + return cred, project_id + else: + _LOGGER.warning( + "Authentication failed using Compute Engine authentication due to unavailable metadata server." + ) + return None, None + + +def _get_external_account_credentials( + info, filename, scopes=None, default_scopes=None, request=None +): + """Loads external account Credentials from the parsed external account info. + + The credentials information must correspond to a supported external account + credentials. + + Args: + info (Mapping[str, str]): The external account info in Google format. + filename (str): The full path to the credentials file. + scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If + specified, the credentials will automatically be scoped if + necessary. + default_scopes (Optional[Sequence[str]]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + request (Optional[google.auth.transport.Request]): An object used to make + HTTP requests. This is used to determine the associated project ID + for a workload identity pool resource (external account credentials). + If not specified, then it will use a + google.auth.transport.requests.Request client to make requests. + + Returns: + Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded + credentials and the project ID. External account credentials project + IDs may not always be determined. + + Raises: + google.auth.exceptions.DefaultCredentialsError: if the info dictionary + is in the wrong format or is missing required information. + """ + # There are currently 3 types of external_account credentials. + if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE: + # Check if configuration corresponds to an AWS credentials. + from google.auth import aws + + credentials = aws.Credentials.from_info( + info, scopes=scopes, default_scopes=default_scopes + ) + elif ( + info.get("credential_source") is not None + and info.get("credential_source").get("executable") is not None + ): + from google.auth import pluggable + + credentials = pluggable.Credentials.from_info( + info, scopes=scopes, default_scopes=default_scopes + ) + else: + try: + # Check if configuration corresponds to an Identity Pool credentials. + from google.auth import identity_pool + + credentials = identity_pool.Credentials.from_info( + info, scopes=scopes, default_scopes=default_scopes + ) + except ValueError: + # If the configuration is invalid or does not correspond to any + # supported external_account credentials, raise an error. + raise exceptions.DefaultCredentialsError( + "Failed to load external account credentials from {}".format(filename) + ) + if request is None: + import google.auth.transport.requests + + request = google.auth.transport.requests.Request() + + return credentials, credentials.get_project_id(request=request) + + +def _get_external_account_authorized_user_credentials( + filename, info, scopes=None, default_scopes=None, request=None +): + try: + from google.auth import external_account_authorized_user + + credentials = external_account_authorized_user.Credentials.from_info(info) + except ValueError: + raise exceptions.DefaultCredentialsError( + "Failed to load external account authorized user credentials from {}".format( + filename + ) + ) + + return credentials, None + + +def _get_authorized_user_credentials(filename, info, scopes=None): + from google.oauth2 import credentials + + try: + credentials = credentials.Credentials.from_authorized_user_info( + info, scopes=scopes + ) + except ValueError as caught_exc: + msg = "Failed to load authorized user credentials from {}".format(filename) + new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) + six.raise_from(new_exc, caught_exc) + return credentials, None + + +def _get_service_account_credentials(filename, info, scopes=None, default_scopes=None): + from google.oauth2 import service_account + + try: + credentials = service_account.Credentials.from_service_account_info( + info, scopes=scopes, default_scopes=default_scopes + ) + except ValueError as caught_exc: + msg = "Failed to load service account credentials from {}".format(filename) + new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) + six.raise_from(new_exc, caught_exc) + return credentials, info.get("project_id") + + +def _get_impersonated_service_account_credentials(filename, info, scopes): + from google.auth import impersonated_credentials + + try: + source_credentials_info = info.get("source_credentials") + source_credentials_type = source_credentials_info.get("type") + if source_credentials_type == _AUTHORIZED_USER_TYPE: + source_credentials, _ = _get_authorized_user_credentials( + filename, source_credentials_info + ) + elif source_credentials_type == _SERVICE_ACCOUNT_TYPE: + source_credentials, _ = _get_service_account_credentials( + filename, source_credentials_info + ) + else: + raise ValueError( + "source credential of type {} is not supported.".format( + source_credentials_type + ) + ) + impersonation_url = info.get("service_account_impersonation_url") + start_index = impersonation_url.rfind("/") + end_index = impersonation_url.find(":generateAccessToken") + if start_index == -1 or end_index == -1 or start_index > end_index: + raise ValueError( + "Cannot extract target principal from {}".format(impersonation_url) + ) + target_principal = impersonation_url[start_index + 1 : end_index] + delegates = info.get("delegates") + quota_project_id = info.get("quota_project_id") + credentials = impersonated_credentials.Credentials( + source_credentials, + target_principal, + scopes, + delegates, + quota_project_id=quota_project_id, + ) + except ValueError as caught_exc: + msg = "Failed to load impersonated service account credentials from {}".format( + filename + ) + new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) + six.raise_from(new_exc, caught_exc) + return credentials, None + + +def _get_gdch_service_account_credentials(filename, info): + from google.oauth2 import gdch_credentials + + try: + credentials = gdch_credentials.ServiceAccountCredentials.from_service_account_info( + info + ) + except ValueError as caught_exc: + msg = "Failed to load GDCH service account credentials from {}".format(filename) + new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) + six.raise_from(new_exc, caught_exc) + return credentials, info.get("project") + + +def get_api_key_credentials(key): + """Return credentials with the given API key.""" + from google.auth import api_key + + return api_key.Credentials(key) + + +def _apply_quota_project_id(credentials, quota_project_id): + if quota_project_id: + credentials = credentials.with_quota_project(quota_project_id) + else: + credentials = credentials.with_quota_project_from_environment() + + from google.oauth2 import credentials as authorized_user_credentials + + if isinstance(credentials, authorized_user_credentials.Credentials) and ( + not credentials.quota_project_id + ): + _warn_about_problematic_credentials(credentials) + return credentials + + +def default(scopes=None, request=None, quota_project_id=None, default_scopes=None): + """Gets the default credentials for the current environment. + + `Application Default Credentials`_ provides an easy way to obtain + credentials to call Google APIs for server-to-server or local applications. + This function acquires credentials from the environment in the following + order: + + 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set + to the path of a valid service account JSON private key file, then it is + loaded and returned. The project ID returned is the project ID defined + in the service account file if available (some older files do not + contain project ID information). + + If the environment variable is set to the path of a valid external + account JSON configuration file (workload identity federation), then the + configuration file is used to determine and retrieve the external + credentials from the current environment (AWS, Azure, etc). + These will then be exchanged for Google access tokens via the Google STS + endpoint. + The project ID returned in this case is the one corresponding to the + underlying workload identity pool resource if determinable. + + If the environment variable is set to the path of a valid GDCH service + account JSON file (`Google Distributed Cloud Hosted`_), then a GDCH + credential will be returned. The project ID returned is the project + specified in the JSON file. + 2. If the `Google Cloud SDK`_ is installed and has application default + credentials set they are loaded and returned. + + To enable application default credentials with the Cloud SDK run:: + + gcloud auth application-default login + + If the Cloud SDK has an active project, the project ID is returned. The + active project can be set using:: + + gcloud config set project + + 3. If the application is running in the `App Engine standard environment`_ + (first generation) then the credentials and project ID from the + `App Identity Service`_ are used. + 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or + the `App Engine flexible environment`_ or the `App Engine standard + environment`_ (second generation) then the credentials and project ID + are obtained from the `Metadata Service`_. + 5. If no credentials are found, + :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised. + + .. _Application Default Credentials: https://developers.google.com\ + /identity/protocols/application-default-credentials + .. _Google Cloud SDK: https://cloud.google.com/sdk + .. _App Engine standard environment: https://cloud.google.com/appengine + .. _App Identity Service: https://cloud.google.com/appengine/docs/python\ + /appidentity/ + .. _Compute Engine: https://cloud.google.com/compute + .. _App Engine flexible environment: https://cloud.google.com\ + /appengine/flexible + .. _Metadata Service: https://cloud.google.com/compute/docs\ + /storing-retrieving-metadata + .. _Cloud Run: https://cloud.google.com/run + .. _Google Distributed Cloud Hosted: https://cloud.google.com/blog/topics\ + /hybrid-cloud/announcing-google-distributed-cloud-edge-and-hosted + + Example:: + + import google.auth + + credentials, project_id = google.auth.default() + + Args: + scopes (Sequence[str]): The list of scopes for the credentials. If + specified, the credentials will automatically be scoped if + necessary. + request (Optional[google.auth.transport.Request]): An object used to make + HTTP requests. This is used to either detect whether the application + is running on Compute Engine or to determine the associated project + ID for a workload identity pool resource (external account + credentials). If not specified, then it will either use the standard + library http client to make requests for Compute Engine credentials + or a google.auth.transport.requests.Request client for external + account credentials. + quota_project_id (Optional[str]): The project ID used for + quota and billing. + default_scopes (Optional[Sequence[str]]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + Returns: + Tuple[~google.auth.credentials.Credentials, Optional[str]]: + the current environment's credentials and project ID. Project ID + may be None, which indicates that the Project ID could not be + ascertained from the environment. + + Raises: + ~google.auth.exceptions.DefaultCredentialsError: + If no credentials were found, or if the credentials found were + invalid. + """ + from google.auth.credentials import with_scopes_if_required + from google.auth.credentials import CredentialsWithQuotaProject + + explicit_project_id = os.environ.get( + environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT) + ) + + checkers = ( + # Avoid passing scopes here to prevent passing scopes to user credentials. + # with_scopes_if_required() below will ensure scopes/default scopes are + # safely set on the returned credentials since requires_scopes will + # guard against setting scopes on user credentials. + lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id), + lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id), + _get_gae_credentials, + lambda: _get_gce_credentials(request, quota_project_id=quota_project_id), + ) + + for checker in checkers: + credentials, project_id = checker() + if credentials is not None: + credentials = with_scopes_if_required( + credentials, scopes, default_scopes=default_scopes + ) + + # For external account credentials, scopes are required to determine + # the project ID. Try to get the project ID again if not yet + # determined. + if not project_id and callable( + getattr(credentials, "get_project_id", None) + ): + if request is None: + import google.auth.transport.requests + + request = google.auth.transport.requests.Request() + project_id = credentials.get_project_id(request=request) + + if quota_project_id and isinstance( + credentials, CredentialsWithQuotaProject + ): + credentials = credentials.with_quota_project(quota_project_id) + + effective_project_id = explicit_project_id or project_id + if not effective_project_id: + _LOGGER.warning( + "No project ID could be determined. Consider running " + "`gcloud config set project` or setting the %s " + "environment variable", + environment_vars.PROJECT, + ) + return credentials, effective_project_id + + raise exceptions.DefaultCredentialsError(_HELP_MESSAGE) diff --git a/script.module.google-auth-library/lib/google/auth/_default_async.py b/script.module.google-auth-library/lib/google/auth/_default_async.py new file mode 100644 index 000000000..5a41f2a6e --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_default_async.py @@ -0,0 +1,284 @@ +# Copyright 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Application default credentials. + +Implements application default credentials and project ID detection. +""" + +import io +import json +import os + +import six + +from google.auth import _default +from google.auth import environment_vars +from google.auth import exceptions + + +def load_credentials_from_file(filename, scopes=None, quota_project_id=None): + """Loads Google credentials from a file. + + The credentials file must be a service account key or stored authorized + user credentials. + + Args: + filename (str): The full path to the credentials file. + scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If + specified, the credentials will automatically be scoped if + necessary + quota_project_id (Optional[str]): The project ID used for + quota and billing. + + Returns: + Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded + credentials and the project ID. Authorized user credentials do not + have the project ID information. + + Raises: + google.auth.exceptions.DefaultCredentialsError: if the file is in the + wrong format or is missing. + """ + if not os.path.exists(filename): + raise exceptions.DefaultCredentialsError( + "File {} was not found.".format(filename) + ) + + with io.open(filename, "r") as file_obj: + try: + info = json.load(file_obj) + except ValueError as caught_exc: + new_exc = exceptions.DefaultCredentialsError( + "File {} is not a valid json file.".format(filename), caught_exc + ) + six.raise_from(new_exc, caught_exc) + + # The type key should indicate that the file is either a service account + # credentials file or an authorized user credentials file. + credential_type = info.get("type") + + if credential_type == _default._AUTHORIZED_USER_TYPE: + from google.oauth2 import _credentials_async as credentials + + try: + credentials = credentials.Credentials.from_authorized_user_info( + info, scopes=scopes + ) + except ValueError as caught_exc: + msg = "Failed to load authorized user credentials from {}".format(filename) + new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) + six.raise_from(new_exc, caught_exc) + if quota_project_id: + credentials = credentials.with_quota_project(quota_project_id) + if not credentials.quota_project_id: + _default._warn_about_problematic_credentials(credentials) + return credentials, None + + elif credential_type == _default._SERVICE_ACCOUNT_TYPE: + from google.oauth2 import _service_account_async as service_account + + try: + credentials = service_account.Credentials.from_service_account_info( + info, scopes=scopes + ).with_quota_project(quota_project_id) + except ValueError as caught_exc: + msg = "Failed to load service account credentials from {}".format(filename) + new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) + six.raise_from(new_exc, caught_exc) + return credentials, info.get("project_id") + + else: + raise exceptions.DefaultCredentialsError( + "The file {file} does not have a valid type. " + "Type is {type}, expected one of {valid_types}.".format( + file=filename, type=credential_type, valid_types=_default._VALID_TYPES + ) + ) + + +def _get_gcloud_sdk_credentials(quota_project_id=None): + """Gets the credentials and project ID from the Cloud SDK.""" + from google.auth import _cloud_sdk + + # Check if application default credentials exist. + credentials_filename = _cloud_sdk.get_application_default_credentials_path() + + if not os.path.isfile(credentials_filename): + return None, None + + credentials, project_id = load_credentials_from_file( + credentials_filename, quota_project_id=quota_project_id + ) + + if not project_id: + project_id = _cloud_sdk.get_project_id() + + return credentials, project_id + + +def _get_explicit_environ_credentials(quota_project_id=None): + """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment + variable.""" + from google.auth import _cloud_sdk + + cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path() + explicit_file = os.environ.get(environment_vars.CREDENTIALS) + + if explicit_file is not None and explicit_file == cloud_sdk_adc_path: + # Cloud sdk flow calls gcloud to fetch project id, so if the explicit + # file path is cloud sdk credentials path, then we should fall back + # to cloud sdk flow, otherwise project id cannot be obtained. + return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id) + + if explicit_file is not None: + credentials, project_id = load_credentials_from_file( + os.environ[environment_vars.CREDENTIALS], quota_project_id=quota_project_id + ) + + return credentials, project_id + + else: + return None, None + + +def _get_gae_credentials(): + """Gets Google App Engine App Identity credentials and project ID.""" + # While this library is normally bundled with app_engine, there are + # some cases where it's not available, so we tolerate ImportError. + + return _default._get_gae_credentials() + + +def _get_gce_credentials(request=None): + """Gets credentials and project ID from the GCE Metadata Service.""" + # Ping requires a transport, but we want application default credentials + # to require no arguments. So, we'll use the _http_client transport which + # uses http.client. This is only acceptable because the metadata server + # doesn't do SSL and never requires proxies. + + # While this library is normally bundled with compute_engine, there are + # some cases where it's not available, so we tolerate ImportError. + + return _default._get_gce_credentials(request) + + +def default_async(scopes=None, request=None, quota_project_id=None): + """Gets the default credentials for the current environment. + + `Application Default Credentials`_ provides an easy way to obtain + credentials to call Google APIs for server-to-server or local applications. + This function acquires credentials from the environment in the following + order: + + 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set + to the path of a valid service account JSON private key file, then it is + loaded and returned. The project ID returned is the project ID defined + in the service account file if available (some older files do not + contain project ID information). + 2. If the `Google Cloud SDK`_ is installed and has application default + credentials set they are loaded and returned. + + To enable application default credentials with the Cloud SDK run:: + + gcloud auth application-default login + + If the Cloud SDK has an active project, the project ID is returned. The + active project can be set using:: + + gcloud config set project + + 3. If the application is running in the `App Engine standard environment`_ + (first generation) then the credentials and project ID from the + `App Identity Service`_ are used. + 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or + the `App Engine flexible environment`_ or the `App Engine standard + environment`_ (second generation) then the credentials and project ID + are obtained from the `Metadata Service`_. + 5. If no credentials are found, + :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised. + + .. _Application Default Credentials: https://developers.google.com\ + /identity/protocols/application-default-credentials + .. _Google Cloud SDK: https://cloud.google.com/sdk + .. _App Engine standard environment: https://cloud.google.com/appengine + .. _App Identity Service: https://cloud.google.com/appengine/docs/python\ + /appidentity/ + .. _Compute Engine: https://cloud.google.com/compute + .. _App Engine flexible environment: https://cloud.google.com\ + /appengine/flexible + .. _Metadata Service: https://cloud.google.com/compute/docs\ + /storing-retrieving-metadata + .. _Cloud Run: https://cloud.google.com/run + + Example:: + + import google.auth + + credentials, project_id = google.auth.default() + + Args: + scopes (Sequence[str]): The list of scopes for the credentials. If + specified, the credentials will automatically be scoped if + necessary. + request (google.auth.transport.Request): An object used to make + HTTP requests. This is used to detect whether the application + is running on Compute Engine. If not specified, then it will + use the standard library http client to make requests. + quota_project_id (Optional[str]): The project ID used for + quota and billing. + Returns: + Tuple[~google.auth.credentials.Credentials, Optional[str]]: + the current environment's credentials and project ID. Project ID + may be None, which indicates that the Project ID could not be + ascertained from the environment. + + Raises: + ~google.auth.exceptions.DefaultCredentialsError: + If no credentials were found, or if the credentials found were + invalid. + """ + from google.auth._credentials_async import with_scopes_if_required + from google.auth.credentials import CredentialsWithQuotaProject + + explicit_project_id = os.environ.get( + environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT) + ) + + checkers = ( + lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id), + lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id), + _get_gae_credentials, + lambda: _get_gce_credentials(request), + ) + + for checker in checkers: + credentials, project_id = checker() + if credentials is not None: + credentials = with_scopes_if_required(credentials, scopes) + if quota_project_id and isinstance( + credentials, CredentialsWithQuotaProject + ): + credentials = credentials.with_quota_project(quota_project_id) + effective_project_id = explicit_project_id or project_id + if not effective_project_id: + _default._LOGGER.warning( + "No project ID could be determined. Consider running " + "`gcloud config set project` or setting the %s " + "environment variable", + environment_vars.PROJECT, + ) + return credentials, effective_project_id + + raise exceptions.DefaultCredentialsError(_default._HELP_MESSAGE) diff --git a/script.module.google-auth-library/lib/google/auth/_exponential_backoff.py b/script.module.google-auth-library/lib/google/auth/_exponential_backoff.py new file mode 100644 index 000000000..b5801bec9 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_exponential_backoff.py @@ -0,0 +1,111 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import random +import time + +import six + +# The default amount of retry attempts +_DEFAULT_RETRY_TOTAL_ATTEMPTS = 3 + +# The default initial backoff period (1.0 second). +_DEFAULT_INITIAL_INTERVAL_SECONDS = 1.0 + +# The default randomization factor (0.1 which results in a random period ranging +# between 10% below and 10% above the retry interval). +_DEFAULT_RANDOMIZATION_FACTOR = 0.1 + +# The default multiplier value (2 which is 100% increase per back off). +_DEFAULT_MULTIPLIER = 2.0 + +"""Exponential Backoff Utility + +This is a private module that implements the exponential back off algorithm. +It can be used as a utility for code that needs to retry on failure, for example +an HTTP request. +""" + + +class ExponentialBackoff(six.Iterator): + """An exponential backoff iterator. This can be used in a for loop to + perform requests with exponential backoff. + + Args: + total_attempts Optional[int]: + The maximum amount of retries that should happen. + The default value is 3 attempts. + initial_wait_seconds Optional[int]: + The amount of time to sleep in the first backoff. This parameter + should be in seconds. + The default value is 1 second. + randomization_factor Optional[float]: + The amount of jitter that should be in each backoff. For example, + a value of 0.1 will introduce a jitter range of 10% to the + current backoff period. + The default value is 0.1. + multiplier Optional[float]: + The backoff multipler. This adjusts how much each backoff will + increase. For example a value of 2.0 leads to a 200% backoff + on each attempt. If the initial_wait is 1.0 it would look like + this sequence [1.0, 2.0, 4.0, 8.0]. + The default value is 2.0. + """ + + def __init__( + self, + total_attempts=_DEFAULT_RETRY_TOTAL_ATTEMPTS, + initial_wait_seconds=_DEFAULT_INITIAL_INTERVAL_SECONDS, + randomization_factor=_DEFAULT_RANDOMIZATION_FACTOR, + multiplier=_DEFAULT_MULTIPLIER, + ): + self._total_attempts = total_attempts + self._initial_wait_seconds = initial_wait_seconds + + self._current_wait_in_seconds = self._initial_wait_seconds + + self._randomization_factor = randomization_factor + self._multiplier = multiplier + self._backoff_count = 0 + + def __iter__(self): + self._backoff_count = 0 + self._current_wait_in_seconds = self._initial_wait_seconds + return self + + def __next__(self): + if self._backoff_count >= self._total_attempts: + raise StopIteration + self._backoff_count += 1 + + jitter_variance = self._current_wait_in_seconds * self._randomization_factor + jitter = random.uniform( + self._current_wait_in_seconds - jitter_variance, + self._current_wait_in_seconds + jitter_variance, + ) + + time.sleep(jitter) + + self._current_wait_in_seconds *= self._multiplier + return self._backoff_count + + @property + def total_attempts(self): + """The total amount of backoff attempts that will be made.""" + return self._total_attempts + + @property + def backoff_count(self): + """The current amount of backoff attempts that have been made.""" + return self._backoff_count diff --git a/script.module.google-auth-library/lib/google/auth/_helpers.py b/script.module.google-auth-library/lib/google/auth/_helpers.py new file mode 100644 index 000000000..1b08ab87f --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_helpers.py @@ -0,0 +1,245 @@ +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helper functions for commonly used utilities.""" + +import base64 +import calendar +import datetime +import sys + +import six +from six.moves import urllib + + +# Token server doesn't provide a new a token when doing refresh unless the +# token is expiring within 30 seconds, so refresh threshold should not be +# more than 30 seconds. Otherwise auth lib will send tons of refresh requests +# until 30 seconds before the expiration, and cause a spike of CPU usage. +REFRESH_THRESHOLD = datetime.timedelta(seconds=20) + + +def copy_docstring(source_class): + """Decorator that copies a method's docstring from another class. + + Args: + source_class (type): The class that has the documented method. + + Returns: + Callable: A decorator that will copy the docstring of the same + named method in the source class to the decorated method. + """ + + def decorator(method): + """Decorator implementation. + + Args: + method (Callable): The method to copy the docstring to. + + Returns: + Callable: the same method passed in with an updated docstring. + + Raises: + ValueError: if the method already has a docstring. + """ + if method.__doc__: + raise ValueError("Method already has a docstring.") + + source_method = getattr(source_class, method.__name__) + method.__doc__ = source_method.__doc__ + + return method + + return decorator + + +def utcnow(): + """Returns the current UTC datetime. + + Returns: + datetime: The current time in UTC. + """ + return datetime.datetime.utcnow() + + +def datetime_to_secs(value): + """Convert a datetime object to the number of seconds since the UNIX epoch. + + Args: + value (datetime): The datetime to convert. + + Returns: + int: The number of seconds since the UNIX epoch. + """ + return calendar.timegm(value.utctimetuple()) + + +def to_bytes(value, encoding="utf-8"): + """Converts a string value to bytes, if necessary. + + Unfortunately, ``six.b`` is insufficient for this task since in + Python 2 because it does not modify ``unicode`` objects. + + Args: + value (Union[str, bytes]): The value to be converted. + encoding (str): The encoding to use to convert unicode to bytes. + Defaults to "utf-8". + + Returns: + bytes: The original value converted to bytes (if unicode) or as + passed in if it started out as bytes. + + Raises: + ValueError: If the value could not be converted to bytes. + """ + result = value.encode(encoding) if isinstance(value, six.text_type) else value + if isinstance(result, six.binary_type): + return result + else: + raise ValueError("{0!r} could not be converted to bytes".format(value)) + + +def from_bytes(value): + """Converts bytes to a string value, if necessary. + + Args: + value (Union[str, bytes]): The value to be converted. + + Returns: + str: The original value converted to unicode (if bytes) or as passed in + if it started out as unicode. + + Raises: + ValueError: If the value could not be converted to unicode. + """ + result = value.decode("utf-8") if isinstance(value, six.binary_type) else value + if isinstance(result, six.text_type): + return result + else: + raise ValueError("{0!r} could not be converted to unicode".format(value)) + + +def update_query(url, params, remove=None): + """Updates a URL's query parameters. + + Replaces any current values if they are already present in the URL. + + Args: + url (str): The URL to update. + params (Mapping[str, str]): A mapping of query parameter + keys to values. + remove (Sequence[str]): Parameters to remove from the query string. + + Returns: + str: The URL with updated query parameters. + + Examples: + + >>> url = 'http://example.com?a=1' + >>> update_query(url, {'a': '2'}) + http://example.com?a=2 + >>> update_query(url, {'b': '3'}) + http://example.com?a=1&b=3 + >> update_query(url, {'b': '3'}, remove=['a']) + http://example.com?b=3 + + """ + if remove is None: + remove = [] + + # Split the URL into parts. + parts = urllib.parse.urlparse(url) + # Parse the query string. + query_params = urllib.parse.parse_qs(parts.query) + # Update the query parameters with the new parameters. + query_params.update(params) + # Remove any values specified in remove. + query_params = { + key: value for key, value in six.iteritems(query_params) if key not in remove + } + # Re-encoded the query string. + new_query = urllib.parse.urlencode(query_params, doseq=True) + # Unsplit the url. + new_parts = parts._replace(query=new_query) + return urllib.parse.urlunparse(new_parts) + + +def scopes_to_string(scopes): + """Converts scope value to a string suitable for sending to OAuth 2.0 + authorization servers. + + Args: + scopes (Sequence[str]): The sequence of scopes to convert. + + Returns: + str: The scopes formatted as a single string. + """ + return " ".join(scopes) + + +def string_to_scopes(scopes): + """Converts stringifed scopes value to a list. + + Args: + scopes (Union[Sequence, str]): The string of space-separated scopes + to convert. + Returns: + Sequence(str): The separated scopes. + """ + if not scopes: + return [] + + return scopes.split(" ") + + +def padded_urlsafe_b64decode(value): + """Decodes base64 strings lacking padding characters. + + Google infrastructure tends to omit the base64 padding characters. + + Args: + value (Union[str, bytes]): The encoded value. + + Returns: + bytes: The decoded value + """ + b64string = to_bytes(value) + padded = b64string + b"=" * (-len(b64string) % 4) + return base64.urlsafe_b64decode(padded) + + +def unpadded_urlsafe_b64encode(value): + """Encodes base64 strings removing any padding characters. + + `rfc 7515`_ defines Base64url to NOT include any padding + characters, but the stdlib doesn't do that by default. + + _rfc7515: https://tools.ietf.org/html/rfc7515#page-6 + + Args: + value (Union[str|bytes]): The bytes-like value to encode + + Returns: + Union[str|bytes]: The encoded value + """ + return base64.urlsafe_b64encode(value).rstrip(b"=") + + +def is_python_3(): + """Check if the Python interpreter is Python 2 or 3. + + Returns: + bool: True if the Python interpreter is Python 3 and False otherwise. + """ + return sys.version_info > (3, 0) diff --git a/script.module.google-auth-library/lib/google/auth/_jwt_async.py b/script.module.google-auth-library/lib/google/auth/_jwt_async.py new file mode 100644 index 000000000..3a1abc5b8 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_jwt_async.py @@ -0,0 +1,164 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""JSON Web Tokens + +Provides support for creating (encoding) and verifying (decoding) JWTs, +especially JWTs generated and consumed by Google infrastructure. + +See `rfc7519`_ for more details on JWTs. + +To encode a JWT use :func:`encode`:: + + from google.auth import crypt + from google.auth import jwt_async + + signer = crypt.Signer(private_key) + payload = {'some': 'payload'} + encoded = jwt_async.encode(signer, payload) + +To decode a JWT and verify claims use :func:`decode`:: + + claims = jwt_async.decode(encoded, certs=public_certs) + +You can also skip verification:: + + claims = jwt_async.decode(encoded, verify=False) + +.. _rfc7519: https://tools.ietf.org/html/rfc7519 + + +NOTE: This async support is experimental and marked internal. This surface may +change in minor releases. +""" + +from google.auth import _credentials_async +from google.auth import jwt + + +def encode(signer, payload, header=None, key_id=None): + """Make a signed JWT. + + Args: + signer (google.auth.crypt.Signer): The signer used to sign the JWT. + payload (Mapping[str, str]): The JWT payload. + header (Mapping[str, str]): Additional JWT header payload. + key_id (str): The key id to add to the JWT header. If the + signer has a key id it will be used as the default. If this is + specified it will override the signer's key id. + + Returns: + bytes: The encoded JWT. + """ + return jwt.encode(signer, payload, header, key_id) + + +def decode(token, certs=None, verify=True, audience=None): + """Decode and verify a JWT. + + Args: + token (str): The encoded JWT. + certs (Union[str, bytes, Mapping[str, Union[str, bytes]]]): The + certificate used to validate the JWT signature. If bytes or string, + it must the the public key certificate in PEM format. If a mapping, + it must be a mapping of key IDs to public key certificates in PEM + format. The mapping must contain the same key ID that's specified + in the token's header. + verify (bool): Whether to perform signature and claim validation. + Verification is done by default. + audience (str): The audience claim, 'aud', that this JWT should + contain. If None then the JWT's 'aud' parameter is not verified. + + Returns: + Mapping[str, str]: The deserialized JSON payload in the JWT. + + Raises: + ValueError: if any verification checks failed. + """ + + return jwt.decode(token, certs, verify, audience) + + +class Credentials( + jwt.Credentials, _credentials_async.Signing, _credentials_async.Credentials +): + """Credentials that use a JWT as the bearer token. + + These credentials require an "audience" claim. This claim identifies the + intended recipient of the bearer token. + + The constructor arguments determine the claims for the JWT that is + sent with requests. Usually, you'll construct these credentials with + one of the helper constructors as shown in the next section. + + To create JWT credentials using a Google service account private key + JSON file:: + + audience = 'https://pubsub.googleapis.com/google.pubsub.v1.Publisher' + credentials = jwt_async.Credentials.from_service_account_file( + 'service-account.json', + audience=audience) + + If you already have the service account file loaded and parsed:: + + service_account_info = json.load(open('service_account.json')) + credentials = jwt_async.Credentials.from_service_account_info( + service_account_info, + audience=audience) + + Both helper methods pass on arguments to the constructor, so you can + specify the JWT claims:: + + credentials = jwt_async.Credentials.from_service_account_file( + 'service-account.json', + audience=audience, + additional_claims={'meta': 'data'}) + + You can also construct the credentials directly if you have a + :class:`~google.auth.crypt.Signer` instance:: + + credentials = jwt_async.Credentials( + signer, + issuer='your-issuer', + subject='your-subject', + audience=audience) + + The claims are considered immutable. If you want to modify the claims, + you can easily create another instance using :meth:`with_claims`:: + + new_audience = ( + 'https://pubsub.googleapis.com/google.pubsub.v1.Subscriber') + new_credentials = credentials.with_claims(audience=new_audience) + """ + + +class OnDemandCredentials( + jwt.OnDemandCredentials, _credentials_async.Signing, _credentials_async.Credentials +): + """On-demand JWT credentials. + + Like :class:`Credentials`, this class uses a JWT as the bearer token for + authentication. However, this class does not require the audience at + construction time. Instead, it will generate a new token on-demand for + each request using the request URI as the audience. It caches tokens + so that multiple requests to the same URI do not incur the overhead + of generating a new token every time. + + This behavior is especially useful for `gRPC`_ clients. A gRPC service may + have multiple audience and gRPC clients may not know all of the audiences + required for accessing a particular service. With these credentials, + no knowledge of the audiences is required ahead of time. + + .. _grpc: http://www.grpc.io/ + """ diff --git a/script.module.google-auth-library/lib/google/auth/_oauth2client.py b/script.module.google-auth-library/lib/google/auth/_oauth2client.py new file mode 100644 index 000000000..a86ba8dd6 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_oauth2client.py @@ -0,0 +1,169 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for transitioning from oauth2client to google-auth. + +.. warning:: + This module is private as it is intended to assist first-party downstream + clients with the transition from oauth2client to google-auth. +""" + +from __future__ import absolute_import + +import six + +from google.auth import _helpers +import google.auth.app_engine +import google.auth.compute_engine +import google.oauth2.credentials +import google.oauth2.service_account + +try: + import oauth2client.client # type: ignore + import oauth2client.contrib.gce # type: ignore + import oauth2client.service_account # type: ignore +except ImportError as caught_exc: + six.raise_from(ImportError("oauth2client is not installed."), caught_exc) + +try: + import oauth2client.contrib.appengine # type: ignore + + _HAS_APPENGINE = True +except ImportError: + _HAS_APPENGINE = False + + +_CONVERT_ERROR_TMPL = "Unable to convert {} to a google-auth credentials class." + + +def _convert_oauth2_credentials(credentials): + """Converts to :class:`google.oauth2.credentials.Credentials`. + + Args: + credentials (Union[oauth2client.client.OAuth2Credentials, + oauth2client.client.GoogleCredentials]): The credentials to + convert. + + Returns: + google.oauth2.credentials.Credentials: The converted credentials. + """ + new_credentials = google.oauth2.credentials.Credentials( + token=credentials.access_token, + refresh_token=credentials.refresh_token, + token_uri=credentials.token_uri, + client_id=credentials.client_id, + client_secret=credentials.client_secret, + scopes=credentials.scopes, + ) + + new_credentials._expires = credentials.token_expiry + + return new_credentials + + +def _convert_service_account_credentials(credentials): + """Converts to :class:`google.oauth2.service_account.Credentials`. + + Args: + credentials (Union[ + oauth2client.service_account.ServiceAccountCredentials, + oauth2client.service_account._JWTAccessCredentials]): The + credentials to convert. + + Returns: + google.oauth2.service_account.Credentials: The converted credentials. + """ + info = credentials.serialization_data.copy() + info["token_uri"] = credentials.token_uri + return google.oauth2.service_account.Credentials.from_service_account_info(info) + + +def _convert_gce_app_assertion_credentials(credentials): + """Converts to :class:`google.auth.compute_engine.Credentials`. + + Args: + credentials (oauth2client.contrib.gce.AppAssertionCredentials): The + credentials to convert. + + Returns: + google.oauth2.service_account.Credentials: The converted credentials. + """ + return google.auth.compute_engine.Credentials( + service_account_email=credentials.service_account_email + ) + + +def _convert_appengine_app_assertion_credentials(credentials): + """Converts to :class:`google.auth.app_engine.Credentials`. + + Args: + credentials (oauth2client.contrib.app_engine.AppAssertionCredentials): + The credentials to convert. + + Returns: + google.oauth2.service_account.Credentials: The converted credentials. + """ + # pylint: disable=invalid-name + return google.auth.app_engine.Credentials( + scopes=_helpers.string_to_scopes(credentials.scope), + service_account_id=credentials.service_account_id, + ) + + +_CLASS_CONVERSION_MAP = { + oauth2client.client.OAuth2Credentials: _convert_oauth2_credentials, + oauth2client.client.GoogleCredentials: _convert_oauth2_credentials, + oauth2client.service_account.ServiceAccountCredentials: _convert_service_account_credentials, + oauth2client.service_account._JWTAccessCredentials: _convert_service_account_credentials, + oauth2client.contrib.gce.AppAssertionCredentials: _convert_gce_app_assertion_credentials, +} + +if _HAS_APPENGINE: + _CLASS_CONVERSION_MAP[ + oauth2client.contrib.appengine.AppAssertionCredentials + ] = _convert_appengine_app_assertion_credentials + + +def convert(credentials): + """Convert oauth2client credentials to google-auth credentials. + + This class converts: + + - :class:`oauth2client.client.OAuth2Credentials` to + :class:`google.oauth2.credentials.Credentials`. + - :class:`oauth2client.client.GoogleCredentials` to + :class:`google.oauth2.credentials.Credentials`. + - :class:`oauth2client.service_account.ServiceAccountCredentials` to + :class:`google.oauth2.service_account.Credentials`. + - :class:`oauth2client.service_account._JWTAccessCredentials` to + :class:`google.oauth2.service_account.Credentials`. + - :class:`oauth2client.contrib.gce.AppAssertionCredentials` to + :class:`google.auth.compute_engine.Credentials`. + - :class:`oauth2client.contrib.appengine.AppAssertionCredentials` to + :class:`google.auth.app_engine.Credentials`. + + Returns: + google.auth.credentials.Credentials: The converted credentials. + + Raises: + ValueError: If the credentials could not be converted. + """ + + credentials_class = type(credentials) + + try: + return _CLASS_CONVERSION_MAP[credentials_class](credentials) + except KeyError as caught_exc: + new_exc = ValueError(_CONVERT_ERROR_TMPL.format(credentials_class)) + six.raise_from(new_exc, caught_exc) diff --git a/script.module.google-auth-library/lib/google/auth/_service_account_info.py b/script.module.google-auth-library/lib/google/auth/_service_account_info.py new file mode 100644 index 000000000..157099273 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/_service_account_info.py @@ -0,0 +1,81 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helper functions for loading data from a Google service account file.""" + +import io +import json + +import six + +from google.auth import crypt + + +def from_dict(data, require=None, use_rsa_signer=True): + """Validates a dictionary containing Google service account data. + + Creates and returns a :class:`google.auth.crypt.Signer` instance from the + private key specified in the data. + + Args: + data (Mapping[str, str]): The service account data + require (Sequence[str]): List of keys required to be present in the + info. + use_rsa_signer (Optional[bool]): Whether to use RSA signer or EC signer. + We use RSA signer by default. + + Returns: + google.auth.crypt.Signer: A signer created from the private key in the + service account file. + + Raises: + ValueError: if the data was in the wrong format, or if one of the + required keys is missing. + """ + keys_needed = set(require if require is not None else []) + + missing = keys_needed.difference(six.iterkeys(data)) + + if missing: + raise ValueError( + "Service account info was not in the expected format, missing " + "fields {}.".format(", ".join(missing)) + ) + + # Create a signer. + if use_rsa_signer: + signer = crypt.RSASigner.from_service_account_info(data) + else: + signer = crypt.ES256Signer.from_service_account_info(data) + + return signer + + +def from_filename(filename, require=None, use_rsa_signer=True): + """Reads a Google service account JSON file and returns its parsed info. + + Args: + filename (str): The path to the service account .json file. + require (Sequence[str]): List of keys required to be present in the + info. + use_rsa_signer (Optional[bool]): Whether to use RSA signer or EC signer. + We use RSA signer by default. + + Returns: + Tuple[ Mapping[str, str], google.auth.crypt.Signer ]: The verified + info and a signer instance. + """ + with io.open(filename, "r", encoding="utf-8") as json_file: + data = json.load(json_file) + return data, from_dict(data, require=require, use_rsa_signer=use_rsa_signer) diff --git a/script.module.google-auth-library/lib/google/auth/api_key.py b/script.module.google-auth-library/lib/google/auth/api_key.py new file mode 100644 index 000000000..49c6ffd2d --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/api_key.py @@ -0,0 +1,75 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google API key support. +This module provides authentication using the `API key`_. +.. _API key: + https://cloud.google.com/docs/authentication/api-keys/ +""" + +from google.auth import _helpers +from google.auth import credentials + + +class Credentials(credentials.Credentials): + """API key credentials. + These credentials use API key to provide authorization to applications. + """ + + def __init__(self, token): + """ + Args: + token (str): API key string + Raises: + ValueError: If the provided API key is not a non-empty string. + """ + super(Credentials, self).__init__() + if not token: + raise ValueError("Token must be a non-empty API key string") + self.token = token + + @property + def expired(self): + return False + + @property + def valid(self): + return True + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + return + + def apply(self, headers, token=None): + """Apply the API key token to the x-goog-api-key header. + Args: + headers (Mapping): The HTTP request headers. + token (Optional[str]): If specified, overrides the current access + token. + """ + headers["x-goog-api-key"] = token or self.token + + def before_request(self, request, method, url, headers): + """Performs credential-specific before request logic. + Refreshes the credentials if necessary, then calls :meth:`apply` to + apply the token to the x-goog-api-key header. + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + method (str): The request's HTTP method or the RPC method being + invoked. + url (str): The request's URI or the RPC service's URI. + headers (Mapping): The request's headers. + """ + self.apply(headers) diff --git a/script.module.google-auth-library/lib/google/auth/app_engine.py b/script.module.google-auth-library/lib/google/auth/app_engine.py new file mode 100644 index 000000000..1460a7d1a --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/app_engine.py @@ -0,0 +1,179 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google App Engine standard environment support. + +This module provides authentication and signing for applications running on App +Engine in the standard environment using the `App Identity API`_. + + +.. _App Identity API: + https://cloud.google.com/appengine/docs/python/appidentity/ +""" + +import datetime + +from google.auth import _helpers +from google.auth import credentials +from google.auth import crypt + +# pytype: disable=import-error +try: + from google.appengine.api import app_identity # type: ignore +except ImportError: + app_identity = None # type: ignore +# pytype: enable=import-error + + +class Signer(crypt.Signer): + """Signs messages using the App Engine App Identity service. + + This can be used in place of :class:`google.auth.crypt.Signer` when + running in the App Engine standard environment. + """ + + @property + def key_id(self): + """Optional[str]: The key ID used to identify this private key. + + .. warning:: + This is always ``None``. The key ID used by App Engine can not + be reliably determined ahead of time. + """ + return None + + @_helpers.copy_docstring(crypt.Signer) + def sign(self, message): + message = _helpers.to_bytes(message) + _, signature = app_identity.sign_blob(message) + return signature + + +def get_project_id(): + """Gets the project ID for the current App Engine application. + + Returns: + str: The project ID + + Raises: + EnvironmentError: If the App Engine APIs are unavailable. + """ + # pylint: disable=missing-raises-doc + # Pylint rightfully thinks EnvironmentError is OSError, but doesn't + # realize it's a valid alias. + if app_identity is None: + raise EnvironmentError("The App Engine APIs are not available.") + return app_identity.get_application_id() + + +class Credentials( + credentials.Scoped, credentials.Signing, credentials.CredentialsWithQuotaProject +): + """App Engine standard environment credentials. + + These credentials use the App Engine App Identity API to obtain access + tokens. + """ + + def __init__( + self, + scopes=None, + default_scopes=None, + service_account_id=None, + quota_project_id=None, + ): + """ + Args: + scopes (Sequence[str]): Scopes to request from the App Identity + API. + default_scopes (Sequence[str]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + service_account_id (str): The service account ID passed into + :func:`google.appengine.api.app_identity.get_access_token`. + If not specified, the default application service account + ID will be used. + quota_project_id (Optional[str]): The project ID used for quota + and billing. + + Raises: + EnvironmentError: If the App Engine APIs are unavailable. + """ + # pylint: disable=missing-raises-doc + # Pylint rightfully thinks EnvironmentError is OSError, but doesn't + # realize it's a valid alias. + if app_identity is None: + raise EnvironmentError("The App Engine APIs are not available.") + + super(Credentials, self).__init__() + self._scopes = scopes + self._default_scopes = default_scopes + self._service_account_id = service_account_id + self._signer = Signer() + self._quota_project_id = quota_project_id + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + scopes = self._scopes if self._scopes is not None else self._default_scopes + # pylint: disable=unused-argument + token, ttl = app_identity.get_access_token(scopes, self._service_account_id) + expiry = datetime.datetime.utcfromtimestamp(ttl) + + self.token, self.expiry = token, expiry + + @property + def service_account_email(self): + """The service account email.""" + if self._service_account_id is None: + self._service_account_id = app_identity.get_service_account_name() + return self._service_account_id + + @property + def requires_scopes(self): + """Checks if the credentials requires scopes. + + Returns: + bool: True if there are no scopes set otherwise False. + """ + return not self._scopes and not self._default_scopes + + @_helpers.copy_docstring(credentials.Scoped) + def with_scopes(self, scopes, default_scopes=None): + return self.__class__( + scopes=scopes, + default_scopes=default_scopes, + service_account_id=self._service_account_id, + quota_project_id=self.quota_project_id, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__( + scopes=self._scopes, + service_account_id=self._service_account_id, + quota_project_id=quota_project_id, + ) + + @_helpers.copy_docstring(credentials.Signing) + def sign_bytes(self, message): + return self._signer.sign(message) + + @property # type: ignore + @_helpers.copy_docstring(credentials.Signing) + def signer_email(self): + return self.service_account_email + + @property # type: ignore + @_helpers.copy_docstring(credentials.Signing) + def signer(self): + return self._signer diff --git a/script.module.google-auth-library/lib/google/auth/aws.py b/script.module.google-auth-library/lib/google/auth/aws.py new file mode 100644 index 000000000..04c5e7c5d --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/aws.py @@ -0,0 +1,767 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""AWS Credentials and AWS Signature V4 Request Signer. + +This module provides credentials to access Google Cloud resources from Amazon +Web Services (AWS) workloads. These credentials are recommended over the +use of service account credentials in AWS as they do not involve the management +of long-live service account private keys. + +AWS Credentials are initialized using external_account arguments which are +typically loaded from the external credentials JSON file. +Unlike other Credentials that can be initialized with a list of explicit +arguments, secrets or credentials, external account clients use the +environment and hints/guidelines provided by the external_account JSON +file to retrieve credentials and exchange them for Google access tokens. + +This module also provides a basic implementation of the +`AWS Signature Version 4`_ request signing algorithm. + +AWS Credentials use serialized signed requests to the +`AWS STS GetCallerIdentity`_ API that can be exchanged for Google access tokens +via the GCP STS endpoint. + +.. _AWS Signature Version 4: https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html +.. _AWS STS GetCallerIdentity: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html +""" + +import hashlib +import hmac +import json +import os +import posixpath +import re + +from six.moves import http_client +from six.moves import urllib +from six.moves.urllib.parse import urljoin +from six.moves.urllib.parse import urlparse + +from google.auth import _helpers +from google.auth import environment_vars +from google.auth import exceptions +from google.auth import external_account + +# AWS Signature Version 4 signing algorithm identifier. +_AWS_ALGORITHM = "AWS4-HMAC-SHA256" +# The termination string for the AWS credential scope value as defined in +# https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html +_AWS_REQUEST_TYPE = "aws4_request" +# The AWS authorization header name for the security session token if available. +_AWS_SECURITY_TOKEN_HEADER = "x-amz-security-token" +# The AWS authorization header name for the auto-generated date. +_AWS_DATE_HEADER = "x-amz-date" + + +class RequestSigner(object): + """Implements an AWS request signer based on the AWS Signature Version 4 signing + process. + https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html + """ + + def __init__(self, region_name): + """Instantiates an AWS request signer used to compute authenticated signed + requests to AWS APIs based on the AWS Signature Version 4 signing process. + + Args: + region_name (str): The AWS region to use. + """ + + self._region_name = region_name + + def get_request_options( + self, + aws_security_credentials, + url, + method, + request_payload="", + additional_headers={}, + ): + """Generates the signed request for the provided HTTP request for calling + an AWS API. This follows the steps described at: + https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html + + Args: + aws_security_credentials (Mapping[str, str]): A dictionary containing + the AWS security credentials. + url (str): The AWS service URL containing the canonical URI and + query string. + method (str): The HTTP method used to call this API. + request_payload (Optional[str]): The optional request payload if + available. + additional_headers (Optional[Mapping[str, str]]): The optional + additional headers needed for the requested AWS API. + + Returns: + Mapping[str, str]: The AWS signed request dictionary object. + """ + # Get AWS credentials. + access_key = aws_security_credentials.get("access_key_id") + secret_key = aws_security_credentials.get("secret_access_key") + security_token = aws_security_credentials.get("security_token") + + additional_headers = additional_headers or {} + + uri = urllib.parse.urlparse(url) + # Normalize the URL path. This is needed for the canonical_uri. + # os.path.normpath can't be used since it normalizes "/" paths + # to "\\" in Windows OS. + normalized_uri = urllib.parse.urlparse( + urljoin(url, posixpath.normpath(uri.path)) + ) + # Validate provided URL. + if not uri.hostname or uri.scheme != "https": + raise ValueError("Invalid AWS service URL") + + header_map = _generate_authentication_header_map( + host=uri.hostname, + canonical_uri=normalized_uri.path or "/", + canonical_querystring=_get_canonical_querystring(uri.query), + method=method, + region=self._region_name, + access_key=access_key, + secret_key=secret_key, + security_token=security_token, + request_payload=request_payload, + additional_headers=additional_headers, + ) + headers = { + "Authorization": header_map.get("authorization_header"), + "host": uri.hostname, + } + # Add x-amz-date if available. + if "amz_date" in header_map: + headers[_AWS_DATE_HEADER] = header_map.get("amz_date") + # Append additional optional headers, eg. X-Amz-Target, Content-Type, etc. + for key in additional_headers: + headers[key] = additional_headers[key] + + # Add session token if available. + if security_token is not None: + headers[_AWS_SECURITY_TOKEN_HEADER] = security_token + + signed_request = {"url": url, "method": method, "headers": headers} + if request_payload: + signed_request["data"] = request_payload + return signed_request + + +def _get_canonical_querystring(query): + """Generates the canonical query string given a raw query string. + Logic is based on + https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html + + Args: + query (str): The raw query string. + + Returns: + str: The canonical query string. + """ + # Parse raw query string. + querystring = urllib.parse.parse_qs(query) + querystring_encoded_map = {} + for key in querystring: + quote_key = urllib.parse.quote(key, safe="-_.~") + # URI encode key. + querystring_encoded_map[quote_key] = [] + for item in querystring[key]: + # For each key, URI encode all values for that key. + querystring_encoded_map[quote_key].append( + urllib.parse.quote(item, safe="-_.~") + ) + # Sort values for each key. + querystring_encoded_map[quote_key].sort() + # Sort keys. + sorted_keys = list(querystring_encoded_map.keys()) + sorted_keys.sort() + # Reconstruct the query string. Preserve keys with multiple values. + querystring_encoded_pairs = [] + for key in sorted_keys: + for item in querystring_encoded_map[key]: + querystring_encoded_pairs.append("{}={}".format(key, item)) + return "&".join(querystring_encoded_pairs) + + +def _sign(key, msg): + """Creates the HMAC-SHA256 hash of the provided message using the provided + key. + + Args: + key (str): The HMAC-SHA256 key to use. + msg (str): The message to hash. + + Returns: + str: The computed hash bytes. + """ + return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() + + +def _get_signing_key(key, date_stamp, region_name, service_name): + """Calculates the signing key used to calculate the signature for + AWS Signature Version 4 based on: + https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html + + Args: + key (str): The AWS secret access key. + date_stamp (str): The '%Y%m%d' date format. + region_name (str): The AWS region. + service_name (str): The AWS service name, eg. sts. + + Returns: + str: The signing key bytes. + """ + k_date = _sign(("AWS4" + key).encode("utf-8"), date_stamp) + k_region = _sign(k_date, region_name) + k_service = _sign(k_region, service_name) + k_signing = _sign(k_service, "aws4_request") + return k_signing + + +def _generate_authentication_header_map( + host, + canonical_uri, + canonical_querystring, + method, + region, + access_key, + secret_key, + security_token, + request_payload="", + additional_headers={}, +): + """Generates the authentication header map needed for generating the AWS + Signature Version 4 signed request. + + Args: + host (str): The AWS service URL hostname. + canonical_uri (str): The AWS service URL path name. + canonical_querystring (str): The AWS service URL query string. + method (str): The HTTP method used to call this API. + region (str): The AWS region. + access_key (str): The AWS access key ID. + secret_key (str): The AWS secret access key. + security_token (Optional[str]): The AWS security session token. This is + available for temporary sessions. + request_payload (Optional[str]): The optional request payload if + available. + additional_headers (Optional[Mapping[str, str]]): The optional + additional headers needed for the requested AWS API. + + Returns: + Mapping[str, str]: The AWS authentication header dictionary object. + This contains the x-amz-date and authorization header information. + """ + # iam.amazonaws.com host => iam service. + # sts.us-east-2.amazonaws.com host => sts service. + service_name = host.split(".")[0] + + current_time = _helpers.utcnow() + amz_date = current_time.strftime("%Y%m%dT%H%M%SZ") + date_stamp = current_time.strftime("%Y%m%d") + + # Change all additional headers to be lower case. + full_headers = {} + for key in additional_headers: + full_headers[key.lower()] = additional_headers[key] + # Add AWS session token if available. + if security_token is not None: + full_headers[_AWS_SECURITY_TOKEN_HEADER] = security_token + + # Required headers + full_headers["host"] = host + # Do not use generated x-amz-date if the date header is provided. + # Previously the date was not fixed with x-amz- and could be provided + # manually. + # https://github.com/boto/botocore/blob/879f8440a4e9ace5d3cf145ce8b3d5e5ffb892ef/tests/unit/auth/aws4_testsuite/get-header-value-trim.req + if "date" not in full_headers: + full_headers[_AWS_DATE_HEADER] = amz_date + + # Header keys need to be sorted alphabetically. + canonical_headers = "" + header_keys = list(full_headers.keys()) + header_keys.sort() + for key in header_keys: + canonical_headers = "{}{}:{}\n".format( + canonical_headers, key, full_headers[key] + ) + signed_headers = ";".join(header_keys) + + payload_hash = hashlib.sha256((request_payload or "").encode("utf-8")).hexdigest() + + # https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html + canonical_request = "{}\n{}\n{}\n{}\n{}\n{}".format( + method, + canonical_uri, + canonical_querystring, + canonical_headers, + signed_headers, + payload_hash, + ) + + credential_scope = "{}/{}/{}/{}".format( + date_stamp, region, service_name, _AWS_REQUEST_TYPE + ) + + # https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html + string_to_sign = "{}\n{}\n{}\n{}".format( + _AWS_ALGORITHM, + amz_date, + credential_scope, + hashlib.sha256(canonical_request.encode("utf-8")).hexdigest(), + ) + + # https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html + signing_key = _get_signing_key(secret_key, date_stamp, region, service_name) + signature = hmac.new( + signing_key, string_to_sign.encode("utf-8"), hashlib.sha256 + ).hexdigest() + + # https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html + authorization_header = "{} Credential={}/{}, SignedHeaders={}, Signature={}".format( + _AWS_ALGORITHM, access_key, credential_scope, signed_headers, signature + ) + + authentication_header = {"authorization_header": authorization_header} + # Do not use generated x-amz-date if the date header is provided. + if "date" not in full_headers: + authentication_header["amz_date"] = amz_date + return authentication_header + + +class Credentials(external_account.Credentials): + """AWS external account credentials. + This is used to exchange serialized AWS signature v4 signed requests to + AWS STS GetCallerIdentity service for Google access tokens. + """ + + def __init__( + self, + audience, + subject_token_type, + token_url, + credential_source=None, + *args, + **kwargs + ): + """Instantiates an AWS workload external account credentials object. + + Args: + audience (str): The STS audience field. + subject_token_type (str): The subject token type. + token_url (str): The STS endpoint URL. + credential_source (Mapping): The credential source dictionary used + to provide instructions on how to retrieve external credential + to be exchanged for Google access tokens. + args (List): Optional positional arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method. + kwargs (Mapping): Optional keyword arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method. + + Raises: + google.auth.exceptions.RefreshError: If an error is encountered during + access token retrieval logic. + ValueError: For invalid parameters. + + .. note:: Typically one of the helper constructors + :meth:`from_file` or + :meth:`from_info` are used instead of calling the constructor directly. + """ + super(Credentials, self).__init__( + audience=audience, + subject_token_type=subject_token_type, + token_url=token_url, + credential_source=credential_source, + *args, + **kwargs + ) + credential_source = credential_source or {} + self._environment_id = credential_source.get("environment_id") or "" + self._region_url = credential_source.get("region_url") + self._security_credentials_url = credential_source.get("url") + self._cred_verification_url = credential_source.get( + "regional_cred_verification_url" + ) + self._imdsv2_session_token_url = credential_source.get( + "imdsv2_session_token_url" + ) + self._region = None + self._request_signer = None + self._target_resource = audience + + self.validate_metadata_server_urls() + + # Get the environment ID. Currently, only one version supported (v1). + matches = re.match(r"^(aws)([\d]+)$", self._environment_id) + if matches: + env_id, env_version = matches.groups() + else: + env_id, env_version = (None, None) + + if env_id != "aws" or self._cred_verification_url is None: + raise ValueError("No valid AWS 'credential_source' provided") + elif int(env_version or "") != 1: + raise ValueError( + "aws version '{}' is not supported in the current build.".format( + env_version + ) + ) + + def validate_metadata_server_urls(self): + self.validate_metadata_server_url_if_any(self._region_url, "region_url") + self.validate_metadata_server_url_if_any(self._security_credentials_url, "url") + self.validate_metadata_server_url_if_any( + self._imdsv2_session_token_url, "imdsv2_session_token_url" + ) + + @staticmethod + def validate_metadata_server_url_if_any(url_string, name_of_data): + if url_string: + url = urlparse(url_string) + if url.hostname != "169.254.169.254" and url.hostname != "fd00:ec2::254": + raise ValueError( + "Invalid hostname '{}' for '{}'".format(url.hostname, name_of_data) + ) + + def retrieve_subject_token(self, request): + """Retrieves the subject token using the credential_source object. + The subject token is a serialized `AWS GetCallerIdentity signed request`_. + + The logic is summarized as: + + Retrieve the AWS region from the AWS_REGION or AWS_DEFAULT_REGION + environment variable or from the AWS metadata server availability-zone + if not found in the environment variable. + + Check AWS credentials in environment variables. If not found, retrieve + from the AWS metadata server security-credentials endpoint. + + When retrieving AWS credentials from the metadata server + security-credentials endpoint, the AWS role needs to be determined by + calling the security-credentials endpoint without any argument. Then the + credentials can be retrieved via: security-credentials/role_name + + Generate the signed request to AWS STS GetCallerIdentity action. + + Inject x-goog-cloud-target-resource into header and serialize the + signed request. This will be the subject-token to pass to GCP STS. + + .. _AWS GetCallerIdentity signed request: + https://cloud.google.com/iam/docs/access-resources-aws#exchange-token + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + Returns: + str: The retrieved subject token. + """ + # Fetch the session token required to make meta data endpoint calls to aws + if request is not None and self._imdsv2_session_token_url is not None: + headers = {"X-aws-ec2-metadata-token-ttl-seconds": "300"} + + imdsv2_session_token_response = request( + url=self._imdsv2_session_token_url, method="PUT", headers=headers + ) + + if imdsv2_session_token_response.status != 200: + raise exceptions.RefreshError( + "Unable to retrieve AWS Session Token", + imdsv2_session_token_response.data, + ) + + imdsv2_session_token = imdsv2_session_token_response.data + else: + imdsv2_session_token = None + + # Initialize the request signer if not yet initialized after determining + # the current AWS region. + if self._request_signer is None: + self._region = self._get_region( + request, self._region_url, imdsv2_session_token + ) + self._request_signer = RequestSigner(self._region) + + # Retrieve the AWS security credentials needed to generate the signed + # request. + aws_security_credentials = self._get_security_credentials( + request, imdsv2_session_token + ) + # Generate the signed request to AWS STS GetCallerIdentity API. + # Use the required regional endpoint. Otherwise, the request will fail. + request_options = self._request_signer.get_request_options( + aws_security_credentials, + self._cred_verification_url.replace("{region}", self._region), + "POST", + ) + # The GCP STS endpoint expects the headers to be formatted as: + # [ + # {key: 'x-amz-date', value: '...'}, + # {key: 'Authorization', value: '...'}, + # ... + # ] + # And then serialized as: + # quote(json.dumps({ + # url: '...', + # method: 'POST', + # headers: [{key: 'x-amz-date', value: '...'}, ...] + # })) + request_headers = request_options.get("headers") + # The full, canonical resource name of the workload identity pool + # provider, with or without the HTTPS prefix. + # Including this header as part of the signature is recommended to + # ensure data integrity. + request_headers["x-goog-cloud-target-resource"] = self._target_resource + + # Serialize AWS signed request. + # Keeping inner keys in sorted order makes testing easier for Python + # versions <=3.5 as the stringified JSON string would have a predictable + # key order. + aws_signed_req = {} + aws_signed_req["url"] = request_options.get("url") + aws_signed_req["method"] = request_options.get("method") + aws_signed_req["headers"] = [] + # Reformat header to GCP STS expected format. + for key in sorted(request_headers.keys()): + aws_signed_req["headers"].append( + {"key": key, "value": request_headers[key]} + ) + + return urllib.parse.quote( + json.dumps(aws_signed_req, separators=(",", ":"), sort_keys=True) + ) + + def _get_region(self, request, url, imdsv2_session_token): + """Retrieves the current AWS region from either the AWS_REGION or + AWS_DEFAULT_REGION environment variable or from the AWS metadata server. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + url (str): The AWS metadata server region URL. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. + + Returns: + str: The current AWS region. + + Raises: + google.auth.exceptions.RefreshError: If an error occurs while + retrieving the AWS region. + """ + # The AWS metadata server is not available in some AWS environments + # such as AWS lambda. Instead, it is available via environment + # variable. + env_aws_region = os.environ.get(environment_vars.AWS_REGION) + if env_aws_region is not None: + return env_aws_region + + env_aws_region = os.environ.get(environment_vars.AWS_DEFAULT_REGION) + if env_aws_region is not None: + return env_aws_region + + if not self._region_url: + raise exceptions.RefreshError("Unable to determine AWS region") + + headers = None + if imdsv2_session_token is not None: + headers = {"X-aws-ec2-metadata-token": imdsv2_session_token} + + response = request(url=self._region_url, method="GET", headers=headers) + + # Support both string and bytes type response.data. + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + + if response.status != 200: + raise exceptions.RefreshError( + "Unable to retrieve AWS region", response_body + ) + + # This endpoint will return the region in format: us-east-2b. + # Only the us-east-2 part should be used. + return response_body[:-1] + + def _get_security_credentials(self, request, imdsv2_session_token): + """Retrieves the AWS security credentials required for signing AWS + requests from either the AWS security credentials environment variables + or from the AWS metadata server. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. + + Returns: + Mapping[str, str]: The AWS security credentials dictionary object. + + Raises: + google.auth.exceptions.RefreshError: If an error occurs while + retrieving the AWS security credentials. + """ + + # Check environment variables for permanent credentials first. + # https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html + env_aws_access_key_id = os.environ.get(environment_vars.AWS_ACCESS_KEY_ID) + env_aws_secret_access_key = os.environ.get( + environment_vars.AWS_SECRET_ACCESS_KEY + ) + # This is normally not available for permanent credentials. + env_aws_session_token = os.environ.get(environment_vars.AWS_SESSION_TOKEN) + if env_aws_access_key_id and env_aws_secret_access_key: + return { + "access_key_id": env_aws_access_key_id, + "secret_access_key": env_aws_secret_access_key, + "security_token": env_aws_session_token, + } + + # Get role name. + role_name = self._get_metadata_role_name(request, imdsv2_session_token) + + # Get security credentials. + credentials = self._get_metadata_security_credentials( + request, role_name, imdsv2_session_token + ) + + return { + "access_key_id": credentials.get("AccessKeyId"), + "secret_access_key": credentials.get("SecretAccessKey"), + "security_token": credentials.get("Token"), + } + + def _get_metadata_security_credentials( + self, request, role_name, imdsv2_session_token + ): + """Retrieves the AWS security credentials required for signing AWS + requests from the AWS metadata server. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + role_name (str): The AWS role name required by the AWS metadata + server security_credentials endpoint in order to return the + credentials. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. + + Returns: + Mapping[str, str]: The AWS metadata server security credentials + response. + + Raises: + google.auth.exceptions.RefreshError: If an error occurs while + retrieving the AWS security credentials. + """ + headers = {"Content-Type": "application/json"} + if imdsv2_session_token is not None: + headers["X-aws-ec2-metadata-token"] = imdsv2_session_token + + response = request( + url="{}/{}".format(self._security_credentials_url, role_name), + method="GET", + headers=headers, + ) + + # support both string and bytes type response.data + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + + if response.status != http_client.OK: + raise exceptions.RefreshError( + "Unable to retrieve AWS security credentials", response_body + ) + + credentials_response = json.loads(response_body) + + return credentials_response + + def _get_metadata_role_name(self, request, imdsv2_session_token): + """Retrieves the AWS role currently attached to the current AWS + workload by querying the AWS metadata server. This is needed for the + AWS metadata server security credentials endpoint in order to retrieve + the AWS security credentials needed to sign requests to AWS APIs. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. + + Returns: + str: The AWS role name. + + Raises: + google.auth.exceptions.RefreshError: If an error occurs while + retrieving the AWS role name. + """ + if self._security_credentials_url is None: + raise exceptions.RefreshError( + "Unable to determine the AWS metadata server security credentials endpoint" + ) + + headers = None + if imdsv2_session_token is not None: + headers = {"X-aws-ec2-metadata-token": imdsv2_session_token} + + response = request( + url=self._security_credentials_url, method="GET", headers=headers + ) + + # support both string and bytes type response.data + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + + if response.status != http_client.OK: + raise exceptions.RefreshError( + "Unable to retrieve AWS role name", response_body + ) + + return response_body + + @classmethod + def from_info(cls, info, **kwargs): + """Creates an AWS Credentials instance from parsed external account info. + + Args: + info (Mapping[str, str]): The AWS external account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.aws.Credentials: The constructed credentials. + + Raises: + ValueError: For invalid parameters. + """ + return super(Credentials, cls).from_info(info, **kwargs) + + @classmethod + def from_file(cls, filename, **kwargs): + """Creates an AWS Credentials instance from an external account json file. + + Args: + filename (str): The path to the AWS external account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.aws.Credentials: The constructed credentials. + """ + return super(Credentials, cls).from_file(filename, **kwargs) diff --git a/script.module.google-auth-library/lib/google/auth/compute_engine/__init__.py b/script.module.google-auth-library/lib/google/auth/compute_engine/__init__.py new file mode 100644 index 000000000..5c84234e9 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/compute_engine/__init__.py @@ -0,0 +1,21 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Compute Engine authentication.""" + +from google.auth.compute_engine.credentials import Credentials +from google.auth.compute_engine.credentials import IDTokenCredentials + + +__all__ = ["Credentials", "IDTokenCredentials"] diff --git a/script.module.google-auth-library/lib/google/auth/compute_engine/_metadata.py b/script.module.google-auth-library/lib/google/auth/compute_engine/_metadata.py new file mode 100644 index 000000000..16c5e2138 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/compute_engine/_metadata.py @@ -0,0 +1,267 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Provides helper methods for talking to the Compute Engine metadata server. + +See https://cloud.google.com/compute/docs/metadata for more details. +""" + +import datetime +import json +import logging +import os + +import six +from six.moves import http_client +from six.moves.urllib import parse as urlparse + +from google.auth import _helpers +from google.auth import environment_vars +from google.auth import exceptions + +_LOGGER = logging.getLogger(__name__) + +# Environment variable GCE_METADATA_HOST is originally named +# GCE_METADATA_ROOT. For compatiblity reasons, here it checks +# the new variable first; if not set, the system falls back +# to the old variable. +_GCE_METADATA_HOST = os.getenv(environment_vars.GCE_METADATA_HOST, None) +if not _GCE_METADATA_HOST: + _GCE_METADATA_HOST = os.getenv( + environment_vars.GCE_METADATA_ROOT, "metadata.google.internal" + ) +_METADATA_ROOT = "http://{}/computeMetadata/v1/".format(_GCE_METADATA_HOST) + +# This is used to ping the metadata server, it avoids the cost of a DNS +# lookup. +_METADATA_IP_ROOT = "http://{}".format( + os.getenv(environment_vars.GCE_METADATA_IP, "169.254.169.254") +) +_METADATA_FLAVOR_HEADER = "metadata-flavor" +_METADATA_FLAVOR_VALUE = "Google" +_METADATA_HEADERS = {_METADATA_FLAVOR_HEADER: _METADATA_FLAVOR_VALUE} + +# Timeout in seconds to wait for the GCE metadata server when detecting the +# GCE environment. +try: + _METADATA_DEFAULT_TIMEOUT = int(os.getenv("GCE_METADATA_TIMEOUT", 3)) +except ValueError: # pragma: NO COVER + _METADATA_DEFAULT_TIMEOUT = 3 + + +def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3): + """Checks to see if the metadata server is available. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + timeout (int): How long to wait for the metadata server to respond. + retry_count (int): How many times to attempt connecting to metadata + server using above timeout. + + Returns: + bool: True if the metadata server is reachable, False otherwise. + """ + # NOTE: The explicit ``timeout`` is a workaround. The underlying + # issue is that resolving an unknown host on some networks will take + # 20-30 seconds; making this timeout short fixes the issue, but + # could lead to false negatives in the event that we are on GCE, but + # the metadata resolution was particularly slow. The latter case is + # "unlikely". + retries = 0 + while retries < retry_count: + try: + response = request( + url=_METADATA_IP_ROOT, + method="GET", + headers=_METADATA_HEADERS, + timeout=timeout, + ) + + metadata_flavor = response.headers.get(_METADATA_FLAVOR_HEADER) + return ( + response.status == http_client.OK + and metadata_flavor == _METADATA_FLAVOR_VALUE + ) + + except exceptions.TransportError as e: + _LOGGER.warning( + "Compute Engine Metadata server unavailable on " + "attempt %s of %s. Reason: %s", + retries + 1, + retry_count, + e, + ) + retries += 1 + + return False + + +def get( + request, path, root=_METADATA_ROOT, params=None, recursive=False, retry_count=5 +): + """Fetch a resource from the metadata server. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + path (str): The resource to retrieve. For example, + ``'instance/service-accounts/default'``. + root (str): The full path to the metadata server root. + params (Optional[Mapping[str, str]]): A mapping of query parameter + keys to values. + recursive (bool): Whether to do a recursive query of metadata. See + https://cloud.google.com/compute/docs/metadata#aggcontents for more + details. + retry_count (int): How many times to attempt connecting to metadata + server using above timeout. + + Returns: + Union[Mapping, str]: If the metadata server returns JSON, a mapping of + the decoded JSON is return. Otherwise, the response content is + returned as a string. + + Raises: + google.auth.exceptions.TransportError: if an error occurred while + retrieving metadata. + """ + base_url = urlparse.urljoin(root, path) + query_params = {} if params is None else params + + if recursive: + query_params["recursive"] = "true" + + url = _helpers.update_query(base_url, query_params) + + retries = 0 + while retries < retry_count: + try: + response = request(url=url, method="GET", headers=_METADATA_HEADERS) + break + + except exceptions.TransportError as e: + _LOGGER.warning( + "Compute Engine Metadata server unavailable on " + "attempt %s of %s. Reason: %s", + retries + 1, + retry_count, + e, + ) + retries += 1 + else: + raise exceptions.TransportError( + "Failed to retrieve {} from the Google Compute Engine " + "metadata service. Compute Engine Metadata server unavailable".format(url) + ) + + if response.status == http_client.OK: + content = _helpers.from_bytes(response.data) + if response.headers["content-type"] == "application/json": + try: + return json.loads(content) + except ValueError as caught_exc: + new_exc = exceptions.TransportError( + "Received invalid JSON from the Google Compute Engine " + "metadata service: {:.20}".format(content) + ) + six.raise_from(new_exc, caught_exc) + else: + return content + else: + raise exceptions.TransportError( + "Failed to retrieve {} from the Google Compute Engine " + "metadata service. Status: {} Response:\n{}".format( + url, response.status, response.data + ), + response, + ) + + +def get_project_id(request): + """Get the Google Cloud Project ID from the metadata server. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + + Returns: + str: The project ID + + Raises: + google.auth.exceptions.TransportError: if an error occurred while + retrieving metadata. + """ + return get(request, "project/project-id") + + +def get_service_account_info(request, service_account="default"): + """Get information about a service account from the metadata server. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + service_account (str): The string 'default' or a service account email + address. The determines which service account for which to acquire + information. + + Returns: + Mapping: The service account's information, for example:: + + { + 'email': '...', + 'scopes': ['scope', ...], + 'aliases': ['default', '...'] + } + + Raises: + google.auth.exceptions.TransportError: if an error occurred while + retrieving metadata. + """ + path = "instance/service-accounts/{0}/".format(service_account) + # See https://cloud.google.com/compute/docs/metadata#aggcontents + # for more on the use of 'recursive'. + return get(request, path, params={"recursive": "true"}) + + +def get_service_account_token(request, service_account="default", scopes=None): + """Get the OAuth 2.0 access token for a service account. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + service_account (str): The string 'default' or a service account email + address. The determines which service account for which to acquire + an access token. + scopes (Optional[Union[str, List[str]]]): Optional string or list of + strings with auth scopes. + Returns: + Tuple[str, datetime]: The access token and its expiration. + + Raises: + google.auth.exceptions.TransportError: if an error occurred while + retrieving metadata. + """ + if scopes: + if not isinstance(scopes, str): + scopes = ",".join(scopes) + params = {"scopes": scopes} + else: + params = None + + path = "instance/service-accounts/{0}/token".format(service_account) + token_json = get(request, path, params=params) + token_expiry = _helpers.utcnow() + datetime.timedelta( + seconds=token_json["expires_in"] + ) + return token_json["access_token"], token_expiry diff --git a/script.module.google-auth-library/lib/google/auth/compute_engine/credentials.py b/script.module.google-auth-library/lib/google/auth/compute_engine/credentials.py new file mode 100644 index 000000000..e97fabea9 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/compute_engine/credentials.py @@ -0,0 +1,438 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Compute Engine credentials. + +This module provides authentication for an application running on Google +Compute Engine using the Compute Engine metadata server. + +""" + +import datetime + +import six + +from google.auth import _helpers +from google.auth import credentials +from google.auth import exceptions +from google.auth import iam +from google.auth import jwt +from google.auth.compute_engine import _metadata +from google.oauth2 import _client + + +class Credentials(credentials.Scoped, credentials.CredentialsWithQuotaProject): + """Compute Engine Credentials. + + These credentials use the Google Compute Engine metadata server to obtain + OAuth 2.0 access tokens associated with the instance's service account, + and are also used for Cloud Run, Flex and App Engine (except for the Python + 2.7 runtime, which is supported only on older versions of this library). + + For more information about Compute Engine authentication, including how + to configure scopes, see the `Compute Engine authentication + documentation`_. + + .. note:: On Compute Engine the metadata server ignores requested scopes. + On Cloud Run, Flex and App Engine the server honours requested scopes. + + .. _Compute Engine authentication documentation: + https://cloud.google.com/compute/docs/authentication#using + """ + + def __init__( + self, + service_account_email="default", + quota_project_id=None, + scopes=None, + default_scopes=None, + ): + """ + Args: + service_account_email (str): The service account email to use, or + 'default'. A Compute Engine instance may have multiple service + accounts. + quota_project_id (Optional[str]): The project ID used for quota and + billing. + scopes (Optional[Sequence[str]]): The list of scopes for the credentials. + default_scopes (Optional[Sequence[str]]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + """ + super(Credentials, self).__init__() + self._service_account_email = service_account_email + self._quota_project_id = quota_project_id + self._scopes = scopes + self._default_scopes = default_scopes + + def _retrieve_info(self, request): + """Retrieve information about the service account. + + Updates the scopes and retrieves the full service account email. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + """ + info = _metadata.get_service_account_info( + request, service_account=self._service_account_email + ) + + self._service_account_email = info["email"] + + # Don't override scopes requested by the user. + if self._scopes is None: + self._scopes = info["scopes"] + + def refresh(self, request): + """Refresh the access token and scopes. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + + Raises: + google.auth.exceptions.RefreshError: If the Compute Engine metadata + service can't be reached if if the instance has not + credentials. + """ + scopes = self._scopes if self._scopes is not None else self._default_scopes + try: + self._retrieve_info(request) + self.token, self.expiry = _metadata.get_service_account_token( + request, service_account=self._service_account_email, scopes=scopes + ) + except exceptions.TransportError as caught_exc: + new_exc = exceptions.RefreshError(caught_exc) + six.raise_from(new_exc, caught_exc) + + @property + def service_account_email(self): + """The service account email. + + .. note:: This is not guaranteed to be set until :meth:`refresh` has been + called. + """ + return self._service_account_email + + @property + def requires_scopes(self): + return not self._scopes + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__( + service_account_email=self._service_account_email, + quota_project_id=quota_project_id, + scopes=self._scopes, + ) + + @_helpers.copy_docstring(credentials.Scoped) + def with_scopes(self, scopes, default_scopes=None): + # Compute Engine credentials can not be scoped (the metadata service + # ignores the scopes parameter). App Engine, Cloud Run and Flex support + # requesting scopes. + return self.__class__( + scopes=scopes, + default_scopes=default_scopes, + service_account_email=self._service_account_email, + quota_project_id=self._quota_project_id, + ) + + +_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds +_DEFAULT_TOKEN_URI = "https://www.googleapis.com/oauth2/v4/token" + + +class IDTokenCredentials( + credentials.CredentialsWithQuotaProject, + credentials.Signing, + credentials.CredentialsWithTokenUri, +): + """Open ID Connect ID Token-based service account credentials. + + These credentials relies on the default service account of a GCE instance. + + ID token can be requested from `GCE metadata server identity endpoint`_, IAM + token endpoint or other token endpoints you specify. If metadata server + identity endpoint is not used, the GCE instance must have been started with + a service account that has access to the IAM Cloud API. + + .. _GCE metadata server identity endpoint: + https://cloud.google.com/compute/docs/instances/verifying-instance-identity + """ + + def __init__( + self, + request, + target_audience, + token_uri=None, + additional_claims=None, + service_account_email=None, + signer=None, + use_metadata_identity_endpoint=False, + quota_project_id=None, + ): + """ + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + target_audience (str): The intended audience for these credentials, + used when requesting the ID Token. The ID Token's ``aud`` claim + will be set to this string. + token_uri (str): The OAuth 2.0 Token URI. + additional_claims (Mapping[str, str]): Any additional claims for + the JWT assertion used in the authorization grant. + service_account_email (str): Optional explicit service account to + use to sign JWT tokens. + By default, this is the default GCE service account. + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + In case the signer is specified, the request argument will be + ignored. + use_metadata_identity_endpoint (bool): Whether to use GCE metadata + identity endpoint. For backward compatibility the default value + is False. If set to True, ``token_uri``, ``additional_claims``, + ``service_account_email``, ``signer`` argument should not be set; + otherwise ValueError will be raised. + quota_project_id (Optional[str]): The project ID used for quota and + billing. + + Raises: + ValueError: + If ``use_metadata_identity_endpoint`` is set to True, and one of + ``token_uri``, ``additional_claims``, ``service_account_email``, + ``signer`` arguments is set. + """ + super(IDTokenCredentials, self).__init__() + + self._quota_project_id = quota_project_id + self._use_metadata_identity_endpoint = use_metadata_identity_endpoint + self._target_audience = target_audience + + if use_metadata_identity_endpoint: + if token_uri or additional_claims or service_account_email or signer: + raise ValueError( + "If use_metadata_identity_endpoint is set, token_uri, " + "additional_claims, service_account_email, signer arguments" + " must not be set" + ) + self._token_uri = None + self._additional_claims = None + self._signer = None + + if service_account_email is None: + sa_info = _metadata.get_service_account_info(request) + self._service_account_email = sa_info["email"] + else: + self._service_account_email = service_account_email + + if not use_metadata_identity_endpoint: + if signer is None: + signer = iam.Signer( + request=request, + credentials=Credentials(), + service_account_email=self._service_account_email, + ) + self._signer = signer + self._token_uri = token_uri or _DEFAULT_TOKEN_URI + + if additional_claims is not None: + self._additional_claims = additional_claims + else: + self._additional_claims = {} + + def with_target_audience(self, target_audience): + """Create a copy of these credentials with the specified target + audience. + Args: + target_audience (str): The intended audience for these credentials, + used when requesting the ID Token. + Returns: + google.auth.service_account.IDTokenCredentials: A new credentials + instance. + """ + # since the signer is already instantiated, + # the request is not needed + if self._use_metadata_identity_endpoint: + return self.__class__( + None, + target_audience=target_audience, + use_metadata_identity_endpoint=True, + quota_project_id=self._quota_project_id, + ) + else: + return self.__class__( + None, + service_account_email=self._service_account_email, + token_uri=self._token_uri, + target_audience=target_audience, + additional_claims=self._additional_claims.copy(), + signer=self.signer, + use_metadata_identity_endpoint=False, + quota_project_id=self._quota_project_id, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + + # since the signer is already instantiated, + # the request is not needed + if self._use_metadata_identity_endpoint: + return self.__class__( + None, + target_audience=self._target_audience, + use_metadata_identity_endpoint=True, + quota_project_id=quota_project_id, + ) + else: + return self.__class__( + None, + service_account_email=self._service_account_email, + token_uri=self._token_uri, + target_audience=self._target_audience, + additional_claims=self._additional_claims.copy(), + signer=self.signer, + use_metadata_identity_endpoint=False, + quota_project_id=quota_project_id, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithTokenUri) + def with_token_uri(self, token_uri): + + # since the signer is already instantiated, + # the request is not needed + if self._use_metadata_identity_endpoint: + raise ValueError( + "If use_metadata_identity_endpoint is set, token_uri" " must not be set" + ) + else: + return self.__class__( + None, + service_account_email=self._service_account_email, + token_uri=token_uri, + target_audience=self._target_audience, + additional_claims=self._additional_claims.copy(), + signer=self.signer, + use_metadata_identity_endpoint=False, + quota_project_id=self.quota_project_id, + ) + + def _make_authorization_grant_assertion(self): + """Create the OAuth 2.0 assertion. + This assertion is used during the OAuth 2.0 grant to acquire an + ID token. + Returns: + bytes: The authorization grant assertion. + """ + now = _helpers.utcnow() + lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS) + expiry = now + lifetime + + payload = { + "iat": _helpers.datetime_to_secs(now), + "exp": _helpers.datetime_to_secs(expiry), + # The issuer must be the service account email. + "iss": self.service_account_email, + # The audience must be the auth token endpoint's URI + "aud": self._token_uri, + # The target audience specifies which service the ID token is + # intended for. + "target_audience": self._target_audience, + } + + payload.update(self._additional_claims) + + token = jwt.encode(self._signer, payload) + + return token + + def _call_metadata_identity_endpoint(self, request): + """Request ID token from metadata identity endpoint. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + + Returns: + Tuple[str, datetime.datetime]: The ID token and the expiry of the ID token. + + Raises: + google.auth.exceptions.RefreshError: If the Compute Engine metadata + service can't be reached or if the instance has no credentials. + ValueError: If extracting expiry from the obtained ID token fails. + """ + try: + path = "instance/service-accounts/default/identity" + params = {"audience": self._target_audience, "format": "full"} + id_token = _metadata.get(request, path, params=params) + except exceptions.TransportError as caught_exc: + new_exc = exceptions.RefreshError(caught_exc) + six.raise_from(new_exc, caught_exc) + + _, payload, _, _ = jwt._unverified_decode(id_token) + return id_token, datetime.datetime.fromtimestamp(payload["exp"]) + + def refresh(self, request): + """Refreshes the ID token. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + + Raises: + google.auth.exceptions.RefreshError: If the credentials could + not be refreshed. + ValueError: If extracting expiry from the obtained ID token fails. + """ + if self._use_metadata_identity_endpoint: + self.token, self.expiry = self._call_metadata_identity_endpoint(request) + else: + assertion = self._make_authorization_grant_assertion() + access_token, expiry, _ = _client.id_token_jwt_grant( + request, self._token_uri, assertion + ) + self.token = access_token + self.expiry = expiry + + @property # type: ignore + @_helpers.copy_docstring(credentials.Signing) + def signer(self): + return self._signer + + def sign_bytes(self, message): + """Signs the given message. + + Args: + message (bytes): The message to sign. + + Returns: + bytes: The message's cryptographic signature. + + Raises: + ValueError: + Signer is not available if metadata identity endpoint is used. + """ + if self._use_metadata_identity_endpoint: + raise ValueError( + "Signer is not available if metadata identity endpoint is used" + ) + return self._signer.sign(message) + + @property + def service_account_email(self): + """The service account email.""" + return self._service_account_email + + @property + def signer_email(self): + return self._service_account_email diff --git a/script.module.google-auth-library/lib/google/auth/credentials.py b/script.module.google-auth-library/lib/google/auth/credentials.py new file mode 100644 index 000000000..ca1032a14 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/credentials.py @@ -0,0 +1,384 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +"""Interfaces for credentials.""" + +import abc +import os + +import six + +from google.auth import _helpers, environment_vars + + +@six.add_metaclass(abc.ABCMeta) +class Credentials(object): + """Base class for all credentials. + + All credentials have a :attr:`token` that is used for authentication and + may also optionally set an :attr:`expiry` to indicate when the token will + no longer be valid. + + Most credentials will be :attr:`invalid` until :meth:`refresh` is called. + Credentials can do this automatically before the first HTTP request in + :meth:`before_request`. + + Although the token and expiration will change as the credentials are + :meth:`refreshed ` and used, credentials should be considered + immutable. Various credentials will accept configuration such as private + keys, scopes, and other options. These options are not changeable after + construction. Some classes will provide mechanisms to copy the credentials + with modifications such as :meth:`ScopedCredentials.with_scopes`. + """ + + def __init__(self): + self.token = None + """str: The bearer token that can be used in HTTP headers to make + authenticated requests.""" + self.expiry = None + """Optional[datetime]: When the token expires and is no longer valid. + If this is None, the token is assumed to never expire.""" + self._quota_project_id = None + """Optional[str]: Project to use for quota and billing purposes.""" + + @property + def expired(self): + """Checks if the credentials are expired. + + Note that credentials can be invalid but not expired because + Credentials with :attr:`expiry` set to None is considered to never + expire. + """ + if not self.expiry: + return False + + # Remove some threshold from expiry to err on the side of reporting + # expiration early so that we avoid the 401-refresh-retry loop. + skewed_expiry = self.expiry - _helpers.REFRESH_THRESHOLD + return _helpers.utcnow() >= skewed_expiry + + @property + def valid(self): + """Checks the validity of the credentials. + + This is True if the credentials have a :attr:`token` and the token + is not :attr:`expired`. + """ + return self.token is not None and not self.expired + + @property + def quota_project_id(self): + """Project to use for quota and billing purposes.""" + return self._quota_project_id + + @abc.abstractmethod + def refresh(self, request): + """Refreshes the access token. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + + Raises: + google.auth.exceptions.RefreshError: If the credentials could + not be refreshed. + """ + # pylint: disable=missing-raises-doc + # (pylint doesn't recognize that this is abstract) + raise NotImplementedError("Refresh must be implemented") + + def apply(self, headers, token=None): + """Apply the token to the authentication header. + + Args: + headers (Mapping): The HTTP request headers. + token (Optional[str]): If specified, overrides the current access + token. + """ + headers["authorization"] = "Bearer {}".format( + _helpers.from_bytes(token or self.token) + ) + if self.quota_project_id: + headers["x-goog-user-project"] = self.quota_project_id + + def before_request(self, request, method, url, headers): + """Performs credential-specific before request logic. + + Refreshes the credentials if necessary, then calls :meth:`apply` to + apply the token to the authentication header. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + method (str): The request's HTTP method or the RPC method being + invoked. + url (str): The request's URI or the RPC service's URI. + headers (Mapping): The request's headers. + """ + # pylint: disable=unused-argument + # (Subclasses may use these arguments to ascertain information about + # the http request.) + if not self.valid: + self.refresh(request) + self.apply(headers) + + +class CredentialsWithQuotaProject(Credentials): + """Abstract base for credentials supporting ``with_quota_project`` factory""" + + def with_quota_project(self, quota_project_id): + """Returns a copy of these credentials with a modified quota project. + + Args: + quota_project_id (str): The project to use for quota and + billing purposes + + Returns: + google.oauth2.credentials.Credentials: A new credentials instance. + """ + raise NotImplementedError("This credential does not support quota project.") + + def with_quota_project_from_environment(self): + quota_from_env = os.environ.get(environment_vars.GOOGLE_CLOUD_QUOTA_PROJECT) + if quota_from_env: + return self.with_quota_project(quota_from_env) + return self + + +class CredentialsWithTokenUri(Credentials): + """Abstract base for credentials supporting ``with_token_uri`` factory""" + + def with_token_uri(self, token_uri): + """Returns a copy of these credentials with a modified token uri. + + Args: + token_uri (str): The uri to use for fetching/exchanging tokens + + Returns: + google.oauth2.credentials.Credentials: A new credentials instance. + """ + raise NotImplementedError("This credential does not use token uri.") + + +class AnonymousCredentials(Credentials): + """Credentials that do not provide any authentication information. + + These are useful in the case of services that support anonymous access or + local service emulators that do not use credentials. + """ + + @property + def expired(self): + """Returns `False`, anonymous credentials never expire.""" + return False + + @property + def valid(self): + """Returns `True`, anonymous credentials are always valid.""" + return True + + def refresh(self, request): + """Raises :class:`ValueError``, anonymous credentials cannot be + refreshed.""" + raise ValueError("Anonymous credentials cannot be refreshed.") + + def apply(self, headers, token=None): + """Anonymous credentials do nothing to the request. + + The optional ``token`` argument is not supported. + + Raises: + ValueError: If a token was specified. + """ + if token is not None: + raise ValueError("Anonymous credentials don't support tokens.") + + def before_request(self, request, method, url, headers): + """Anonymous credentials do nothing to the request.""" + + +@six.add_metaclass(abc.ABCMeta) +class ReadOnlyScoped(object): + """Interface for credentials whose scopes can be queried. + + OAuth 2.0-based credentials allow limiting access using scopes as described + in `RFC6749 Section 3.3`_. + If a credential class implements this interface then the credentials either + use scopes in their implementation. + + Some credentials require scopes in order to obtain a token. You can check + if scoping is necessary with :attr:`requires_scopes`:: + + if credentials.requires_scopes: + # Scoping is required. + credentials = credentials.with_scopes(scopes=['one', 'two']) + + Credentials that require scopes must either be constructed with scopes:: + + credentials = SomeScopedCredentials(scopes=['one', 'two']) + + Or must copy an existing instance using :meth:`with_scopes`:: + + scoped_credentials = credentials.with_scopes(scopes=['one', 'two']) + + Some credentials have scopes but do not allow or require scopes to be set, + these credentials can be used as-is. + + .. _RFC6749 Section 3.3: https://tools.ietf.org/html/rfc6749#section-3.3 + """ + + def __init__(self): + super(ReadOnlyScoped, self).__init__() + self._scopes = None + self._default_scopes = None + + @property + def scopes(self): + """Sequence[str]: the credentials' current set of scopes.""" + return self._scopes + + @property + def default_scopes(self): + """Sequence[str]: the credentials' current set of default scopes.""" + return self._default_scopes + + @abc.abstractproperty + def requires_scopes(self): + """True if these credentials require scopes to obtain an access token. + """ + return False + + def has_scopes(self, scopes): + """Checks if the credentials have the given scopes. + + .. warning: This method is not guaranteed to be accurate if the + credentials are :attr:`~Credentials.invalid`. + + Args: + scopes (Sequence[str]): The list of scopes to check. + + Returns: + bool: True if the credentials have the given scopes. + """ + credential_scopes = ( + self._scopes if self._scopes is not None else self._default_scopes + ) + return set(scopes).issubset(set(credential_scopes or [])) + + +class Scoped(ReadOnlyScoped): + """Interface for credentials whose scopes can be replaced while copying. + + OAuth 2.0-based credentials allow limiting access using scopes as described + in `RFC6749 Section 3.3`_. + If a credential class implements this interface then the credentials either + use scopes in their implementation. + + Some credentials require scopes in order to obtain a token. You can check + if scoping is necessary with :attr:`requires_scopes`:: + + if credentials.requires_scopes: + # Scoping is required. + credentials = credentials.create_scoped(['one', 'two']) + + Credentials that require scopes must either be constructed with scopes:: + + credentials = SomeScopedCredentials(scopes=['one', 'two']) + + Or must copy an existing instance using :meth:`with_scopes`:: + + scoped_credentials = credentials.with_scopes(scopes=['one', 'two']) + + Some credentials have scopes but do not allow or require scopes to be set, + these credentials can be used as-is. + + .. _RFC6749 Section 3.3: https://tools.ietf.org/html/rfc6749#section-3.3 + """ + + @abc.abstractmethod + def with_scopes(self, scopes, default_scopes=None): + """Create a copy of these credentials with the specified scopes. + + Args: + scopes (Sequence[str]): The list of scopes to attach to the + current credentials. + + Raises: + NotImplementedError: If the credentials' scopes can not be changed. + This can be avoided by checking :attr:`requires_scopes` before + calling this method. + """ + raise NotImplementedError("This class does not require scoping.") + + +def with_scopes_if_required(credentials, scopes, default_scopes=None): + """Creates a copy of the credentials with scopes if scoping is required. + + This helper function is useful when you do not know (or care to know) the + specific type of credentials you are using (such as when you use + :func:`google.auth.default`). This function will call + :meth:`Scoped.with_scopes` if the credentials are scoped credentials and if + the credentials require scoping. Otherwise, it will return the credentials + as-is. + + Args: + credentials (google.auth.credentials.Credentials): The credentials to + scope if necessary. + scopes (Sequence[str]): The list of scopes to use. + default_scopes (Sequence[str]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + + Returns: + google.auth.credentials.Credentials: Either a new set of scoped + credentials, or the passed in credentials instance if no scoping + was required. + """ + if isinstance(credentials, Scoped) and credentials.requires_scopes: + return credentials.with_scopes(scopes, default_scopes=default_scopes) + else: + return credentials + + +@six.add_metaclass(abc.ABCMeta) +class Signing(object): + """Interface for credentials that can cryptographically sign messages.""" + + @abc.abstractmethod + def sign_bytes(self, message): + """Signs the given message. + + Args: + message (bytes): The message to sign. + + Returns: + bytes: The message's cryptographic signature. + """ + # pylint: disable=missing-raises-doc,redundant-returns-doc + # (pylint doesn't recognize that this is abstract) + raise NotImplementedError("Sign bytes must be implemented.") + + @abc.abstractproperty + def signer_email(self): + """Optional[str]: An email address that identifies the signer.""" + # pylint: disable=missing-raises-doc + # (pylint doesn't recognize that this is abstract) + raise NotImplementedError("Signer email must be implemented.") + + @abc.abstractproperty + def signer(self): + """google.auth.crypt.Signer: The signer used to sign bytes.""" + # pylint: disable=missing-raises-doc + # (pylint doesn't recognize that this is abstract) + raise NotImplementedError("Signer must be implemented.") diff --git a/script.module.google-auth-library/lib/google/auth/crypt/__init__.py b/script.module.google-auth-library/lib/google/auth/crypt/__init__.py new file mode 100644 index 000000000..9f91f0d0b --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/crypt/__init__.py @@ -0,0 +1,100 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Cryptography helpers for verifying and signing messages. + +The simplest way to verify signatures is using :func:`verify_signature`:: + + cert = open('certs.pem').read() + valid = crypt.verify_signature(message, signature, cert) + +If you're going to verify many messages with the same certificate, you can use +:class:`RSAVerifier`:: + + cert = open('certs.pem').read() + verifier = crypt.RSAVerifier.from_string(cert) + valid = verifier.verify(message, signature) + +To sign messages use :class:`RSASigner` with a private key:: + + private_key = open('private_key.pem').read() + signer = crypt.RSASigner.from_string(private_key) + signature = signer.sign(message) + +The code above also works for :class:`ES256Signer` and :class:`ES256Verifier`. +Note that these two classes are only available if your `cryptography` dependency +version is at least 1.4.0. +""" + +import six + +from google.auth.crypt import base +from google.auth.crypt import rsa + +try: + from google.auth.crypt import es256 +except ImportError: # pragma: NO COVER + es256 = None # type: ignore + +if es256 is not None: # pragma: NO COVER + __all__ = [ + "ES256Signer", + "ES256Verifier", + "RSASigner", + "RSAVerifier", + "Signer", + "Verifier", + ] +else: # pragma: NO COVER + __all__ = ["RSASigner", "RSAVerifier", "Signer", "Verifier"] + + +# Aliases to maintain the v1.0.0 interface, as the crypt module was split +# into submodules. +Signer = base.Signer +Verifier = base.Verifier +RSASigner = rsa.RSASigner +RSAVerifier = rsa.RSAVerifier + +if es256 is not None: # pragma: NO COVER + ES256Signer = es256.ES256Signer + ES256Verifier = es256.ES256Verifier + + +def verify_signature(message, signature, certs, verifier_cls=rsa.RSAVerifier): + """Verify an RSA or ECDSA cryptographic signature. + + Checks that the provided ``signature`` was generated from ``bytes`` using + the private key associated with the ``cert``. + + Args: + message (Union[str, bytes]): The plaintext message. + signature (Union[str, bytes]): The cryptographic signature to check. + certs (Union[Sequence, str, bytes]): The certificate or certificates + to use to check the signature. + verifier_cls (Optional[~google.auth.crypt.base.Signer]): Which verifier + class to use for verification. This can be used to select different + algorithms, such as RSA or ECDSA. Default value is :class:`RSAVerifier`. + + Returns: + bool: True if the signature is valid, otherwise False. + """ + if isinstance(certs, (six.text_type, six.binary_type)): + certs = [certs] + + for cert in certs: + verifier = verifier_cls.from_string(cert) + if verifier.verify(message, signature): + return True + return False diff --git a/script.module.google-auth-library/lib/google/auth/crypt/_cryptography_rsa.py b/script.module.google-auth-library/lib/google/auth/crypt/_cryptography_rsa.py new file mode 100644 index 000000000..4f2d61166 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/crypt/_cryptography_rsa.py @@ -0,0 +1,136 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""RSA verifier and signer that use the ``cryptography`` library. + +This is a much faster implementation than the default (in +``google.auth.crypt._python_rsa``), which depends on the pure-Python +``rsa`` library. +""" + +import cryptography.exceptions +from cryptography.hazmat import backends +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import padding +import cryptography.x509 + +from google.auth import _helpers +from google.auth.crypt import base + +_CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----" +_BACKEND = backends.default_backend() +_PADDING = padding.PKCS1v15() +_SHA256 = hashes.SHA256() + + +class RSAVerifier(base.Verifier): + """Verifies RSA cryptographic signatures using public keys. + + Args: + public_key ( + cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey): + The public key used to verify signatures. + """ + + def __init__(self, public_key): + self._pubkey = public_key + + @_helpers.copy_docstring(base.Verifier) + def verify(self, message, signature): + message = _helpers.to_bytes(message) + try: + self._pubkey.verify(signature, message, _PADDING, _SHA256) + return True + except (ValueError, cryptography.exceptions.InvalidSignature): + return False + + @classmethod + def from_string(cls, public_key): + """Construct an Verifier instance from a public key or public + certificate string. + + Args: + public_key (Union[str, bytes]): The public key in PEM format or the + x509 public key certificate. + + Returns: + Verifier: The constructed verifier. + + Raises: + ValueError: If the public key can't be parsed. + """ + public_key_data = _helpers.to_bytes(public_key) + + if _CERTIFICATE_MARKER in public_key_data: + cert = cryptography.x509.load_pem_x509_certificate( + public_key_data, _BACKEND + ) + pubkey = cert.public_key() + + else: + pubkey = serialization.load_pem_public_key(public_key_data, _BACKEND) + + return cls(pubkey) + + +class RSASigner(base.Signer, base.FromServiceAccountMixin): + """Signs messages with an RSA private key. + + Args: + private_key ( + cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey): + The private key to sign with. + key_id (str): Optional key ID used to identify this private key. This + can be useful to associate the private key with its associated + public key or certificate. + """ + + def __init__(self, private_key, key_id=None): + self._key = private_key + self._key_id = key_id + + @property # type: ignore + @_helpers.copy_docstring(base.Signer) + def key_id(self): + return self._key_id + + @_helpers.copy_docstring(base.Signer) + def sign(self, message): + message = _helpers.to_bytes(message) + return self._key.sign(message, _PADDING, _SHA256) + + @classmethod + def from_string(cls, key, key_id=None): + """Construct a RSASigner from a private key in PEM format. + + Args: + key (Union[bytes, str]): Private key in PEM format. + key_id (str): An optional key id used to identify the private key. + + Returns: + google.auth.crypt._cryptography_rsa.RSASigner: The + constructed signer. + + Raises: + ValueError: If ``key`` is not ``bytes`` or ``str`` (unicode). + UnicodeDecodeError: If ``key`` is ``bytes`` but cannot be decoded + into a UTF-8 ``str``. + ValueError: If ``cryptography`` "Could not deserialize key data." + """ + key = _helpers.to_bytes(key) + private_key = serialization.load_pem_private_key( + key, password=None, backend=_BACKEND + ) + return cls(private_key, key_id=key_id) diff --git a/script.module.google-auth-library/lib/google/auth/crypt/_helpers.py b/script.module.google-auth-library/lib/google/auth/crypt/_helpers.py new file mode 100644 index 000000000..e69de29bb diff --git a/script.module.google-auth-library/lib/google/auth/crypt/_python_rsa.py b/script.module.google-auth-library/lib/google/auth/crypt/_python_rsa.py new file mode 100644 index 000000000..a09938b4a --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/crypt/_python_rsa.py @@ -0,0 +1,173 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Pure-Python RSA cryptography implementation. + +Uses the ``rsa``, ``pyasn1`` and ``pyasn1_modules`` packages +to parse PEM files storing PKCS#1 or PKCS#8 keys as well as +certificates. There is no support for p12 files. +""" + +from __future__ import absolute_import + +from pyasn1.codec.der import decoder # type: ignore +from pyasn1_modules import pem # type: ignore +from pyasn1_modules.rfc2459 import Certificate # type: ignore +from pyasn1_modules.rfc5208 import PrivateKeyInfo # type: ignore +import google.auth.crypt.rsa # type: ignore +import six + +from google.auth import _helpers +from google.auth.crypt import base + +_POW2 = (128, 64, 32, 16, 8, 4, 2, 1) +_CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----" +_PKCS1_MARKER = ("-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----") +_PKCS8_MARKER = ("-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----") +_PKCS8_SPEC = PrivateKeyInfo() + + +def _bit_list_to_bytes(bit_list): + """Converts an iterable of 1s and 0s to bytes. + + Combines the list 8 at a time, treating each group of 8 bits + as a single byte. + + Args: + bit_list (Sequence): Sequence of 1s and 0s. + + Returns: + bytes: The decoded bytes. + """ + num_bits = len(bit_list) + byte_vals = bytearray() + for start in six.moves.xrange(0, num_bits, 8): + curr_bits = bit_list[start : start + 8] + char_val = sum(val * digit for val, digit in six.moves.zip(_POW2, curr_bits)) + byte_vals.append(char_val) + return bytes(byte_vals) + + +class RSAVerifier(base.Verifier): + """Verifies RSA cryptographic signatures using public keys. + + Args: + public_key (rsa.key.PublicKey): The public key used to verify + signatures. + """ + + def __init__(self, public_key): + self._pubkey = public_key + + @_helpers.copy_docstring(base.Verifier) + def verify(self, message, signature): + message = _helpers.to_bytes(message) + try: + return rsa.pkcs1.verify(message, signature, self._pubkey) + except (ValueError, rsa.pkcs1.VerificationError): + return False + + @classmethod + def from_string(cls, public_key): + """Construct an Verifier instance from a public key or public + certificate string. + + Args: + public_key (Union[str, bytes]): The public key in PEM format or the + x509 public key certificate. + + Returns: + google.auth.crypt._python_rsa.RSAVerifier: The constructed verifier. + + Raises: + ValueError: If the public_key can't be parsed. + """ + public_key = _helpers.to_bytes(public_key) + is_x509_cert = _CERTIFICATE_MARKER in public_key + + # If this is a certificate, extract the public key info. + if is_x509_cert: + der = rsa.pem.load_pem(public_key, "CERTIFICATE") + asn1_cert, remaining = decoder.decode(der, asn1Spec=Certificate()) + if remaining != b"": + raise ValueError("Unused bytes", remaining) + + cert_info = asn1_cert["tbsCertificate"]["subjectPublicKeyInfo"] + key_bytes = _bit_list_to_bytes(cert_info["subjectPublicKey"]) + pubkey = rsa.PublicKey.load_pkcs1(key_bytes, "DER") + else: + pubkey = rsa.PublicKey.load_pkcs1(public_key, "PEM") + return cls(pubkey) + + +class RSASigner(base.Signer, base.FromServiceAccountMixin): + """Signs messages with an RSA private key. + + Args: + private_key (rsa.key.PrivateKey): The private key to sign with. + key_id (str): Optional key ID used to identify this private key. This + can be useful to associate the private key with its associated + public key or certificate. + """ + + def __init__(self, private_key, key_id=None): + self._key = private_key + self._key_id = key_id + + @property # type: ignore + @_helpers.copy_docstring(base.Signer) + def key_id(self): + return self._key_id + + @_helpers.copy_docstring(base.Signer) + def sign(self, message): + message = _helpers.to_bytes(message) + return rsa.pkcs1.sign(message, self._key, "SHA-256") + + @classmethod + def from_string(cls, key, key_id=None): + """Construct an Signer instance from a private key in PEM format. + + Args: + key (str): Private key in PEM format. + key_id (str): An optional key id used to identify the private key. + + Returns: + google.auth.crypt.Signer: The constructed signer. + + Raises: + ValueError: If the key cannot be parsed as PKCS#1 or PKCS#8 in + PEM format. + """ + key = _helpers.from_bytes(key) # PEM expects str in Python 3 + marker_id, key_bytes = pem.readPemBlocksFromFile( + six.StringIO(key), _PKCS1_MARKER, _PKCS8_MARKER + ) + + # Key is in pkcs1 format. + if marker_id == 0: + private_key = rsa.key.PrivateKey.load_pkcs1(key_bytes, format="DER") + # Key is in pkcs8. + elif marker_id == 1: + key_info, remaining = decoder.decode(key_bytes, asn1Spec=_PKCS8_SPEC) + if remaining != b"": + raise ValueError("Unused bytes", remaining) + private_key_info = key_info.getComponentByName("privateKey") + private_key = rsa.key.PrivateKey.load_pkcs1( + private_key_info.asOctets(), format="DER" + ) + else: + raise ValueError("No key could be detected.") + + return cls(private_key, key_id=key_id) diff --git a/script.module.google-auth-library/lib/google/auth/crypt/base.py b/script.module.google-auth-library/lib/google/auth/crypt/base.py new file mode 100644 index 000000000..c98d5bf64 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/crypt/base.py @@ -0,0 +1,131 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Base classes for cryptographic signers and verifiers.""" + +import abc +import io +import json + +import six + + +_JSON_FILE_PRIVATE_KEY = "private_key" +_JSON_FILE_PRIVATE_KEY_ID = "private_key_id" + + +@six.add_metaclass(abc.ABCMeta) +class Verifier(object): + """Abstract base class for crytographic signature verifiers.""" + + @abc.abstractmethod + def verify(self, message, signature): + """Verifies a message against a cryptographic signature. + + Args: + message (Union[str, bytes]): The message to verify. + signature (Union[str, bytes]): The cryptography signature to check. + + Returns: + bool: True if message was signed by the private key associated + with the public key that this object was constructed with. + """ + # pylint: disable=missing-raises-doc,redundant-returns-doc + # (pylint doesn't recognize that this is abstract) + raise NotImplementedError("Verify must be implemented") + + +@six.add_metaclass(abc.ABCMeta) +class Signer(object): + """Abstract base class for cryptographic signers.""" + + @abc.abstractproperty + def key_id(self): + """Optional[str]: The key ID used to identify this private key.""" + raise NotImplementedError("Key id must be implemented") + + @abc.abstractmethod + def sign(self, message): + """Signs a message. + + Args: + message (Union[str, bytes]): The message to be signed. + + Returns: + bytes: The signature of the message. + """ + # pylint: disable=missing-raises-doc,redundant-returns-doc + # (pylint doesn't recognize that this is abstract) + raise NotImplementedError("Sign must be implemented") + + +@six.add_metaclass(abc.ABCMeta) +class FromServiceAccountMixin(object): + """Mix-in to enable factory constructors for a Signer.""" + + @abc.abstractmethod + def from_string(cls, key, key_id=None): + """Construct an Signer instance from a private key string. + + Args: + key (str): Private key as a string. + key_id (str): An optional key id used to identify the private key. + + Returns: + google.auth.crypt.Signer: The constructed signer. + + Raises: + ValueError: If the key cannot be parsed. + """ + raise NotImplementedError("from_string must be implemented") + + @classmethod + def from_service_account_info(cls, info): + """Creates a Signer instance instance from a dictionary containing + service account info in Google format. + + Args: + info (Mapping[str, str]): The service account info in Google + format. + + Returns: + google.auth.crypt.Signer: The constructed signer. + + Raises: + ValueError: If the info is not in the expected format. + """ + if _JSON_FILE_PRIVATE_KEY not in info: + raise ValueError( + "The private_key field was not found in the service account " "info." + ) + + return cls.from_string( + info[_JSON_FILE_PRIVATE_KEY], info.get(_JSON_FILE_PRIVATE_KEY_ID) + ) + + @classmethod + def from_service_account_file(cls, filename): + """Creates a Signer instance from a service account .json file + in Google format. + + Args: + filename (str): The path to the service account .json file. + + Returns: + google.auth.crypt.Signer: The constructed signer. + """ + with io.open(filename, "r", encoding="utf-8") as json_file: + data = json.load(json_file) + + return cls.from_service_account_info(data) diff --git a/script.module.google-auth-library/lib/google/auth/crypt/es256.py b/script.module.google-auth-library/lib/google/auth/crypt/es256.py new file mode 100644 index 000000000..7920cc7ff --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/crypt/es256.py @@ -0,0 +1,160 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""ECDSA (ES256) verifier and signer that use the ``cryptography`` library. +""" + +from cryptography import utils # type: ignore +import cryptography.exceptions +from cryptography.hazmat import backends +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature +from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature +import cryptography.x509 + +from google.auth import _helpers +from google.auth.crypt import base + + +_CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----" +_BACKEND = backends.default_backend() +_PADDING = padding.PKCS1v15() + + +class ES256Verifier(base.Verifier): + """Verifies ECDSA cryptographic signatures using public keys. + + Args: + public_key ( + cryptography.hazmat.primitives.asymmetric.ec.ECDSAPublicKey): + The public key used to verify signatures. + """ + + def __init__(self, public_key): + self._pubkey = public_key + + @_helpers.copy_docstring(base.Verifier) + def verify(self, message, signature): + # First convert (r||s) raw signature to ASN1 encoded signature. + sig_bytes = _helpers.to_bytes(signature) + if len(sig_bytes) != 64: + return False + r = ( + int.from_bytes(sig_bytes[:32], byteorder="big") + if _helpers.is_python_3() + else utils.int_from_bytes(sig_bytes[:32], byteorder="big") + ) + s = ( + int.from_bytes(sig_bytes[32:], byteorder="big") + if _helpers.is_python_3() + else utils.int_from_bytes(sig_bytes[32:], byteorder="big") + ) + asn1_sig = encode_dss_signature(r, s) + + message = _helpers.to_bytes(message) + try: + self._pubkey.verify(asn1_sig, message, ec.ECDSA(hashes.SHA256())) + return True + except (ValueError, cryptography.exceptions.InvalidSignature): + return False + + @classmethod + def from_string(cls, public_key): + """Construct an Verifier instance from a public key or public + certificate string. + + Args: + public_key (Union[str, bytes]): The public key in PEM format or the + x509 public key certificate. + + Returns: + Verifier: The constructed verifier. + + Raises: + ValueError: If the public key can't be parsed. + """ + public_key_data = _helpers.to_bytes(public_key) + + if _CERTIFICATE_MARKER in public_key_data: + cert = cryptography.x509.load_pem_x509_certificate( + public_key_data, _BACKEND + ) + pubkey = cert.public_key() + + else: + pubkey = serialization.load_pem_public_key(public_key_data, _BACKEND) + + return cls(pubkey) + + +class ES256Signer(base.Signer, base.FromServiceAccountMixin): + """Signs messages with an ECDSA private key. + + Args: + private_key ( + cryptography.hazmat.primitives.asymmetric.ec.ECDSAPrivateKey): + The private key to sign with. + key_id (str): Optional key ID used to identify this private key. This + can be useful to associate the private key with its associated + public key or certificate. + """ + + def __init__(self, private_key, key_id=None): + self._key = private_key + self._key_id = key_id + + @property # type: ignore + @_helpers.copy_docstring(base.Signer) + def key_id(self): + return self._key_id + + @_helpers.copy_docstring(base.Signer) + def sign(self, message): + message = _helpers.to_bytes(message) + asn1_signature = self._key.sign(message, ec.ECDSA(hashes.SHA256())) + + # Convert ASN1 encoded signature to (r||s) raw signature. + (r, s) = decode_dss_signature(asn1_signature) + return ( + (r.to_bytes(32, byteorder="big") + s.to_bytes(32, byteorder="big")) + if _helpers.is_python_3() + else (utils.int_to_bytes(r, 32) + utils.int_to_bytes(s, 32)) + ) + + @classmethod + def from_string(cls, key, key_id=None): + """Construct a RSASigner from a private key in PEM format. + + Args: + key (Union[bytes, str]): Private key in PEM format. + key_id (str): An optional key id used to identify the private key. + + Returns: + google.auth.crypt._cryptography_rsa.RSASigner: The + constructed signer. + + Raises: + ValueError: If ``key`` is not ``bytes`` or ``str`` (unicode). + UnicodeDecodeError: If ``key`` is ``bytes`` but cannot be decoded + into a UTF-8 ``str``. + ValueError: If ``cryptography`` "Could not deserialize key data." + """ + key = _helpers.to_bytes(key) + private_key = serialization.load_pem_private_key( + key, password=None, backend=_BACKEND + ) + return cls(private_key, key_id=key_id) diff --git a/script.module.google-auth-library/lib/google/auth/crypt/rsa.py b/script.module.google-auth-library/lib/google/auth/crypt/rsa.py new file mode 100644 index 000000000..6c4b85da1 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/crypt/rsa.py @@ -0,0 +1,30 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""RSA cryptography signer and verifier.""" + + +try: + # Prefer cryptograph-based RSA implementation. + from google.auth.crypt import _cryptography_rsa + + RSASigner = _cryptography_rsa.RSASigner + RSAVerifier = _cryptography_rsa.RSAVerifier +except (ImportError, ModuleNotFoundError): # pragma: NO COVER + # Fallback to pure-python RSA implementation if cryptography is + # unavailable. + from google.auth.crypt import _python_rsa + + RSASigner = _python_rsa.RSASigner # type: ignore + RSAVerifier = _python_rsa.RSAVerifier # type: ignore diff --git a/script.module.google-auth-library/lib/google/auth/downscoped.py b/script.module.google-auth-library/lib/google/auth/downscoped.py new file mode 100644 index 000000000..a1d7b6e46 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/downscoped.py @@ -0,0 +1,501 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Downscoping with Credential Access Boundaries + +This module provides the ability to downscope credentials using +`Downscoping with Credential Access Boundaries`_. This is useful to restrict the +Identity and Access Management (IAM) permissions that a short-lived credential +can use. + +To downscope permissions of a source credential, a Credential Access Boundary +that specifies which resources the new credential can access, as well as +an upper bound on the permissions that are available on each resource, has to +be defined. A downscoped credential can then be instantiated using the source +credential and the Credential Access Boundary. + +The common pattern of usage is to have a token broker with elevated access +generate these downscoped credentials from higher access source credentials and +pass the downscoped short-lived access tokens to a token consumer via some +secure authenticated channel for limited access to Google Cloud Storage +resources. + +For example, a token broker can be set up on a server in a private network. +Various workloads (token consumers) in the same network will send authenticated +requests to that broker for downscoped tokens to access or modify specific google +cloud storage buckets. + +The broker will instantiate downscoped credentials instances that can be used to +generate short lived downscoped access tokens that can be passed to the token +consumer. These downscoped access tokens can be injected by the consumer into +google.oauth2.Credentials and used to initialize a storage client instance to +access Google Cloud Storage resources with restricted access. + +Note: Only Cloud Storage supports Credential Access Boundaries. Other Google +Cloud services do not support this feature. + +.. _Downscoping with Credential Access Boundaries: https://cloud.google.com/iam/docs/downscoping-short-lived-credentials +""" + +import datetime + +import six + +from google.auth import _helpers +from google.auth import credentials +from google.oauth2 import sts + +# The maximum number of access boundary rules a Credential Access Boundary can +# contain. +_MAX_ACCESS_BOUNDARY_RULES_COUNT = 10 +# The token exchange grant_type used for exchanging credentials. +_STS_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange" +# The token exchange requested_token_type. This is always an access_token. +_STS_REQUESTED_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token" +# The STS token URL used to exchanged a short lived access token for a downscoped one. +_STS_TOKEN_URL = "https://sts.googleapis.com/v1/token" +# The subject token type to use when exchanging a short lived access token for a +# downscoped token. +_STS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token" + + +class CredentialAccessBoundary(object): + """Defines a Credential Access Boundary which contains a list of access boundary + rules. Each rule contains information on the resource that the rule applies to, + the upper bound of the permissions that are available on that resource and an + optional condition to further restrict permissions. + """ + + def __init__(self, rules=[]): + """Instantiates a Credential Access Boundary. A Credential Access Boundary + can contain up to 10 access boundary rules. + + Args: + rules (Sequence[google.auth.downscoped.AccessBoundaryRule]): The list of + access boundary rules limiting the access that a downscoped credential + will have. + Raises: + TypeError: If any of the rules are not a valid type. + ValueError: If the provided rules exceed the maximum allowed. + """ + self.rules = rules + + @property + def rules(self): + """Returns the list of access boundary rules defined on the Credential + Access Boundary. + + Returns: + Tuple[google.auth.downscoped.AccessBoundaryRule, ...]: The list of access + boundary rules defined on the Credential Access Boundary. These are returned + as an immutable tuple to prevent modification. + """ + return tuple(self._rules) + + @rules.setter + def rules(self, value): + """Updates the current rules on the Credential Access Boundary. This will overwrite + the existing set of rules. + + Args: + value (Sequence[google.auth.downscoped.AccessBoundaryRule]): The list of + access boundary rules limiting the access that a downscoped credential + will have. + Raises: + TypeError: If any of the rules are not a valid type. + ValueError: If the provided rules exceed the maximum allowed. + """ + if len(value) > _MAX_ACCESS_BOUNDARY_RULES_COUNT: + raise ValueError( + "Credential access boundary rules can have a maximum of {} rules.".format( + _MAX_ACCESS_BOUNDARY_RULES_COUNT + ) + ) + for access_boundary_rule in value: + if not isinstance(access_boundary_rule, AccessBoundaryRule): + raise TypeError( + "List of rules provided do not contain a valid 'google.auth.downscoped.AccessBoundaryRule'." + ) + # Make a copy of the original list. + self._rules = list(value) + + def add_rule(self, rule): + """Adds a single access boundary rule to the existing rules. + + Args: + rule (google.auth.downscoped.AccessBoundaryRule): The access boundary rule, + limiting the access that a downscoped credential will have, to be added to + the existing rules. + Raises: + TypeError: If any of the rules are not a valid type. + ValueError: If the provided rules exceed the maximum allowed. + """ + if len(self.rules) == _MAX_ACCESS_BOUNDARY_RULES_COUNT: + raise ValueError( + "Credential access boundary rules can have a maximum of {} rules.".format( + _MAX_ACCESS_BOUNDARY_RULES_COUNT + ) + ) + if not isinstance(rule, AccessBoundaryRule): + raise TypeError( + "The provided rule does not contain a valid 'google.auth.downscoped.AccessBoundaryRule'." + ) + self._rules.append(rule) + + def to_json(self): + """Generates the dictionary representation of the Credential Access Boundary. + This uses the format expected by the Security Token Service API as documented in + `Defining a Credential Access Boundary`_. + + .. _Defining a Credential Access Boundary: + https://cloud.google.com/iam/docs/downscoping-short-lived-credentials#define-boundary + + Returns: + Mapping: Credential Access Boundary Rule represented in a dictionary object. + """ + rules = [] + for access_boundary_rule in self.rules: + rules.append(access_boundary_rule.to_json()) + + return {"accessBoundary": {"accessBoundaryRules": rules}} + + +class AccessBoundaryRule(object): + """Defines an access boundary rule which contains information on the resource that + the rule applies to, the upper bound of the permissions that are available on that + resource and an optional condition to further restrict permissions. + """ + + def __init__( + self, available_resource, available_permissions, availability_condition=None + ): + """Instantiates a single access boundary rule. + + Args: + available_resource (str): The full resource name of the Cloud Storage bucket + that the rule applies to. Use the format + "//storage.googleapis.com/projects/_/buckets/bucket-name". + available_permissions (Sequence[str]): A list defining the upper bound that + the downscoped token will have on the available permissions for the + resource. Each value is the identifier for an IAM predefined role or + custom role, with the prefix "inRole:". For example: + "inRole:roles/storage.objectViewer". + Only the permissions in these roles will be available. + availability_condition (Optional[google.auth.downscoped.AvailabilityCondition]): + Optional condition that restricts the availability of permissions to + specific Cloud Storage objects. + + Raises: + TypeError: If any of the parameters are not of the expected types. + ValueError: If any of the parameters are not of the expected values. + """ + self.available_resource = available_resource + self.available_permissions = available_permissions + self.availability_condition = availability_condition + + @property + def available_resource(self): + """Returns the current available resource. + + Returns: + str: The current available resource. + """ + return self._available_resource + + @available_resource.setter + def available_resource(self, value): + """Updates the current available resource. + + Args: + value (str): The updated value of the available resource. + + Raises: + TypeError: If the value is not a string. + """ + if not isinstance(value, six.string_types): + raise TypeError("The provided available_resource is not a string.") + self._available_resource = value + + @property + def available_permissions(self): + """Returns the current available permissions. + + Returns: + Tuple[str, ...]: The current available permissions. These are returned + as an immutable tuple to prevent modification. + """ + return tuple(self._available_permissions) + + @available_permissions.setter + def available_permissions(self, value): + """Updates the current available permissions. + + Args: + value (Sequence[str]): The updated value of the available permissions. + + Raises: + TypeError: If the value is not a list of strings. + ValueError: If the value is not valid. + """ + for available_permission in value: + if not isinstance(available_permission, six.string_types): + raise TypeError( + "Provided available_permissions are not a list of strings." + ) + if available_permission.find("inRole:") != 0: + raise ValueError( + "available_permissions must be prefixed with 'inRole:'." + ) + # Make a copy of the original list. + self._available_permissions = list(value) + + @property + def availability_condition(self): + """Returns the current availability condition. + + Returns: + Optional[google.auth.downscoped.AvailabilityCondition]: The current + availability condition. + """ + return self._availability_condition + + @availability_condition.setter + def availability_condition(self, value): + """Updates the current availability condition. + + Args: + value (Optional[google.auth.downscoped.AvailabilityCondition]): The updated + value of the availability condition. + + Raises: + TypeError: If the value is not of type google.auth.downscoped.AvailabilityCondition + or None. + """ + if not isinstance(value, AvailabilityCondition) and value is not None: + raise TypeError( + "The provided availability_condition is not a 'google.auth.downscoped.AvailabilityCondition' or None." + ) + self._availability_condition = value + + def to_json(self): + """Generates the dictionary representation of the access boundary rule. + This uses the format expected by the Security Token Service API as documented in + `Defining a Credential Access Boundary`_. + + .. _Defining a Credential Access Boundary: + https://cloud.google.com/iam/docs/downscoping-short-lived-credentials#define-boundary + + Returns: + Mapping: The access boundary rule represented in a dictionary object. + """ + json = { + "availablePermissions": list(self.available_permissions), + "availableResource": self.available_resource, + } + if self.availability_condition: + json["availabilityCondition"] = self.availability_condition.to_json() + return json + + +class AvailabilityCondition(object): + """An optional condition that can be used as part of a Credential Access Boundary + to further restrict permissions.""" + + def __init__(self, expression, title=None, description=None): + """Instantiates an availability condition using the provided expression and + optional title or description. + + Args: + expression (str): A condition expression that specifies the Cloud Storage + objects where permissions are available. For example, this expression + makes permissions available for objects whose name starts with "customer-a": + "resource.name.startsWith('projects/_/buckets/example-bucket/objects/customer-a')" + title (Optional[str]): An optional short string that identifies the purpose of + the condition. + description (Optional[str]): Optional details about the purpose of the condition. + + Raises: + TypeError: If any of the parameters are not of the expected types. + ValueError: If any of the parameters are not of the expected values. + """ + self.expression = expression + self.title = title + self.description = description + + @property + def expression(self): + """Returns the current condition expression. + + Returns: + str: The current conditon expression. + """ + return self._expression + + @expression.setter + def expression(self, value): + """Updates the current condition expression. + + Args: + value (str): The updated value of the condition expression. + + Raises: + TypeError: If the value is not of type string. + """ + if not isinstance(value, six.string_types): + raise TypeError("The provided expression is not a string.") + self._expression = value + + @property + def title(self): + """Returns the current title. + + Returns: + Optional[str]: The current title. + """ + return self._title + + @title.setter + def title(self, value): + """Updates the current title. + + Args: + value (Optional[str]): The updated value of the title. + + Raises: + TypeError: If the value is not of type string or None. + """ + if not isinstance(value, six.string_types) and value is not None: + raise TypeError("The provided title is not a string or None.") + self._title = value + + @property + def description(self): + """Returns the current description. + + Returns: + Optional[str]: The current description. + """ + return self._description + + @description.setter + def description(self, value): + """Updates the current description. + + Args: + value (Optional[str]): The updated value of the description. + + Raises: + TypeError: If the value is not of type string or None. + """ + if not isinstance(value, six.string_types) and value is not None: + raise TypeError("The provided description is not a string or None.") + self._description = value + + def to_json(self): + """Generates the dictionary representation of the availability condition. + This uses the format expected by the Security Token Service API as documented in + `Defining a Credential Access Boundary`_. + + .. _Defining a Credential Access Boundary: + https://cloud.google.com/iam/docs/downscoping-short-lived-credentials#define-boundary + + Returns: + Mapping[str, str]: The availability condition represented in a dictionary + object. + """ + json = {"expression": self.expression} + if self.title: + json["title"] = self.title + if self.description: + json["description"] = self.description + return json + + +class Credentials(credentials.CredentialsWithQuotaProject): + """Defines a set of Google credentials that are downscoped from an existing set + of Google OAuth2 credentials. This is useful to restrict the Identity and Access + Management (IAM) permissions that a short-lived credential can use. + The common pattern of usage is to have a token broker with elevated access + generate these downscoped credentials from higher access source credentials and + pass the downscoped short-lived access tokens to a token consumer via some + secure authenticated channel for limited access to Google Cloud Storage + resources. + """ + + def __init__( + self, source_credentials, credential_access_boundary, quota_project_id=None + ): + """Instantiates a downscoped credentials object using the provided source + credentials and credential access boundary rules. + To downscope permissions of a source credential, a Credential Access Boundary + that specifies which resources the new credential can access, as well as an + upper bound on the permissions that are available on each resource, has to be + defined. A downscoped credential can then be instantiated using the source + credential and the Credential Access Boundary. + + Args: + source_credentials (google.auth.credentials.Credentials): The source credentials + to be downscoped based on the provided Credential Access Boundary rules. + credential_access_boundary (google.auth.downscoped.CredentialAccessBoundary): + The Credential Access Boundary which contains a list of access boundary + rules. Each rule contains information on the resource that the rule applies to, + the upper bound of the permissions that are available on that resource and an + optional condition to further restrict permissions. + quota_project_id (Optional[str]): The optional quota project ID. + Raises: + google.auth.exceptions.RefreshError: If the source credentials + return an error on token refresh. + google.auth.exceptions.OAuthError: If the STS token exchange + endpoint returned an error during downscoped token generation. + """ + + super(Credentials, self).__init__() + self._source_credentials = source_credentials + self._credential_access_boundary = credential_access_boundary + self._quota_project_id = quota_project_id + self._sts_client = sts.Client(_STS_TOKEN_URL) + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + # Generate an access token from the source credentials. + self._source_credentials.refresh(request) + now = _helpers.utcnow() + # Exchange the access token for a downscoped access token. + response_data = self._sts_client.exchange_token( + request=request, + grant_type=_STS_GRANT_TYPE, + subject_token=self._source_credentials.token, + subject_token_type=_STS_SUBJECT_TOKEN_TYPE, + requested_token_type=_STS_REQUESTED_TOKEN_TYPE, + additional_options=self._credential_access_boundary.to_json(), + ) + self.token = response_data.get("access_token") + # For downscoping CAB flow, the STS endpoint may not return the expiration + # field for some flows. The generated downscoped token should always have + # the same expiration time as the source credentials. When no expires_in + # field is returned in the response, we can just get the expiration time + # from the source credentials. + if response_data.get("expires_in"): + lifetime = datetime.timedelta(seconds=response_data.get("expires_in")) + self.expiry = now + lifetime + else: + self.expiry = self._source_credentials.expiry + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__( + self._source_credentials, + self._credential_access_boundary, + quota_project_id=quota_project_id, + ) diff --git a/script.module.google-auth-library/lib/google/auth/environment_vars.py b/script.module.google-auth-library/lib/google/auth/environment_vars.py new file mode 100644 index 000000000..81f31571e --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/environment_vars.py @@ -0,0 +1,84 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Environment variables used by :mod:`google.auth`.""" + + +PROJECT = "GOOGLE_CLOUD_PROJECT" +"""Environment variable defining default project. + +This used by :func:`google.auth.default` to explicitly set a project ID. This +environment variable is also used by the Google Cloud Python Library. +""" + +LEGACY_PROJECT = "GCLOUD_PROJECT" +"""Previously used environment variable defining the default project. + +This environment variable is used instead of the current one in some +situations (such as Google App Engine). +""" + +GOOGLE_CLOUD_QUOTA_PROJECT = "GOOGLE_CLOUD_QUOTA_PROJECT" +"""Environment variable defining the project to be used for +quota and billing.""" + +CREDENTIALS = "GOOGLE_APPLICATION_CREDENTIALS" +"""Environment variable defining the location of Google application default +credentials.""" + +# The environment variable name which can replace ~/.config if set. +CLOUD_SDK_CONFIG_DIR = "CLOUDSDK_CONFIG" +"""Environment variable defines the location of Google Cloud SDK's config +files.""" + +# These two variables allow for customization of the addresses used when +# contacting the GCE metadata service. +GCE_METADATA_HOST = "GCE_METADATA_HOST" +"""Environment variable providing an alternate hostname or host:port to be +used for GCE metadata requests. + +This environment variable was originally named GCE_METADATA_ROOT. The system will +check this environemnt variable first; should there be no value present, +the system will fall back to the old variable. +""" + +GCE_METADATA_ROOT = "GCE_METADATA_ROOT" +"""Old environment variable for GCE_METADATA_HOST.""" + +GCE_METADATA_IP = "GCE_METADATA_IP" +"""Environment variable providing an alternate ip:port to be used for ip-only +GCE metadata requests.""" + +GOOGLE_API_USE_CLIENT_CERTIFICATE = "GOOGLE_API_USE_CLIENT_CERTIFICATE" +"""Environment variable controlling whether to use client certificate or not. + +The default value is false. Users have to explicitly set this value to true +in order to use client certificate to establish a mutual TLS channel.""" + +LEGACY_APPENGINE_RUNTIME = "APPENGINE_RUNTIME" +"""Gen1 environment variable defining the App Engine Runtime. + +Used to distinguish between GAE gen1 and GAE gen2+. +""" + +# AWS environment variables used with AWS workload identity pools to retrieve +# AWS security credentials and the AWS region needed to create a serialized +# signed requests to the AWS STS GetCalledIdentity API that can be exchanged +# for a Google access tokens via the GCP STS endpoint. +# When not available the AWS metadata server is used to retrieve these values. +AWS_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID" +AWS_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY" +AWS_SESSION_TOKEN = "AWS_SESSION_TOKEN" +AWS_REGION = "AWS_REGION" +AWS_DEFAULT_REGION = "AWS_DEFAULT_REGION" diff --git a/script.module.google-auth-library/lib/google/auth/exceptions.py b/script.module.google-auth-library/lib/google/auth/exceptions.py new file mode 100644 index 000000000..7760c87b8 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/exceptions.py @@ -0,0 +1,76 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Exceptions used in the google.auth package.""" + + +class GoogleAuthError(Exception): + """Base class for all google.auth errors.""" + + def __init__(self, *args, **kwargs): + super(GoogleAuthError, self).__init__(*args) + retryable = kwargs.get("retryable", False) + self._retryable = retryable + + @property + def retryable(self): + return self._retryable + + +class TransportError(GoogleAuthError): + """Used to indicate an error occurred during an HTTP request.""" + + +class RefreshError(GoogleAuthError): + """Used to indicate that an refreshing the credentials' access token + failed.""" + + +class UserAccessTokenError(GoogleAuthError): + """Used to indicate ``gcloud auth print-access-token`` command failed.""" + + +class DefaultCredentialsError(GoogleAuthError): + """Used to indicate that acquiring default credentials failed.""" + + +class MutualTLSChannelError(GoogleAuthError): + """Used to indicate that mutual TLS channel creation is failed, or mutual + TLS channel credentials is missing or invalid.""" + + +class ClientCertError(GoogleAuthError): + """Used to indicate that client certificate is missing or invalid.""" + + @property + def retryable(self): + return False + + +class OAuthError(GoogleAuthError): + """Used to indicate an error occurred during an OAuth related HTTP + request.""" + + +class ReauthFailError(RefreshError): + """An exception for when reauth failed.""" + + def __init__(self, message=None, **kwargs): + super(ReauthFailError, self).__init__( + "Reauthentication failed. {0}".format(message), **kwargs + ) + + +class ReauthSamlChallengeFailError(ReauthFailError): + """An exception for SAML reauth challenge failures.""" diff --git a/script.module.google-auth-library/lib/google/auth/external_account.py b/script.module.google-auth-library/lib/google/auth/external_account.py new file mode 100644 index 000000000..4249529e8 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/external_account.py @@ -0,0 +1,537 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""External Account Credentials. + +This module provides credentials that exchange workload identity pool external +credentials for Google access tokens. This facilitates accessing Google Cloud +Platform resources from on-prem and non-Google Cloud platforms (e.g. AWS, +Microsoft Azure, OIDC identity providers), using native credentials retrieved +from the current environment without the need to copy, save and manage +long-lived service account credentials. + +Specifically, this is intended to use access tokens acquired using the GCP STS +token exchange endpoint following the `OAuth 2.0 Token Exchange`_ spec. + +.. _OAuth 2.0 Token Exchange: https://tools.ietf.org/html/rfc8693 +""" + +import abc +import copy +import datetime +import io +import json +import re + +import six +from urllib3.util import parse_url + +from google.auth import _helpers +from google.auth import credentials +from google.auth import exceptions +from google.auth import impersonated_credentials +from google.oauth2 import sts +from google.oauth2 import utils + +# External account JSON type identifier. +_EXTERNAL_ACCOUNT_JSON_TYPE = "external_account" +# The token exchange grant_type used for exchanging credentials. +_STS_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange" +# The token exchange requested_token_type. This is always an access_token. +_STS_REQUESTED_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token" +# Cloud resource manager URL used to retrieve project information. +_CLOUD_RESOURCE_MANAGER = "https://cloudresourcemanager.googleapis.com/v1/projects/" + + +@six.add_metaclass(abc.ABCMeta) +class Credentials( + credentials.Scoped, + credentials.CredentialsWithQuotaProject, + credentials.CredentialsWithTokenUri, +): + """Base class for all external account credentials. + + This is used to instantiate Credentials for exchanging external account + credentials for Google access token and authorizing requests to Google APIs. + The base class implements the common logic for exchanging external account + credentials for Google access tokens. + """ + + def __init__( + self, + audience, + subject_token_type, + token_url, + credential_source, + service_account_impersonation_url=None, + service_account_impersonation_options=None, + client_id=None, + client_secret=None, + token_info_url=None, + quota_project_id=None, + scopes=None, + default_scopes=None, + workforce_pool_user_project=None, + ): + """Instantiates an external account credentials object. + + Args: + audience (str): The STS audience field. + subject_token_type (str): The subject token type. + token_url (str): The STS endpoint URL. + credential_source (Mapping): The credential source dictionary. + service_account_impersonation_url (Optional[str]): The optional service account + impersonation generateAccessToken URL. + client_id (Optional[str]): The optional client ID. + client_secret (Optional[str]): The optional client secret. + token_info_url (str): The optional STS endpoint URL for token introspection. + quota_project_id (Optional[str]): The optional quota project ID. + scopes (Optional[Sequence[str]]): Optional scopes to request during the + authorization grant. + default_scopes (Optional[Sequence[str]]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + workforce_pool_user_project (Optona[str]): The optional workforce pool user + project number when the credential corresponds to a workforce pool and not + a workload identity pool. The underlying principal must still have + serviceusage.services.use IAM permission to use the project for + billing/quota. + Raises: + google.auth.exceptions.RefreshError: If the generateAccessToken + endpoint returned an error. + """ + super(Credentials, self).__init__() + self._audience = audience + self._subject_token_type = subject_token_type + self._token_url = token_url + self._token_info_url = token_info_url + self._credential_source = credential_source + self._service_account_impersonation_url = service_account_impersonation_url + self._service_account_impersonation_options = ( + service_account_impersonation_options or {} + ) + self._client_id = client_id + self._client_secret = client_secret + self._quota_project_id = quota_project_id + self._scopes = scopes + self._default_scopes = default_scopes + self._workforce_pool_user_project = workforce_pool_user_project + + Credentials.validate_token_url(token_url) + if token_info_url: + Credentials.validate_token_url(token_info_url, url_type="token info") + if service_account_impersonation_url: + Credentials.validate_service_account_impersonation_url( + service_account_impersonation_url + ) + + if self._client_id: + self._client_auth = utils.ClientAuthentication( + utils.ClientAuthType.basic, self._client_id, self._client_secret + ) + else: + self._client_auth = None + self._sts_client = sts.Client(self._token_url, self._client_auth) + + if self._service_account_impersonation_url: + self._impersonated_credentials = self._initialize_impersonated_credentials() + else: + self._impersonated_credentials = None + self._project_id = None + + if not self.is_workforce_pool and self._workforce_pool_user_project: + # Workload identity pools do not support workforce pool user projects. + raise ValueError( + "workforce_pool_user_project should not be set for non-workforce pool " + "credentials" + ) + + @property + def info(self): + """Generates the dictionary representation of the current credentials. + + Returns: + Mapping: The dictionary representation of the credentials. This is the + reverse of "from_info" defined on the subclasses of this class. It is + useful for serializing the current credentials so it can deserialized + later. + """ + config_info = self._constructor_args() + config_info.update( + type=_EXTERNAL_ACCOUNT_JSON_TYPE, + service_account_impersonation=config_info.pop( + "service_account_impersonation_options", None + ), + ) + config_info.pop("scopes", None) + config_info.pop("default_scopes", None) + return {key: value for key, value in config_info.items() if value is not None} + + def _constructor_args(self): + args = { + "audience": self._audience, + "subject_token_type": self._subject_token_type, + "token_url": self._token_url, + "token_info_url": self._token_info_url, + "service_account_impersonation_url": self._service_account_impersonation_url, + "service_account_impersonation_options": copy.deepcopy( + self._service_account_impersonation_options + ) + or None, + "credential_source": copy.deepcopy(self._credential_source), + "quota_project_id": self._quota_project_id, + "client_id": self._client_id, + "client_secret": self._client_secret, + "workforce_pool_user_project": self._workforce_pool_user_project, + "scopes": self._scopes, + "default_scopes": self._default_scopes, + } + if not self.is_workforce_pool: + args.pop("workforce_pool_user_project") + return args + + @property + def service_account_email(self): + """Returns the service account email if service account impersonation is used. + + Returns: + Optional[str]: The service account email if impersonation is used. Otherwise + None is returned. + """ + if self._service_account_impersonation_url: + # Parse email from URL. The formal looks as follows: + # https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/name@project-id.iam.gserviceaccount.com:generateAccessToken + url = self._service_account_impersonation_url + start_index = url.rfind("/") + end_index = url.find(":generateAccessToken") + if start_index != -1 and end_index != -1 and start_index < end_index: + start_index = start_index + 1 + return url[start_index:end_index] + return None + + @property + def is_user(self): + """Returns whether the credentials represent a user (True) or workload (False). + Workloads behave similarly to service accounts. Currently workloads will use + service account impersonation but will eventually not require impersonation. + As a result, this property is more reliable than the service account email + property in determining if the credentials represent a user or workload. + + Returns: + bool: True if the credentials represent a user. False if they represent a + workload. + """ + # If service account impersonation is used, the credentials will always represent a + # service account. + if self._service_account_impersonation_url: + return False + return self.is_workforce_pool + + @property + def is_workforce_pool(self): + """Returns whether the credentials represent a workforce pool (True) or + workload (False) based on the credentials' audience. + + This will also return True for impersonated workforce pool credentials. + + Returns: + bool: True if the credentials represent a workforce pool. False if they + represent a workload. + """ + # Workforce pools representing users have the following audience format: + # //iam.googleapis.com/locations/$location/workforcePools/$poolId/providers/$providerId + p = re.compile(r"//iam\.googleapis\.com/locations/[^/]+/workforcePools/") + return p.match(self._audience or "") is not None + + @property + def requires_scopes(self): + """Checks if the credentials requires scopes. + + Returns: + bool: True if there are no scopes set otherwise False. + """ + return not self._scopes and not self._default_scopes + + @property + def project_number(self): + """Optional[str]: The project number corresponding to the workload identity pool.""" + + # STS audience pattern: + # //iam.googleapis.com/projects/$PROJECT_NUMBER/locations/... + components = self._audience.split("/") + try: + project_index = components.index("projects") + if project_index + 1 < len(components): + return components[project_index + 1] or None + except ValueError: + return None + + @property + def token_info_url(self): + """Optional[str]: The STS token introspection endpoint.""" + + return self._token_info_url + + @_helpers.copy_docstring(credentials.Scoped) + def with_scopes(self, scopes, default_scopes=None): + kwargs = self._constructor_args() + kwargs.update(scopes=scopes, default_scopes=default_scopes) + return self.__class__(**kwargs) + + @abc.abstractmethod + def retrieve_subject_token(self, request): + """Retrieves the subject token using the credential_source object. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + Returns: + str: The retrieved subject token. + """ + # pylint: disable=missing-raises-doc + # (pylint doesn't recognize that this is abstract) + raise NotImplementedError("retrieve_subject_token must be implemented") + + def get_project_id(self, request): + """Retrieves the project ID corresponding to the workload identity or workforce pool. + For workforce pool credentials, it returns the project ID corresponding to + the workforce_pool_user_project. + + When not determinable, None is returned. + + This is introduced to support the current pattern of using the Auth library: + + credentials, project_id = google.auth.default() + + The resource may not have permission (resourcemanager.projects.get) to + call this API or the required scopes may not be selected: + https://cloud.google.com/resource-manager/reference/rest/v1/projects/get#authorization-scopes + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + Returns: + Optional[str]: The project ID corresponding to the workload identity pool + or workforce pool if determinable. + """ + if self._project_id: + # If already retrieved, return the cached project ID value. + return self._project_id + scopes = self._scopes if self._scopes is not None else self._default_scopes + # Scopes are required in order to retrieve a valid access token. + project_number = self.project_number or self._workforce_pool_user_project + if project_number and scopes: + headers = {} + url = _CLOUD_RESOURCE_MANAGER + project_number + self.before_request(request, "GET", url, headers) + response = request(url=url, method="GET", headers=headers) + + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + response_data = json.loads(response_body) + + if response.status == 200: + # Cache result as this field is immutable. + self._project_id = response_data.get("projectId") + return self._project_id + + return None + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + scopes = self._scopes if self._scopes is not None else self._default_scopes + if self._impersonated_credentials: + self._impersonated_credentials.refresh(request) + self.token = self._impersonated_credentials.token + self.expiry = self._impersonated_credentials.expiry + else: + now = _helpers.utcnow() + additional_options = None + # Do not pass workforce_pool_user_project when client authentication + # is used. The client ID is sufficient for determining the user project. + if self._workforce_pool_user_project and not self._client_id: + additional_options = {"userProject": self._workforce_pool_user_project} + response_data = self._sts_client.exchange_token( + request=request, + grant_type=_STS_GRANT_TYPE, + subject_token=self.retrieve_subject_token(request), + subject_token_type=self._subject_token_type, + audience=self._audience, + scopes=scopes, + requested_token_type=_STS_REQUESTED_TOKEN_TYPE, + additional_options=additional_options, + ) + self.token = response_data.get("access_token") + lifetime = datetime.timedelta(seconds=response_data.get("expires_in")) + self.expiry = now + lifetime + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + # Return copy of instance with the provided quota project ID. + kwargs = self._constructor_args() + kwargs.update(quota_project_id=quota_project_id) + return self.__class__(**kwargs) + + @_helpers.copy_docstring(credentials.CredentialsWithTokenUri) + def with_token_uri(self, token_uri): + kwargs = self._constructor_args() + kwargs.update(token_url=token_uri) + return self.__class__(**kwargs) + + def _initialize_impersonated_credentials(self): + """Generates an impersonated credentials. + + For more details, see `projects.serviceAccounts.generateAccessToken`_. + + .. _projects.serviceAccounts.generateAccessToken: https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/generateAccessToken + + Returns: + impersonated_credentials.Credential: The impersonated credentials + object. + + Raises: + google.auth.exceptions.RefreshError: If the generateAccessToken + endpoint returned an error. + """ + # Return copy of instance with no service account impersonation. + kwargs = self._constructor_args() + kwargs.update( + service_account_impersonation_url=None, + service_account_impersonation_options={}, + ) + source_credentials = self.__class__(**kwargs) + + # Determine target_principal. + target_principal = self.service_account_email + if not target_principal: + raise exceptions.RefreshError( + "Unable to determine target principal from service account impersonation URL." + ) + + scopes = self._scopes if self._scopes is not None else self._default_scopes + # Initialize and return impersonated credentials. + return impersonated_credentials.Credentials( + source_credentials=source_credentials, + target_principal=target_principal, + target_scopes=scopes, + quota_project_id=self._quota_project_id, + iam_endpoint_override=self._service_account_impersonation_url, + lifetime=self._service_account_impersonation_options.get( + "token_lifetime_seconds" + ), + ) + + @staticmethod + def validate_token_url(token_url, url_type="token"): + _TOKEN_URL_PATTERNS = [ + "^[^\\.\\s\\/\\\\]+\\.sts(?:\\.mtls)?\\.googleapis\\.com$", + "^sts(?:\\.mtls)?\\.googleapis\\.com$", + "^sts\\.[^\\.\\s\\/\\\\]+(?:\\.mtls)?\\.googleapis\\.com$", + "^[^\\.\\s\\/\\\\]+\\-sts(?:\\.mtls)?\\.googleapis\\.com$", + "^sts\\-[^\\.\\s\\/\\\\]+\\.p(?:\\.mtls)?\\.googleapis\\.com$", + ] + + if not Credentials.is_valid_url(_TOKEN_URL_PATTERNS, token_url): + raise ValueError("The provided {} URL is invalid.".format(url_type)) + + @staticmethod + def validate_service_account_impersonation_url(url): + _SERVICE_ACCOUNT_IMPERSONATION_URL_PATTERNS = [ + "^[^\\.\\s\\/\\\\]+\\.iamcredentials\\.googleapis\\.com$", + "^iamcredentials\\.googleapis\\.com$", + "^iamcredentials\\.[^\\.\\s\\/\\\\]+\\.googleapis\\.com$", + "^[^\\.\\s\\/\\\\]+\\-iamcredentials\\.googleapis\\.com$", + "^iamcredentials\\-[^\\.\\s\\/\\\\]+\\.p\\.googleapis\\.com$", + ] + + if not Credentials.is_valid_url( + _SERVICE_ACCOUNT_IMPERSONATION_URL_PATTERNS, url + ): + raise ValueError( + "The provided service account impersonation URL is invalid." + ) + + @staticmethod + def is_valid_url(patterns, url): + """ + Returns True if the provided URL's scheme is HTTPS and the host comforms to at least one of the provided patterns. + """ + # Check specifically for whitespcaces: + # Some python3.6 will parse the space character into %20 and pass the regex check which shouldn't be passed + if not url or len(str(url).split()) > 1: + return False + + try: + uri = parse_url(url) + except Exception: + return False + + if not uri.scheme or uri.scheme != "https" or not uri.hostname: + return False + + return any(re.compile(p).match(uri.hostname.lower()) for p in patterns) + + @classmethod + def from_info(cls, info, **kwargs): + """Creates a Credentials instance from parsed external account info. + + Args: + info (Mapping[str, str]): The external account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.identity_pool.Credentials: The constructed + credentials. + + Raises: + ValueError: For invalid parameters. + """ + return cls( + audience=info.get("audience"), + subject_token_type=info.get("subject_token_type"), + token_url=info.get("token_url"), + token_info_url=info.get("token_info_url"), + service_account_impersonation_url=info.get( + "service_account_impersonation_url" + ), + service_account_impersonation_options=info.get( + "service_account_impersonation" + ) + or {}, + client_id=info.get("client_id"), + client_secret=info.get("client_secret"), + credential_source=info.get("credential_source"), + quota_project_id=info.get("quota_project_id"), + workforce_pool_user_project=info.get("workforce_pool_user_project"), + **kwargs + ) + + @classmethod + def from_file(cls, filename, **kwargs): + """Creates a Credentials instance from an external account json file. + + Args: + filename (str): The path to the external account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.identity_pool.Credentials: The constructed + credentials. + """ + with io.open(filename, "r", encoding="utf-8") as json_file: + data = json.load(json_file) + return cls.from_info(data, **kwargs) diff --git a/script.module.google-auth-library/lib/google/auth/external_account_authorized_user.py b/script.module.google-auth-library/lib/google/auth/external_account_authorized_user.py new file mode 100644 index 000000000..51e7f2058 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/external_account_authorized_user.py @@ -0,0 +1,343 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""External Account Authorized User Credentials. +This module provides credentials based on OAuth 2.0 access and refresh tokens. +These credentials usually access resources on behalf of a user (resource +owner). + +Specifically, these are sourced using external identities via Workforce Identity Federation. + +Obtaining the initial access and refresh token can be done through the Google Cloud CLI. + +Example credential: +{ + "type": "external_account_authorized_user", + "audience": "//iam.googleapis.com/locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID", + "refresh_token": "refreshToken", + "token_url": "https://sts.googleapis.com/v1/oauth/token", + "token_info_url": "https://sts.googleapis.com/v1/instrospect", + "client_id": "clientId", + "client_secret": "clientSecret" +} +""" + +import datetime +import io +import json + +from google.auth import _helpers +from google.auth import credentials +from google.auth import exceptions +from google.oauth2 import sts +from google.oauth2 import utils + +_EXTERNAL_ACCOUNT_AUTHORIZED_USER_JSON_TYPE = "external_account_authorized_user" + + +class Credentials( + credentials.CredentialsWithQuotaProject, + credentials.ReadOnlyScoped, + credentials.CredentialsWithTokenUri, +): + """Credentials for External Account Authorized Users. + + This is used to instantiate Credentials for exchanging refresh tokens from + authorized users for Google access token and authorizing requests to Google + APIs. + + The credentials are considered immutable. If you want to modify the + quota project, use `with_quota_project` and if you want to modify the token + uri, use `with_token_uri`. + """ + + def __init__( + self, + token=None, + expiry=None, + refresh_token=None, + audience=None, + client_id=None, + client_secret=None, + token_url=None, + token_info_url=None, + revoke_url=None, + scopes=None, + quota_project_id=None, + ): + """Instantiates a external account authorized user credentials object. + + Args: + token (str): The OAuth 2.0 access token. Can be None if refresh information + is provided. + expiry (datetime.datetime): The optional expiration datetime of the OAuth 2.0 access + token. + refresh_token (str): The optional OAuth 2.0 refresh token. If specified, + credentials can be refreshed. + audience (str): The optional STS audience which contains the resource name for the workforce + pool and the provider identifier in that pool. + client_id (str): The OAuth 2.0 client ID. Must be specified for refresh, can be left as + None if the token can not be refreshed. + client_secret (str): The OAuth 2.0 client secret. Must be specified for refresh, can be + left as None if the token can not be refreshed. + token_url (str): The optional STS token exchange endpoint for refresh. Must be specified for + refresh, can be left as None if the token can not be refreshed. + token_info_url (str): The optional STS endpoint URL for token introspection. + revoke_url (str): The optional STS endpoint URL for revoking tokens. + quota_project_id (str): The optional project ID used for quota and billing. + This project may be different from the project used to + create the credentials. + + Returns: + google.auth.external_account_authorized_user.Credentials: The + constructed credentials. + """ + super(Credentials, self).__init__() + + self.token = token + self.expiry = expiry + self._audience = audience + self._refresh_token = refresh_token + self._token_url = token_url + self._token_info_url = token_info_url + self._client_id = client_id + self._client_secret = client_secret + self._revoke_url = revoke_url + self._quota_project_id = quota_project_id + self._scopes = scopes + + if not self.valid and not self.can_refresh: + raise ValueError( + "Token should be created with fields to make it valid (`token` and " + "`expiry`), or fields to allow it to refresh (`refresh_token`, " + "`token_url`, `client_id`, `client_secret`)." + ) + + self._client_auth = None + if self._client_id: + self._client_auth = utils.ClientAuthentication( + utils.ClientAuthType.basic, self._client_id, self._client_secret + ) + self._sts_client = sts.Client(self._token_url, self._client_auth) + + @property + def info(self): + """Generates the serializable dictionary representation of the current + credentials. + + Returns: + Mapping: The dictionary representation of the credentials. This is the + reverse of the "from_info" method defined in this class. It is + useful for serializing the current credentials so it can deserialized + later. + """ + config_info = self.constructor_args() + config_info.update(type=_EXTERNAL_ACCOUNT_AUTHORIZED_USER_JSON_TYPE) + if config_info["expiry"]: + config_info["expiry"] = config_info["expiry"].isoformat() + "Z" + + return {key: value for key, value in config_info.items() if value is not None} + + def constructor_args(self): + return { + "audience": self._audience, + "refresh_token": self._refresh_token, + "token_url": self._token_url, + "token_info_url": self._token_info_url, + "client_id": self._client_id, + "client_secret": self._client_secret, + "token": self.token, + "expiry": self.expiry, + "revoke_url": self._revoke_url, + "scopes": self._scopes, + "quota_project_id": self._quota_project_id, + } + + @property + def scopes(self): + """Optional[str]: The OAuth 2.0 permission scopes.""" + return self._scopes + + @property + def requires_scopes(self): + """ False: OAuth 2.0 credentials have their scopes set when + the initial token is requested and can not be changed.""" + return False + + @property + def client_id(self): + """Optional[str]: The OAuth 2.0 client ID.""" + return self._client_id + + @property + def client_secret(self): + """Optional[str]: The OAuth 2.0 client secret.""" + return self._client_secret + + @property + def audience(self): + """Optional[str]: The STS audience which contains the resource name for the + workforce pool and the provider identifier in that pool.""" + return self._audience + + @property + def refresh_token(self): + """Optional[str]: The OAuth 2.0 refresh token.""" + return self._refresh_token + + @property + def token_url(self): + """Optional[str]: The STS token exchange endpoint for refresh.""" + return self._token_url + + @property + def token_info_url(self): + """Optional[str]: The STS endpoint for token info.""" + return self._token_info_url + + @property + def revoke_url(self): + """Optional[str]: The STS endpoint for token revocation.""" + return self._revoke_url + + @property + def is_user(self): + """ True: This credential always represents a user.""" + return True + + @property + def can_refresh(self): + return all( + (self._refresh_token, self._token_url, self._client_id, self._client_secret) + ) + + def get_project_id(self): + """Retrieves the project ID corresponding to the workload identity or workforce pool. + For workforce pool credentials, it returns the project ID corresponding to + the workforce_pool_user_project. + + When not determinable, None is returned. + """ + + return None + + def to_json(self, strip=None): + """Utility function that creates a JSON representation of this + credential. + Args: + strip (Sequence[str]): Optional list of members to exclude from the + generated JSON. + Returns: + str: A JSON representation of this instance. When converted into + a dictionary, it can be passed to from_info() + to create a new instance. + """ + strip = strip if strip else [] + return json.dumps({k: v for (k, v) in self.info.items() if k not in strip}) + + def refresh(self, request): + """Refreshes the access token. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + + Raises: + google.auth.exceptions.RefreshError: If the credentials could + not be refreshed. + """ + if not self.can_refresh: + raise exceptions.RefreshError( + "The credentials do not contain the necessary fields need to " + "refresh the access token. You must specify refresh_token, " + "token_url, client_id, and client_secret." + ) + + now = _helpers.utcnow() + response_data = self._make_sts_request(request) + + self.token = response_data.get("access_token") + + lifetime = datetime.timedelta(seconds=response_data.get("expires_in")) + self.expiry = now + lifetime + + if "refresh_token" in response_data: + self._refresh_token = response_data["refresh_token"] + + def _make_sts_request(self, request): + return self._sts_client.refresh_token(request, self._refresh_token) + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + kwargs = self.constructor_args() + kwargs.update(quota_project_id=quota_project_id) + return self.__class__(**kwargs) + + @_helpers.copy_docstring(credentials.CredentialsWithTokenUri) + def with_token_uri(self, token_uri): + kwargs = self.constructor_args() + kwargs.update(token_url=token_uri) + return self.__class__(**kwargs) + + @classmethod + def from_info(cls, info, **kwargs): + """Creates a Credentials instance from parsed external account info. + + Args: + info (Mapping[str, str]): The external account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.external_account_authorized_user.Credentials: The + constructed credentials. + + Raises: + ValueError: For invalid parameters. + """ + expiry = info.get("expiry") + if expiry: + expiry = datetime.datetime.strptime( + expiry.rstrip("Z").split(".")[0], "%Y-%m-%dT%H:%M:%S" + ) + return cls( + audience=info.get("audience"), + refresh_token=info.get("refresh_token"), + token_url=info.get("token_url"), + token_info_url=info.get("token_info_url"), + client_id=info.get("client_id"), + client_secret=info.get("client_secret"), + token=info.get("token"), + expiry=expiry, + revoke_url=info.get("revoke_url"), + quota_project_id=info.get("quota_project_id"), + scopes=info.get("scopes"), + **kwargs + ) + + @classmethod + def from_file(cls, filename, **kwargs): + """Creates a Credentials instance from an external account json file. + + Args: + filename (str): The path to the external account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.external_account_authorized_user.Credentials: The + constructed credentials. + """ + with io.open(filename, "r", encoding="utf-8") as json_file: + data = json.load(json_file) + return cls.from_info(data, **kwargs) diff --git a/script.module.google-auth-library/lib/google/auth/iam.py b/script.module.google-auth-library/lib/google/auth/iam.py new file mode 100644 index 000000000..5d63dc5d8 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/iam.py @@ -0,0 +1,100 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tools for using the Google `Cloud Identity and Access Management (IAM) +API`_'s auth-related functionality. + +.. _Cloud Identity and Access Management (IAM) API: + https://cloud.google.com/iam/docs/ +""" + +import base64 +import json + +from six.moves import http_client + +from google.auth import _helpers +from google.auth import crypt +from google.auth import exceptions + +_IAM_API_ROOT_URI = "https://iamcredentials.googleapis.com/v1" +_SIGN_BLOB_URI = _IAM_API_ROOT_URI + "/projects/-/serviceAccounts/{}:signBlob?alt=json" + + +class Signer(crypt.Signer): + """Signs messages using the IAM `signBlob API`_. + + This is useful when you need to sign bytes but do not have access to the + credential's private key file. + + .. _signBlob API: + https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts + /signBlob + """ + + def __init__(self, request, credentials, service_account_email): + """ + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + credentials (google.auth.credentials.Credentials): The credentials + that will be used to authenticate the request to the IAM API. + The credentials must have of one the following scopes: + + - https://www.googleapis.com/auth/iam + - https://www.googleapis.com/auth/cloud-platform + service_account_email (str): The service account email identifying + which service account to use to sign bytes. Often, this can + be the same as the service account email in the given + credentials. + """ + self._request = request + self._credentials = credentials + self._service_account_email = service_account_email + + def _make_signing_request(self, message): + """Makes a request to the API signBlob API.""" + message = _helpers.to_bytes(message) + + method = "POST" + url = _SIGN_BLOB_URI.format(self._service_account_email) + headers = {"Content-Type": "application/json"} + body = json.dumps( + {"payload": base64.b64encode(message).decode("utf-8")} + ).encode("utf-8") + + self._credentials.before_request(self._request, method, url, headers) + response = self._request(url=url, method=method, body=body, headers=headers) + + if response.status != http_client.OK: + raise exceptions.TransportError( + "Error calling the IAM signBlob API: {}".format(response.data) + ) + + return json.loads(response.data.decode("utf-8")) + + @property + def key_id(self): + """Optional[str]: The key ID used to identify this private key. + + .. warning:: + This is always ``None``. The key ID used by IAM can not + be reliably determined ahead of time. + """ + return None + + @_helpers.copy_docstring(crypt.Signer) + def sign(self, message): + response = self._make_signing_request(message) + return base64.b64decode(response["signedBlob"]) diff --git a/script.module.google-auth-library/lib/google/auth/identity_pool.py b/script.module.google-auth-library/lib/google/auth/identity_pool.py new file mode 100644 index 000000000..5fa9faef9 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/identity_pool.py @@ -0,0 +1,249 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Identity Pool Credentials. + +This module provides credentials to access Google Cloud resources from on-prem +or non-Google Cloud platforms which support external credentials (e.g. OIDC ID +tokens) retrieved from local file locations or local servers. This includes +Microsoft Azure and OIDC identity providers (e.g. K8s workloads registered with +Hub with Hub workload identity enabled). + +These credentials are recommended over the use of service account credentials +in on-prem/non-Google Cloud platforms as they do not involve the management of +long-live service account private keys. + +Identity Pool Credentials are initialized using external_account +arguments which are typically loaded from an external credentials file or +an external credentials URL. Unlike other Credentials that can be initialized +with a list of explicit arguments, secrets or credentials, external account +clients use the environment and hints/guidelines provided by the +external_account JSON file to retrieve credentials and exchange them for Google +access tokens. +""" + +try: + from collections.abc import Mapping +# Python 2.7 compatibility +except ImportError: # pragma: NO COVER + from collections import Mapping +import io +import json +import os + +from google.auth import _helpers +from google.auth import exceptions +from google.auth import external_account + + +class Credentials(external_account.Credentials): + """External account credentials sourced from files and URLs.""" + + def __init__( + self, + audience, + subject_token_type, + token_url, + credential_source, + *args, + **kwargs + ): + """Instantiates an external account credentials object from a file/URL. + + Args: + audience (str): The STS audience field. + subject_token_type (str): The subject token type. + token_url (str): The STS endpoint URL. + credential_source (Mapping): The credential source dictionary used to + provide instructions on how to retrieve external credential to be + exchanged for Google access tokens. + + Example credential_source for url-sourced credential:: + + { + "url": "http://www.example.com", + "format": { + "type": "json", + "subject_token_field_name": "access_token", + }, + "headers": {"foo": "bar"}, + } + + Example credential_source for file-sourced credential:: + + { + "file": "/path/to/token/file.txt" + } + args (List): Optional positional arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method. + kwargs (Mapping): Optional keyword arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method. + + Raises: + google.auth.exceptions.RefreshError: If an error is encountered during + access token retrieval logic. + ValueError: For invalid parameters. + + .. note:: Typically one of the helper constructors + :meth:`from_file` or + :meth:`from_info` are used instead of calling the constructor directly. + """ + + super(Credentials, self).__init__( + audience=audience, + subject_token_type=subject_token_type, + token_url=token_url, + credential_source=credential_source, + *args, + **kwargs + ) + if not isinstance(credential_source, Mapping): + self._credential_source_file = None + self._credential_source_url = None + else: + self._credential_source_file = credential_source.get("file") + self._credential_source_url = credential_source.get("url") + self._credential_source_headers = credential_source.get("headers") + credential_source_format = credential_source.get("format", {}) + # Get credential_source format type. When not provided, this + # defaults to text. + self._credential_source_format_type = ( + credential_source_format.get("type") or "text" + ) + # environment_id is only supported in AWS or dedicated future external + # account credentials. + if "environment_id" in credential_source: + raise ValueError( + "Invalid Identity Pool credential_source field 'environment_id'" + ) + if self._credential_source_format_type not in ["text", "json"]: + raise ValueError( + "Invalid credential_source format '{}'".format( + self._credential_source_format_type + ) + ) + # For JSON types, get the required subject_token field name. + if self._credential_source_format_type == "json": + self._credential_source_field_name = credential_source_format.get( + "subject_token_field_name" + ) + if self._credential_source_field_name is None: + raise ValueError( + "Missing subject_token_field_name for JSON credential_source format" + ) + else: + self._credential_source_field_name = None + + if self._credential_source_file and self._credential_source_url: + raise ValueError( + "Ambiguous credential_source. 'file' is mutually exclusive with 'url'." + ) + if not self._credential_source_file and not self._credential_source_url: + raise ValueError( + "Missing credential_source. A 'file' or 'url' must be provided." + ) + + @_helpers.copy_docstring(external_account.Credentials) + def retrieve_subject_token(self, request): + return self._parse_token_data( + self._get_token_data(request), + self._credential_source_format_type, + self._credential_source_field_name, + ) + + def _get_token_data(self, request): + if self._credential_source_file: + return self._get_file_data(self._credential_source_file) + else: + return self._get_url_data( + request, self._credential_source_url, self._credential_source_headers + ) + + def _get_file_data(self, filename): + if not os.path.exists(filename): + raise exceptions.RefreshError("File '{}' was not found.".format(filename)) + + with io.open(filename, "r", encoding="utf-8") as file_obj: + return file_obj.read(), filename + + def _get_url_data(self, request, url, headers): + response = request(url=url, method="GET", headers=headers) + + # support both string and bytes type response.data + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + + if response.status != 200: + raise exceptions.RefreshError( + "Unable to retrieve Identity Pool subject token", response_body + ) + + return response_body, url + + def _parse_token_data( + self, token_content, format_type="text", subject_token_field_name=None + ): + content, filename = token_content + if format_type == "text": + token = content + else: + try: + # Parse file content as JSON. + response_data = json.loads(content) + # Get the subject_token. + token = response_data[subject_token_field_name] + except (KeyError, ValueError): + raise exceptions.RefreshError( + "Unable to parse subject_token from JSON file '{}' using key '{}'".format( + filename, subject_token_field_name + ) + ) + if not token: + raise exceptions.RefreshError( + "Missing subject_token in the credential_source file" + ) + return token + + @classmethod + def from_info(cls, info, **kwargs): + """Creates an Identity Pool Credentials instance from parsed external account info. + + Args: + info (Mapping[str, str]): The Identity Pool external account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.identity_pool.Credentials: The constructed + credentials. + + Raises: + ValueError: For invalid parameters. + """ + return super(Credentials, cls).from_info(info, **kwargs) + + @classmethod + def from_file(cls, filename, **kwargs): + """Creates an IdentityPool Credentials instance from an external account json file. + + Args: + filename (str): The path to the IdentityPool external account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.identity_pool.Credentials: The constructed + credentials. + """ + return super(Credentials, cls).from_file(filename, **kwargs) diff --git a/script.module.google-auth-library/lib/google/auth/impersonated_credentials.py b/script.module.google-auth-library/lib/google/auth/impersonated_credentials.py new file mode 100644 index 000000000..f978b64ef --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/impersonated_credentials.py @@ -0,0 +1,439 @@ +# Copyright 2018 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google Cloud Impersonated credentials. + +This module provides authentication for applications where local credentials +impersonates a remote service account using `IAM Credentials API`_. + +This class can be used to impersonate a service account as long as the original +Credential object has the "Service Account Token Creator" role on the target +service account. + + .. _IAM Credentials API: + https://cloud.google.com/iam/credentials/reference/rest/ +""" + +import base64 +import copy +from datetime import datetime +import json + +import six +from six.moves import http_client + +from google.auth import _helpers +from google.auth import credentials +from google.auth import exceptions +from google.auth import jwt + +_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds + +_IAM_SCOPE = ["https://www.googleapis.com/auth/iam"] + +_IAM_ENDPOINT = ( + "https://iamcredentials.googleapis.com/v1/projects/-" + + "/serviceAccounts/{}:generateAccessToken" +) + +_IAM_SIGN_ENDPOINT = ( + "https://iamcredentials.googleapis.com/v1/projects/-" + + "/serviceAccounts/{}:signBlob" +) + +_IAM_IDTOKEN_ENDPOINT = ( + "https://iamcredentials.googleapis.com/v1/" + + "projects/-/serviceAccounts/{}:generateIdToken" +) + +_REFRESH_ERROR = "Unable to acquire impersonated credentials" + +_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds + +_DEFAULT_TOKEN_URI = "https://oauth2.googleapis.com/token" + + +def _make_iam_token_request( + request, principal, headers, body, iam_endpoint_override=None +): + """Makes a request to the Google Cloud IAM service for an access token. + Args: + request (Request): The Request object to use. + principal (str): The principal to request an access token for. + headers (Mapping[str, str]): Map of headers to transmit. + body (Mapping[str, str]): JSON Payload body for the iamcredentials + API call. + iam_endpoint_override (Optiona[str]): The full IAM endpoint override + with the target_principal embedded. This is useful when supporting + impersonation with regional endpoints. + + Raises: + google.auth.exceptions.TransportError: Raised if there is an underlying + HTTP connection error + google.auth.exceptions.RefreshError: Raised if the impersonated + credentials are not available. Common reasons are + `iamcredentials.googleapis.com` is not enabled or the + `Service Account Token Creator` is not assigned + """ + iam_endpoint = iam_endpoint_override or _IAM_ENDPOINT.format(principal) + + body = json.dumps(body).encode("utf-8") + + response = request(url=iam_endpoint, method="POST", headers=headers, body=body) + + # support both string and bytes type response.data + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + + if response.status != http_client.OK: + raise exceptions.RefreshError(_REFRESH_ERROR, response_body) + + try: + token_response = json.loads(response_body) + token = token_response["accessToken"] + expiry = datetime.strptime(token_response["expireTime"], "%Y-%m-%dT%H:%M:%SZ") + + return token, expiry + + except (KeyError, ValueError) as caught_exc: + new_exc = exceptions.RefreshError( + "{}: No access token or invalid expiration in response.".format( + _REFRESH_ERROR + ), + response_body, + ) + six.raise_from(new_exc, caught_exc) + + +class Credentials( + credentials.Scoped, credentials.CredentialsWithQuotaProject, credentials.Signing +): + """This module defines impersonated credentials which are essentially + impersonated identities. + + Impersonated Credentials allows credentials issued to a user or + service account to impersonate another. The target service account must + grant the originating credential principal the + `Service Account Token Creator`_ IAM role: + + For more information about Token Creator IAM role and + IAMCredentials API, see + `Creating Short-Lived Service Account Credentials`_. + + .. _Service Account Token Creator: + https://cloud.google.com/iam/docs/service-accounts#the_service_account_token_creator_role + + .. _Creating Short-Lived Service Account Credentials: + https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials + + Usage: + + First grant source_credentials the `Service Account Token Creator` + role on the target account to impersonate. In this example, the + service account represented by svc_account.json has the + token creator role on + `impersonated-account@_project_.iam.gserviceaccount.com`. + + Enable the IAMCredentials API on the source project: + `gcloud services enable iamcredentials.googleapis.com`. + + Initialize a source credential which does not have access to + list bucket:: + + from google.oauth2 import service_account + + target_scopes = [ + 'https://www.googleapis.com/auth/devstorage.read_only'] + + source_credentials = ( + service_account.Credentials.from_service_account_file( + '/path/to/svc_account.json', + scopes=target_scopes)) + + Now use the source credentials to acquire credentials to impersonate + another service account:: + + from google.auth import impersonated_credentials + + target_credentials = impersonated_credentials.Credentials( + source_credentials=source_credentials, + target_principal='impersonated-account@_project_.iam.gserviceaccount.com', + target_scopes = target_scopes, + lifetime=500) + + Resource access is granted:: + + client = storage.Client(credentials=target_credentials) + buckets = client.list_buckets(project='your_project') + for bucket in buckets: + print(bucket.name) + """ + + def __init__( + self, + source_credentials, + target_principal, + target_scopes, + delegates=None, + lifetime=_DEFAULT_TOKEN_LIFETIME_SECS, + quota_project_id=None, + iam_endpoint_override=None, + ): + """ + Args: + source_credentials (google.auth.Credentials): The source credential + used as to acquire the impersonated credentials. + target_principal (str): The service account to impersonate. + target_scopes (Sequence[str]): Scopes to request during the + authorization grant. + delegates (Sequence[str]): The chained list of delegates required + to grant the final access_token. If set, the sequence of + identities must have "Service Account Token Creator" capability + granted to the prceeding identity. For example, if set to + [serviceAccountB, serviceAccountC], the source_credential + must have the Token Creator role on serviceAccountB. + serviceAccountB must have the Token Creator on + serviceAccountC. + Finally, C must have Token Creator on target_principal. + If left unset, source_credential must have that role on + target_principal. + lifetime (int): Number of seconds the delegated credential should + be valid for (upto 3600). + quota_project_id (Optional[str]): The project ID used for quota and billing. + This project may be different from the project used to + create the credentials. + iam_endpoint_override (Optiona[str]): The full IAM endpoint override + with the target_principal embedded. This is useful when supporting + impersonation with regional endpoints. + """ + + super(Credentials, self).__init__() + + self._source_credentials = copy.copy(source_credentials) + # Service account source credentials must have the _IAM_SCOPE + # added to refresh correctly. User credentials cannot have + # their original scopes modified. + if isinstance(self._source_credentials, credentials.Scoped): + self._source_credentials = self._source_credentials.with_scopes(_IAM_SCOPE) + self._target_principal = target_principal + self._target_scopes = target_scopes + self._delegates = delegates + self._lifetime = lifetime or _DEFAULT_TOKEN_LIFETIME_SECS + self.token = None + self.expiry = _helpers.utcnow() + self._quota_project_id = quota_project_id + self._iam_endpoint_override = iam_endpoint_override + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + self._update_token(request) + + def _update_token(self, request): + """Updates credentials with a new access_token representing + the impersonated account. + + Args: + request (google.auth.transport.requests.Request): Request object + to use for refreshing credentials. + """ + + # Refresh our source credentials if it is not valid. + if not self._source_credentials.valid: + self._source_credentials.refresh(request) + + body = { + "delegates": self._delegates, + "scope": self._target_scopes, + "lifetime": str(self._lifetime) + "s", + } + + headers = {"Content-Type": "application/json"} + + # Apply the source credentials authentication info. + self._source_credentials.apply(headers) + + self.token, self.expiry = _make_iam_token_request( + request=request, + principal=self._target_principal, + headers=headers, + body=body, + iam_endpoint_override=self._iam_endpoint_override, + ) + + def sign_bytes(self, message): + from google.auth.transport.requests import AuthorizedSession + + iam_sign_endpoint = _IAM_SIGN_ENDPOINT.format(self._target_principal) + + body = { + "payload": base64.b64encode(message).decode("utf-8"), + "delegates": self._delegates, + } + + headers = {"Content-Type": "application/json"} + + authed_session = AuthorizedSession(self._source_credentials) + + try: + response = authed_session.post( + url=iam_sign_endpoint, headers=headers, json=body + ) + finally: + authed_session.close() + + if response.status_code != http_client.OK: + raise exceptions.TransportError( + "Error calling sign_bytes: {}".format(response.json()) + ) + + return base64.b64decode(response.json()["signedBlob"]) + + @property + def signer_email(self): + return self._target_principal + + @property + def service_account_email(self): + return self._target_principal + + @property + def signer(self): + return self + + @property + def requires_scopes(self): + return not self._target_scopes + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__( + self._source_credentials, + target_principal=self._target_principal, + target_scopes=self._target_scopes, + delegates=self._delegates, + lifetime=self._lifetime, + quota_project_id=quota_project_id, + iam_endpoint_override=self._iam_endpoint_override, + ) + + @_helpers.copy_docstring(credentials.Scoped) + def with_scopes(self, scopes, default_scopes=None): + return self.__class__( + self._source_credentials, + target_principal=self._target_principal, + target_scopes=scopes or default_scopes, + delegates=self._delegates, + lifetime=self._lifetime, + quota_project_id=self._quota_project_id, + iam_endpoint_override=self._iam_endpoint_override, + ) + + +class IDTokenCredentials(credentials.CredentialsWithQuotaProject): + """Open ID Connect ID Token-based service account credentials. + + """ + + def __init__( + self, + target_credentials, + target_audience=None, + include_email=False, + quota_project_id=None, + ): + """ + Args: + target_credentials (google.auth.Credentials): The target + credential used as to acquire the id tokens for. + target_audience (string): Audience to issue the token for. + include_email (bool): Include email in IdToken + quota_project_id (Optional[str]): The project ID used for + quota and billing. + """ + super(IDTokenCredentials, self).__init__() + + if not isinstance(target_credentials, Credentials): + raise exceptions.GoogleAuthError( + "Provided Credential must be " "impersonated_credentials" + ) + self._target_credentials = target_credentials + self._target_audience = target_audience + self._include_email = include_email + self._quota_project_id = quota_project_id + + def from_credentials(self, target_credentials, target_audience=None): + return self.__class__( + target_credentials=target_credentials, + target_audience=target_audience, + include_email=self._include_email, + quota_project_id=self._quota_project_id, + ) + + def with_target_audience(self, target_audience): + return self.__class__( + target_credentials=self._target_credentials, + target_audience=target_audience, + include_email=self._include_email, + quota_project_id=self._quota_project_id, + ) + + def with_include_email(self, include_email): + return self.__class__( + target_credentials=self._target_credentials, + target_audience=self._target_audience, + include_email=include_email, + quota_project_id=self._quota_project_id, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__( + target_credentials=self._target_credentials, + target_audience=self._target_audience, + include_email=self._include_email, + quota_project_id=quota_project_id, + ) + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + from google.auth.transport.requests import AuthorizedSession + + iam_sign_endpoint = _IAM_IDTOKEN_ENDPOINT.format( + self._target_credentials.signer_email + ) + + body = { + "audience": self._target_audience, + "delegates": self._target_credentials._delegates, + "includeEmail": self._include_email, + } + + headers = {"Content-Type": "application/json"} + + authed_session = AuthorizedSession( + self._target_credentials._source_credentials, auth_request=request + ) + + response = authed_session.post( + url=iam_sign_endpoint, + headers=headers, + data=json.dumps(body).encode("utf-8"), + ) + + id_token = response.json()["token"] + self.token = id_token + self.expiry = datetime.fromtimestamp(jwt.decode(id_token, verify=False)["exp"]) diff --git a/script.module.google-auth-library/lib/google/auth/jwt.py b/script.module.google-auth-library/lib/google/auth/jwt.py new file mode 100644 index 000000000..21de8fe95 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/jwt.py @@ -0,0 +1,868 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""JSON Web Tokens + +Provides support for creating (encoding) and verifying (decoding) JWTs, +especially JWTs generated and consumed by Google infrastructure. + +See `rfc7519`_ for more details on JWTs. + +To encode a JWT use :func:`encode`:: + + from google.auth import crypt + from google.auth import jwt + + signer = crypt.Signer(private_key) + payload = {'some': 'payload'} + encoded = jwt.encode(signer, payload) + +To decode a JWT and verify claims use :func:`decode`:: + + claims = jwt.decode(encoded, certs=public_certs) + +You can also skip verification:: + + claims = jwt.decode(encoded, verify=False) + +.. _rfc7519: https://tools.ietf.org/html/rfc7519 + +""" + +try: + from collections.abc import Mapping +# Python 2.7 compatibility +except ImportError: # pragma: NO COVER + from collections import Mapping # type: ignore +import copy +import datetime +import json + +import cachetools +import six +from six.moves import urllib + +from google.auth import _helpers +from google.auth import _service_account_info +from google.auth import crypt +from google.auth import exceptions +import google.auth.credentials + +try: + from google.auth.crypt import es256 +except ImportError: # pragma: NO COVER + es256 = None # type: ignore + +_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds +_DEFAULT_MAX_CACHE_SIZE = 10 +_ALGORITHM_TO_VERIFIER_CLASS = {"RS256": crypt.RSAVerifier} +_CRYPTOGRAPHY_BASED_ALGORITHMS = frozenset(["ES256"]) + +if es256 is not None: # pragma: NO COVER + _ALGORITHM_TO_VERIFIER_CLASS["ES256"] = es256.ES256Verifier # type: ignore + + +def encode(signer, payload, header=None, key_id=None): + """Make a signed JWT. + + Args: + signer (google.auth.crypt.Signer): The signer used to sign the JWT. + payload (Mapping[str, str]): The JWT payload. + header (Mapping[str, str]): Additional JWT header payload. + key_id (str): The key id to add to the JWT header. If the + signer has a key id it will be used as the default. If this is + specified it will override the signer's key id. + + Returns: + bytes: The encoded JWT. + """ + if header is None: + header = {} + + if key_id is None: + key_id = signer.key_id + + header.update({"typ": "JWT"}) + + if "alg" not in header: + if es256 is not None and isinstance(signer, es256.ES256Signer): + header.update({"alg": "ES256"}) + else: + header.update({"alg": "RS256"}) + + if key_id is not None: + header["kid"] = key_id + + segments = [ + _helpers.unpadded_urlsafe_b64encode(json.dumps(header).encode("utf-8")), + _helpers.unpadded_urlsafe_b64encode(json.dumps(payload).encode("utf-8")), + ] + + signing_input = b".".join(segments) + signature = signer.sign(signing_input) + segments.append(_helpers.unpadded_urlsafe_b64encode(signature)) + + return b".".join(segments) + + +def _decode_jwt_segment(encoded_section): + """Decodes a single JWT segment.""" + section_bytes = _helpers.padded_urlsafe_b64decode(encoded_section) + try: + return json.loads(section_bytes.decode("utf-8")) + except ValueError as caught_exc: + new_exc = ValueError("Can't parse segment: {0}".format(section_bytes)) + six.raise_from(new_exc, caught_exc) + + +def _unverified_decode(token): + """Decodes a token and does no verification. + + Args: + token (Union[str, bytes]): The encoded JWT. + + Returns: + Tuple[Mapping, Mapping, str, str]: header, payload, signed_section, and + signature. + + Raises: + ValueError: if there are an incorrect amount of segments in the token or + segments of the wrong type. + """ + token = _helpers.to_bytes(token) + + if token.count(b".") != 2: + raise ValueError("Wrong number of segments in token: {0}".format(token)) + + encoded_header, encoded_payload, signature = token.split(b".") + signed_section = encoded_header + b"." + encoded_payload + signature = _helpers.padded_urlsafe_b64decode(signature) + + # Parse segments + header = _decode_jwt_segment(encoded_header) + payload = _decode_jwt_segment(encoded_payload) + + if not isinstance(header, Mapping): + raise ValueError( + "Header segment should be a JSON object: {0}".format(encoded_header) + ) + + if not isinstance(payload, Mapping): + raise ValueError( + "Payload segment should be a JSON object: {0}".format(encoded_payload) + ) + + return header, payload, signed_section, signature + + +def decode_header(token): + """Return the decoded header of a token. + + No verification is done. This is useful to extract the key id from + the header in order to acquire the appropriate certificate to verify + the token. + + Args: + token (Union[str, bytes]): the encoded JWT. + + Returns: + Mapping: The decoded JWT header. + """ + header, _, _, _ = _unverified_decode(token) + return header + + +def _verify_iat_and_exp(payload, clock_skew_in_seconds=0): + """Verifies the ``iat`` (Issued At) and ``exp`` (Expires) claims in a token + payload. + + Args: + payload (Mapping[str, str]): The JWT payload. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Raises: + ValueError: if any checks failed. + """ + now = _helpers.datetime_to_secs(_helpers.utcnow()) + + # Make sure the iat and exp claims are present. + for key in ("iat", "exp"): + if key not in payload: + raise ValueError("Token does not contain required claim {}".format(key)) + + # Make sure the token wasn't issued in the future. + iat = payload["iat"] + # Err on the side of accepting a token that is slightly early to account + # for clock skew. + earliest = iat - clock_skew_in_seconds + if now < earliest: + raise ValueError( + "Token used too early, {} < {}. Check that your computer's clock is set correctly.".format( + now, iat + ) + ) + + # Make sure the token wasn't issued in the past. + exp = payload["exp"] + # Err on the side of accepting a token that is slightly out of date + # to account for clow skew. + latest = exp + clock_skew_in_seconds + if latest < now: + raise ValueError("Token expired, {} < {}".format(latest, now)) + + +def decode(token, certs=None, verify=True, audience=None, clock_skew_in_seconds=0): + """Decode and verify a JWT. + + Args: + token (str): The encoded JWT. + certs (Union[str, bytes, Mapping[str, Union[str, bytes]]]): The + certificate used to validate the JWT signature. If bytes or string, + it must the the public key certificate in PEM format. If a mapping, + it must be a mapping of key IDs to public key certificates in PEM + format. The mapping must contain the same key ID that's specified + in the token's header. + verify (bool): Whether to perform signature and claim validation. + Verification is done by default. + audience (str or list): The audience claim, 'aud', that this JWT should + contain. Or a list of audience claims. If None then the JWT's 'aud' + parameter is not verified. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Returns: + Mapping[str, str]: The deserialized JSON payload in the JWT. + + Raises: + ValueError: if any verification checks failed. + """ + header, payload, signed_section, signature = _unverified_decode(token) + + if not verify: + return payload + + # Pluck the key id and algorithm from the header and make sure we have + # a verifier that can support it. + key_alg = header.get("alg") + key_id = header.get("kid") + + try: + verifier_cls = _ALGORITHM_TO_VERIFIER_CLASS[key_alg] + except KeyError as exc: + if key_alg in _CRYPTOGRAPHY_BASED_ALGORITHMS: + six.raise_from( + ValueError( + "The key algorithm {} requires the cryptography package " + "to be installed.".format(key_alg) + ), + exc, + ) + else: + six.raise_from( + ValueError("Unsupported signature algorithm {}".format(key_alg)), exc + ) + + # If certs is specified as a dictionary of key IDs to certificates, then + # use the certificate identified by the key ID in the token header. + if isinstance(certs, Mapping): + if key_id: + if key_id not in certs: + raise ValueError("Certificate for key id {} not found.".format(key_id)) + certs_to_check = [certs[key_id]] + # If there's no key id in the header, check against all of the certs. + else: + certs_to_check = certs.values() + else: + certs_to_check = certs + + # Verify that the signature matches the message. + if not crypt.verify_signature( + signed_section, signature, certs_to_check, verifier_cls + ): + raise ValueError("Could not verify token signature.") + + # Verify the issued at and created times in the payload. + _verify_iat_and_exp(payload, clock_skew_in_seconds) + + # Check audience. + if audience is not None: + claim_audience = payload.get("aud") + if isinstance(audience, str): + audience = [audience] + if claim_audience not in audience: + raise ValueError( + "Token has wrong audience {}, expected one of {}".format( + claim_audience, audience + ) + ) + + return payload + + +class Credentials( + google.auth.credentials.Signing, google.auth.credentials.CredentialsWithQuotaProject +): + """Credentials that use a JWT as the bearer token. + + These credentials require an "audience" claim. This claim identifies the + intended recipient of the bearer token. + + The constructor arguments determine the claims for the JWT that is + sent with requests. Usually, you'll construct these credentials with + one of the helper constructors as shown in the next section. + + To create JWT credentials using a Google service account private key + JSON file:: + + audience = 'https://pubsub.googleapis.com/google.pubsub.v1.Publisher' + credentials = jwt.Credentials.from_service_account_file( + 'service-account.json', + audience=audience) + + If you already have the service account file loaded and parsed:: + + service_account_info = json.load(open('service_account.json')) + credentials = jwt.Credentials.from_service_account_info( + service_account_info, + audience=audience) + + Both helper methods pass on arguments to the constructor, so you can + specify the JWT claims:: + + credentials = jwt.Credentials.from_service_account_file( + 'service-account.json', + audience=audience, + additional_claims={'meta': 'data'}) + + You can also construct the credentials directly if you have a + :class:`~google.auth.crypt.Signer` instance:: + + credentials = jwt.Credentials( + signer, + issuer='your-issuer', + subject='your-subject', + audience=audience) + + The claims are considered immutable. If you want to modify the claims, + you can easily create another instance using :meth:`with_claims`:: + + new_audience = ( + 'https://pubsub.googleapis.com/google.pubsub.v1.Subscriber') + new_credentials = credentials.with_claims(audience=new_audience) + """ + + def __init__( + self, + signer, + issuer, + subject, + audience, + additional_claims=None, + token_lifetime=_DEFAULT_TOKEN_LIFETIME_SECS, + quota_project_id=None, + ): + """ + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + issuer (str): The `iss` claim. + subject (str): The `sub` claim. + audience (str): the `aud` claim. The intended audience for the + credentials. + additional_claims (Mapping[str, str]): Any additional claims for + the JWT payload. + token_lifetime (int): The amount of time in seconds for + which the token is valid. Defaults to 1 hour. + quota_project_id (Optional[str]): The project ID used for quota + and billing. + """ + super(Credentials, self).__init__() + self._signer = signer + self._issuer = issuer + self._subject = subject + self._audience = audience + self._token_lifetime = token_lifetime + self._quota_project_id = quota_project_id + + if additional_claims is None: + additional_claims = {} + + self._additional_claims = additional_claims + + @classmethod + def _from_signer_and_info(cls, signer, info, **kwargs): + """Creates a Credentials instance from a signer and service account + info. + + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + info (Mapping[str, str]): The service account info. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.Credentials: The constructed credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + kwargs.setdefault("subject", info["client_email"]) + kwargs.setdefault("issuer", info["client_email"]) + return cls(signer, **kwargs) + + @classmethod + def from_service_account_info(cls, info, **kwargs): + """Creates an Credentials instance from a dictionary. + + Args: + info (Mapping[str, str]): The service account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.Credentials: The constructed credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + signer = _service_account_info.from_dict(info, require=["client_email"]) + return cls._from_signer_and_info(signer, info, **kwargs) + + @classmethod + def from_service_account_file(cls, filename, **kwargs): + """Creates a Credentials instance from a service account .json file + in Google format. + + Args: + filename (str): The path to the service account .json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.Credentials: The constructed credentials. + """ + info, signer = _service_account_info.from_filename( + filename, require=["client_email"] + ) + return cls._from_signer_and_info(signer, info, **kwargs) + + @classmethod + def from_signing_credentials(cls, credentials, audience, **kwargs): + """Creates a new :class:`google.auth.jwt.Credentials` instance from an + existing :class:`google.auth.credentials.Signing` instance. + + The new instance will use the same signer as the existing instance and + will use the existing instance's signer email as the issuer and + subject by default. + + Example:: + + svc_creds = service_account.Credentials.from_service_account_file( + 'service_account.json') + audience = ( + 'https://pubsub.googleapis.com/google.pubsub.v1.Publisher') + jwt_creds = jwt.Credentials.from_signing_credentials( + svc_creds, audience=audience) + + Args: + credentials (google.auth.credentials.Signing): The credentials to + use to construct the new credentials. + audience (str): the `aud` claim. The intended audience for the + credentials. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.Credentials: A new Credentials instance. + """ + kwargs.setdefault("issuer", credentials.signer_email) + kwargs.setdefault("subject", credentials.signer_email) + return cls(credentials.signer, audience=audience, **kwargs) + + def with_claims( + self, issuer=None, subject=None, audience=None, additional_claims=None + ): + """Returns a copy of these credentials with modified claims. + + Args: + issuer (str): The `iss` claim. If unspecified the current issuer + claim will be used. + subject (str): The `sub` claim. If unspecified the current subject + claim will be used. + audience (str): the `aud` claim. If unspecified the current + audience claim will be used. + additional_claims (Mapping[str, str]): Any additional claims for + the JWT payload. This will be merged with the current + additional claims. + + Returns: + google.auth.jwt.Credentials: A new credentials instance. + """ + new_additional_claims = copy.deepcopy(self._additional_claims) + new_additional_claims.update(additional_claims or {}) + + return self.__class__( + self._signer, + issuer=issuer if issuer is not None else self._issuer, + subject=subject if subject is not None else self._subject, + audience=audience if audience is not None else self._audience, + additional_claims=new_additional_claims, + quota_project_id=self._quota_project_id, + ) + + @_helpers.copy_docstring(google.auth.credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__( + self._signer, + issuer=self._issuer, + subject=self._subject, + audience=self._audience, + additional_claims=self._additional_claims, + quota_project_id=quota_project_id, + ) + + def _make_jwt(self): + """Make a signed JWT. + + Returns: + Tuple[bytes, datetime]: The encoded JWT and the expiration. + """ + now = _helpers.utcnow() + lifetime = datetime.timedelta(seconds=self._token_lifetime) + expiry = now + lifetime + + payload = { + "iss": self._issuer, + "sub": self._subject, + "iat": _helpers.datetime_to_secs(now), + "exp": _helpers.datetime_to_secs(expiry), + } + if self._audience: + payload["aud"] = self._audience + + payload.update(self._additional_claims) + + jwt = encode(self._signer, payload) + + return jwt, expiry + + def refresh(self, request): + """Refreshes the access token. + + Args: + request (Any): Unused. + """ + # pylint: disable=unused-argument + # (pylint doesn't correctly recognize overridden methods.) + self.token, self.expiry = self._make_jwt() + + @_helpers.copy_docstring(google.auth.credentials.Signing) + def sign_bytes(self, message): + return self._signer.sign(message) + + @property # type: ignore + @_helpers.copy_docstring(google.auth.credentials.Signing) + def signer_email(self): + return self._issuer + + @property # type: ignore + @_helpers.copy_docstring(google.auth.credentials.Signing) + def signer(self): + return self._signer + + +class OnDemandCredentials( + google.auth.credentials.Signing, google.auth.credentials.CredentialsWithQuotaProject +): + """On-demand JWT credentials. + + Like :class:`Credentials`, this class uses a JWT as the bearer token for + authentication. However, this class does not require the audience at + construction time. Instead, it will generate a new token on-demand for + each request using the request URI as the audience. It caches tokens + so that multiple requests to the same URI do not incur the overhead + of generating a new token every time. + + This behavior is especially useful for `gRPC`_ clients. A gRPC service may + have multiple audience and gRPC clients may not know all of the audiences + required for accessing a particular service. With these credentials, + no knowledge of the audiences is required ahead of time. + + .. _grpc: http://www.grpc.io/ + """ + + def __init__( + self, + signer, + issuer, + subject, + additional_claims=None, + token_lifetime=_DEFAULT_TOKEN_LIFETIME_SECS, + max_cache_size=_DEFAULT_MAX_CACHE_SIZE, + quota_project_id=None, + ): + """ + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + issuer (str): The `iss` claim. + subject (str): The `sub` claim. + additional_claims (Mapping[str, str]): Any additional claims for + the JWT payload. + token_lifetime (int): The amount of time in seconds for + which the token is valid. Defaults to 1 hour. + max_cache_size (int): The maximum number of JWT tokens to keep in + cache. Tokens are cached using :class:`cachetools.LRUCache`. + quota_project_id (Optional[str]): The project ID used for quota + and billing. + + """ + super(OnDemandCredentials, self).__init__() + self._signer = signer + self._issuer = issuer + self._subject = subject + self._token_lifetime = token_lifetime + self._quota_project_id = quota_project_id + + if additional_claims is None: + additional_claims = {} + + self._additional_claims = additional_claims + self._cache = cachetools.LRUCache(maxsize=max_cache_size) + + @classmethod + def _from_signer_and_info(cls, signer, info, **kwargs): + """Creates an OnDemandCredentials instance from a signer and service + account info. + + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + info (Mapping[str, str]): The service account info. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.OnDemandCredentials: The constructed credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + kwargs.setdefault("subject", info["client_email"]) + kwargs.setdefault("issuer", info["client_email"]) + return cls(signer, **kwargs) + + @classmethod + def from_service_account_info(cls, info, **kwargs): + """Creates an OnDemandCredentials instance from a dictionary. + + Args: + info (Mapping[str, str]): The service account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.OnDemandCredentials: The constructed credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + signer = _service_account_info.from_dict(info, require=["client_email"]) + return cls._from_signer_and_info(signer, info, **kwargs) + + @classmethod + def from_service_account_file(cls, filename, **kwargs): + """Creates an OnDemandCredentials instance from a service account .json + file in Google format. + + Args: + filename (str): The path to the service account .json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.OnDemandCredentials: The constructed credentials. + """ + info, signer = _service_account_info.from_filename( + filename, require=["client_email"] + ) + return cls._from_signer_and_info(signer, info, **kwargs) + + @classmethod + def from_signing_credentials(cls, credentials, **kwargs): + """Creates a new :class:`google.auth.jwt.OnDemandCredentials` instance + from an existing :class:`google.auth.credentials.Signing` instance. + + The new instance will use the same signer as the existing instance and + will use the existing instance's signer email as the issuer and + subject by default. + + Example:: + + svc_creds = service_account.Credentials.from_service_account_file( + 'service_account.json') + jwt_creds = jwt.OnDemandCredentials.from_signing_credentials( + svc_creds) + + Args: + credentials (google.auth.credentials.Signing): The credentials to + use to construct the new credentials. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.Credentials: A new Credentials instance. + """ + kwargs.setdefault("issuer", credentials.signer_email) + kwargs.setdefault("subject", credentials.signer_email) + return cls(credentials.signer, **kwargs) + + def with_claims(self, issuer=None, subject=None, additional_claims=None): + """Returns a copy of these credentials with modified claims. + + Args: + issuer (str): The `iss` claim. If unspecified the current issuer + claim will be used. + subject (str): The `sub` claim. If unspecified the current subject + claim will be used. + additional_claims (Mapping[str, str]): Any additional claims for + the JWT payload. This will be merged with the current + additional claims. + + Returns: + google.auth.jwt.OnDemandCredentials: A new credentials instance. + """ + new_additional_claims = copy.deepcopy(self._additional_claims) + new_additional_claims.update(additional_claims or {}) + + return self.__class__( + self._signer, + issuer=issuer if issuer is not None else self._issuer, + subject=subject if subject is not None else self._subject, + additional_claims=new_additional_claims, + max_cache_size=self._cache.maxsize, + quota_project_id=self._quota_project_id, + ) + + @_helpers.copy_docstring(google.auth.credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + + return self.__class__( + self._signer, + issuer=self._issuer, + subject=self._subject, + additional_claims=self._additional_claims, + max_cache_size=self._cache.maxsize, + quota_project_id=quota_project_id, + ) + + @property + def valid(self): + """Checks the validity of the credentials. + + These credentials are always valid because it generates tokens on + demand. + """ + return True + + def _make_jwt_for_audience(self, audience): + """Make a new JWT for the given audience. + + Args: + audience (str): The intended audience. + + Returns: + Tuple[bytes, datetime]: The encoded JWT and the expiration. + """ + now = _helpers.utcnow() + lifetime = datetime.timedelta(seconds=self._token_lifetime) + expiry = now + lifetime + + payload = { + "iss": self._issuer, + "sub": self._subject, + "iat": _helpers.datetime_to_secs(now), + "exp": _helpers.datetime_to_secs(expiry), + "aud": audience, + } + + payload.update(self._additional_claims) + + jwt = encode(self._signer, payload) + + return jwt, expiry + + def _get_jwt_for_audience(self, audience): + """Get a JWT For a given audience. + + If there is already an existing, non-expired token in the cache for + the audience, that token is used. Otherwise, a new token will be + created. + + Args: + audience (str): The intended audience. + + Returns: + bytes: The encoded JWT. + """ + token, expiry = self._cache.get(audience, (None, None)) + + if token is None or expiry < _helpers.utcnow(): + token, expiry = self._make_jwt_for_audience(audience) + self._cache[audience] = token, expiry + + return token + + def refresh(self, request): + """Raises an exception, these credentials can not be directly + refreshed. + + Args: + request (Any): Unused. + + Raises: + google.auth.RefreshError + """ + # pylint: disable=unused-argument + # (pylint doesn't correctly recognize overridden methods.) + raise exceptions.RefreshError( + "OnDemandCredentials can not be directly refreshed." + ) + + def before_request(self, request, method, url, headers): + """Performs credential-specific before request logic. + + Args: + request (Any): Unused. JWT credentials do not need to make an + HTTP request to refresh. + method (str): The request's HTTP method. + url (str): The request's URI. This is used as the audience claim + when generating the JWT. + headers (Mapping): The request's headers. + """ + # pylint: disable=unused-argument + # (pylint doesn't correctly recognize overridden methods.) + parts = urllib.parse.urlsplit(url) + # Strip query string and fragment + audience = urllib.parse.urlunsplit( + (parts.scheme, parts.netloc, parts.path, "", "") + ) + token = self._get_jwt_for_audience(audience) + self.apply(headers, token=token) + + @_helpers.copy_docstring(google.auth.credentials.Signing) + def sign_bytes(self, message): + return self._signer.sign(message) + + @property # type: ignore + @_helpers.copy_docstring(google.auth.credentials.Signing) + def signer_email(self): + return self._issuer + + @property # type: ignore + @_helpers.copy_docstring(google.auth.credentials.Signing) + def signer(self): + return self._signer diff --git a/script.module.google-auth-library/lib/google/auth/pluggable.py b/script.module.google-auth-library/lib/google/auth/pluggable.py new file mode 100644 index 000000000..b4fa448b8 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/pluggable.py @@ -0,0 +1,412 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Pluggable Credentials. +Pluggable Credentials are initialized using external_account arguments which +are typically loaded from third-party executables. Unlike other +credentials that can be initialized with a list of explicit arguments, secrets +or credentials, external account clients use the environment and hints/guidelines +provided by the external_account JSON file to retrieve credentials and exchange +them for Google access tokens. + +Example credential_source for pluggable credential: +{ + "executable": { + "command": "/path/to/get/credentials.sh --arg1=value1 --arg2=value2", + "timeout_millis": 5000, + "output_file": "/path/to/generated/cached/credentials" + } +} +""" + +try: + from collections.abc import Mapping +# Python 2.7 compatibility +except ImportError: # pragma: NO COVER + from collections import Mapping +import json +import os +import subprocess +import sys +import time + +from google.auth import _helpers +from google.auth import exceptions +from google.auth import external_account + +# The max supported executable spec version. +EXECUTABLE_SUPPORTED_MAX_VERSION = 1 + +EXECUTABLE_TIMEOUT_MILLIS_DEFAULT = 30 * 1000 # 30 seconds +EXECUTABLE_TIMEOUT_MILLIS_LOWER_BOUND = 5 * 1000 # 5 seconds +EXECUTABLE_TIMEOUT_MILLIS_UPPER_BOUND = 120 * 1000 # 2 minutes + +EXECUTABLE_INTERACTIVE_TIMEOUT_MILLIS_LOWER_BOUND = 30 * 1000 # 30 seconds +EXECUTABLE_INTERACTIVE_TIMEOUT_MILLIS_UPPER_BOUND = 30 * 60 * 1000 # 30 minutes + + +class Credentials(external_account.Credentials): + """External account credentials sourced from executables.""" + + def __init__( + self, + audience, + subject_token_type, + token_url, + credential_source, + *args, + **kwargs + ): + """Instantiates an external account credentials object from a executables. + + Args: + audience (str): The STS audience field. + subject_token_type (str): The subject token type. + token_url (str): The STS endpoint URL. + credential_source (Mapping): The credential source dictionary used to + provide instructions on how to retrieve external credential to be + exchanged for Google access tokens. + + Example credential_source for pluggable credential: + + { + "executable": { + "command": "/path/to/get/credentials.sh --arg1=value1 --arg2=value2", + "timeout_millis": 5000, + "output_file": "/path/to/generated/cached/credentials" + } + } + args (List): Optional positional arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method. + kwargs (Mapping): Optional keyword arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method. + + Raises: + google.auth.exceptions.RefreshError: If an error is encountered during + access token retrieval logic. + ValueError: For invalid parameters. + + .. note:: Typically one of the helper constructors + :meth:`from_file` or + :meth:`from_info` are used instead of calling the constructor directly. + """ + + self.interactive = kwargs.pop("interactive", False) + super(Credentials, self).__init__( + audience=audience, + subject_token_type=subject_token_type, + token_url=token_url, + credential_source=credential_source, + *args, + **kwargs + ) + if not isinstance(credential_source, Mapping): + self._credential_source_executable = None + raise ValueError( + "Missing credential_source. The credential_source is not a dict." + ) + self._credential_source_executable = credential_source.get("executable") + if not self._credential_source_executable: + raise ValueError( + "Missing credential_source. An 'executable' must be provided." + ) + self._credential_source_executable_command = self._credential_source_executable.get( + "command" + ) + self._credential_source_executable_timeout_millis = self._credential_source_executable.get( + "timeout_millis" + ) + self._credential_source_executable_interactive_timeout_millis = self._credential_source_executable.get( + "interactive_timeout_millis" + ) + self._credential_source_executable_output_file = self._credential_source_executable.get( + "output_file" + ) + + # Dummy value. This variable is only used via injection, not exposed to ctor + self._tokeninfo_username = "" + + if not self._credential_source_executable_command: + raise ValueError( + "Missing command field. Executable command must be provided." + ) + if not self._credential_source_executable_timeout_millis: + self._credential_source_executable_timeout_millis = ( + EXECUTABLE_TIMEOUT_MILLIS_DEFAULT + ) + elif ( + self._credential_source_executable_timeout_millis + < EXECUTABLE_TIMEOUT_MILLIS_LOWER_BOUND + or self._credential_source_executable_timeout_millis + > EXECUTABLE_TIMEOUT_MILLIS_UPPER_BOUND + ): + raise ValueError("Timeout must be between 5 and 120 seconds.") + + if self._credential_source_executable_interactive_timeout_millis: + if ( + self._credential_source_executable_interactive_timeout_millis + < EXECUTABLE_INTERACTIVE_TIMEOUT_MILLIS_LOWER_BOUND + or self._credential_source_executable_interactive_timeout_millis + > EXECUTABLE_INTERACTIVE_TIMEOUT_MILLIS_UPPER_BOUND + ): + raise ValueError( + "Interactive timeout must be between 30 seconds and 30 minutes." + ) + + @_helpers.copy_docstring(external_account.Credentials) + def retrieve_subject_token(self, request): + self._validate_running_mode() + + # Check output file. + if self._credential_source_executable_output_file is not None: + try: + with open( + self._credential_source_executable_output_file, encoding="utf-8" + ) as output_file: + response = json.load(output_file) + except Exception: + pass + else: + try: + # If the cached response is expired, _parse_subject_token will raise an error which will be ignored and we will call the executable again. + subject_token = self._parse_subject_token(response) + if ( + "expiration_time" not in response + ): # Always treat missing expiration_time as expired and proceed to executable run. + raise exceptions.RefreshError + except ValueError: + raise + except exceptions.RefreshError: + pass + else: + return subject_token + + if not _helpers.is_python_3(): + raise exceptions.RefreshError( + "Pluggable auth is only supported for python 3.6+" + ) + + # Inject env vars. + env = os.environ.copy() + self._inject_env_variables(env) + env["GOOGLE_EXTERNAL_ACCOUNT_REVOKE"] = "0" + + # Run executable. + exe_timeout = ( + self._credential_source_executable_interactive_timeout_millis / 1000 + if self.interactive + else self._credential_source_executable_timeout_millis / 1000 + ) + exe_stdin = sys.stdin if self.interactive else None + exe_stdout = sys.stdout if self.interactive else subprocess.PIPE + exe_stderr = sys.stdout if self.interactive else subprocess.STDOUT + + result = subprocess.run( + self._credential_source_executable_command.split(), + timeout=exe_timeout, + stdin=exe_stdin, + stdout=exe_stdout, + stderr=exe_stderr, + env=env, + ) + if result.returncode != 0: + raise exceptions.RefreshError( + "Executable exited with non-zero return code {}. Error: {}".format( + result.returncode, result.stdout + ) + ) + + # Handle executable output. + response = json.loads(result.stdout.decode("utf-8")) if result.stdout else None + if not response and self._credential_source_executable_output_file is not None: + response = json.load( + open(self._credential_source_executable_output_file, encoding="utf-8") + ) + + subject_token = self._parse_subject_token(response) + return subject_token + + def revoke(self, request): + """Revokes the subject token using the credential_source object. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + Raises: + google.auth.exceptions.RefreshError: If the executable revocation + not properly executed. + + """ + if not self.interactive: + raise ValueError("Revoke is only enabled under interactive mode.") + self._validate_running_mode() + + if not _helpers.is_python_3(): + raise exceptions.RefreshError( + "Pluggable auth is only supported for python 3.6+" + ) + + # Inject variables + env = os.environ.copy() + self._inject_env_variables(env) + env["GOOGLE_EXTERNAL_ACCOUNT_REVOKE"] = "1" + + # Run executable + result = subprocess.run( + self._credential_source_executable_command.split(), + timeout=self._credential_source_executable_interactive_timeout_millis + / 1000, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=env, + ) + + if result.returncode != 0: + raise exceptions.RefreshError( + "Auth revoke failed on executable. Exit with non-zero return code {}. Error: {}".format( + result.returncode, result.stdout + ) + ) + + response = json.loads(result.stdout.decode("utf-8")) + self._validate_revoke_response(response) + + @property + def external_account_id(self): + """Returns the external account identifier. + + When service account impersonation is used the identifier is the service + account email. + + Without service account impersonation, this returns None, unless it is + being used by the Google Cloud CLI which populates this field. + """ + + return self.service_account_email or self._tokeninfo_username + + @classmethod + def from_info(cls, info, **kwargs): + """Creates a Pluggable Credentials instance from parsed external account info. + + Args: + info (Mapping[str, str]): The Pluggable external account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.pluggable.Credentials: The constructed + credentials. + + Raises: + ValueError: For invalid parameters. + """ + return super(Credentials, cls).from_info(info, **kwargs) + + @classmethod + def from_file(cls, filename, **kwargs): + """Creates an Pluggable Credentials instance from an external account json file. + + Args: + filename (str): The path to the Pluggable external account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.pluggable.Credentials: The constructed + credentials. + """ + return super(Credentials, cls).from_file(filename, **kwargs) + + def _inject_env_variables(self, env): + env["GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE"] = self._audience + env["GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE"] = self._subject_token_type + env["GOOGLE_EXTERNAL_ACCOUNT_ID"] = self.external_account_id + env["GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE"] = "1" if self.interactive else "0" + + if self._service_account_impersonation_url is not None: + env[ + "GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL" + ] = self.service_account_email + if self._credential_source_executable_output_file is not None: + env[ + "GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE" + ] = self._credential_source_executable_output_file + + def _parse_subject_token(self, response): + self._validate_response_schema(response) + if not response["success"]: + if "code" not in response or "message" not in response: + raise ValueError( + "Error code and message fields are required in the response." + ) + raise exceptions.RefreshError( + "Executable returned unsuccessful response: code: {}, message: {}.".format( + response["code"], response["message"] + ) + ) + if "expiration_time" in response and response["expiration_time"] < time.time(): + raise exceptions.RefreshError( + "The token returned by the executable is expired." + ) + if "token_type" not in response: + raise ValueError("The executable response is missing the token_type field.") + if ( + response["token_type"] == "urn:ietf:params:oauth:token-type:jwt" + or response["token_type"] == "urn:ietf:params:oauth:token-type:id_token" + ): # OIDC + return response["id_token"] + elif response["token_type"] == "urn:ietf:params:oauth:token-type:saml2": # SAML + return response["saml_response"] + else: + raise exceptions.RefreshError("Executable returned unsupported token type.") + + def _validate_revoke_response(self, response): + self._validate_response_schema(response) + if not response["success"]: + raise exceptions.RefreshError("Revoke failed with unsuccessful response.") + + def _validate_response_schema(self, response): + if "version" not in response: + raise ValueError("The executable response is missing the version field.") + if response["version"] > EXECUTABLE_SUPPORTED_MAX_VERSION: + raise exceptions.RefreshError( + "Executable returned unsupported version {}.".format( + response["version"] + ) + ) + + if "success" not in response: + raise ValueError("The executable response is missing the success field.") + + def _validate_running_mode(self): + env_allow_executables = os.environ.get( + "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES" + ) + if env_allow_executables != "1": + raise ValueError( + "Executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run." + ) + + if self.interactive and not self._credential_source_executable_output_file: + raise ValueError( + "An output_file must be specified in the credential configuration for interactive mode." + ) + + if ( + self.interactive + and not self._credential_source_executable_interactive_timeout_millis + ): + raise ValueError( + "Interactive mode cannot run without an interactive timeout." + ) + + if self.interactive and not self.is_workforce_pool: + raise ValueError("Interactive mode is only enabled for workforce pool.") diff --git a/script.module.google-auth-library/lib/google/auth/py.typed b/script.module.google-auth-library/lib/google/auth/py.typed new file mode 100644 index 000000000..aa7b68923 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-auth package uses inline types. diff --git a/script.module.google-auth-library/lib/google/auth/transport/__init__.py b/script.module.google-auth-library/lib/google/auth/transport/__init__.py new file mode 100644 index 000000000..8334145a1 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/__init__.py @@ -0,0 +1,109 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Transport - HTTP client library support. + +:mod:`google.auth` is designed to work with various HTTP client libraries such +as urllib3 and requests. In order to work across these libraries with different +interfaces some abstraction is needed. + +This module provides two interfaces that are implemented by transport adapters +to support HTTP libraries. :class:`Request` defines the interface expected by +:mod:`google.auth` to make requests. :class:`Response` defines the interface +for the return value of :class:`Request`. +""" + +import abc + +import six +from six.moves import http_client + +TOO_MANY_REQUESTS = 429 # Python 2.7 six is missing this status code. + +DEFAULT_RETRYABLE_STATUS_CODES = ( + http_client.INTERNAL_SERVER_ERROR, + http_client.SERVICE_UNAVAILABLE, + http_client.REQUEST_TIMEOUT, + TOO_MANY_REQUESTS, +) +"""Sequence[int]: HTTP status codes indicating a request can be retried. +""" + + +DEFAULT_REFRESH_STATUS_CODES = (http_client.UNAUTHORIZED,) +"""Sequence[int]: Which HTTP status code indicate that credentials should be +refreshed. +""" + +DEFAULT_MAX_REFRESH_ATTEMPTS = 2 +"""int: How many times to refresh the credentials and retry a request.""" + + +@six.add_metaclass(abc.ABCMeta) +class Response(object): + """HTTP Response data.""" + + @abc.abstractproperty + def status(self): + """int: The HTTP status code.""" + raise NotImplementedError("status must be implemented.") + + @abc.abstractproperty + def headers(self): + """Mapping[str, str]: The HTTP response headers.""" + raise NotImplementedError("headers must be implemented.") + + @abc.abstractproperty + def data(self): + """bytes: The response body.""" + raise NotImplementedError("data must be implemented.") + + +@six.add_metaclass(abc.ABCMeta) +class Request(object): + """Interface for a callable that makes HTTP requests. + + Specific transport implementations should provide an implementation of + this that adapts their specific request / response API. + + .. automethod:: __call__ + """ + + @abc.abstractmethod + def __call__( + self, url, method="GET", body=None, headers=None, timeout=None, **kwargs + ): + """Make an HTTP request. + + Args: + url (str): The URI to be requested. + method (str): The HTTP method to use for the request. Defaults + to 'GET'. + body (bytes): The payload / body in HTTP request. + headers (Mapping[str, str]): Request headers. + timeout (Optional[int]): The number of seconds to wait for a + response from the server. If not specified or if None, the + transport-specific default timeout will be used. + kwargs: Additionally arguments passed on to the transport's + request method. + + Returns: + Response: The HTTP response. + + Raises: + google.auth.exceptions.TransportError: If any exception occurred. + """ + # pylint: disable=redundant-returns-doc, missing-raises-doc + # (pylint doesn't play well with abstract docstrings.) + raise NotImplementedError("__call__ must be implemented.") diff --git a/script.module.google-auth-library/lib/google/auth/transport/_aiohttp_requests.py b/script.module.google-auth-library/lib/google/auth/transport/_aiohttp_requests.py new file mode 100644 index 000000000..179cadbdf --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/_aiohttp_requests.py @@ -0,0 +1,391 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Transport adapter for Async HTTP (aiohttp). + +NOTE: This async support is experimental and marked internal. This surface may +change in minor releases. +""" + +from __future__ import absolute_import + +import asyncio +import functools + +import aiohttp # type: ignore +import six +import urllib3 # type: ignore + +from google.auth import exceptions +from google.auth import transport +from google.auth.transport import requests + +# Timeout can be re-defined depending on async requirement. Currently made 60s more than +# sync timeout. +_DEFAULT_TIMEOUT = 180 # in seconds + + +class _CombinedResponse(transport.Response): + """ + In order to more closely resemble the `requests` interface, where a raw + and deflated content could be accessed at once, this class lazily reads the + stream in `transport.Response` so both return forms can be used. + + The gzip and deflate transfer-encodings are automatically decoded for you + because the default parameter for autodecompress into the ClientSession is set + to False, and therefore we add this class to act as a wrapper for a user to be + able to access both the raw and decoded response bodies - mirroring the sync + implementation. + """ + + def __init__(self, response): + self._response = response + self._raw_content = None + + def _is_compressed(self): + headers = self._response.headers + return "Content-Encoding" in headers and ( + headers["Content-Encoding"] == "gzip" + or headers["Content-Encoding"] == "deflate" + ) + + @property + def status(self): + return self._response.status + + @property + def headers(self): + return self._response.headers + + @property + def data(self): + return self._response.content + + async def raw_content(self): + if self._raw_content is None: + self._raw_content = await self._response.content.read() + return self._raw_content + + async def content(self): + # Load raw_content if necessary + await self.raw_content() + if self._is_compressed(): + decoder = urllib3.response.MultiDecoder( + self._response.headers["Content-Encoding"] + ) + decompressed = decoder.decompress(self._raw_content) + return decompressed + + return self._raw_content + + +class _Response(transport.Response): + """ + Requests transport response adapter. + + Args: + response (requests.Response): The raw Requests response. + """ + + def __init__(self, response): + self._response = response + + @property + def status(self): + return self._response.status + + @property + def headers(self): + return self._response.headers + + @property + def data(self): + return self._response.content + + +class Request(transport.Request): + """Requests request adapter. + + This class is used internally for making requests using asyncio transports + in a consistent way. If you use :class:`AuthorizedSession` you do not need + to construct or use this class directly. + + This class can be useful if you want to manually refresh a + :class:`~google.auth.credentials.Credentials` instance:: + + import google.auth.transport.aiohttp_requests + + request = google.auth.transport.aiohttp_requests.Request() + + credentials.refresh(request) + + Args: + session (aiohttp.ClientSession): An instance :class:`aiohttp.ClientSession` used + to make HTTP requests. If not specified, a session will be created. + + .. automethod:: __call__ + """ + + def __init__(self, session=None): + # TODO: Use auto_decompress property for aiohttp 3.7+ + if session is not None and session._auto_decompress: + raise ValueError( + "Client sessions with auto_decompress=True are not supported." + ) + self.session = session + + async def __call__( + self, + url, + method="GET", + body=None, + headers=None, + timeout=_DEFAULT_TIMEOUT, + **kwargs, + ): + """ + Make an HTTP request using aiohttp. + + Args: + url (str): The URL to be requested. + method (Optional[str]): + The HTTP method to use for the request. Defaults to 'GET'. + body (Optional[bytes]): + The payload or body in HTTP request. + headers (Optional[Mapping[str, str]]): + Request headers. + timeout (Optional[int]): The number of seconds to wait for a + response from the server. If not specified or if None, the + requests default timeout will be used. + kwargs: Additional arguments passed through to the underlying + requests :meth:`requests.Session.request` method. + + Returns: + google.auth.transport.Response: The HTTP response. + + Raises: + google.auth.exceptions.TransportError: If any exception occurred. + """ + + try: + if self.session is None: # pragma: NO COVER + self.session = aiohttp.ClientSession( + auto_decompress=False + ) # pragma: NO COVER + requests._LOGGER.debug("Making request: %s %s", method, url) + response = await self.session.request( + method, url, data=body, headers=headers, timeout=timeout, **kwargs + ) + return _CombinedResponse(response) + + except aiohttp.ClientError as caught_exc: + new_exc = exceptions.TransportError(caught_exc) + six.raise_from(new_exc, caught_exc) + + except asyncio.TimeoutError as caught_exc: + new_exc = exceptions.TransportError(caught_exc) + six.raise_from(new_exc, caught_exc) + + +class AuthorizedSession(aiohttp.ClientSession): + """This is an async implementation of the Authorized Session class. We utilize an + aiohttp transport instance, and the interface mirrors the google.auth.transport.requests + Authorized Session class, except for the change in the transport used in the async use case. + + A Requests Session class with credentials. + + This class is used to perform requests to API endpoints that require + authorization:: + + from google.auth.transport import aiohttp_requests + + async with aiohttp_requests.AuthorizedSession(credentials) as authed_session: + response = await authed_session.request( + 'GET', 'https://www.googleapis.com/storage/v1/b') + + The underlying :meth:`request` implementation handles adding the + credentials' headers to the request and refreshing credentials as needed. + + Args: + credentials (google.auth._credentials_async.Credentials): + The credentials to add to the request. + refresh_status_codes (Sequence[int]): Which HTTP status codes indicate + that credentials should be refreshed and the request should be + retried. + max_refresh_attempts (int): The maximum number of times to attempt to + refresh the credentials and retry the request. + refresh_timeout (Optional[int]): The timeout value in seconds for + credential refresh HTTP requests. + auth_request (google.auth.transport.aiohttp_requests.Request): + (Optional) An instance of + :class:`~google.auth.transport.aiohttp_requests.Request` used when + refreshing credentials. If not passed, + an instance of :class:`~google.auth.transport.aiohttp_requests.Request` + is created. + kwargs: Additional arguments passed through to the underlying + ClientSession :meth:`aiohttp.ClientSession` object. + """ + + def __init__( + self, + credentials, + refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES, + max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS, + refresh_timeout=None, + auth_request=None, + auto_decompress=False, + **kwargs, + ): + super(AuthorizedSession, self).__init__(**kwargs) + self.credentials = credentials + self._refresh_status_codes = refresh_status_codes + self._max_refresh_attempts = max_refresh_attempts + self._refresh_timeout = refresh_timeout + self._is_mtls = False + self._auth_request = auth_request + self._auth_request_session = None + self._loop = asyncio.get_event_loop() + self._refresh_lock = asyncio.Lock() + self._auto_decompress = auto_decompress + + async def request( + self, + method, + url, + data=None, + headers=None, + max_allowed_time=None, + timeout=_DEFAULT_TIMEOUT, + auto_decompress=False, + **kwargs, + ): + + """Implementation of Authorized Session aiohttp request. + + Args: + method (str): + The http request method used (e.g. GET, PUT, DELETE) + url (str): + The url at which the http request is sent. + data (Optional[dict]): Dictionary, list of tuples, bytes, or file-like + object to send in the body of the Request. + headers (Optional[dict]): Dictionary of HTTP Headers to send with the + Request. + timeout (Optional[Union[float, aiohttp.ClientTimeout]]): + The amount of time in seconds to wait for the server response + with each individual request. Can also be passed as an + ``aiohttp.ClientTimeout`` object. + max_allowed_time (Optional[float]): + If the method runs longer than this, a ``Timeout`` exception is + automatically raised. Unlike the ``timeout`` parameter, this + value applies to the total method execution time, even if + multiple requests are made under the hood. + + Mind that it is not guaranteed that the timeout error is raised + at ``max_allowed_time``. It might take longer, for example, if + an underlying request takes a lot of time, but the request + itself does not timeout, e.g. if a large file is being + transmitted. The timout error will be raised after such + request completes. + """ + # Headers come in as bytes which isn't expected behavior, the resumable + # media libraries in some cases expect a str type for the header values, + # but sometimes the operations return these in bytes types. + if headers: + for key in headers.keys(): + if type(headers[key]) is bytes: + headers[key] = headers[key].decode("utf-8") + + async with aiohttp.ClientSession( + auto_decompress=self._auto_decompress + ) as self._auth_request_session: + auth_request = Request(self._auth_request_session) + self._auth_request = auth_request + + # Use a kwarg for this instead of an attribute to maintain + # thread-safety. + _credential_refresh_attempt = kwargs.pop("_credential_refresh_attempt", 0) + # Make a copy of the headers. They will be modified by the credentials + # and we want to pass the original headers if we recurse. + request_headers = headers.copy() if headers is not None else {} + + # Do not apply the timeout unconditionally in order to not override the + # _auth_request's default timeout. + auth_request = ( + self._auth_request + if timeout is None + else functools.partial(self._auth_request, timeout=timeout) + ) + + remaining_time = max_allowed_time + + with requests.TimeoutGuard(remaining_time, asyncio.TimeoutError) as guard: + await self.credentials.before_request( + auth_request, method, url, request_headers + ) + + with requests.TimeoutGuard(remaining_time, asyncio.TimeoutError) as guard: + response = await super(AuthorizedSession, self).request( + method, + url, + data=data, + headers=request_headers, + timeout=timeout, + **kwargs, + ) + + remaining_time = guard.remaining_timeout + + if ( + response.status in self._refresh_status_codes + and _credential_refresh_attempt < self._max_refresh_attempts + ): + + requests._LOGGER.info( + "Refreshing credentials due to a %s response. Attempt %s/%s.", + response.status, + _credential_refresh_attempt + 1, + self._max_refresh_attempts, + ) + + # Do not apply the timeout unconditionally in order to not override the + # _auth_request's default timeout. + auth_request = ( + self._auth_request + if timeout is None + else functools.partial(self._auth_request, timeout=timeout) + ) + + with requests.TimeoutGuard( + remaining_time, asyncio.TimeoutError + ) as guard: + async with self._refresh_lock: + await self._loop.run_in_executor( + None, self.credentials.refresh, auth_request + ) + + remaining_time = guard.remaining_timeout + + return await self.request( + method, + url, + data=data, + headers=headers, + max_allowed_time=remaining_time, + timeout=timeout, + _credential_refresh_attempt=_credential_refresh_attempt + 1, + **kwargs, + ) + + return response diff --git a/script.module.google-auth-library/lib/google/auth/transport/_custom_tls_signer.py b/script.module.google-auth-library/lib/google/auth/transport/_custom_tls_signer.py new file mode 100644 index 000000000..dfef6d00f --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/_custom_tls_signer.py @@ -0,0 +1,235 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Code for configuring client side TLS to offload the signing operation to +signing libraries. +""" + +import ctypes +import json +import logging +import os +import sys + +import cffi # type: ignore +import six + +from google.auth import exceptions + +_LOGGER = logging.getLogger(__name__) + +# C++ offload lib requires google-auth lib to provide the following callback: +# using SignFunc = int (*)(unsigned char *sig, size_t *sig_len, +# const unsigned char *tbs, size_t tbs_len) +# The bytes to be signed and the length are provided via `tbs` and `tbs_len`, +# the callback computes the signature, and write the signature and its length +# into `sig` and `sig_len`. +# If the signing is successful, the callback returns 1, otherwise it returns 0. +SIGN_CALLBACK_CTYPE = ctypes.CFUNCTYPE( + ctypes.c_int, # return type + ctypes.POINTER(ctypes.c_ubyte), # sig + ctypes.POINTER(ctypes.c_size_t), # sig_len + ctypes.POINTER(ctypes.c_ubyte), # tbs + ctypes.c_size_t, # tbs_len +) + + +# Cast SSL_CTX* to void* +def _cast_ssl_ctx_to_void_p(ssl_ctx): + return ctypes.cast(int(cffi.FFI().cast("intptr_t", ssl_ctx)), ctypes.c_void_p) + + +# Load offload library and set up the function types. +def load_offload_lib(offload_lib_path): + _LOGGER.debug("loading offload library from %s", offload_lib_path) + + # winmode parameter is only available for python 3.8+. + lib = ( + ctypes.CDLL(offload_lib_path, winmode=0) + if sys.version_info >= (3, 8) and os.name == "nt" + else ctypes.CDLL(offload_lib_path) + ) + + # Set up types for: + # int ConfigureSslContext(SignFunc sign_func, const char *cert, SSL_CTX *ctx) + lib.ConfigureSslContext.argtypes = [ + SIGN_CALLBACK_CTYPE, + ctypes.c_char_p, + ctypes.c_void_p, + ] + lib.ConfigureSslContext.restype = ctypes.c_int + + return lib + + +# Load signer library and set up the function types. +# See: https://github.com/googleapis/enterprise-certificate-proxy/blob/main/cshared/main.go +def load_signer_lib(signer_lib_path): + _LOGGER.debug("loading signer library from %s", signer_lib_path) + + # winmode parameter is only available for python 3.8+. + lib = ( + ctypes.CDLL(signer_lib_path, winmode=0) + if sys.version_info >= (3, 8) and os.name == "nt" + else ctypes.CDLL(signer_lib_path) + ) + + # Set up types for: + # func GetCertPemForPython(configFilePath *C.char, certHolder *byte, certHolderLen int) + lib.GetCertPemForPython.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int] + # Returns: certLen + lib.GetCertPemForPython.restype = ctypes.c_int + + # Set up types for: + # func SignForPython(configFilePath *C.char, digest *byte, digestLen int, + # sigHolder *byte, sigHolderLen int) + lib.SignForPython.argtypes = [ + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_int, + ctypes.c_char_p, + ctypes.c_int, + ] + # Returns: the signature length + lib.SignForPython.restype = ctypes.c_int + + return lib + + +# Computes SHA256 hash. +def _compute_sha256_digest(to_be_signed, to_be_signed_len): + from cryptography.hazmat.primitives import hashes + + data = ctypes.string_at(to_be_signed, to_be_signed_len) + hash = hashes.Hash(hashes.SHA256()) + hash.update(data) + return hash.finalize() + + +# Create the signing callback. The actual signing work is done by the +# `SignForPython` method from the signer lib. +def get_sign_callback(signer_lib, config_file_path): + def sign_callback(sig, sig_len, tbs, tbs_len): + _LOGGER.debug("calling sign callback...") + + digest = _compute_sha256_digest(tbs, tbs_len) + digestArray = ctypes.c_char * len(digest) + + # reserve 2000 bytes for the signature, shoud be more then enough. + # RSA signature is 256 bytes, EC signature is 70~72. + sig_holder_len = 2000 + sig_holder = ctypes.create_string_buffer(sig_holder_len) + + signature_len = signer_lib.SignForPython( + config_file_path.encode(), # configFilePath + digestArray.from_buffer(bytearray(digest)), # digest + len(digest), # digestLen + sig_holder, # sigHolder + sig_holder_len, # sigHolderLen + ) + + if signature_len == 0: + # signing failed, return 0 + return 0 + + sig_len[0] = signature_len + bs = bytearray(sig_holder) + for i in range(signature_len): + sig[i] = bs[i] + + return 1 + + return SIGN_CALLBACK_CTYPE(sign_callback) + + +# Obtain the certificate bytes by calling the `GetCertPemForPython` method from +# the signer lib. The method is called twice, the first time is to compute the +# cert length, then we create a buffer to hold the cert, and call it again to +# fill the buffer. +def get_cert(signer_lib, config_file_path): + # First call to calculate the cert length + cert_len = signer_lib.GetCertPemForPython( + config_file_path.encode(), # configFilePath + None, # certHolder + 0, # certHolderLen + ) + if cert_len == 0: + raise exceptions.MutualTLSChannelError("failed to get certificate") + + # Then we create an array to hold the cert, and call again to fill the cert + cert_holder = ctypes.create_string_buffer(cert_len) + signer_lib.GetCertPemForPython( + config_file_path.encode(), # configFilePath + cert_holder, # certHolder + cert_len, # certHolderLen + ) + return bytes(cert_holder) + + +class CustomTlsSigner(object): + def __init__(self, enterprise_cert_file_path): + """ + This class loads the offload and signer library, and calls APIs from + these libraries to obtain the cert and a signing callback, and attach + them to SSL context. The cert and the signing callback will be used + for client authentication in TLS handshake. + + Args: + enterprise_cert_file_path (str): the path to a enterprise cert JSON + file. The file should contain the following field: + + { + "libs": { + "ecp_client": "...", + "tls_offload": "..." + } + } + """ + self._enterprise_cert_file_path = enterprise_cert_file_path + self._cert = None + self._sign_callback = None + + def load_libraries(self): + try: + with open(self._enterprise_cert_file_path, "r") as f: + enterprise_cert_json = json.load(f) + libs = enterprise_cert_json["libs"] + signer_library = libs["ecp_client"] + offload_library = libs["tls_offload"] + except (KeyError, ValueError) as caught_exc: + new_exc = exceptions.MutualTLSChannelError( + "enterprise cert file is invalid", caught_exc + ) + six.raise_from(new_exc, caught_exc) + self._offload_lib = load_offload_lib(offload_library) + self._signer_lib = load_signer_lib(signer_library) + + def set_up_custom_key(self): + # We need to keep a reference of the cert and sign callback so it won't + # be garbage collected, otherwise it will crash when used by signer lib. + self._cert = get_cert(self._signer_lib, self._enterprise_cert_file_path) + self._sign_callback = get_sign_callback( + self._signer_lib, self._enterprise_cert_file_path + ) + + def attach_to_ssl_context(self, ctx): + # In the TLS handshake, the signing operation will be done by the + # sign_callback. + if not self._offload_lib.ConfigureSslContext( + self._sign_callback, + ctypes.c_char_p(self._cert), + _cast_ssl_ctx_to_void_p(ctx._ctx._context), + ): + raise exceptions.MutualTLSChannelError("failed to configure SSL context") diff --git a/script.module.google-auth-library/lib/google/auth/transport/_http_client.py b/script.module.google-auth-library/lib/google/auth/transport/_http_client.py new file mode 100644 index 000000000..c153763ef --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/_http_client.py @@ -0,0 +1,115 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Transport adapter for http.client, for internal use only.""" + +import logging +import socket + +import six +from six.moves import http_client +from six.moves import urllib + +from google.auth import exceptions +from google.auth import transport + +_LOGGER = logging.getLogger(__name__) + + +class Response(transport.Response): + """http.client transport response adapter. + + Args: + response (http.client.HTTPResponse): The raw http client response. + """ + + def __init__(self, response): + self._status = response.status + self._headers = {key.lower(): value for key, value in response.getheaders()} + self._data = response.read() + + @property + def status(self): + return self._status + + @property + def headers(self): + return self._headers + + @property + def data(self): + return self._data + + +class Request(transport.Request): + """http.client transport request adapter.""" + + def __call__( + self, url, method="GET", body=None, headers=None, timeout=None, **kwargs + ): + """Make an HTTP request using http.client. + + Args: + url (str): The URI to be requested. + method (str): The HTTP method to use for the request. Defaults + to 'GET'. + body (bytes): The payload / body in HTTP request. + headers (Mapping): Request headers. + timeout (Optional(int)): The number of seconds to wait for a + response from the server. If not specified or if None, the + socket global default timeout will be used. + kwargs: Additional arguments passed throught to the underlying + :meth:`~http.client.HTTPConnection.request` method. + + Returns: + Response: The HTTP response. + + Raises: + google.auth.exceptions.TransportError: If any exception occurred. + """ + # socket._GLOBAL_DEFAULT_TIMEOUT is the default in http.client. + if timeout is None: + timeout = socket._GLOBAL_DEFAULT_TIMEOUT + + # http.client doesn't allow None as the headers argument. + if headers is None: + headers = {} + + # http.client needs the host and path parts specified separately. + parts = urllib.parse.urlsplit(url) + path = urllib.parse.urlunsplit( + ("", "", parts.path, parts.query, parts.fragment) + ) + + if parts.scheme != "http": + raise exceptions.TransportError( + "http.client transport only supports the http scheme, {}" + "was specified".format(parts.scheme) + ) + + connection = http_client.HTTPConnection(parts.netloc, timeout=timeout) + + try: + _LOGGER.debug("Making request: %s %s", method, url) + + connection.request(method, path, body=body, headers=headers, **kwargs) + response = connection.getresponse() + return Response(response) + + except (http_client.HTTPException, socket.error) as caught_exc: + new_exc = exceptions.TransportError(caught_exc) + six.raise_from(new_exc, caught_exc) + + finally: + connection.close() diff --git a/script.module.google-auth-library/lib/google/auth/transport/_mtls_helper.py b/script.module.google-auth-library/lib/google/auth/transport/_mtls_helper.py new file mode 100644 index 000000000..4dccb1062 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/_mtls_helper.py @@ -0,0 +1,254 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helper functions for getting mTLS cert and key.""" + +import json +import logging +from os import path +import re +import subprocess + +import six + +from google.auth import exceptions + +CONTEXT_AWARE_METADATA_PATH = "~/.secureConnect/context_aware_metadata.json" +_CERT_PROVIDER_COMMAND = "cert_provider_command" +_CERT_REGEX = re.compile( + b"-----BEGIN CERTIFICATE-----.+-----END CERTIFICATE-----\r?\n?", re.DOTALL +) + +# support various format of key files, e.g. +# "-----BEGIN PRIVATE KEY-----...", +# "-----BEGIN EC PRIVATE KEY-----...", +# "-----BEGIN RSA PRIVATE KEY-----..." +# "-----BEGIN ENCRYPTED PRIVATE KEY-----" +_KEY_REGEX = re.compile( + b"-----BEGIN [A-Z ]*PRIVATE KEY-----.+-----END [A-Z ]*PRIVATE KEY-----\r?\n?", + re.DOTALL, +) + +_LOGGER = logging.getLogger(__name__) + + +_PASSPHRASE_REGEX = re.compile( + b"-----BEGIN PASSPHRASE-----(.+)-----END PASSPHRASE-----", re.DOTALL +) + + +def _check_dca_metadata_path(metadata_path): + """Checks for context aware metadata. If it exists, returns the absolute path; + otherwise returns None. + + Args: + metadata_path (str): context aware metadata path. + + Returns: + str: absolute path if exists and None otherwise. + """ + metadata_path = path.expanduser(metadata_path) + if not path.exists(metadata_path): + _LOGGER.debug("%s is not found, skip client SSL authentication.", metadata_path) + return None + return metadata_path + + +def _read_dca_metadata_file(metadata_path): + """Loads context aware metadata from the given path. + + Args: + metadata_path (str): context aware metadata path. + + Returns: + Dict[str, str]: The metadata. + + Raises: + google.auth.exceptions.ClientCertError: If failed to parse metadata as JSON. + """ + try: + with open(metadata_path) as f: + metadata = json.load(f) + except ValueError as caught_exc: + new_exc = exceptions.ClientCertError(caught_exc) + six.raise_from(new_exc, caught_exc) + + return metadata + + +def _run_cert_provider_command(command, expect_encrypted_key=False): + """Run the provided command, and return client side mTLS cert, key and + passphrase. + + Args: + command (List[str]): cert provider command. + expect_encrypted_key (bool): If encrypted private key is expected. + + Returns: + Tuple[bytes, bytes, bytes]: client certificate bytes in PEM format, key + bytes in PEM format and passphrase bytes. + + Raises: + google.auth.exceptions.ClientCertError: if problems occurs when running + the cert provider command or generating cert, key and passphrase. + """ + try: + process = subprocess.Popen( + command, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + stdout, stderr = process.communicate() + except OSError as caught_exc: + new_exc = exceptions.ClientCertError(caught_exc) + six.raise_from(new_exc, caught_exc) + + # Check cert provider command execution error. + if process.returncode != 0: + raise exceptions.ClientCertError( + "Cert provider command returns non-zero status code %s" % process.returncode + ) + + # Extract certificate (chain), key and passphrase. + cert_match = re.findall(_CERT_REGEX, stdout) + if len(cert_match) != 1: + raise exceptions.ClientCertError("Client SSL certificate is missing or invalid") + key_match = re.findall(_KEY_REGEX, stdout) + if len(key_match) != 1: + raise exceptions.ClientCertError("Client SSL key is missing or invalid") + passphrase_match = re.findall(_PASSPHRASE_REGEX, stdout) + + if expect_encrypted_key: + if len(passphrase_match) != 1: + raise exceptions.ClientCertError("Passphrase is missing or invalid") + if b"ENCRYPTED" not in key_match[0]: + raise exceptions.ClientCertError("Encrypted private key is expected") + return cert_match[0], key_match[0], passphrase_match[0].strip() + + if b"ENCRYPTED" in key_match[0]: + raise exceptions.ClientCertError("Encrypted private key is not expected") + if len(passphrase_match) > 0: + raise exceptions.ClientCertError("Passphrase is not expected") + return cert_match[0], key_match[0], None + + +def get_client_ssl_credentials( + generate_encrypted_key=False, + context_aware_metadata_path=CONTEXT_AWARE_METADATA_PATH, +): + """Returns the client side certificate, private key and passphrase. + + Args: + generate_encrypted_key (bool): If set to True, encrypted private key + and passphrase will be generated; otherwise, unencrypted private key + will be generated and passphrase will be None. + context_aware_metadata_path (str): The context_aware_metadata.json file path. + + Returns: + Tuple[bool, bytes, bytes, bytes]: + A boolean indicating if cert, key and passphrase are obtained, the + cert bytes and key bytes both in PEM format, and passphrase bytes. + + Raises: + google.auth.exceptions.ClientCertError: if problems occurs when getting + the cert, key and passphrase. + """ + metadata_path = _check_dca_metadata_path(context_aware_metadata_path) + + if metadata_path: + metadata_json = _read_dca_metadata_file(metadata_path) + + if _CERT_PROVIDER_COMMAND not in metadata_json: + raise exceptions.ClientCertError("Cert provider command is not found") + + command = metadata_json[_CERT_PROVIDER_COMMAND] + + if generate_encrypted_key and "--with_passphrase" not in command: + command.append("--with_passphrase") + + # Execute the command. + cert, key, passphrase = _run_cert_provider_command( + command, expect_encrypted_key=generate_encrypted_key + ) + return True, cert, key, passphrase + + return False, None, None, None + + +def get_client_cert_and_key(client_cert_callback=None): + """Returns the client side certificate and private key. The function first + tries to get certificate and key from client_cert_callback; if the callback + is None or doesn't provide certificate and key, the function tries application + default SSL credentials. + + Args: + client_cert_callback (Optional[Callable[[], (bytes, bytes)]]): An + optional callback which returns client certificate bytes and private + key bytes both in PEM format. + + Returns: + Tuple[bool, bytes, bytes]: + A boolean indicating if cert and key are obtained, the cert bytes + and key bytes both in PEM format. + + Raises: + google.auth.exceptions.ClientCertError: if problems occurs when getting + the cert and key. + """ + if client_cert_callback: + cert, key = client_cert_callback() + return True, cert, key + + has_cert, cert, key, _ = get_client_ssl_credentials(generate_encrypted_key=False) + return has_cert, cert, key + + +def decrypt_private_key(key, passphrase): + """A helper function to decrypt the private key with the given passphrase. + google-auth library doesn't support passphrase protected private key for + mutual TLS channel. This helper function can be used to decrypt the + passphrase protected private key in order to estalish mutual TLS channel. + + For example, if you have a function which produces client cert, passphrase + protected private key and passphrase, you can convert it to a client cert + callback function accepted by google-auth:: + + from google.auth.transport import _mtls_helper + + def your_client_cert_function(): + return cert, encrypted_key, passphrase + + # callback accepted by google-auth for mutual TLS channel. + def client_cert_callback(): + cert, encrypted_key, passphrase = your_client_cert_function() + decrypted_key = _mtls_helper.decrypt_private_key(encrypted_key, + passphrase) + return cert, decrypted_key + + Args: + key (bytes): The private key bytes in PEM format. + passphrase (bytes): The passphrase bytes. + + Returns: + bytes: The decrypted private key in PEM format. + + Raises: + ImportError: If pyOpenSSL is not installed. + OpenSSL.crypto.Error: If there is any problem decrypting the private key. + """ + from OpenSSL import crypto + + # First convert encrypted_key_bytes to PKey object + pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key, passphrase=passphrase) + + # Then dump the decrypted key bytes + return crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey) diff --git a/script.module.google-auth-library/lib/google/auth/transport/grpc.py b/script.module.google-auth-library/lib/google/auth/transport/grpc.py new file mode 100644 index 000000000..87fa5042f --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/grpc.py @@ -0,0 +1,349 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Authorization support for gRPC.""" + +from __future__ import absolute_import + +import logging +import os + +import six + +from google.auth import environment_vars +from google.auth import exceptions +from google.auth.transport import _mtls_helper +from google.oauth2 import service_account + +try: + import grpc # type: ignore +except ImportError as caught_exc: # pragma: NO COVER + six.raise_from( + ImportError( + "gRPC is not installed, please install the grpcio package " + "to use the gRPC transport." + ), + caught_exc, + ) + +_LOGGER = logging.getLogger(__name__) + + +class AuthMetadataPlugin(grpc.AuthMetadataPlugin): + """A `gRPC AuthMetadataPlugin`_ that inserts the credentials into each + request. + + .. _gRPC AuthMetadataPlugin: + http://www.grpc.io/grpc/python/grpc.html#grpc.AuthMetadataPlugin + + Args: + credentials (google.auth.credentials.Credentials): The credentials to + add to requests. + request (google.auth.transport.Request): A HTTP transport request + object used to refresh credentials as needed. + default_host (Optional[str]): A host like "pubsub.googleapis.com". + This is used when a self-signed JWT is created from service + account credentials. + """ + + def __init__(self, credentials, request, default_host=None): + # pylint: disable=no-value-for-parameter + # pylint doesn't realize that the super method takes no arguments + # because this class is the same name as the superclass. + super(AuthMetadataPlugin, self).__init__() + self._credentials = credentials + self._request = request + self._default_host = default_host + + def _get_authorization_headers(self, context): + """Gets the authorization headers for a request. + + Returns: + Sequence[Tuple[str, str]]: A list of request headers (key, value) + to add to the request. + """ + headers = {} + + # https://google.aip.dev/auth/4111 + # Attempt to use self-signed JWTs when a service account is used. + # A default host must be explicitly provided since it cannot always + # be determined from the context.service_url. + if isinstance(self._credentials, service_account.Credentials): + self._credentials._create_self_signed_jwt( + "https://{}/".format(self._default_host) if self._default_host else None + ) + + self._credentials.before_request( + self._request, context.method_name, context.service_url, headers + ) + + return list(six.iteritems(headers)) + + def __call__(self, context, callback): + """Passes authorization metadata into the given callback. + + Args: + context (grpc.AuthMetadataContext): The RPC context. + callback (grpc.AuthMetadataPluginCallback): The callback that will + be invoked to pass in the authorization metadata. + """ + callback(self._get_authorization_headers(context), None) + + +def secure_authorized_channel( + credentials, + request, + target, + ssl_credentials=None, + client_cert_callback=None, + **kwargs +): + """Creates a secure authorized gRPC channel. + + This creates a channel with SSL and :class:`AuthMetadataPlugin`. This + channel can be used to create a stub that can make authorized requests. + Users can configure client certificate or rely on device certificates to + establish a mutual TLS channel, if the `GOOGLE_API_USE_CLIENT_CERTIFICATE` + variable is explicitly set to `true`. + + Example:: + + import google.auth + import google.auth.transport.grpc + import google.auth.transport.requests + from google.cloud.speech.v1 import cloud_speech_pb2 + + # Get credentials. + credentials, _ = google.auth.default() + + # Get an HTTP request function to refresh credentials. + request = google.auth.transport.requests.Request() + + # Create a channel. + channel = google.auth.transport.grpc.secure_authorized_channel( + credentials, regular_endpoint, request, + ssl_credentials=grpc.ssl_channel_credentials()) + + # Use the channel to create a stub. + cloud_speech.create_Speech_stub(channel) + + Usage: + + There are actually a couple of options to create a channel, depending on if + you want to create a regular or mutual TLS channel. + + First let's list the endpoints (regular vs mutual TLS) to choose from:: + + regular_endpoint = 'speech.googleapis.com:443' + mtls_endpoint = 'speech.mtls.googleapis.com:443' + + Option 1: create a regular (non-mutual) TLS channel by explicitly setting + the ssl_credentials:: + + regular_ssl_credentials = grpc.ssl_channel_credentials() + + channel = google.auth.transport.grpc.secure_authorized_channel( + credentials, regular_endpoint, request, + ssl_credentials=regular_ssl_credentials) + + Option 2: create a mutual TLS channel by calling a callback which returns + the client side certificate and the key (Note that + `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly + set to `true`):: + + def my_client_cert_callback(): + code_to_load_client_cert_and_key() + if loaded: + return (pem_cert_bytes, pem_key_bytes) + raise MyClientCertFailureException() + + try: + channel = google.auth.transport.grpc.secure_authorized_channel( + credentials, mtls_endpoint, request, + client_cert_callback=my_client_cert_callback) + except MyClientCertFailureException: + # handle the exception + + Option 3: use application default SSL credentials. It searches and uses + the command in a context aware metadata file, which is available on devices + with endpoint verification support (Note that + `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly + set to `true`). + See https://cloud.google.com/endpoint-verification/docs/overview:: + + try: + default_ssl_credentials = SslCredentials() + except: + # Exception can be raised if the context aware metadata is malformed. + # See :class:`SslCredentials` for the possible exceptions. + + # Choose the endpoint based on the SSL credentials type. + if default_ssl_credentials.is_mtls: + endpoint_to_use = mtls_endpoint + else: + endpoint_to_use = regular_endpoint + channel = google.auth.transport.grpc.secure_authorized_channel( + credentials, endpoint_to_use, request, + ssl_credentials=default_ssl_credentials) + + Option 4: not setting ssl_credentials and client_cert_callback. For devices + without endpoint verification support or `GOOGLE_API_USE_CLIENT_CERTIFICATE` + environment variable is not `true`, a regular TLS channel is created; + otherwise, a mutual TLS channel is created, however, the call should be + wrapped in a try/except block in case of malformed context aware metadata. + + The following code uses regular_endpoint, it works the same no matter the + created channle is regular or mutual TLS. Regular endpoint ignores client + certificate and key:: + + channel = google.auth.transport.grpc.secure_authorized_channel( + credentials, regular_endpoint, request) + + The following code uses mtls_endpoint, if the created channle is regular, + and API mtls_endpoint is confgured to require client SSL credentials, API + calls using this channel will be rejected:: + + channel = google.auth.transport.grpc.secure_authorized_channel( + credentials, mtls_endpoint, request) + + Args: + credentials (google.auth.credentials.Credentials): The credentials to + add to requests. + request (google.auth.transport.Request): A HTTP transport request + object used to refresh credentials as needed. Even though gRPC + is a separate transport, there's no way to refresh the credentials + without using a standard http transport. + target (str): The host and port of the service. + ssl_credentials (grpc.ChannelCredentials): Optional SSL channel + credentials. This can be used to specify different certificates. + This argument is mutually exclusive with client_cert_callback; + providing both will raise an exception. + If ssl_credentials and client_cert_callback are None, application + default SSL credentials are used if `GOOGLE_API_USE_CLIENT_CERTIFICATE` + environment variable is explicitly set to `true`, otherwise one way TLS + SSL credentials are used. + client_cert_callback (Callable[[], (bytes, bytes)]): Optional + callback function to obtain client certicate and key for mutual TLS + connection. This argument is mutually exclusive with + ssl_credentials; providing both will raise an exception. + This argument does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE` + environment variable is explicitly set to `true`. + kwargs: Additional arguments to pass to :func:`grpc.secure_channel`. + + Returns: + grpc.Channel: The created gRPC channel. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel + creation failed for any reason. + """ + # Create the metadata plugin for inserting the authorization header. + metadata_plugin = AuthMetadataPlugin(credentials, request) + + # Create a set of grpc.CallCredentials using the metadata plugin. + google_auth_credentials = grpc.metadata_call_credentials(metadata_plugin) + + if ssl_credentials and client_cert_callback: + raise ValueError( + "Received both ssl_credentials and client_cert_callback; " + "these are mutually exclusive." + ) + + # If SSL credentials are not explicitly set, try client_cert_callback and ADC. + if not ssl_credentials: + use_client_cert = os.getenv( + environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false" + ) + if use_client_cert == "true" and client_cert_callback: + # Use the callback if provided. + cert, key = client_cert_callback() + ssl_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + elif use_client_cert == "true": + # Use application default SSL credentials. + adc_ssl_credentils = SslCredentials() + ssl_credentials = adc_ssl_credentils.ssl_credentials + else: + ssl_credentials = grpc.ssl_channel_credentials() + + # Combine the ssl credentials and the authorization credentials. + composite_credentials = grpc.composite_channel_credentials( + ssl_credentials, google_auth_credentials + ) + + return grpc.secure_channel(target, composite_credentials, **kwargs) + + +class SslCredentials: + """Class for application default SSL credentials. + + The behavior is controlled by `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment + variable whose default value is `false`. Client certificate will not be used + unless the environment variable is explicitly set to `true`. See + https://google.aip.dev/auth/4114 + + If the environment variable is `true`, then for devices with endpoint verification + support, a device certificate will be automatically loaded and mutual TLS will + be established. + See https://cloud.google.com/endpoint-verification/docs/overview. + """ + + def __init__(self): + use_client_cert = os.getenv( + environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false" + ) + if use_client_cert != "true": + self._is_mtls = False + else: + # Load client SSL credentials. + metadata_path = _mtls_helper._check_dca_metadata_path( + _mtls_helper.CONTEXT_AWARE_METADATA_PATH + ) + self._is_mtls = metadata_path is not None + + @property + def ssl_credentials(self): + """Get the created SSL channel credentials. + + For devices with endpoint verification support, if the device certificate + loading has any problems, corresponding exceptions will be raised. For + a device without endpoint verification support, no exceptions will be + raised. + + Returns: + grpc.ChannelCredentials: The created grpc channel credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel + creation failed for any reason. + """ + if self._is_mtls: + try: + _, cert, key, _ = _mtls_helper.get_client_ssl_credentials() + self._ssl_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + except exceptions.ClientCertError as caught_exc: + new_exc = exceptions.MutualTLSChannelError(caught_exc) + six.raise_from(new_exc, caught_exc) + else: + self._ssl_credentials = grpc.ssl_channel_credentials() + + return self._ssl_credentials + + @property + def is_mtls(self): + """Indicates if the created SSL channel credentials is mutual TLS.""" + return self._is_mtls diff --git a/script.module.google-auth-library/lib/google/auth/transport/mtls.py b/script.module.google-auth-library/lib/google/auth/transport/mtls.py new file mode 100644 index 000000000..b40bfbedf --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/mtls.py @@ -0,0 +1,105 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utilites for mutual TLS.""" + +import six + +from google.auth import exceptions +from google.auth.transport import _mtls_helper + + +def has_default_client_cert_source(): + """Check if default client SSL credentials exists on the device. + + Returns: + bool: indicating if the default client cert source exists. + """ + metadata_path = _mtls_helper._check_dca_metadata_path( + _mtls_helper.CONTEXT_AWARE_METADATA_PATH + ) + return metadata_path is not None + + +def default_client_cert_source(): + """Get a callback which returns the default client SSL credentials. + + Returns: + Callable[[], [bytes, bytes]]: A callback which returns the default + client certificate bytes and private key bytes, both in PEM format. + + Raises: + google.auth.exceptions.DefaultClientCertSourceError: If the default + client SSL credentials don't exist or are malformed. + """ + if not has_default_client_cert_source(): + raise exceptions.MutualTLSChannelError( + "Default client cert source doesn't exist" + ) + + def callback(): + try: + _, cert_bytes, key_bytes = _mtls_helper.get_client_cert_and_key() + except (OSError, RuntimeError, ValueError) as caught_exc: + new_exc = exceptions.MutualTLSChannelError(caught_exc) + six.raise_from(new_exc, caught_exc) + + return cert_bytes, key_bytes + + return callback + + +def default_client_encrypted_cert_source(cert_path, key_path): + """Get a callback which returns the default encrpyted client SSL credentials. + + Args: + cert_path (str): The cert file path. The default client certificate will + be written to this file when the returned callback is called. + key_path (str): The key file path. The default encrypted client key will + be written to this file when the returned callback is called. + + Returns: + Callable[[], [str, str, bytes]]: A callback which generates the default + client certificate, encrpyted private key and passphrase. It writes + the certificate and private key into the cert_path and key_path, and + returns the cert_path, key_path and passphrase bytes. + + Raises: + google.auth.exceptions.DefaultClientCertSourceError: If any problem + occurs when loading or saving the client certificate and key. + """ + if not has_default_client_cert_source(): + raise exceptions.MutualTLSChannelError( + "Default client encrypted cert source doesn't exist" + ) + + def callback(): + try: + ( + _, + cert_bytes, + key_bytes, + passphrase_bytes, + ) = _mtls_helper.get_client_ssl_credentials(generate_encrypted_key=True) + with open(cert_path, "wb") as cert_file: + cert_file.write(cert_bytes) + with open(key_path, "wb") as key_file: + key_file.write(key_bytes) + except (exceptions.ClientCertError, OSError) as caught_exc: + new_exc = exceptions.MutualTLSChannelError(caught_exc) + six.raise_from(new_exc, caught_exc) + + return cert_path, key_path, passphrase_bytes + + return callback diff --git a/script.module.google-auth-library/lib/google/auth/transport/requests.py b/script.module.google-auth-library/lib/google/auth/transport/requests.py new file mode 100644 index 000000000..2c746f8d7 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/requests.py @@ -0,0 +1,611 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Transport adapter for Requests.""" + +from __future__ import absolute_import + +import functools +import logging +import numbers +import os +import time + +try: + import requests +except ImportError as caught_exc: # pragma: NO COVER + import six + + six.raise_from( + ImportError( + "The requests library is not installed, please install the " + "requests package to use the requests transport." + ), + caught_exc, + ) +import requests.adapters # pylint: disable=ungrouped-imports +import requests.exceptions # pylint: disable=ungrouped-imports +from requests.packages.urllib3.util.ssl_ import ( # type: ignore + create_urllib3_context, +) # pylint: disable=ungrouped-imports +import six # pylint: disable=ungrouped-imports + +from google.auth import environment_vars +from google.auth import exceptions +from google.auth import transport +import google.auth.transport._mtls_helper +from google.oauth2 import service_account + +_LOGGER = logging.getLogger(__name__) + +_DEFAULT_TIMEOUT = 120 # in seconds + + +class _Response(transport.Response): + """Requests transport response adapter. + + Args: + response (requests.Response): The raw Requests response. + """ + + def __init__(self, response): + self._response = response + + @property + def status(self): + return self._response.status_code + + @property + def headers(self): + return self._response.headers + + @property + def data(self): + return self._response.content + + +class TimeoutGuard(object): + """A context manager raising an error if the suite execution took too long. + + Args: + timeout (Union[None, Union[float, Tuple[float, float]]]): + The maximum number of seconds a suite can run without the context + manager raising a timeout exception on exit. If passed as a tuple, + the smaller of the values is taken as a timeout. If ``None``, a + timeout error is never raised. + timeout_error_type (Optional[Exception]): + The type of the error to raise on timeout. Defaults to + :class:`requests.exceptions.Timeout`. + """ + + def __init__(self, timeout, timeout_error_type=requests.exceptions.Timeout): + self._timeout = timeout + self.remaining_timeout = timeout + self._timeout_error_type = timeout_error_type + + def __enter__(self): + self._start = time.time() + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_value: + return # let the error bubble up automatically + + if self._timeout is None: + return # nothing to do, the timeout was not specified + + elapsed = time.time() - self._start + deadline_hit = False + + if isinstance(self._timeout, numbers.Number): + self.remaining_timeout = self._timeout - elapsed + deadline_hit = self.remaining_timeout <= 0 + else: + self.remaining_timeout = tuple(x - elapsed for x in self._timeout) + deadline_hit = min(self.remaining_timeout) <= 0 + + if deadline_hit: + raise self._timeout_error_type() + + +class Request(transport.Request): + """Requests request adapter. + + This class is used internally for making requests using various transports + in a consistent way. If you use :class:`AuthorizedSession` you do not need + to construct or use this class directly. + + This class can be useful if you want to manually refresh a + :class:`~google.auth.credentials.Credentials` instance:: + + import google.auth.transport.requests + import requests + + request = google.auth.transport.requests.Request() + + credentials.refresh(request) + + Args: + session (requests.Session): An instance :class:`requests.Session` used + to make HTTP requests. If not specified, a session will be created. + + .. automethod:: __call__ + """ + + def __init__(self, session=None): + if not session: + session = requests.Session() + + self.session = session + + def __del__(self): + try: + if hasattr(self, "session") and self.session is not None: + self.session.close() + except TypeError: + # NOTE: For certain Python binary built, the queue.Empty exception + # might not be considered a normal Python exception causing + # TypeError. + pass + + def __call__( + self, + url, + method="GET", + body=None, + headers=None, + timeout=_DEFAULT_TIMEOUT, + **kwargs + ): + """Make an HTTP request using requests. + + Args: + url (str): The URI to be requested. + method (str): The HTTP method to use for the request. Defaults + to 'GET'. + body (bytes): The payload or body in HTTP request. + headers (Mapping[str, str]): Request headers. + timeout (Optional[int]): The number of seconds to wait for a + response from the server. If not specified or if None, the + requests default timeout will be used. + kwargs: Additional arguments passed through to the underlying + requests :meth:`~requests.Session.request` method. + + Returns: + google.auth.transport.Response: The HTTP response. + + Raises: + google.auth.exceptions.TransportError: If any exception occurred. + """ + try: + _LOGGER.debug("Making request: %s %s", method, url) + response = self.session.request( + method, url, data=body, headers=headers, timeout=timeout, **kwargs + ) + return _Response(response) + except requests.exceptions.RequestException as caught_exc: + new_exc = exceptions.TransportError(caught_exc) + six.raise_from(new_exc, caught_exc) + + +class _MutualTlsAdapter(requests.adapters.HTTPAdapter): + """ + A TransportAdapter that enables mutual TLS. + + Args: + cert (bytes): client certificate in PEM format + key (bytes): client private key in PEM format + + Raises: + ImportError: if certifi or pyOpenSSL is not installed + OpenSSL.crypto.Error: if client cert or key is invalid + """ + + def __init__(self, cert, key): + import certifi + from OpenSSL import crypto + import urllib3.contrib.pyopenssl # type: ignore + + urllib3.contrib.pyopenssl.inject_into_urllib3() + + pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key) + x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert) + + ctx_poolmanager = create_urllib3_context() + ctx_poolmanager.load_verify_locations(cafile=certifi.where()) + ctx_poolmanager._ctx.use_certificate(x509) + ctx_poolmanager._ctx.use_privatekey(pkey) + self._ctx_poolmanager = ctx_poolmanager + + ctx_proxymanager = create_urllib3_context() + ctx_proxymanager.load_verify_locations(cafile=certifi.where()) + ctx_proxymanager._ctx.use_certificate(x509) + ctx_proxymanager._ctx.use_privatekey(pkey) + self._ctx_proxymanager = ctx_proxymanager + + super(_MutualTlsAdapter, self).__init__() + + def init_poolmanager(self, *args, **kwargs): + kwargs["ssl_context"] = self._ctx_poolmanager + super(_MutualTlsAdapter, self).init_poolmanager(*args, **kwargs) + + def proxy_manager_for(self, *args, **kwargs): + kwargs["ssl_context"] = self._ctx_proxymanager + return super(_MutualTlsAdapter, self).proxy_manager_for(*args, **kwargs) + + +class _MutualTlsOffloadAdapter(requests.adapters.HTTPAdapter): + """ + A TransportAdapter that enables mutual TLS and offloads the client side + signing operation to the signing library. + + Args: + enterprise_cert_file_path (str): the path to a enterprise cert JSON + file. The file should contain the following field: + + { + "libs": { + "signer_library": "...", + "offload_library": "..." + } + } + + Raises: + ImportError: if certifi or pyOpenSSL is not installed + google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel + creation failed for any reason. + """ + + def __init__(self, enterprise_cert_file_path): + import certifi + import urllib3.contrib.pyopenssl + + from google.auth.transport import _custom_tls_signer + + # Call inject_into_urllib3 to activate certificate checking. See the + # following links for more info: + # (1) doc: https://github.com/urllib3/urllib3/blob/cb9ebf8aac5d75f64c8551820d760b72b619beff/src/urllib3/contrib/pyopenssl.py#L31-L32 + # (2) mTLS example: https://github.com/urllib3/urllib3/issues/474#issuecomment-253168415 + urllib3.contrib.pyopenssl.inject_into_urllib3() + + self.signer = _custom_tls_signer.CustomTlsSigner(enterprise_cert_file_path) + self.signer.load_libraries() + self.signer.set_up_custom_key() + + poolmanager = create_urllib3_context() + poolmanager.load_verify_locations(cafile=certifi.where()) + self.signer.attach_to_ssl_context(poolmanager) + self._ctx_poolmanager = poolmanager + + proxymanager = create_urllib3_context() + proxymanager.load_verify_locations(cafile=certifi.where()) + self.signer.attach_to_ssl_context(proxymanager) + self._ctx_proxymanager = proxymanager + + super(_MutualTlsOffloadAdapter, self).__init__() + + def init_poolmanager(self, *args, **kwargs): + kwargs["ssl_context"] = self._ctx_poolmanager + super(_MutualTlsOffloadAdapter, self).init_poolmanager(*args, **kwargs) + + def proxy_manager_for(self, *args, **kwargs): + kwargs["ssl_context"] = self._ctx_proxymanager + return super(_MutualTlsOffloadAdapter, self).proxy_manager_for(*args, **kwargs) + + +class AuthorizedSession(requests.Session): + """A Requests Session class with credentials. + + This class is used to perform requests to API endpoints that require + authorization:: + + from google.auth.transport.requests import AuthorizedSession + + authed_session = AuthorizedSession(credentials) + + response = authed_session.request( + 'GET', 'https://www.googleapis.com/storage/v1/b') + + + The underlying :meth:`request` implementation handles adding the + credentials' headers to the request and refreshing credentials as needed. + + This class also supports mutual TLS via :meth:`configure_mtls_channel` + method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE` + environment variable must be explicitly set to ``true``, otherwise it does + nothing. Assume the environment is set to ``true``, the method behaves in the + following manner: + + If client_cert_callback is provided, client certificate and private + key are loaded using the callback; if client_cert_callback is None, + application default SSL credentials will be used. Exceptions are raised if + there are problems with the certificate, private key, or the loading process, + so it should be called within a try/except block. + + First we set the environment variable to ``true``, then create an :class:`AuthorizedSession` + instance and specify the endpoints:: + + regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics' + mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics' + + authed_session = AuthorizedSession(credentials) + + Now we can pass a callback to :meth:`configure_mtls_channel`:: + + def my_cert_callback(): + # some code to load client cert bytes and private key bytes, both in + # PEM format. + some_code_to_load_client_cert_and_key() + if loaded: + return cert, key + raise MyClientCertFailureException() + + # Always call configure_mtls_channel within a try/except block. + try: + authed_session.configure_mtls_channel(my_cert_callback) + except: + # handle exceptions. + + if authed_session.is_mtls: + response = authed_session.request('GET', mtls_endpoint) + else: + response = authed_session.request('GET', regular_endpoint) + + + You can alternatively use application default SSL credentials like this:: + + try: + authed_session.configure_mtls_channel() + except: + # handle exceptions. + + Args: + credentials (google.auth.credentials.Credentials): The credentials to + add to the request. + refresh_status_codes (Sequence[int]): Which HTTP status codes indicate + that credentials should be refreshed and the request should be + retried. + max_refresh_attempts (int): The maximum number of times to attempt to + refresh the credentials and retry the request. + refresh_timeout (Optional[int]): The timeout value in seconds for + credential refresh HTTP requests. + auth_request (google.auth.transport.requests.Request): + (Optional) An instance of + :class:`~google.auth.transport.requests.Request` used when + refreshing credentials. If not passed, + an instance of :class:`~google.auth.transport.requests.Request` + is created. + default_host (Optional[str]): A host like "pubsub.googleapis.com". + This is used when a self-signed JWT is created from service + account credentials. + """ + + def __init__( + self, + credentials, + refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES, + max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS, + refresh_timeout=None, + auth_request=None, + default_host=None, + ): + super(AuthorizedSession, self).__init__() + self.credentials = credentials + self._refresh_status_codes = refresh_status_codes + self._max_refresh_attempts = max_refresh_attempts + self._refresh_timeout = refresh_timeout + self._is_mtls = False + self._default_host = default_host + + if auth_request is None: + self._auth_request_session = requests.Session() + + # Using an adapter to make HTTP requests robust to network errors. + # This adapter retrys HTTP requests when network errors occur + # and the requests seems safely retryable. + retry_adapter = requests.adapters.HTTPAdapter(max_retries=3) + self._auth_request_session.mount("https://", retry_adapter) + + # Do not pass `self` as the session here, as it can lead to + # infinite recursion. + auth_request = Request(self._auth_request_session) + else: + self._auth_request_session = None + + # Request instance used by internal methods (for example, + # credentials.refresh). + self._auth_request = auth_request + + # https://google.aip.dev/auth/4111 + # Attempt to use self-signed JWTs when a service account is used. + if isinstance(self.credentials, service_account.Credentials): + self.credentials._create_self_signed_jwt( + "https://{}/".format(self._default_host) if self._default_host else None + ) + + def configure_mtls_channel(self, client_cert_callback=None): + """Configure the client certificate and key for SSL connection. + + The function does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE` is + explicitly set to `true`. In this case if client certificate and key are + successfully obtained (from the given client_cert_callback or from application + default SSL credentials), a :class:`_MutualTlsAdapter` instance will be mounted + to "https://" prefix. + + Args: + client_cert_callback (Optional[Callable[[], (bytes, bytes)]]): + The optional callback returns the client certificate and private + key bytes both in PEM format. + If the callback is None, application default SSL credentials + will be used. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel + creation failed for any reason. + """ + use_client_cert = os.getenv( + environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false" + ) + if use_client_cert != "true": + self._is_mtls = False + return + + try: + import OpenSSL + except ImportError as caught_exc: + new_exc = exceptions.MutualTLSChannelError(caught_exc) + six.raise_from(new_exc, caught_exc) + + try: + ( + self._is_mtls, + cert, + key, + ) = google.auth.transport._mtls_helper.get_client_cert_and_key( + client_cert_callback + ) + + if self._is_mtls: + mtls_adapter = _MutualTlsAdapter(cert, key) + self.mount("https://", mtls_adapter) + except ( + exceptions.ClientCertError, + ImportError, + OpenSSL.crypto.Error, + ) as caught_exc: + new_exc = exceptions.MutualTLSChannelError(caught_exc) + six.raise_from(new_exc, caught_exc) + + def request( + self, + method, + url, + data=None, + headers=None, + max_allowed_time=None, + timeout=_DEFAULT_TIMEOUT, + **kwargs + ): + """Implementation of Requests' request. + + Args: + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time in seconds to wait for the server response + with each individual request. Can also be passed as a tuple + ``(connect_timeout, read_timeout)``. See :meth:`requests.Session.request` + documentation for details. + max_allowed_time (Optional[float]): + If the method runs longer than this, a ``Timeout`` exception is + automatically raised. Unlike the ``timeout`` parameter, this + value applies to the total method execution time, even if + multiple requests are made under the hood. + + Mind that it is not guaranteed that the timeout error is raised + at ``max_allowed_time``. It might take longer, for example, if + an underlying request takes a lot of time, but the request + itself does not timeout, e.g. if a large file is being + transmitted. The timout error will be raised after such + request completes. + """ + # pylint: disable=arguments-differ + # Requests has a ton of arguments to request, but only two + # (method, url) are required. We pass through all of the other + # arguments to super, so no need to exhaustively list them here. + + # Use a kwarg for this instead of an attribute to maintain + # thread-safety. + _credential_refresh_attempt = kwargs.pop("_credential_refresh_attempt", 0) + + # Make a copy of the headers. They will be modified by the credentials + # and we want to pass the original headers if we recurse. + request_headers = headers.copy() if headers is not None else {} + + # Do not apply the timeout unconditionally in order to not override the + # _auth_request's default timeout. + auth_request = ( + self._auth_request + if timeout is None + else functools.partial(self._auth_request, timeout=timeout) + ) + + remaining_time = max_allowed_time + + with TimeoutGuard(remaining_time) as guard: + self.credentials.before_request(auth_request, method, url, request_headers) + remaining_time = guard.remaining_timeout + + with TimeoutGuard(remaining_time) as guard: + response = super(AuthorizedSession, self).request( + method, + url, + data=data, + headers=request_headers, + timeout=timeout, + **kwargs + ) + remaining_time = guard.remaining_timeout + + # If the response indicated that the credentials needed to be + # refreshed, then refresh the credentials and re-attempt the + # request. + # A stored token may expire between the time it is retrieved and + # the time the request is made, so we may need to try twice. + if ( + response.status_code in self._refresh_status_codes + and _credential_refresh_attempt < self._max_refresh_attempts + ): + + _LOGGER.info( + "Refreshing credentials due to a %s response. Attempt %s/%s.", + response.status_code, + _credential_refresh_attempt + 1, + self._max_refresh_attempts, + ) + + # Do not apply the timeout unconditionally in order to not override the + # _auth_request's default timeout. + auth_request = ( + self._auth_request + if timeout is None + else functools.partial(self._auth_request, timeout=timeout) + ) + + with TimeoutGuard(remaining_time) as guard: + self.credentials.refresh(auth_request) + remaining_time = guard.remaining_timeout + + # Recurse. Pass in the original headers, not our modified set, but + # do pass the adjusted max allowed time (i.e. the remaining total time). + return self.request( + method, + url, + data=data, + headers=headers, + max_allowed_time=remaining_time, + timeout=timeout, + _credential_refresh_attempt=_credential_refresh_attempt + 1, + **kwargs + ) + + return response + + @property + def is_mtls(self): + """Indicates if the created SSL channel is mutual TLS.""" + return self._is_mtls + + def close(self): + if self._auth_request_session is not None: + self._auth_request_session.close() + super(AuthorizedSession, self).close() diff --git a/script.module.google-auth-library/lib/google/auth/transport/urllib3.py b/script.module.google-auth-library/lib/google/auth/transport/urllib3.py new file mode 100644 index 000000000..4abc26b52 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/transport/urllib3.py @@ -0,0 +1,442 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Transport adapter for urllib3.""" + +from __future__ import absolute_import + +import logging +import os +import warnings + +# Certifi is Mozilla's certificate bundle. Urllib3 needs a certificate bundle +# to verify HTTPS requests, and certifi is the recommended and most reliable +# way to get a root certificate bundle. See +# http://urllib3.readthedocs.io/en/latest/user-guide.html\ +# #certificate-verification +# For more details. +try: + import certifi +except ImportError: # pragma: NO COVER + certifi = None # type: ignore + +import six + +try: + import urllib3 # type: ignore + import urllib3.exceptions # type: ignore +except ImportError as caught_exc: # pragma: NO COVER + six.raise_from( + ImportError( + "The urllib3 library is not installed, please install the " + "urllib3 package to use the urllib3 transport." + ), + caught_exc, + ) + +from google.auth import environment_vars +from google.auth import exceptions +from google.auth import transport +from google.oauth2 import service_account + +_LOGGER = logging.getLogger(__name__) + + +class _Response(transport.Response): + """urllib3 transport response adapter. + + Args: + response (urllib3.response.HTTPResponse): The raw urllib3 response. + """ + + def __init__(self, response): + self._response = response + + @property + def status(self): + return self._response.status + + @property + def headers(self): + return self._response.headers + + @property + def data(self): + return self._response.data + + +class Request(transport.Request): + """urllib3 request adapter. + + This class is used internally for making requests using various transports + in a consistent way. If you use :class:`AuthorizedHttp` you do not need + to construct or use this class directly. + + This class can be useful if you want to manually refresh a + :class:`~google.auth.credentials.Credentials` instance:: + + import google.auth.transport.urllib3 + import urllib3 + + http = urllib3.PoolManager() + request = google.auth.transport.urllib3.Request(http) + + credentials.refresh(request) + + Args: + http (urllib3.request.RequestMethods): An instance of any urllib3 + class that implements :class:`~urllib3.request.RequestMethods`, + usually :class:`urllib3.PoolManager`. + + .. automethod:: __call__ + """ + + def __init__(self, http): + self.http = http + + def __call__( + self, url, method="GET", body=None, headers=None, timeout=None, **kwargs + ): + """Make an HTTP request using urllib3. + + Args: + url (str): The URI to be requested. + method (str): The HTTP method to use for the request. Defaults + to 'GET'. + body (bytes): The payload / body in HTTP request. + headers (Mapping[str, str]): Request headers. + timeout (Optional[int]): The number of seconds to wait for a + response from the server. If not specified or if None, the + urllib3 default timeout will be used. + kwargs: Additional arguments passed throught to the underlying + urllib3 :meth:`urlopen` method. + + Returns: + google.auth.transport.Response: The HTTP response. + + Raises: + google.auth.exceptions.TransportError: If any exception occurred. + """ + # urllib3 uses a sentinel default value for timeout, so only set it if + # specified. + if timeout is not None: + kwargs["timeout"] = timeout + + try: + _LOGGER.debug("Making request: %s %s", method, url) + response = self.http.request( + method, url, body=body, headers=headers, **kwargs + ) + return _Response(response) + except urllib3.exceptions.HTTPError as caught_exc: + new_exc = exceptions.TransportError(caught_exc) + six.raise_from(new_exc, caught_exc) + + +def _make_default_http(): + if certifi is not None: + return urllib3.PoolManager(cert_reqs="CERT_REQUIRED", ca_certs=certifi.where()) + else: + return urllib3.PoolManager() + + +def _make_mutual_tls_http(cert, key): + """Create a mutual TLS HTTP connection with the given client cert and key. + See https://github.com/urllib3/urllib3/issues/474#issuecomment-253168415 + + Args: + cert (bytes): client certificate in PEM format + key (bytes): client private key in PEM format + + Returns: + urllib3.PoolManager: Mutual TLS HTTP connection. + + Raises: + ImportError: If certifi or pyOpenSSL is not installed. + OpenSSL.crypto.Error: If the cert or key is invalid. + """ + import certifi + from OpenSSL import crypto + import urllib3.contrib.pyopenssl # type: ignore + + urllib3.contrib.pyopenssl.inject_into_urllib3() + ctx = urllib3.util.ssl_.create_urllib3_context() + ctx.load_verify_locations(cafile=certifi.where()) + + pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key) + x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert) + + ctx._ctx.use_certificate(x509) + ctx._ctx.use_privatekey(pkey) + + http = urllib3.PoolManager(ssl_context=ctx) + return http + + +class AuthorizedHttp(urllib3.request.RequestMethods): + """A urllib3 HTTP class with credentials. + + This class is used to perform requests to API endpoints that require + authorization:: + + from google.auth.transport.urllib3 import AuthorizedHttp + + authed_http = AuthorizedHttp(credentials) + + response = authed_http.request( + 'GET', 'https://www.googleapis.com/storage/v1/b') + + This class implements :class:`urllib3.request.RequestMethods` and can be + used just like any other :class:`urllib3.PoolManager`. + + The underlying :meth:`urlopen` implementation handles adding the + credentials' headers to the request and refreshing credentials as needed. + + This class also supports mutual TLS via :meth:`configure_mtls_channel` + method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE` + environment variable must be explicitly set to `true`, otherwise it does + nothing. Assume the environment is set to `true`, the method behaves in the + following manner: + If client_cert_callback is provided, client certificate and private + key are loaded using the callback; if client_cert_callback is None, + application default SSL credentials will be used. Exceptions are raised if + there are problems with the certificate, private key, or the loading process, + so it should be called within a try/except block. + + First we set the environment variable to `true`, then create an :class:`AuthorizedHttp` + instance and specify the endpoints:: + + regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics' + mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics' + + authed_http = AuthorizedHttp(credentials) + + Now we can pass a callback to :meth:`configure_mtls_channel`:: + + def my_cert_callback(): + # some code to load client cert bytes and private key bytes, both in + # PEM format. + some_code_to_load_client_cert_and_key() + if loaded: + return cert, key + raise MyClientCertFailureException() + + # Always call configure_mtls_channel within a try/except block. + try: + is_mtls = authed_http.configure_mtls_channel(my_cert_callback) + except: + # handle exceptions. + + if is_mtls: + response = authed_http.request('GET', mtls_endpoint) + else: + response = authed_http.request('GET', regular_endpoint) + + You can alternatively use application default SSL credentials like this:: + + try: + is_mtls = authed_http.configure_mtls_channel() + except: + # handle exceptions. + + Args: + credentials (google.auth.credentials.Credentials): The credentials to + add to the request. + http (urllib3.PoolManager): The underlying HTTP object to + use to make requests. If not specified, a + :class:`urllib3.PoolManager` instance will be constructed with + sane defaults. + refresh_status_codes (Sequence[int]): Which HTTP status codes indicate + that credentials should be refreshed and the request should be + retried. + max_refresh_attempts (int): The maximum number of times to attempt to + refresh the credentials and retry the request. + default_host (Optional[str]): A host like "pubsub.googleapis.com". + This is used when a self-signed JWT is created from service + account credentials. + """ + + def __init__( + self, + credentials, + http=None, + refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES, + max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS, + default_host=None, + ): + if http is None: + self.http = _make_default_http() + self._has_user_provided_http = False + else: + self.http = http + self._has_user_provided_http = True + + self.credentials = credentials + self._refresh_status_codes = refresh_status_codes + self._max_refresh_attempts = max_refresh_attempts + self._default_host = default_host + # Request instance used by internal methods (for example, + # credentials.refresh). + self._request = Request(self.http) + + # https://google.aip.dev/auth/4111 + # Attempt to use self-signed JWTs when a service account is used. + if isinstance(self.credentials, service_account.Credentials): + self.credentials._create_self_signed_jwt( + "https://{}/".format(self._default_host) if self._default_host else None + ) + + super(AuthorizedHttp, self).__init__() + + def configure_mtls_channel(self, client_cert_callback=None): + """Configures mutual TLS channel using the given client_cert_callback or + application default SSL credentials. The behavior is controlled by + `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable. + (1) If the environment variable value is `true`, the function returns True + if the channel is mutual TLS and False otherwise. The `http` provided + in the constructor will be overwritten. + (2) If the environment variable is not set or `false`, the function does + nothing and it always return False. + + Args: + client_cert_callback (Optional[Callable[[], (bytes, bytes)]]): + The optional callback returns the client certificate and private + key bytes both in PEM format. + If the callback is None, application default SSL credentials + will be used. + + Returns: + True if the channel is mutual TLS and False otherwise. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel + creation failed for any reason. + """ + use_client_cert = os.getenv( + environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false" + ) + if use_client_cert != "true": + return False + + try: + import OpenSSL + except ImportError as caught_exc: + new_exc = exceptions.MutualTLSChannelError(caught_exc) + six.raise_from(new_exc, caught_exc) + + try: + found_cert_key, cert, key = transport._mtls_helper.get_client_cert_and_key( + client_cert_callback + ) + + if found_cert_key: + self.http = _make_mutual_tls_http(cert, key) + else: + self.http = _make_default_http() + except ( + exceptions.ClientCertError, + ImportError, + OpenSSL.crypto.Error, + ) as caught_exc: + new_exc = exceptions.MutualTLSChannelError(caught_exc) + six.raise_from(new_exc, caught_exc) + + if self._has_user_provided_http: + self._has_user_provided_http = False + warnings.warn( + "`http` provided in the constructor is overwritten", UserWarning + ) + + return found_cert_key + + def urlopen(self, method, url, body=None, headers=None, **kwargs): + """Implementation of urllib3's urlopen.""" + # pylint: disable=arguments-differ + # We use kwargs to collect additional args that we don't need to + # introspect here. However, we do explicitly collect the two + # positional arguments. + + # Use a kwarg for this instead of an attribute to maintain + # thread-safety. + _credential_refresh_attempt = kwargs.pop("_credential_refresh_attempt", 0) + + if headers is None: + headers = self.headers + + # Make a copy of the headers. They will be modified by the credentials + # and we want to pass the original headers if we recurse. + request_headers = headers.copy() + + self.credentials.before_request(self._request, method, url, request_headers) + + response = self.http.urlopen( + method, url, body=body, headers=request_headers, **kwargs + ) + + # If the response indicated that the credentials needed to be + # refreshed, then refresh the credentials and re-attempt the + # request. + # A stored token may expire between the time it is retrieved and + # the time the request is made, so we may need to try twice. + # The reason urllib3's retries aren't used is because they + # don't allow you to modify the request headers. :/ + if ( + response.status in self._refresh_status_codes + and _credential_refresh_attempt < self._max_refresh_attempts + ): + + _LOGGER.info( + "Refreshing credentials due to a %s response. Attempt %s/%s.", + response.status, + _credential_refresh_attempt + 1, + self._max_refresh_attempts, + ) + + self.credentials.refresh(self._request) + + # Recurse. Pass in the original headers, not our modified set. + return self.urlopen( + method, + url, + body=body, + headers=headers, + _credential_refresh_attempt=_credential_refresh_attempt + 1, + **kwargs + ) + + return response + + # Proxy methods for compliance with the urllib3.PoolManager interface + + def __enter__(self): + """Proxy to ``self.http``.""" + return self.http.__enter__() + + def __exit__(self, exc_type, exc_val, exc_tb): + """Proxy to ``self.http``.""" + return self.http.__exit__(exc_type, exc_val, exc_tb) + + def __del__(self): + if hasattr(self, "http") and self.http is not None: + self.http.clear() + + @property + def headers(self): + """Proxy to ``self.http``.""" + return self.http.headers + + @headers.setter + def headers(self, value): + """Proxy to ``self.http``.""" + self.http.headers = value diff --git a/script.module.google-auth-library/lib/google/auth/version.py b/script.module.google-auth-library/lib/google/auth/version.py new file mode 100644 index 000000000..5a2a1ee06 --- /dev/null +++ b/script.module.google-auth-library/lib/google/auth/version.py @@ -0,0 +1,15 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__version__ = "2.14.1" diff --git a/script.module.google-auth-library/lib/google/oauth2/__init__.py b/script.module.google-auth-library/lib/google/oauth2/__init__.py new file mode 100644 index 000000000..4fb71fd1a --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google OAuth 2.0 Library for Python.""" diff --git a/script.module.google-auth-library/lib/google/oauth2/_client.py b/script.module.google-auth-library/lib/google/oauth2/_client.py new file mode 100644 index 000000000..7f866d446 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/_client.py @@ -0,0 +1,438 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""OAuth 2.0 client. + +This is a client for interacting with an OAuth 2.0 authorization server's +token endpoint. + +For more information about the token endpoint, see +`Section 3.1 of rfc6749`_ + +.. _Section 3.1 of rfc6749: https://tools.ietf.org/html/rfc6749#section-3.2 +""" + +import datetime +import json + +import six +from six.moves import http_client +from six.moves import urllib + +from google.auth import _exponential_backoff +from google.auth import _helpers +from google.auth import exceptions +from google.auth import jwt +from google.auth import transport + +_URLENCODED_CONTENT_TYPE = "application/x-www-form-urlencoded" +_JSON_CONTENT_TYPE = "application/json" +_JWT_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer" +_REFRESH_GRANT_TYPE = "refresh_token" + + +def _handle_error_response(response_data, retryable_error): + """Translates an error response into an exception. + + Args: + response_data (Mapping | str): The decoded response data. + retryable_error Optional[bool]: A boolean indicating if an error is retryable. + Defaults to False. + + Raises: + google.auth.exceptions.RefreshError: The errors contained in response_data. + """ + + retryable_error = retryable_error if retryable_error else False + + if isinstance(response_data, six.string_types): + raise exceptions.RefreshError(response_data, retryable=retryable_error) + try: + error_details = "{}: {}".format( + response_data["error"], response_data.get("error_description") + ) + # If no details could be extracted, use the response data. + except (KeyError, ValueError): + error_details = json.dumps(response_data) + + raise exceptions.RefreshError( + error_details, response_data, retryable=retryable_error + ) + + +def _can_retry(status_code, response_data): + """Checks if a request can be retried by inspecting the status code + and response body of the request. + + Args: + status_code (int): The response status code. + response_data (Mapping | str): The decoded response data. + + Returns: + bool: True if the response is retryable. False otherwise. + """ + if status_code in transport.DEFAULT_RETRYABLE_STATUS_CODES: + return True + + try: + # For a failed response, response_body could be a string + error_desc = response_data.get("error_description") or "" + error_code = response_data.get("error") or "" + + # Per Oauth 2.0 RFC https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1.2.1 + # This is needed because a redirect will not return a 500 status code. + retryable_error_descriptions = { + "internal_failure", + "server_error", + "temporarily_unavailable", + } + + if any(e in retryable_error_descriptions for e in (error_code, error_desc)): + return True + + except AttributeError: + pass + + return False + + +def _parse_expiry(response_data): + """Parses the expiry field from a response into a datetime. + + Args: + response_data (Mapping): The JSON-parsed response data. + + Returns: + Optional[datetime]: The expiration or ``None`` if no expiration was + specified. + """ + expires_in = response_data.get("expires_in", None) + + if expires_in is not None: + return _helpers.utcnow() + datetime.timedelta(seconds=expires_in) + else: + return None + + +def _token_endpoint_request_no_throw( + request, + token_uri, + body, + access_token=None, + use_json=False, + can_retry=True, + **kwargs +): + """Makes a request to the OAuth 2.0 authorization server's token endpoint. + This function doesn't throw on response errors. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + body (Mapping[str, str]): The parameters to send in the request body. + access_token (Optional(str)): The access token needed to make the request. + use_json (Optional(bool)): Use urlencoded format or json format for the + content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. + kwargs: Additional arguments passed on to the request method. The + kwargs will be passed to `requests.request` method, see: + https://docs.python-requests.org/en/latest/api/#requests.request. + For example, you can use `cert=("cert_pem_path", "key_pem_path")` + to set up client side SSL certificate, and use + `verify="ca_bundle_path"` to set up the CA certificates for sever + side SSL certificate verification. + + Returns: + Tuple(bool, Mapping[str, str], Optional[bool]): A boolean indicating + if the request is successful, a mapping for the JSON-decoded response + data and in the case of an error a boolean indicating if the error + is retryable. + """ + if use_json: + headers = {"Content-Type": _JSON_CONTENT_TYPE} + body = json.dumps(body).encode("utf-8") + else: + headers = {"Content-Type": _URLENCODED_CONTENT_TYPE} + body = urllib.parse.urlencode(body).encode("utf-8") + + if access_token: + headers["Authorization"] = "Bearer {}".format(access_token) + + def _perform_request(): + response = request( + method="POST", url=token_uri, headers=headers, body=body, **kwargs + ) + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + response_data = "" + try: + # response_body should be a JSON + response_data = json.loads(response_body) + except ValueError: + response_data = response_body + + if response.status == http_client.OK: + return True, response_data, None + + retryable_error = _can_retry( + status_code=response.status, response_data=response_data + ) + + return False, response_data, retryable_error + + request_succeeded, response_data, retryable_error = _perform_request() + + if request_succeeded or not retryable_error or not can_retry: + return request_succeeded, response_data, retryable_error + + retries = _exponential_backoff.ExponentialBackoff() + for _ in retries: + request_succeeded, response_data, retryable_error = _perform_request() + if request_succeeded or not retryable_error: + return request_succeeded, response_data, retryable_error + + return False, response_data, retryable_error + + +def _token_endpoint_request( + request, + token_uri, + body, + access_token=None, + use_json=False, + can_retry=True, + **kwargs +): + """Makes a request to the OAuth 2.0 authorization server's token endpoint. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + body (Mapping[str, str]): The parameters to send in the request body. + access_token (Optional(str)): The access token needed to make the request. + use_json (Optional(bool)): Use urlencoded format or json format for the + content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. + kwargs: Additional arguments passed on to the request method. The + kwargs will be passed to `requests.request` method, see: + https://docs.python-requests.org/en/latest/api/#requests.request. + For example, you can use `cert=("cert_pem_path", "key_pem_path")` + to set up client side SSL certificate, and use + `verify="ca_bundle_path"` to set up the CA certificates for sever + side SSL certificate verification. + + Returns: + Mapping[str, str]: The JSON-decoded response data. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + """ + + response_status_ok, response_data, retryable_error = _token_endpoint_request_no_throw( + request, + token_uri, + body, + access_token=access_token, + use_json=use_json, + can_retry=can_retry, + **kwargs + ) + if not response_status_ok: + _handle_error_response(response_data, retryable_error) + return response_data + + +def jwt_grant(request, token_uri, assertion, can_retry=True): + """Implements the JWT Profile for OAuth 2.0 Authorization Grants. + + For more details, see `rfc7523 section 4`_. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + assertion (str): The OAuth 2.0 assertion. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Tuple[str, Optional[datetime], Mapping[str, str]]: The access token, + expiration, and additional data returned by the token endpoint. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + + .. _rfc7523 section 4: https://tools.ietf.org/html/rfc7523#section-4 + """ + body = {"assertion": assertion, "grant_type": _JWT_GRANT_TYPE} + + response_data = _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) + + try: + access_token = response_data["access_token"] + except KeyError as caught_exc: + new_exc = exceptions.RefreshError( + "No access token in response.", response_data, retryable=False + ) + six.raise_from(new_exc, caught_exc) + + expiry = _parse_expiry(response_data) + + return access_token, expiry, response_data + + +def id_token_jwt_grant(request, token_uri, assertion, can_retry=True): + """Implements the JWT Profile for OAuth 2.0 Authorization Grants, but + requests an OpenID Connect ID Token instead of an access token. + + This is a variant on the standard JWT Profile that is currently unique + to Google. This was added for the benefit of authenticating to services + that require ID Tokens instead of access tokens or JWT bearer tokens. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorization server's token endpoint + URI. + assertion (str): JWT token signed by a service account. The token's + payload must include a ``target_audience`` claim. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Tuple[str, Optional[datetime], Mapping[str, str]]: + The (encoded) Open ID Connect ID Token, expiration, and additional + data returned by the endpoint. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + """ + body = {"assertion": assertion, "grant_type": _JWT_GRANT_TYPE} + + response_data = _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) + + try: + id_token = response_data["id_token"] + except KeyError as caught_exc: + new_exc = exceptions.RefreshError( + "No ID token in response.", response_data, retryable=False + ) + six.raise_from(new_exc, caught_exc) + + payload = jwt.decode(id_token, verify=False) + expiry = datetime.datetime.utcfromtimestamp(payload["exp"]) + + return id_token, expiry, response_data + + +def _handle_refresh_grant_response(response_data, refresh_token): + """Extract tokens from refresh grant response. + + Args: + response_data (Mapping[str, str]): Refresh grant response data. + refresh_token (str): Current refresh token. + + Returns: + Tuple[str, str, Optional[datetime], Mapping[str, str]]: The access token, + refresh token, expiration, and additional data returned by the token + endpoint. If response_data doesn't have refresh token, then the current + refresh token will be returned. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + """ + try: + access_token = response_data["access_token"] + except KeyError as caught_exc: + new_exc = exceptions.RefreshError( + "No access token in response.", response_data, retryable=False + ) + six.raise_from(new_exc, caught_exc) + + refresh_token = response_data.get("refresh_token", refresh_token) + expiry = _parse_expiry(response_data) + + return access_token, refresh_token, expiry, response_data + + +def refresh_grant( + request, + token_uri, + refresh_token, + client_id, + client_secret, + scopes=None, + rapt_token=None, + can_retry=True, +): + """Implements the OAuth 2.0 refresh token grant. + + For more details, see `rfc678 section 6`_. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + refresh_token (str): The refresh token to use to get a new access + token. + client_id (str): The OAuth 2.0 application's client ID. + client_secret (str): The Oauth 2.0 appliaction's client secret. + scopes (Optional(Sequence[str])): Scopes to request. If present, all + scopes must be authorized for the refresh token. Useful if refresh + token has a wild card scope (e.g. + 'https://www.googleapis.com/auth/any-api'). + rapt_token (Optional(str)): The reauth Proof Token. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Tuple[str, str, Optional[datetime], Mapping[str, str]]: The access + token, new or current refresh token, expiration, and additional data + returned by the token endpoint. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + + .. _rfc6748 section 6: https://tools.ietf.org/html/rfc6749#section-6 + """ + body = { + "grant_type": _REFRESH_GRANT_TYPE, + "client_id": client_id, + "client_secret": client_secret, + "refresh_token": refresh_token, + } + if scopes: + body["scope"] = " ".join(scopes) + if rapt_token: + body["rapt"] = rapt_token + + response_data = _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) + return _handle_refresh_grant_response(response_data, refresh_token) diff --git a/script.module.google-auth-library/lib/google/oauth2/_client_async.py b/script.module.google-auth-library/lib/google/oauth2/_client_async.py new file mode 100644 index 000000000..428084a70 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/_client_async.py @@ -0,0 +1,294 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""OAuth 2.0 async client. + +This is a client for interacting with an OAuth 2.0 authorization server's +token endpoint. + +For more information about the token endpoint, see +`Section 3.1 of rfc6749`_ + +.. _Section 3.1 of rfc6749: https://tools.ietf.org/html/rfc6749#section-3.2 +""" + +import datetime +import json + +import six +from six.moves import http_client +from six.moves import urllib + +from google.auth import _exponential_backoff +from google.auth import exceptions +from google.auth import jwt +from google.oauth2 import _client as client + + +async def _token_endpoint_request_no_throw( + request, token_uri, body, access_token=None, use_json=False, can_retry=True +): + """Makes a request to the OAuth 2.0 authorization server's token endpoint. + This function doesn't throw on response errors. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + body (Mapping[str, str]): The parameters to send in the request body. + access_token (Optional(str)): The access token needed to make the request. + use_json (Optional(bool)): Use urlencoded format or json format for the + content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Tuple(bool, Mapping[str, str], Optional[bool]): A boolean indicating + if the request is successful, a mapping for the JSON-decoded response + data and in the case of an error a boolean indicating if the error + is retryable. + """ + if use_json: + headers = {"Content-Type": client._JSON_CONTENT_TYPE} + body = json.dumps(body).encode("utf-8") + else: + headers = {"Content-Type": client._URLENCODED_CONTENT_TYPE} + body = urllib.parse.urlencode(body).encode("utf-8") + + if access_token: + headers["Authorization"] = "Bearer {}".format(access_token) + + async def _perform_request(): + response = await request( + method="POST", url=token_uri, headers=headers, body=body + ) + + # Using data.read() resulted in zlib decompression errors. This may require future investigation. + response_body1 = await response.content() + + response_body = ( + response_body1.decode("utf-8") + if hasattr(response_body1, "decode") + else response_body1 + ) + + try: + response_data = json.loads(response_body) + except ValueError: + response_data = response_body + + if response.status == http_client.OK: + return True, response_data, None + + retryable_error = client._can_retry( + status_code=response.status, response_data=response_data + ) + + return False, response_data, retryable_error + + request_succeeded, response_data, retryable_error = await _perform_request() + + if request_succeeded or not retryable_error or not can_retry: + return request_succeeded, response_data, retryable_error + + retries = _exponential_backoff.ExponentialBackoff() + for _ in retries: + request_succeeded, response_data, retryable_error = await _perform_request() + if request_succeeded or not retryable_error: + return request_succeeded, response_data, retryable_error + + return False, response_data, retryable_error + + +async def _token_endpoint_request( + request, token_uri, body, access_token=None, use_json=False, can_retry=True +): + """Makes a request to the OAuth 2.0 authorization server's token endpoint. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + body (Mapping[str, str]): The parameters to send in the request body. + access_token (Optional(str)): The access token needed to make the request. + use_json (Optional(bool)): Use urlencoded format or json format for the + content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Mapping[str, str]: The JSON-decoded response data. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + """ + + response_status_ok, response_data, retryable_error = await _token_endpoint_request_no_throw( + request, + token_uri, + body, + access_token=access_token, + use_json=use_json, + can_retry=can_retry, + ) + if not response_status_ok: + client._handle_error_response(response_data, retryable_error) + return response_data + + +async def jwt_grant(request, token_uri, assertion, can_retry=True): + """Implements the JWT Profile for OAuth 2.0 Authorization Grants. + + For more details, see `rfc7523 section 4`_. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + assertion (str): The OAuth 2.0 assertion. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Tuple[str, Optional[datetime], Mapping[str, str]]: The access token, + expiration, and additional data returned by the token endpoint. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + + .. _rfc7523 section 4: https://tools.ietf.org/html/rfc7523#section-4 + """ + body = {"assertion": assertion, "grant_type": client._JWT_GRANT_TYPE} + + response_data = await _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) + + try: + access_token = response_data["access_token"] + except KeyError as caught_exc: + new_exc = exceptions.RefreshError( + "No access token in response.", response_data, retryable=False + ) + six.raise_from(new_exc, caught_exc) + + expiry = client._parse_expiry(response_data) + + return access_token, expiry, response_data + + +async def id_token_jwt_grant(request, token_uri, assertion, can_retry=True): + """Implements the JWT Profile for OAuth 2.0 Authorization Grants, but + requests an OpenID Connect ID Token instead of an access token. + + This is a variant on the standard JWT Profile that is currently unique + to Google. This was added for the benefit of authenticating to services + that require ID Tokens instead of access tokens or JWT bearer tokens. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorization server's token endpoint + URI. + assertion (str): JWT token signed by a service account. The token's + payload must include a ``target_audience`` claim. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Tuple[str, Optional[datetime], Mapping[str, str]]: + The (encoded) Open ID Connect ID Token, expiration, and additional + data returned by the endpoint. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + """ + body = {"assertion": assertion, "grant_type": client._JWT_GRANT_TYPE} + + response_data = await _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) + + try: + id_token = response_data["id_token"] + except KeyError as caught_exc: + new_exc = exceptions.RefreshError( + "No ID token in response.", response_data, retryable=False + ) + six.raise_from(new_exc, caught_exc) + + payload = jwt.decode(id_token, verify=False) + expiry = datetime.datetime.utcfromtimestamp(payload["exp"]) + + return id_token, expiry, response_data + + +async def refresh_grant( + request, + token_uri, + refresh_token, + client_id, + client_secret, + scopes=None, + rapt_token=None, + can_retry=True, +): + """Implements the OAuth 2.0 refresh token grant. + + For more details, see `rfc678 section 6`_. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + refresh_token (str): The refresh token to use to get a new access + token. + client_id (str): The OAuth 2.0 application's client ID. + client_secret (str): The Oauth 2.0 appliaction's client secret. + scopes (Optional(Sequence[str])): Scopes to request. If present, all + scopes must be authorized for the refresh token. Useful if refresh + token has a wild card scope (e.g. + 'https://www.googleapis.com/auth/any-api'). + rapt_token (Optional(str)): The reauth Proof Token. + can_retry (bool): Enable or disable request retry behavior. + + Returns: + Tuple[str, Optional[str], Optional[datetime], Mapping[str, str]]: The + access token, new or current refresh token, expiration, and additional data + returned by the token endpoint. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + + .. _rfc6748 section 6: https://tools.ietf.org/html/rfc6749#section-6 + """ + body = { + "grant_type": client._REFRESH_GRANT_TYPE, + "client_id": client_id, + "client_secret": client_secret, + "refresh_token": refresh_token, + } + if scopes: + body["scope"] = " ".join(scopes) + if rapt_token: + body["rapt"] = rapt_token + + response_data = await _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) + return client._handle_refresh_grant_response(response_data, refresh_token) diff --git a/script.module.google-auth-library/lib/google/oauth2/_credentials_async.py b/script.module.google-auth-library/lib/google/oauth2/_credentials_async.py new file mode 100644 index 000000000..e7b9637c8 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/_credentials_async.py @@ -0,0 +1,112 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""OAuth 2.0 Async Credentials. + +This module provides credentials based on OAuth 2.0 access and refresh tokens. +These credentials usually access resources on behalf of a user (resource +owner). + +Specifically, this is intended to use access tokens acquired using the +`Authorization Code grant`_ and can refresh those tokens using a +optional `refresh token`_. + +Obtaining the initial access and refresh token is outside of the scope of this +module. Consult `rfc6749 section 4.1`_ for complete details on the +Authorization Code grant flow. + +.. _Authorization Code grant: https://tools.ietf.org/html/rfc6749#section-1.3.1 +.. _refresh token: https://tools.ietf.org/html/rfc6749#section-6 +.. _rfc6749 section 4.1: https://tools.ietf.org/html/rfc6749#section-4.1 +""" + +from google.auth import _credentials_async as credentials +from google.auth import _helpers +from google.auth import exceptions +from google.oauth2 import _reauth_async as reauth +from google.oauth2 import credentials as oauth2_credentials + + +class Credentials(oauth2_credentials.Credentials): + """Credentials using OAuth 2.0 access and refresh tokens. + + The credentials are considered immutable. If you want to modify the + quota project, use :meth:`with_quota_project` or :: + + credentials = credentials.with_quota_project('myproject-123) + """ + + @_helpers.copy_docstring(credentials.Credentials) + async def refresh(self, request): + if ( + self._refresh_token is None + or self._token_uri is None + or self._client_id is None + or self._client_secret is None + ): + raise exceptions.RefreshError( + "The credentials do not contain the necessary fields need to " + "refresh the access token. You must specify refresh_token, " + "token_uri, client_id, and client_secret." + ) + + ( + access_token, + refresh_token, + expiry, + grant_response, + rapt_token, + ) = await reauth.refresh_grant( + request, + self._token_uri, + self._refresh_token, + self._client_id, + self._client_secret, + scopes=self._scopes, + rapt_token=self._rapt_token, + enable_reauth_refresh=self._enable_reauth_refresh, + ) + + self.token = access_token + self.expiry = expiry + self._refresh_token = refresh_token + self._id_token = grant_response.get("id_token") + self._rapt_token = rapt_token + + if self._scopes and "scope" in grant_response: + requested_scopes = frozenset(self._scopes) + granted_scopes = frozenset(grant_response["scope"].split()) + scopes_requested_but_not_granted = requested_scopes - granted_scopes + if scopes_requested_but_not_granted: + raise exceptions.RefreshError( + "Not all requested scopes were granted by the " + "authorization server, missing scopes {}.".format( + ", ".join(scopes_requested_but_not_granted) + ) + ) + + +class UserAccessTokenCredentials(oauth2_credentials.UserAccessTokenCredentials): + """Access token credentials for user account. + + Obtain the access token for a given user account or the current active + user account with the ``gcloud auth print-access-token`` command. + + Args: + account (Optional[str]): Account to get the access token for. If not + specified, the current active account will be used. + quota_project_id (Optional[str]): The project ID used for quota + and billing. + + """ diff --git a/script.module.google-auth-library/lib/google/oauth2/_id_token_async.py b/script.module.google-auth-library/lib/google/oauth2/_id_token_async.py new file mode 100644 index 000000000..c32dfa47d --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/_id_token_async.py @@ -0,0 +1,287 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google ID Token helpers. + +Provides support for verifying `OpenID Connect ID Tokens`_, especially ones +generated by Google infrastructure. + +To parse and verify an ID Token issued by Google's OAuth 2.0 authorization +server use :func:`verify_oauth2_token`. To verify an ID Token issued by +Firebase, use :func:`verify_firebase_token`. + +A general purpose ID Token verifier is available as :func:`verify_token`. + +Example:: + + from google.oauth2 import _id_token_async + from google.auth.transport import aiohttp_requests + + request = aiohttp_requests.Request() + + id_info = await _id_token_async.verify_oauth2_token( + token, request, 'my-client-id.example.com') + + if id_info['iss'] != 'https://accounts.google.com': + raise ValueError('Wrong issuer.') + + userid = id_info['sub'] + +By default, this will re-fetch certificates for each verification. Because +Google's public keys are only changed infrequently (on the order of once per +day), you may wish to take advantage of caching to reduce latency and the +potential for network errors. This can be accomplished using an external +library like `CacheControl`_ to create a cache-aware +:class:`google.auth.transport.Request`:: + + import cachecontrol + import google.auth.transport.requests + import requests + + session = requests.session() + cached_session = cachecontrol.CacheControl(session) + request = google.auth.transport.requests.Request(session=cached_session) + +.. _OpenID Connect ID Token: + http://openid.net/specs/openid-connect-core-1_0.html#IDToken +.. _CacheControl: https://cachecontrol.readthedocs.io +""" + +import json +import os + +import six +from six.moves import http_client + +from google.auth import environment_vars +from google.auth import exceptions +from google.auth import jwt +from google.auth.transport import requests +from google.oauth2 import id_token as sync_id_token + + +async def _fetch_certs(request, certs_url): + """Fetches certificates. + + Google-style cerificate endpoints return JSON in the format of + ``{'key id': 'x509 certificate'}``. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. This must be an aiohttp request. + certs_url (str): The certificate endpoint URL. + + Returns: + Mapping[str, str]: A mapping of public key ID to x.509 certificate + data. + """ + response = await request(certs_url, method="GET") + + if response.status != http_client.OK: + raise exceptions.TransportError( + "Could not fetch certificates at {}".format(certs_url) + ) + + data = await response.content() + + return json.loads(data) + + +async def verify_token( + id_token, + request, + audience=None, + certs_url=sync_id_token._GOOGLE_OAUTH2_CERTS_URL, + clock_skew_in_seconds=0, +): + """Verifies an ID token and returns the decoded token. + + Args: + id_token (Union[str, bytes]): The encoded token. + request (google.auth.transport.Request): The object used to make + HTTP requests. This must be an aiohttp request. + audience (str): The audience that this token is intended for. If None + then the audience is not verified. + certs_url (str): The URL that specifies the certificates to use to + verify the token. This URL should return JSON in the format of + ``{'key id': 'x509 certificate'}``. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Returns: + Mapping[str, Any]: The decoded token. + """ + certs = await _fetch_certs(request, certs_url) + + return jwt.decode( + id_token, + certs=certs, + audience=audience, + clock_skew_in_seconds=clock_skew_in_seconds, + ) + + +async def verify_oauth2_token( + id_token, request, audience=None, clock_skew_in_seconds=0 +): + """Verifies an ID Token issued by Google's OAuth 2.0 authorization server. + + Args: + id_token (Union[str, bytes]): The encoded token. + request (google.auth.transport.Request): The object used to make + HTTP requests. This must be an aiohttp request. + audience (str): The audience that this token is intended for. This is + typically your application's OAuth 2.0 client ID. If None then the + audience is not verified. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Returns: + Mapping[str, Any]: The decoded token. + + Raises: + exceptions.GoogleAuthError: If the issuer is invalid. + """ + idinfo = await verify_token( + id_token, + request, + audience=audience, + certs_url=sync_id_token._GOOGLE_OAUTH2_CERTS_URL, + clock_skew_in_seconds=clock_skew_in_seconds, + ) + + if idinfo["iss"] not in sync_id_token._GOOGLE_ISSUERS: + raise exceptions.GoogleAuthError( + "Wrong issuer. 'iss' should be one of the following: {}".format( + sync_id_token._GOOGLE_ISSUERS + ) + ) + + return idinfo + + +async def verify_firebase_token( + id_token, request, audience=None, clock_skew_in_seconds=0 +): + """Verifies an ID Token issued by Firebase Authentication. + + Args: + id_token (Union[str, bytes]): The encoded token. + request (google.auth.transport.Request): The object used to make + HTTP requests. This must be an aiohttp request. + audience (str): The audience that this token is intended for. This is + typically your Firebase application ID. If None then the audience + is not verified. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Returns: + Mapping[str, Any]: The decoded token. + """ + return await verify_token( + id_token, + request, + audience=audience, + certs_url=sync_id_token._GOOGLE_APIS_CERTS_URL, + clock_skew_in_seconds=clock_skew_in_seconds, + ) + + +async def fetch_id_token(request, audience): + """Fetch the ID Token from the current environment. + + This function acquires ID token from the environment in the following order. + See https://google.aip.dev/auth/4110. + + 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set + to the path of a valid service account JSON file, then ID token is + acquired using this service account credentials. + 2. If the application is running in Compute Engine, App Engine or Cloud Run, + then the ID token are obtained from the metadata server. + 3. If metadata server doesn't exist and no valid service account credentials + are found, :class:`~google.auth.exceptions.DefaultCredentialsError` will + be raised. + + Example:: + + import google.oauth2._id_token_async + import google.auth.transport.aiohttp_requests + + request = google.auth.transport.aiohttp_requests.Request() + target_audience = "https://pubsub.googleapis.com" + + id_token = await google.oauth2._id_token_async.fetch_id_token(request, target_audience) + + Args: + request (google.auth.transport.aiohttp_requests.Request): A callable used to make + HTTP requests. + audience (str): The audience that this ID token is intended for. + + Returns: + str: The ID token. + + Raises: + ~google.auth.exceptions.DefaultCredentialsError: + If metadata server doesn't exist and no valid service account + credentials are found. + """ + # 1. Try to get credentials from the GOOGLE_APPLICATION_CREDENTIALS environment + # variable. + credentials_filename = os.environ.get(environment_vars.CREDENTIALS) + if credentials_filename: + if not ( + os.path.exists(credentials_filename) + and os.path.isfile(credentials_filename) + ): + raise exceptions.DefaultCredentialsError( + "GOOGLE_APPLICATION_CREDENTIALS path is either not found or invalid." + ) + + try: + with open(credentials_filename, "r") as f: + from google.oauth2 import _service_account_async as service_account + + info = json.load(f) + if info.get("type") == "service_account": + credentials = service_account.IDTokenCredentials.from_service_account_info( + info, target_audience=audience + ) + await credentials.refresh(request) + return credentials.token + except ValueError as caught_exc: + new_exc = exceptions.DefaultCredentialsError( + "GOOGLE_APPLICATION_CREDENTIALS is not valid service account credentials.", + caught_exc, + ) + six.raise_from(new_exc, caught_exc) + + # 2. Try to fetch ID token from metada server if it exists. The code works + # for GAE and Cloud Run metadata server as well. + try: + from google.auth import compute_engine + from google.auth.compute_engine import _metadata + + request_new = requests.Request() + if _metadata.ping(request_new): + credentials = compute_engine.IDTokenCredentials( + request_new, audience, use_metadata_identity_endpoint=True + ) + credentials.refresh(request_new) + return credentials.token + except (ImportError, exceptions.TransportError): + pass + + raise exceptions.DefaultCredentialsError( + "Neither metadata server or valid service account credentials are found." + ) diff --git a/script.module.google-auth-library/lib/google/oauth2/_reauth_async.py b/script.module.google-auth-library/lib/google/oauth2/_reauth_async.py new file mode 100644 index 000000000..6b69c6e67 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/_reauth_async.py @@ -0,0 +1,330 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A module that provides functions for handling rapt authentication. + +Reauth is a process of obtaining additional authentication (such as password, +security token, etc.) while refreshing OAuth 2.0 credentials for a user. + +Credentials that use the Reauth flow must have the reauth scope, +``https://www.googleapis.com/auth/accounts.reauth``. + +This module provides a high-level function for executing the Reauth process, +:func:`refresh_grant`, and lower-level helpers for doing the individual +steps of the reauth process. + +Those steps are: + +1. Obtaining a list of challenges from the reauth server. +2. Running through each challenge and sending the result back to the reauth + server. +3. Refreshing the access token using the returned rapt token. +""" + +import sys + +from six.moves import range + +from google.auth import exceptions +from google.oauth2 import _client +from google.oauth2 import _client_async +from google.oauth2 import challenges +from google.oauth2 import reauth + + +async def _get_challenges( + request, supported_challenge_types, access_token, requested_scopes=None +): + """Does initial request to reauth API to get the challenges. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. This must be an aiohttp request. + supported_challenge_types (Sequence[str]): list of challenge names + supported by the manager. + access_token (str): Access token with reauth scopes. + requested_scopes (Optional(Sequence[str])): Authorized scopes for the credentials. + + Returns: + dict: The response from the reauth API. + """ + body = {"supportedChallengeTypes": supported_challenge_types} + if requested_scopes: + body["oauthScopesForDomainPolicyLookup"] = requested_scopes + + return await _client_async._token_endpoint_request( + request, + reauth._REAUTH_API + ":start", + body, + access_token=access_token, + use_json=True, + ) + + +async def _send_challenge_result( + request, session_id, challenge_id, client_input, access_token +): + """Attempt to refresh access token by sending next challenge result. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. This must be an aiohttp request. + session_id (str): session id returned by the initial reauth call. + challenge_id (str): challenge id returned by the initial reauth call. + client_input: dict with a challenge-specific client input. For example: + ``{'credential': password}`` for password challenge. + access_token (str): Access token with reauth scopes. + + Returns: + dict: The response from the reauth API. + """ + body = { + "sessionId": session_id, + "challengeId": challenge_id, + "action": "RESPOND", + "proposalResponse": client_input, + } + + return await _client_async._token_endpoint_request( + request, + reauth._REAUTH_API + "/{}:continue".format(session_id), + body, + access_token=access_token, + use_json=True, + ) + + +async def _run_next_challenge(msg, request, access_token): + """Get the next challenge from msg and run it. + + Args: + msg (dict): Reauth API response body (either from the initial request to + https://reauth.googleapis.com/v2/sessions:start or from sending the + previous challenge response to + https://reauth.googleapis.com/v2/sessions/id:continue) + request (google.auth.transport.Request): A callable used to make + HTTP requests. This must be an aiohttp request. + access_token (str): reauth access token + + Returns: + dict: The response from the reauth API. + + Raises: + google.auth.exceptions.ReauthError: if reauth failed. + """ + for challenge in msg["challenges"]: + if challenge["status"] != "READY": + # Skip non-activated challenges. + continue + c = challenges.AVAILABLE_CHALLENGES.get(challenge["challengeType"], None) + if not c: + raise exceptions.ReauthFailError( + "Unsupported challenge type {0}. Supported types: {1}".format( + challenge["challengeType"], + ",".join(list(challenges.AVAILABLE_CHALLENGES.keys())), + ) + ) + if not c.is_locally_eligible: + raise exceptions.ReauthFailError( + "Challenge {0} is not locally eligible".format( + challenge["challengeType"] + ) + ) + client_input = c.obtain_challenge_input(challenge) + if not client_input: + return None + return await _send_challenge_result( + request, + msg["sessionId"], + challenge["challengeId"], + client_input, + access_token, + ) + return None + + +async def _obtain_rapt(request, access_token, requested_scopes): + """Given an http request method and reauth access token, get rapt token. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. This must be an aiohttp request. + access_token (str): reauth access token + requested_scopes (Sequence[str]): scopes required by the client application + + Returns: + str: The rapt token. + + Raises: + google.auth.exceptions.ReauthError: if reauth failed + """ + msg = await _get_challenges( + request, + list(challenges.AVAILABLE_CHALLENGES.keys()), + access_token, + requested_scopes, + ) + + if msg["status"] == reauth._AUTHENTICATED: + return msg["encodedProofOfReauthToken"] + + for _ in range(0, reauth.RUN_CHALLENGE_RETRY_LIMIT): + if not ( + msg["status"] == reauth._CHALLENGE_REQUIRED + or msg["status"] == reauth._CHALLENGE_PENDING + ): + raise exceptions.ReauthFailError( + "Reauthentication challenge failed due to API error: {}".format( + msg["status"] + ) + ) + + if not reauth.is_interactive(): + raise exceptions.ReauthFailError( + "Reauthentication challenge could not be answered because you are not" + " in an interactive session." + ) + + msg = await _run_next_challenge(msg, request, access_token) + + if msg["status"] == reauth._AUTHENTICATED: + return msg["encodedProofOfReauthToken"] + + # If we got here it means we didn't get authenticated. + raise exceptions.ReauthFailError("Failed to obtain rapt token.") + + +async def get_rapt_token( + request, client_id, client_secret, refresh_token, token_uri, scopes=None +): + """Given an http request method and refresh_token, get rapt token. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. This must be an aiohttp request. + client_id (str): client id to get access token for reauth scope. + client_secret (str): client secret for the client_id + refresh_token (str): refresh token to refresh access token + token_uri (str): uri to refresh access token + scopes (Optional(Sequence[str])): scopes required by the client application + + Returns: + str: The rapt token. + Raises: + google.auth.exceptions.RefreshError: If reauth failed. + """ + sys.stderr.write("Reauthentication required.\n") + + # Get access token for reauth. + access_token, _, _, _ = await _client_async.refresh_grant( + request=request, + client_id=client_id, + client_secret=client_secret, + refresh_token=refresh_token, + token_uri=token_uri, + scopes=[reauth._REAUTH_SCOPE], + ) + + # Get rapt token from reauth API. + rapt_token = await _obtain_rapt(request, access_token, requested_scopes=scopes) + + return rapt_token + + +async def refresh_grant( + request, + token_uri, + refresh_token, + client_id, + client_secret, + scopes=None, + rapt_token=None, + enable_reauth_refresh=False, +): + """Implements the reauthentication flow. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. This must be an aiohttp request. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + refresh_token (str): The refresh token to use to get a new access + token. + client_id (str): The OAuth 2.0 application's client ID. + client_secret (str): The Oauth 2.0 appliaction's client secret. + scopes (Optional(Sequence[str])): Scopes to request. If present, all + scopes must be authorized for the refresh token. Useful if refresh + token has a wild card scope (e.g. + 'https://www.googleapis.com/auth/any-api'). + rapt_token (Optional(str)): The rapt token for reauth. + enable_reauth_refresh (Optional[bool]): Whether reauth refresh flow + should be used. The default value is False. This option is for + gcloud only, other users should use the default value. + + Returns: + Tuple[str, Optional[str], Optional[datetime], Mapping[str, str], str]: The + access token, new refresh token, expiration, the additional data + returned by the token endpoint, and the rapt token. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + """ + body = { + "grant_type": _client._REFRESH_GRANT_TYPE, + "client_id": client_id, + "client_secret": client_secret, + "refresh_token": refresh_token, + } + if scopes: + body["scope"] = " ".join(scopes) + if rapt_token: + body["rapt"] = rapt_token + + response_status_ok, response_data, retryable_error = await _client_async._token_endpoint_request_no_throw( + request, token_uri, body + ) + if ( + not response_status_ok + and response_data.get("error") == reauth._REAUTH_NEEDED_ERROR + and ( + response_data.get("error_subtype") + == reauth._REAUTH_NEEDED_ERROR_INVALID_RAPT + or response_data.get("error_subtype") + == reauth._REAUTH_NEEDED_ERROR_RAPT_REQUIRED + ) + ): + if not enable_reauth_refresh: + raise exceptions.RefreshError( + "Reauthentication is needed. Please run `gcloud auth application-default login` to reauthenticate." + ) + + rapt_token = await get_rapt_token( + request, client_id, client_secret, refresh_token, token_uri, scopes=scopes + ) + body["rapt"] = rapt_token + ( + response_status_ok, + response_data, + retryable_error, + ) = await _client_async._token_endpoint_request_no_throw( + request, token_uri, body + ) + + if not response_status_ok: + _client._handle_error_response(response_data, retryable_error) + refresh_response = _client._handle_refresh_grant_response( + response_data, refresh_token + ) + return refresh_response + (rapt_token,) diff --git a/script.module.google-auth-library/lib/google/oauth2/_service_account_async.py b/script.module.google-auth-library/lib/google/oauth2/_service_account_async.py new file mode 100644 index 000000000..cfd315a7f --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/_service_account_async.py @@ -0,0 +1,132 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Service Accounts: JSON Web Token (JWT) Profile for OAuth 2.0 + +NOTE: This file adds asynchronous refresh methods to both credentials +classes, and therefore async/await syntax is required when calling this +method when using service account credentials with asynchronous functionality. +Otherwise, all other methods are inherited from the regular service account +credentials file google.oauth2.service_account + +""" + +from google.auth import _credentials_async as credentials_async +from google.auth import _helpers +from google.oauth2 import _client_async +from google.oauth2 import service_account + + +class Credentials( + service_account.Credentials, credentials_async.Scoped, credentials_async.Credentials +): + """Service account credentials + + Usually, you'll create these credentials with one of the helper + constructors. To create credentials using a Google service account + private key JSON file:: + + credentials = _service_account_async.Credentials.from_service_account_file( + 'service-account.json') + + Or if you already have the service account file loaded:: + + service_account_info = json.load(open('service_account.json')) + credentials = _service_account_async.Credentials.from_service_account_info( + service_account_info) + + Both helper methods pass on arguments to the constructor, so you can + specify additional scopes and a subject if necessary:: + + credentials = _service_account_async.Credentials.from_service_account_file( + 'service-account.json', + scopes=['email'], + subject='user@example.com') + + The credentials are considered immutable. If you want to modify the scopes + or the subject used for delegation, use :meth:`with_scopes` or + :meth:`with_subject`:: + + scoped_credentials = credentials.with_scopes(['email']) + delegated_credentials = credentials.with_subject(subject) + + To add a quota project, use :meth:`with_quota_project`:: + + credentials = credentials.with_quota_project('myproject-123') + """ + + @_helpers.copy_docstring(credentials_async.Credentials) + async def refresh(self, request): + assertion = self._make_authorization_grant_assertion() + access_token, expiry, _ = await _client_async.jwt_grant( + request, self._token_uri, assertion + ) + self.token = access_token + self.expiry = expiry + + +class IDTokenCredentials( + service_account.IDTokenCredentials, + credentials_async.Signing, + credentials_async.Credentials, +): + """Open ID Connect ID Token-based service account credentials. + + These credentials are largely similar to :class:`.Credentials`, but instead + of using an OAuth 2.0 Access Token as the bearer token, they use an Open + ID Connect ID Token as the bearer token. These credentials are useful when + communicating to services that require ID Tokens and can not accept access + tokens. + + Usually, you'll create these credentials with one of the helper + constructors. To create credentials using a Google service account + private key JSON file:: + + credentials = ( + _service_account_async.IDTokenCredentials.from_service_account_file( + 'service-account.json')) + + Or if you already have the service account file loaded:: + + service_account_info = json.load(open('service_account.json')) + credentials = ( + _service_account_async.IDTokenCredentials.from_service_account_info( + service_account_info)) + + Both helper methods pass on arguments to the constructor, so you can + specify additional scopes and a subject if necessary:: + + credentials = ( + _service_account_async.IDTokenCredentials.from_service_account_file( + 'service-account.json', + scopes=['email'], + subject='user@example.com')) + + The credentials are considered immutable. If you want to modify the scopes + or the subject used for delegation, use :meth:`with_scopes` or + :meth:`with_subject`:: + + scoped_credentials = credentials.with_scopes(['email']) + delegated_credentials = credentials.with_subject(subject) + + """ + + @_helpers.copy_docstring(credentials_async.Credentials) + async def refresh(self, request): + assertion = self._make_authorization_grant_assertion() + access_token, expiry, _ = await _client_async.id_token_jwt_grant( + request, self._token_uri, assertion + ) + self.token = access_token + self.expiry = expiry diff --git a/script.module.google-auth-library/lib/google/oauth2/challenges.py b/script.module.google-auth-library/lib/google/oauth2/challenges.py new file mode 100644 index 000000000..bb523e6ca --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/challenges.py @@ -0,0 +1,183 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" Challenges for reauthentication. +""" + +import abc +import base64 +import getpass +import sys + +import six + +from google.auth import _helpers +from google.auth import exceptions + + +REAUTH_ORIGIN = "https://accounts.google.com" +SAML_CHALLENGE_MESSAGE = ( + "Please run `gcloud auth login` to complete reauthentication with SAML." +) + + +def get_user_password(text): + """Get password from user. + + Override this function with a different logic if you are using this library + outside a CLI. + + Args: + text (str): message for the password prompt. + + Returns: + str: password string. + """ + return getpass.getpass(text) + + +@six.add_metaclass(abc.ABCMeta) +class ReauthChallenge(object): + """Base class for reauth challenges.""" + + @property + @abc.abstractmethod + def name(self): # pragma: NO COVER + """Returns the name of the challenge.""" + raise NotImplementedError("name property must be implemented") + + @property + @abc.abstractmethod + def is_locally_eligible(self): # pragma: NO COVER + """Returns true if a challenge is supported locally on this machine.""" + raise NotImplementedError("is_locally_eligible property must be implemented") + + @abc.abstractmethod + def obtain_challenge_input(self, metadata): # pragma: NO COVER + """Performs logic required to obtain credentials and returns it. + + Args: + metadata (Mapping): challenge metadata returned in the 'challenges' field in + the initial reauth request. Includes the 'challengeType' field + and other challenge-specific fields. + + Returns: + response that will be send to the reauth service as the content of + the 'proposalResponse' field in the request body. Usually a dict + with the keys specific to the challenge. For example, + ``{'credential': password}`` for password challenge. + """ + raise NotImplementedError("obtain_challenge_input method must be implemented") + + +class PasswordChallenge(ReauthChallenge): + """Challenge that asks for user's password.""" + + @property + def name(self): + return "PASSWORD" + + @property + def is_locally_eligible(self): + return True + + @_helpers.copy_docstring(ReauthChallenge) + def obtain_challenge_input(self, unused_metadata): + passwd = get_user_password("Please enter your password:") + if not passwd: + passwd = " " # avoid the server crashing in case of no password :D + return {"credential": passwd} + + +class SecurityKeyChallenge(ReauthChallenge): + """Challenge that asks for user's security key touch.""" + + @property + def name(self): + return "SECURITY_KEY" + + @property + def is_locally_eligible(self): + return True + + @_helpers.copy_docstring(ReauthChallenge) + def obtain_challenge_input(self, metadata): + try: + import pyu2f.convenience.authenticator # type: ignore + import pyu2f.errors # type: ignore + import pyu2f.model # type: ignore + except ImportError: + raise exceptions.ReauthFailError( + "pyu2f dependency is required to use Security key reauth feature. " + "It can be installed via `pip install pyu2f` or `pip install google-auth[reauth]`." + ) + sk = metadata["securityKey"] + challenges = sk["challenges"] + app_id = sk["applicationId"] + + challenge_data = [] + for c in challenges: + kh = c["keyHandle"].encode("ascii") + key = pyu2f.model.RegisteredKey(bytearray(base64.urlsafe_b64decode(kh))) + challenge = c["challenge"].encode("ascii") + challenge = base64.urlsafe_b64decode(challenge) + challenge_data.append({"key": key, "challenge": challenge}) + + try: + api = pyu2f.convenience.authenticator.CreateCompositeAuthenticator( + REAUTH_ORIGIN + ) + response = api.Authenticate( + app_id, challenge_data, print_callback=sys.stderr.write + ) + return {"securityKey": response} + except pyu2f.errors.U2FError as e: + if e.code == pyu2f.errors.U2FError.DEVICE_INELIGIBLE: + sys.stderr.write("Ineligible security key.\n") + elif e.code == pyu2f.errors.U2FError.TIMEOUT: + sys.stderr.write("Timed out while waiting for security key touch.\n") + else: + raise e + except pyu2f.errors.NoDeviceFoundError: + sys.stderr.write("No security key found.\n") + return None + + +class SamlChallenge(ReauthChallenge): + """Challenge that asks the users to browse to their ID Providers. + + Currently SAML challenge is not supported. When obtaining the challenge + input, exception will be raised to instruct the users to run + `gcloud auth login` for reauthentication. + """ + + @property + def name(self): + return "SAML" + + @property + def is_locally_eligible(self): + return True + + def obtain_challenge_input(self, metadata): + # Magic Arch has not fully supported returning a proper dedirect URL + # for programmatic SAML users today. So we error our here and request + # users to use gcloud to complete a login. + raise exceptions.ReauthSamlChallengeFailError(SAML_CHALLENGE_MESSAGE) + + +AVAILABLE_CHALLENGES = { + challenge.name: challenge + for challenge in [SecurityKeyChallenge(), PasswordChallenge(), SamlChallenge()] +} diff --git a/script.module.google-auth-library/lib/google/oauth2/credentials.py b/script.module.google-auth-library/lib/google/oauth2/credentials.py new file mode 100644 index 000000000..8f1c3dda4 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/credentials.py @@ -0,0 +1,507 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""OAuth 2.0 Credentials. + +This module provides credentials based on OAuth 2.0 access and refresh tokens. +These credentials usually access resources on behalf of a user (resource +owner). + +Specifically, this is intended to use access tokens acquired using the +`Authorization Code grant`_ and can refresh those tokens using a +optional `refresh token`_. + +Obtaining the initial access and refresh token is outside of the scope of this +module. Consult `rfc6749 section 4.1`_ for complete details on the +Authorization Code grant flow. + +.. _Authorization Code grant: https://tools.ietf.org/html/rfc6749#section-1.3.1 +.. _refresh token: https://tools.ietf.org/html/rfc6749#section-6 +.. _rfc6749 section 4.1: https://tools.ietf.org/html/rfc6749#section-4.1 +""" + +from datetime import datetime +import io +import json + +import six + +from google.auth import _cloud_sdk +from google.auth import _helpers +from google.auth import credentials +from google.auth import exceptions +from google.oauth2 import reauth + + +# The Google OAuth 2.0 token endpoint. Used for authorized user credentials. +_GOOGLE_OAUTH2_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token" + + +class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaProject): + """Credentials using OAuth 2.0 access and refresh tokens. + + The credentials are considered immutable. If you want to modify the + quota project, use :meth:`with_quota_project` or :: + + credentials = credentials.with_quota_project('myproject-123') + + Reauth is disabled by default. To enable reauth, set the + `enable_reauth_refresh` parameter to True in the constructor. Note that + reauth feature is intended for gcloud to use only. + If reauth is enabled, `pyu2f` dependency has to be installed in order to use security + key reauth feature. Dependency can be installed via `pip install pyu2f` or `pip install + google-auth[reauth]`. + """ + + def __init__( + self, + token, + refresh_token=None, + id_token=None, + token_uri=None, + client_id=None, + client_secret=None, + scopes=None, + default_scopes=None, + quota_project_id=None, + expiry=None, + rapt_token=None, + refresh_handler=None, + enable_reauth_refresh=False, + ): + """ + Args: + token (Optional(str)): The OAuth 2.0 access token. Can be None + if refresh information is provided. + refresh_token (str): The OAuth 2.0 refresh token. If specified, + credentials can be refreshed. + id_token (str): The Open ID Connect ID Token. + token_uri (str): The OAuth 2.0 authorization server's token + endpoint URI. Must be specified for refresh, can be left as + None if the token can not be refreshed. + client_id (str): The OAuth 2.0 client ID. Must be specified for + refresh, can be left as None if the token can not be refreshed. + client_secret(str): The OAuth 2.0 client secret. Must be specified + for refresh, can be left as None if the token can not be + refreshed. + scopes (Sequence[str]): The scopes used to obtain authorization. + This parameter is used by :meth:`has_scopes`. OAuth 2.0 + credentials can not request additional scopes after + authorization. The scopes must be derivable from the refresh + token if refresh information is provided (e.g. The refresh + token scopes are a superset of this or contain a wild card + scope like 'https://www.googleapis.com/auth/any-api'). + default_scopes (Sequence[str]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + quota_project_id (Optional[str]): The project ID used for quota and billing. + This project may be different from the project used to + create the credentials. + rapt_token (Optional[str]): The reauth Proof Token. + refresh_handler (Optional[Callable[[google.auth.transport.Request, Sequence[str]], [str, datetime]]]): + A callable which takes in the HTTP request callable and the list of + OAuth scopes and when called returns an access token string for the + requested scopes and its expiry datetime. This is useful when no + refresh tokens are provided and tokens are obtained by calling + some external process on demand. It is particularly useful for + retrieving downscoped tokens from a token broker. + enable_reauth_refresh (Optional[bool]): Whether reauth refresh flow + should be used. This flag is for gcloud to use only. + """ + super(Credentials, self).__init__() + self.token = token + self.expiry = expiry + self._refresh_token = refresh_token + self._id_token = id_token + self._scopes = scopes + self._default_scopes = default_scopes + self._token_uri = token_uri + self._client_id = client_id + self._client_secret = client_secret + self._quota_project_id = quota_project_id + self._rapt_token = rapt_token + self.refresh_handler = refresh_handler + self._enable_reauth_refresh = enable_reauth_refresh + + def __getstate__(self): + """A __getstate__ method must exist for the __setstate__ to be called + This is identical to the default implementation. + See https://docs.python.org/3.7/library/pickle.html#object.__setstate__ + """ + state_dict = self.__dict__.copy() + # Remove _refresh_handler function as there are limitations pickling and + # unpickling certain callables (lambda, functools.partial instances) + # because they need to be importable. + # Instead, the refresh_handler setter should be used to repopulate this. + del state_dict["_refresh_handler"] + return state_dict + + def __setstate__(self, d): + """Credentials pickled with older versions of the class do not have + all the attributes.""" + self.token = d.get("token") + self.expiry = d.get("expiry") + self._refresh_token = d.get("_refresh_token") + self._id_token = d.get("_id_token") + self._scopes = d.get("_scopes") + self._default_scopes = d.get("_default_scopes") + self._token_uri = d.get("_token_uri") + self._client_id = d.get("_client_id") + self._client_secret = d.get("_client_secret") + self._quota_project_id = d.get("_quota_project_id") + self._rapt_token = d.get("_rapt_token") + self._enable_reauth_refresh = d.get("_enable_reauth_refresh") + # The refresh_handler setter should be used to repopulate this. + self._refresh_handler = None + + @property + def refresh_token(self): + """Optional[str]: The OAuth 2.0 refresh token.""" + return self._refresh_token + + @property + def scopes(self): + """Optional[str]: The OAuth 2.0 permission scopes.""" + return self._scopes + + @property + def token_uri(self): + """Optional[str]: The OAuth 2.0 authorization server's token endpoint + URI.""" + return self._token_uri + + @property + def id_token(self): + """Optional[str]: The Open ID Connect ID Token. + + Depending on the authorization server and the scopes requested, this + may be populated when credentials are obtained and updated when + :meth:`refresh` is called. This token is a JWT. It can be verified + and decoded using :func:`google.oauth2.id_token.verify_oauth2_token`. + """ + return self._id_token + + @property + def client_id(self): + """Optional[str]: The OAuth 2.0 client ID.""" + return self._client_id + + @property + def client_secret(self): + """Optional[str]: The OAuth 2.0 client secret.""" + return self._client_secret + + @property + def requires_scopes(self): + """False: OAuth 2.0 credentials have their scopes set when + the initial token is requested and can not be changed.""" + return False + + @property + def rapt_token(self): + """Optional[str]: The reauth Proof Token.""" + return self._rapt_token + + @property + def refresh_handler(self): + """Returns the refresh handler if available. + + Returns: + Optional[Callable[[google.auth.transport.Request, Sequence[str]], [str, datetime]]]: + The current refresh handler. + """ + return self._refresh_handler + + @refresh_handler.setter + def refresh_handler(self, value): + """Updates the current refresh handler. + + Args: + value (Optional[Callable[[google.auth.transport.Request, Sequence[str]], [str, datetime]]]): + The updated value of the refresh handler. + + Raises: + TypeError: If the value is not a callable or None. + """ + if not callable(value) and value is not None: + raise TypeError("The provided refresh_handler is not a callable or None.") + self._refresh_handler = value + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + + return self.__class__( + self.token, + refresh_token=self.refresh_token, + id_token=self.id_token, + token_uri=self.token_uri, + client_id=self.client_id, + client_secret=self.client_secret, + scopes=self.scopes, + default_scopes=self.default_scopes, + quota_project_id=quota_project_id, + rapt_token=self.rapt_token, + enable_reauth_refresh=self._enable_reauth_refresh, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithTokenUri) + def with_token_uri(self, token_uri): + + return self.__class__( + self.token, + refresh_token=self.refresh_token, + id_token=self.id_token, + token_uri=token_uri, + client_id=self.client_id, + client_secret=self.client_secret, + scopes=self.scopes, + default_scopes=self.default_scopes, + quota_project_id=self.quota_project_id, + rapt_token=self.rapt_token, + enable_reauth_refresh=self._enable_reauth_refresh, + ) + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + scopes = self._scopes if self._scopes is not None else self._default_scopes + # Use refresh handler if available and no refresh token is + # available. This is useful in general when tokens are obtained by calling + # some external process on demand. It is particularly useful for retrieving + # downscoped tokens from a token broker. + if self._refresh_token is None and self.refresh_handler: + token, expiry = self.refresh_handler(request, scopes=scopes) + # Validate returned data. + if not isinstance(token, six.string_types): + raise exceptions.RefreshError( + "The refresh_handler returned token is not a string." + ) + if not isinstance(expiry, datetime): + raise exceptions.RefreshError( + "The refresh_handler returned expiry is not a datetime object." + ) + if _helpers.utcnow() >= expiry - _helpers.REFRESH_THRESHOLD: + raise exceptions.RefreshError( + "The credentials returned by the refresh_handler are " + "already expired." + ) + self.token = token + self.expiry = expiry + return + + if ( + self._refresh_token is None + or self._token_uri is None + or self._client_id is None + or self._client_secret is None + ): + raise exceptions.RefreshError( + "The credentials do not contain the necessary fields need to " + "refresh the access token. You must specify refresh_token, " + "token_uri, client_id, and client_secret." + ) + + ( + access_token, + refresh_token, + expiry, + grant_response, + rapt_token, + ) = reauth.refresh_grant( + request, + self._token_uri, + self._refresh_token, + self._client_id, + self._client_secret, + scopes=scopes, + rapt_token=self._rapt_token, + enable_reauth_refresh=self._enable_reauth_refresh, + ) + + self.token = access_token + self.expiry = expiry + self._refresh_token = refresh_token + self._id_token = grant_response.get("id_token") + self._rapt_token = rapt_token + + if scopes and "scope" in grant_response: + requested_scopes = frozenset(scopes) + granted_scopes = frozenset(grant_response["scope"].split()) + scopes_requested_but_not_granted = requested_scopes - granted_scopes + if scopes_requested_but_not_granted: + raise exceptions.RefreshError( + "Not all requested scopes were granted by the " + "authorization server, missing scopes {}.".format( + ", ".join(scopes_requested_but_not_granted) + ) + ) + + @classmethod + def from_authorized_user_info(cls, info, scopes=None): + """Creates a Credentials instance from parsed authorized user info. + + Args: + info (Mapping[str, str]): The authorized user info in Google + format. + scopes (Sequence[str]): Optional list of scopes to include in the + credentials. + + Returns: + google.oauth2.credentials.Credentials: The constructed + credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + keys_needed = set(("refresh_token", "client_id", "client_secret")) + missing = keys_needed.difference(six.iterkeys(info)) + + if missing: + raise ValueError( + "Authorized user info was not in the expected format, missing " + "fields {}.".format(", ".join(missing)) + ) + + # access token expiry (datetime obj); auto-expire if not saved + expiry = info.get("expiry") + if expiry: + expiry = datetime.strptime( + expiry.rstrip("Z").split(".")[0], "%Y-%m-%dT%H:%M:%S" + ) + else: + expiry = _helpers.utcnow() - _helpers.REFRESH_THRESHOLD + + # process scopes, which needs to be a seq + if scopes is None and "scopes" in info: + scopes = info.get("scopes") + if isinstance(scopes, six.string_types): + scopes = scopes.split(" ") + + return cls( + token=info.get("token"), + refresh_token=info.get("refresh_token"), + token_uri=_GOOGLE_OAUTH2_TOKEN_ENDPOINT, # always overrides + scopes=scopes, + client_id=info.get("client_id"), + client_secret=info.get("client_secret"), + quota_project_id=info.get("quota_project_id"), # may not exist + expiry=expiry, + rapt_token=info.get("rapt_token"), # may not exist + ) + + @classmethod + def from_authorized_user_file(cls, filename, scopes=None): + """Creates a Credentials instance from an authorized user json file. + + Args: + filename (str): The path to the authorized user json file. + scopes (Sequence[str]): Optional list of scopes to include in the + credentials. + + Returns: + google.oauth2.credentials.Credentials: The constructed + credentials. + + Raises: + ValueError: If the file is not in the expected format. + """ + with io.open(filename, "r", encoding="utf-8") as json_file: + data = json.load(json_file) + return cls.from_authorized_user_info(data, scopes) + + def to_json(self, strip=None): + """Utility function that creates a JSON representation of a Credentials + object. + + Args: + strip (Sequence[str]): Optional list of members to exclude from the + generated JSON. + + Returns: + str: A JSON representation of this instance. When converted into + a dictionary, it can be passed to from_authorized_user_info() + to create a new credential instance. + """ + prep = { + "token": self.token, + "refresh_token": self.refresh_token, + "token_uri": self.token_uri, + "client_id": self.client_id, + "client_secret": self.client_secret, + "scopes": self.scopes, + "rapt_token": self.rapt_token, + } + if self.expiry: # flatten expiry timestamp + prep["expiry"] = self.expiry.isoformat() + "Z" + + # Remove empty entries (those which are None) + prep = {k: v for k, v in prep.items() if v is not None} + + # Remove entries that explicitely need to be removed + if strip is not None: + prep = {k: v for k, v in prep.items() if k not in strip} + + return json.dumps(prep) + + +class UserAccessTokenCredentials(credentials.CredentialsWithQuotaProject): + """Access token credentials for user account. + + Obtain the access token for a given user account or the current active + user account with the ``gcloud auth print-access-token`` command. + + Args: + account (Optional[str]): Account to get the access token for. If not + specified, the current active account will be used. + quota_project_id (Optional[str]): The project ID used for quota + and billing. + """ + + def __init__(self, account=None, quota_project_id=None): + super(UserAccessTokenCredentials, self).__init__() + self._account = account + self._quota_project_id = quota_project_id + + def with_account(self, account): + """Create a new instance with the given account. + + Args: + account (str): Account to get the access token for. + + Returns: + google.oauth2.credentials.UserAccessTokenCredentials: The created + credentials with the given account. + """ + return self.__class__(account=account, quota_project_id=self._quota_project_id) + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__(account=self._account, quota_project_id=quota_project_id) + + def refresh(self, request): + """Refreshes the access token. + + Args: + request (google.auth.transport.Request): This argument is required + by the base class interface but not used in this implementation, + so just set it to `None`. + + Raises: + google.auth.exceptions.UserAccessTokenError: If the access token + refresh failed. + """ + self.token = _cloud_sdk.get_auth_access_token(self._account) + + @_helpers.copy_docstring(credentials.Credentials) + def before_request(self, request, method, url, headers): + self.refresh(request) + self.apply(headers) diff --git a/script.module.google-auth-library/lib/google/oauth2/gdch_credentials.py b/script.module.google-auth-library/lib/google/oauth2/gdch_credentials.py new file mode 100644 index 000000000..7410cfc2e --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/gdch_credentials.py @@ -0,0 +1,251 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Experimental GDCH credentials support. +""" + +import datetime + +from google.auth import _helpers +from google.auth import _service_account_info +from google.auth import credentials +from google.auth import exceptions +from google.auth import jwt +from google.oauth2 import _client + + +TOKEN_EXCHANGE_TYPE = "urn:ietf:params:oauth:token-type:token-exchange" +ACCESS_TOKEN_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token" +SERVICE_ACCOUNT_TOKEN_TYPE = "urn:k8s:params:oauth:token-type:serviceaccount" +JWT_LIFETIME = datetime.timedelta(seconds=3600) # 1 hour + + +class ServiceAccountCredentials(credentials.Credentials): + """Credentials for GDCH (`Google Distributed Cloud Hosted`_) for service + account users. + + .. _Google Distributed Cloud Hosted: + https://cloud.google.com/blog/topics/hybrid-cloud/\ + announcing-google-distributed-cloud-edge-and-hosted + + To create a GDCH service account credential, first create a JSON file of + the following format:: + + { + "type": "gdch_service_account", + "format_version": "1", + "project": "", + "private_key_id": "", + "private_key": "-----BEGIN EC PRIVATE KEY-----\n\n-----END EC PRIVATE KEY-----\n", + "name": "", + "ca_cert_path": "", + "token_uri": "https://service-identity./authenticate" + } + + The "format_version" field stands for the format of the JSON file. For now + it is always "1". The `private_key_id` and `private_key` is used for signing. + The `ca_cert_path` is used for token server TLS certificate verification. + + After the JSON file is created, set `GOOGLE_APPLICATION_CREDENTIALS` environment + variable to the JSON file path, then use the following code to create the + credential:: + + import google.auth + + credential, _ = google.auth.default() + credential = credential.with_gdch_audience("") + + We can also create the credential directly:: + + from google.oauth import gdch_credentials + + credential = gdch_credentials.ServiceAccountCredentials.from_service_account_file("") + credential = credential.with_gdch_audience("") + + The token is obtained in the following way. This class first creates a + self signed JWT. It uses the `name` value as the `iss` and `sub` claim, and + the `token_uri` as the `aud` claim, and signs the JWT with the `private_key`. + It then sends the JWT to the `token_uri` to exchange a final token for + `audience`. + """ + + def __init__( + self, signer, service_identity_name, project, audience, token_uri, ca_cert_path + ): + """ + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + service_identity_name (str): The service identity name. It will be + used as the `iss` and `sub` claim in the self signed JWT. + project (str): The project. + audience (str): The audience for the final token. + token_uri (str): The token server uri. + ca_cert_path (str): The CA cert path for token server side TLS + certificate verification. If the token server uses well known + CA, then this parameter can be `None`. + """ + super(ServiceAccountCredentials, self).__init__() + self._signer = signer + self._service_identity_name = service_identity_name + self._project = project + self._audience = audience + self._token_uri = token_uri + self._ca_cert_path = ca_cert_path + + def _create_jwt(self): + now = _helpers.utcnow() + expiry = now + JWT_LIFETIME + iss_sub_value = "system:serviceaccount:{}:{}".format( + self._project, self._service_identity_name + ) + + payload = { + "iss": iss_sub_value, + "sub": iss_sub_value, + "aud": self._token_uri, + "iat": _helpers.datetime_to_secs(now), + "exp": _helpers.datetime_to_secs(expiry), + } + + return _helpers.from_bytes(jwt.encode(self._signer, payload)) + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + import google.auth.transport.requests + + if not isinstance(request, google.auth.transport.requests.Request): + raise exceptions.RefreshError( + "For GDCH service account credentials, request must be a google.auth.transport.requests.Request object" + ) + + # Create a self signed JWT, and do token exchange. + jwt_token = self._create_jwt() + request_body = { + "grant_type": TOKEN_EXCHANGE_TYPE, + "audience": self._audience, + "requested_token_type": ACCESS_TOKEN_TOKEN_TYPE, + "subject_token": jwt_token, + "subject_token_type": SERVICE_ACCOUNT_TOKEN_TYPE, + } + response_data = _client._token_endpoint_request( + request, + self._token_uri, + request_body, + access_token=None, + use_json=True, + verify=self._ca_cert_path, + ) + + self.token, _, self.expiry, _ = _client._handle_refresh_grant_response( + response_data, None + ) + + def with_gdch_audience(self, audience): + """Create a copy of GDCH credentials with the specified audience. + + Args: + audience (str): The intended audience for GDCH credentials. + """ + return self.__class__( + self._signer, + self._service_identity_name, + self._project, + audience, + self._token_uri, + self._ca_cert_path, + ) + + @classmethod + def _from_signer_and_info(cls, signer, info): + """Creates a Credentials instance from a signer and service account + info. + + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + info (Mapping[str, str]): The service account info. + + Returns: + google.oauth2.gdch_credentials.ServiceAccountCredentials: The constructed + credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + if info["format_version"] != "1": + raise ValueError("Only format version 1 is supported") + + return cls( + signer, + info["name"], # service_identity_name + info["project"], + None, # audience + info["token_uri"], + info.get("ca_cert_path", None), + ) + + @classmethod + def from_service_account_info(cls, info): + """Creates a Credentials instance from parsed service account info. + + Args: + info (Mapping[str, str]): The service account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.oauth2.gdch_credentials.ServiceAccountCredentials: The constructed + credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + signer = _service_account_info.from_dict( + info, + require=[ + "format_version", + "private_key_id", + "private_key", + "name", + "project", + "token_uri", + ], + use_rsa_signer=False, + ) + return cls._from_signer_and_info(signer, info) + + @classmethod + def from_service_account_file(cls, filename): + """Creates a Credentials instance from a service account json file. + + Args: + filename (str): The path to the service account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.oauth2.gdch_credentials.ServiceAccountCredentials: The constructed + credentials. + """ + info, signer = _service_account_info.from_filename( + filename, + require=[ + "format_version", + "private_key_id", + "private_key", + "name", + "project", + "token_uri", + ], + use_rsa_signer=False, + ) + return cls._from_signer_and_info(signer, info) diff --git a/script.module.google-auth-library/lib/google/oauth2/id_token.py b/script.module.google-auth-library/lib/google/oauth2/id_token.py new file mode 100644 index 000000000..48f5b0a59 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/id_token.py @@ -0,0 +1,341 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google ID Token helpers. + +Provides support for verifying `OpenID Connect ID Tokens`_, especially ones +generated by Google infrastructure. + +To parse and verify an ID Token issued by Google's OAuth 2.0 authorization +server use :func:`verify_oauth2_token`. To verify an ID Token issued by +Firebase, use :func:`verify_firebase_token`. + +A general purpose ID Token verifier is available as :func:`verify_token`. + +Example:: + + from google.oauth2 import id_token + from google.auth.transport import requests + + request = requests.Request() + + id_info = id_token.verify_oauth2_token( + token, request, 'my-client-id.example.com') + + userid = id_info['sub'] + +By default, this will re-fetch certificates for each verification. Because +Google's public keys are only changed infrequently (on the order of once per +day), you may wish to take advantage of caching to reduce latency and the +potential for network errors. This can be accomplished using an external +library like `CacheControl`_ to create a cache-aware +:class:`google.auth.transport.Request`:: + + import cachecontrol + import google.auth.transport.requests + import requests + + session = requests.session() + cached_session = cachecontrol.CacheControl(session) + request = google.auth.transport.requests.Request(session=cached_session) + +.. _OpenID Connect ID Tokens: + http://openid.net/specs/openid-connect-core-1_0.html#IDToken +.. _CacheControl: https://cachecontrol.readthedocs.io +""" + +import json +import os + +import six +from six.moves import http_client + +from google.auth import environment_vars +from google.auth import exceptions +from google.auth import jwt +import google.auth.transport.requests + + +# The URL that provides public certificates for verifying ID tokens issued +# by Google's OAuth 2.0 authorization server. +_GOOGLE_OAUTH2_CERTS_URL = "https://www.googleapis.com/oauth2/v1/certs" + +# The URL that provides public certificates for verifying ID tokens issued +# by Firebase and the Google APIs infrastructure +_GOOGLE_APIS_CERTS_URL = ( + "https://www.googleapis.com/robot/v1/metadata/x509" + "/securetoken@system.gserviceaccount.com" +) + +_GOOGLE_ISSUERS = ["accounts.google.com", "https://accounts.google.com"] + + +def _fetch_certs(request, certs_url): + """Fetches certificates. + + Google-style cerificate endpoints return JSON in the format of + ``{'key id': 'x509 certificate'}``. + + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + certs_url (str): The certificate endpoint URL. + + Returns: + Mapping[str, str]: A mapping of public key ID to x.509 certificate + data. + """ + response = request(certs_url, method="GET") + + if response.status != http_client.OK: + raise exceptions.TransportError( + "Could not fetch certificates at {}".format(certs_url) + ) + + return json.loads(response.data.decode("utf-8")) + + +def verify_token( + id_token, + request, + audience=None, + certs_url=_GOOGLE_OAUTH2_CERTS_URL, + clock_skew_in_seconds=0, +): + """Verifies an ID token and returns the decoded token. + + Args: + id_token (Union[str, bytes]): The encoded token. + request (google.auth.transport.Request): The object used to make + HTTP requests. + audience (str or list): The audience or audiences that this token is + intended for. If None then the audience is not verified. + certs_url (str): The URL that specifies the certificates to use to + verify the token. This URL should return JSON in the format of + ``{'key id': 'x509 certificate'}``. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Returns: + Mapping[str, Any]: The decoded token. + """ + certs = _fetch_certs(request, certs_url) + + return jwt.decode( + id_token, + certs=certs, + audience=audience, + clock_skew_in_seconds=clock_skew_in_seconds, + ) + + +def verify_oauth2_token(id_token, request, audience=None, clock_skew_in_seconds=0): + """Verifies an ID Token issued by Google's OAuth 2.0 authorization server. + + Args: + id_token (Union[str, bytes]): The encoded token. + request (google.auth.transport.Request): The object used to make + HTTP requests. + audience (str): The audience that this token is intended for. This is + typically your application's OAuth 2.0 client ID. If None then the + audience is not verified. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Returns: + Mapping[str, Any]: The decoded token. + + Raises: + exceptions.GoogleAuthError: If the issuer is invalid. + ValueError: If token verification fails + """ + idinfo = verify_token( + id_token, + request, + audience=audience, + certs_url=_GOOGLE_OAUTH2_CERTS_URL, + clock_skew_in_seconds=clock_skew_in_seconds, + ) + + if idinfo["iss"] not in _GOOGLE_ISSUERS: + raise exceptions.GoogleAuthError( + "Wrong issuer. 'iss' should be one of the following: {}".format( + _GOOGLE_ISSUERS + ) + ) + + return idinfo + + +def verify_firebase_token(id_token, request, audience=None, clock_skew_in_seconds=0): + """Verifies an ID Token issued by Firebase Authentication. + + Args: + id_token (Union[str, bytes]): The encoded token. + request (google.auth.transport.Request): The object used to make + HTTP requests. + audience (str): The audience that this token is intended for. This is + typically your Firebase application ID. If None then the audience + is not verified. + clock_skew_in_seconds (int): The clock skew used for `iat` and `exp` + validation. + + Returns: + Mapping[str, Any]: The decoded token. + """ + return verify_token( + id_token, + request, + audience=audience, + certs_url=_GOOGLE_APIS_CERTS_URL, + clock_skew_in_seconds=clock_skew_in_seconds, + ) + + +def fetch_id_token_credentials(audience, request=None): + """Create the ID Token credentials from the current environment. + + This function acquires ID token from the environment in the following order. + See https://google.aip.dev/auth/4110. + + 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set + to the path of a valid service account JSON file, then ID token is + acquired using this service account credentials. + 2. If the application is running in Compute Engine, App Engine or Cloud Run, + then the ID token are obtained from the metadata server. + 3. If metadata server doesn't exist and no valid service account credentials + are found, :class:`~google.auth.exceptions.DefaultCredentialsError` will + be raised. + + Example:: + + import google.oauth2.id_token + import google.auth.transport.requests + + request = google.auth.transport.requests.Request() + target_audience = "https://pubsub.googleapis.com" + + # Create ID token credentials. + credentials = google.oauth2.id_token.fetch_id_token_credentials(target_audience, request=request) + + # Refresh the credential to obtain an ID token. + credentials.refresh(request) + + id_token = credentials.token + id_token_expiry = credentials.expiry + + Args: + audience (str): The audience that this ID token is intended for. + request (Optional[google.auth.transport.Request]): A callable used to make + HTTP requests. A request object will be created if not provided. + + Returns: + google.auth.credentials.Credentials: The ID token credentials. + + Raises: + ~google.auth.exceptions.DefaultCredentialsError: + If metadata server doesn't exist and no valid service account + credentials are found. + """ + # 1. Try to get credentials from the GOOGLE_APPLICATION_CREDENTIALS environment + # variable. + credentials_filename = os.environ.get(environment_vars.CREDENTIALS) + if credentials_filename: + if not ( + os.path.exists(credentials_filename) + and os.path.isfile(credentials_filename) + ): + raise exceptions.DefaultCredentialsError( + "GOOGLE_APPLICATION_CREDENTIALS path is either not found or invalid." + ) + + try: + with open(credentials_filename, "r") as f: + from google.oauth2 import service_account + + info = json.load(f) + if info.get("type") == "service_account": + return service_account.IDTokenCredentials.from_service_account_info( + info, target_audience=audience + ) + except ValueError as caught_exc: + new_exc = exceptions.DefaultCredentialsError( + "GOOGLE_APPLICATION_CREDENTIALS is not valid service account credentials.", + caught_exc, + ) + six.raise_from(new_exc, caught_exc) + + # 2. Try to fetch ID token from metada server if it exists. The code + # works for GAE and Cloud Run metadata server as well. + try: + from google.auth import compute_engine + from google.auth.compute_engine import _metadata + + # Create a request object if not provided. + if not request: + request = google.auth.transport.requests.Request() + + if _metadata.ping(request): + return compute_engine.IDTokenCredentials( + request, audience, use_metadata_identity_endpoint=True + ) + except (ImportError, exceptions.TransportError): + pass + + raise exceptions.DefaultCredentialsError( + "Neither metadata server or valid service account credentials are found." + ) + + +def fetch_id_token(request, audience): + """Fetch the ID Token from the current environment. + + This function acquires ID token from the environment in the following order. + See https://google.aip.dev/auth/4110. + + 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set + to the path of a valid service account JSON file, then ID token is + acquired using this service account credentials. + 2. If the application is running in Compute Engine, App Engine or Cloud Run, + then the ID token are obtained from the metadata server. + 3. If metadata server doesn't exist and no valid service account credentials + are found, :class:`~google.auth.exceptions.DefaultCredentialsError` will + be raised. + + Example:: + + import google.oauth2.id_token + import google.auth.transport.requests + + request = google.auth.transport.requests.Request() + target_audience = "https://pubsub.googleapis.com" + + id_token = google.oauth2.id_token.fetch_id_token(request, target_audience) + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + audience (str): The audience that this ID token is intended for. + + Returns: + str: The ID token. + + Raises: + ~google.auth.exceptions.DefaultCredentialsError: + If metadata server doesn't exist and no valid service account + credentials are found. + """ + id_token_credentials = fetch_id_token_credentials(audience, request=request) + id_token_credentials.refresh(request) + return id_token_credentials.token diff --git a/script.module.google-auth-library/lib/google/oauth2/py.typed b/script.module.google-auth-library/lib/google/oauth2/py.typed new file mode 100644 index 000000000..d82ed62c2 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-oauth2 package uses inline types. diff --git a/script.module.google-auth-library/lib/google/oauth2/reauth.py b/script.module.google-auth-library/lib/google/oauth2/reauth.py new file mode 100644 index 000000000..ad2ad1b2e --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/reauth.py @@ -0,0 +1,352 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A module that provides functions for handling rapt authentication. + +Reauth is a process of obtaining additional authentication (such as password, +security token, etc.) while refreshing OAuth 2.0 credentials for a user. + +Credentials that use the Reauth flow must have the reauth scope, +``https://www.googleapis.com/auth/accounts.reauth``. + +This module provides a high-level function for executing the Reauth process, +:func:`refresh_grant`, and lower-level helpers for doing the individual +steps of the reauth process. + +Those steps are: + +1. Obtaining a list of challenges from the reauth server. +2. Running through each challenge and sending the result back to the reauth + server. +3. Refreshing the access token using the returned rapt token. +""" + +import sys + +from six.moves import range + +from google.auth import exceptions +from google.oauth2 import _client +from google.oauth2 import challenges + + +_REAUTH_SCOPE = "https://www.googleapis.com/auth/accounts.reauth" +_REAUTH_API = "https://reauth.googleapis.com/v2/sessions" + +_REAUTH_NEEDED_ERROR = "invalid_grant" +_REAUTH_NEEDED_ERROR_INVALID_RAPT = "invalid_rapt" +_REAUTH_NEEDED_ERROR_RAPT_REQUIRED = "rapt_required" + +_AUTHENTICATED = "AUTHENTICATED" +_CHALLENGE_REQUIRED = "CHALLENGE_REQUIRED" +_CHALLENGE_PENDING = "CHALLENGE_PENDING" + + +# Override this global variable to set custom max number of rounds of reauth +# challenges should be run. +RUN_CHALLENGE_RETRY_LIMIT = 5 + + +def is_interactive(): + """Check if we are in an interractive environment. + + Override this function with a different logic if you are using this library + outside a CLI. + + If the rapt token needs refreshing, the user needs to answer the challenges. + If the user is not in an interractive environment, the challenges can not + be answered and we just wait for timeout for no reason. + + Returns: + bool: True if is interactive environment, False otherwise. + """ + + return sys.stdin.isatty() + + +def _get_challenges( + request, supported_challenge_types, access_token, requested_scopes=None +): + """Does initial request to reauth API to get the challenges. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + supported_challenge_types (Sequence[str]): list of challenge names + supported by the manager. + access_token (str): Access token with reauth scopes. + requested_scopes (Optional(Sequence[str])): Authorized scopes for the credentials. + + Returns: + dict: The response from the reauth API. + """ + body = {"supportedChallengeTypes": supported_challenge_types} + if requested_scopes: + body["oauthScopesForDomainPolicyLookup"] = requested_scopes + + return _client._token_endpoint_request( + request, _REAUTH_API + ":start", body, access_token=access_token, use_json=True + ) + + +def _send_challenge_result( + request, session_id, challenge_id, client_input, access_token +): + """Attempt to refresh access token by sending next challenge result. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + session_id (str): session id returned by the initial reauth call. + challenge_id (str): challenge id returned by the initial reauth call. + client_input: dict with a challenge-specific client input. For example: + ``{'credential': password}`` for password challenge. + access_token (str): Access token with reauth scopes. + + Returns: + dict: The response from the reauth API. + """ + body = { + "sessionId": session_id, + "challengeId": challenge_id, + "action": "RESPOND", + "proposalResponse": client_input, + } + + return _client._token_endpoint_request( + request, + _REAUTH_API + "/{}:continue".format(session_id), + body, + access_token=access_token, + use_json=True, + ) + + +def _run_next_challenge(msg, request, access_token): + """Get the next challenge from msg and run it. + + Args: + msg (dict): Reauth API response body (either from the initial request to + https://reauth.googleapis.com/v2/sessions:start or from sending the + previous challenge response to + https://reauth.googleapis.com/v2/sessions/id:continue) + request (google.auth.transport.Request): A callable used to make + HTTP requests. + access_token (str): reauth access token + + Returns: + dict: The response from the reauth API. + + Raises: + google.auth.exceptions.ReauthError: if reauth failed. + """ + for challenge in msg["challenges"]: + if challenge["status"] != "READY": + # Skip non-activated challenges. + continue + c = challenges.AVAILABLE_CHALLENGES.get(challenge["challengeType"], None) + if not c: + raise exceptions.ReauthFailError( + "Unsupported challenge type {0}. Supported types: {1}".format( + challenge["challengeType"], + ",".join(list(challenges.AVAILABLE_CHALLENGES.keys())), + ) + ) + if not c.is_locally_eligible: + raise exceptions.ReauthFailError( + "Challenge {0} is not locally eligible".format( + challenge["challengeType"] + ) + ) + client_input = c.obtain_challenge_input(challenge) + if not client_input: + return None + return _send_challenge_result( + request, + msg["sessionId"], + challenge["challengeId"], + client_input, + access_token, + ) + return None + + +def _obtain_rapt(request, access_token, requested_scopes): + """Given an http request method and reauth access token, get rapt token. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + access_token (str): reauth access token + requested_scopes (Sequence[str]): scopes required by the client application + + Returns: + str: The rapt token. + + Raises: + google.auth.exceptions.ReauthError: if reauth failed + """ + msg = _get_challenges( + request, + list(challenges.AVAILABLE_CHALLENGES.keys()), + access_token, + requested_scopes, + ) + + if msg["status"] == _AUTHENTICATED: + return msg["encodedProofOfReauthToken"] + + for _ in range(0, RUN_CHALLENGE_RETRY_LIMIT): + if not ( + msg["status"] == _CHALLENGE_REQUIRED or msg["status"] == _CHALLENGE_PENDING + ): + raise exceptions.ReauthFailError( + "Reauthentication challenge failed due to API error: {}".format( + msg["status"] + ) + ) + + if not is_interactive(): + raise exceptions.ReauthFailError( + "Reauthentication challenge could not be answered because you are not" + " in an interactive session." + ) + + msg = _run_next_challenge(msg, request, access_token) + + if msg["status"] == _AUTHENTICATED: + return msg["encodedProofOfReauthToken"] + + # If we got here it means we didn't get authenticated. + raise exceptions.ReauthFailError("Failed to obtain rapt token.") + + +def get_rapt_token( + request, client_id, client_secret, refresh_token, token_uri, scopes=None +): + """Given an http request method and refresh_token, get rapt token. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + client_id (str): client id to get access token for reauth scope. + client_secret (str): client secret for the client_id + refresh_token (str): refresh token to refresh access token + token_uri (str): uri to refresh access token + scopes (Optional(Sequence[str])): scopes required by the client application + + Returns: + str: The rapt token. + Raises: + google.auth.exceptions.RefreshError: If reauth failed. + """ + sys.stderr.write("Reauthentication required.\n") + + # Get access token for reauth. + access_token, _, _, _ = _client.refresh_grant( + request=request, + client_id=client_id, + client_secret=client_secret, + refresh_token=refresh_token, + token_uri=token_uri, + scopes=[_REAUTH_SCOPE], + ) + + # Get rapt token from reauth API. + rapt_token = _obtain_rapt(request, access_token, requested_scopes=scopes) + + return rapt_token + + +def refresh_grant( + request, + token_uri, + refresh_token, + client_id, + client_secret, + scopes=None, + rapt_token=None, + enable_reauth_refresh=False, +): + """Implements the reauthentication flow. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + token_uri (str): The OAuth 2.0 authorizations server's token endpoint + URI. + refresh_token (str): The refresh token to use to get a new access + token. + client_id (str): The OAuth 2.0 application's client ID. + client_secret (str): The Oauth 2.0 appliaction's client secret. + scopes (Optional(Sequence[str])): Scopes to request. If present, all + scopes must be authorized for the refresh token. Useful if refresh + token has a wild card scope (e.g. + 'https://www.googleapis.com/auth/any-api'). + rapt_token (Optional(str)): The rapt token for reauth. + enable_reauth_refresh (Optional[bool]): Whether reauth refresh flow + should be used. The default value is False. This option is for + gcloud only, other users should use the default value. + + Returns: + Tuple[str, Optional[str], Optional[datetime], Mapping[str, str], str]: The + access token, new refresh token, expiration, the additional data + returned by the token endpoint, and the rapt token. + + Raises: + google.auth.exceptions.RefreshError: If the token endpoint returned + an error. + """ + body = { + "grant_type": _client._REFRESH_GRANT_TYPE, + "client_id": client_id, + "client_secret": client_secret, + "refresh_token": refresh_token, + } + if scopes: + body["scope"] = " ".join(scopes) + if rapt_token: + body["rapt"] = rapt_token + + response_status_ok, response_data, retryable_error = _client._token_endpoint_request_no_throw( + request, token_uri, body + ) + if ( + not response_status_ok + and response_data.get("error") == _REAUTH_NEEDED_ERROR + and ( + response_data.get("error_subtype") == _REAUTH_NEEDED_ERROR_INVALID_RAPT + or response_data.get("error_subtype") == _REAUTH_NEEDED_ERROR_RAPT_REQUIRED + ) + ): + if not enable_reauth_refresh: + raise exceptions.RefreshError( + "Reauthentication is needed. Please run `gcloud auth application-default login` to reauthenticate." + ) + + rapt_token = get_rapt_token( + request, client_id, client_secret, refresh_token, token_uri, scopes=scopes + ) + body["rapt"] = rapt_token + ( + response_status_ok, + response_data, + retryable_error, + ) = _client._token_endpoint_request_no_throw(request, token_uri, body) + + if not response_status_ok: + _client._handle_error_response(response_data, retryable_error) + return _client._handle_refresh_grant_response(response_data, refresh_token) + ( + rapt_token, + ) diff --git a/script.module.google-auth-library/lib/google/oauth2/service_account.py b/script.module.google-auth-library/lib/google/oauth2/service_account.py new file mode 100644 index 000000000..0989750db --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/service_account.py @@ -0,0 +1,721 @@ +# Copyright 2016 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Service Accounts: JSON Web Token (JWT) Profile for OAuth 2.0 + +This module implements the JWT Profile for OAuth 2.0 Authorization Grants +as defined by `RFC 7523`_ with particular support for how this RFC is +implemented in Google's infrastructure. Google refers to these credentials +as *Service Accounts*. + +Service accounts are used for server-to-server communication, such as +interactions between a web application server and a Google service. The +service account belongs to your application instead of to an individual end +user. In contrast to other OAuth 2.0 profiles, no users are involved and your +application "acts" as the service account. + +Typically an application uses a service account when the application uses +Google APIs to work with its own data rather than a user's data. For example, +an application that uses Google Cloud Datastore for data persistence would use +a service account to authenticate its calls to the Google Cloud Datastore API. +However, an application that needs to access a user's Drive documents would +use the normal OAuth 2.0 profile. + +Additionally, Google Apps domain administrators can grant service accounts +`domain-wide delegation`_ authority to access user data on behalf of users in +the domain. + +This profile uses a JWT to acquire an OAuth 2.0 access token. The JWT is used +in place of the usual authorization token returned during the standard +OAuth 2.0 Authorization Code grant. The JWT is only used for this purpose, as +the acquired access token is used as the bearer token when making requests +using these credentials. + +This profile differs from normal OAuth 2.0 profile because no user consent +step is required. The use of the private key allows this profile to assert +identity directly. + +This profile also differs from the :mod:`google.auth.jwt` authentication +because the JWT credentials use the JWT directly as the bearer token. This +profile instead only uses the JWT to obtain an OAuth 2.0 access token. The +obtained OAuth 2.0 access token is used as the bearer token. + +Domain-wide delegation +---------------------- + +Domain-wide delegation allows a service account to access user data on +behalf of any user in a Google Apps domain without consent from the user. +For example, an application that uses the Google Calendar API to add events to +the calendars of all users in a Google Apps domain would use a service account +to access the Google Calendar API on behalf of users. + +The Google Apps administrator must explicitly authorize the service account to +do this. This authorization step is referred to as "delegating domain-wide +authority" to a service account. + +You can use domain-wise delegation by creating a set of credentials with a +specific subject using :meth:`~Credentials.with_subject`. + +.. _RFC 7523: https://tools.ietf.org/html/rfc7523 +""" + +import copy +import datetime + +from google.auth import _helpers +from google.auth import _service_account_info +from google.auth import credentials +from google.auth import jwt +from google.oauth2 import _client + +_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds +_GOOGLE_OAUTH2_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token" + + +class Credentials( + credentials.Signing, + credentials.Scoped, + credentials.CredentialsWithQuotaProject, + credentials.CredentialsWithTokenUri, +): + """Service account credentials + + Usually, you'll create these credentials with one of the helper + constructors. To create credentials using a Google service account + private key JSON file:: + + credentials = service_account.Credentials.from_service_account_file( + 'service-account.json') + + Or if you already have the service account file loaded:: + + service_account_info = json.load(open('service_account.json')) + credentials = service_account.Credentials.from_service_account_info( + service_account_info) + + Both helper methods pass on arguments to the constructor, so you can + specify additional scopes and a subject if necessary:: + + credentials = service_account.Credentials.from_service_account_file( + 'service-account.json', + scopes=['email'], + subject='user@example.com') + + The credentials are considered immutable. If you want to modify the scopes + or the subject used for delegation, use :meth:`with_scopes` or + :meth:`with_subject`:: + + scoped_credentials = credentials.with_scopes(['email']) + delegated_credentials = credentials.with_subject(subject) + + To add a quota project, use :meth:`with_quota_project`:: + + credentials = credentials.with_quota_project('myproject-123') + """ + + def __init__( + self, + signer, + service_account_email, + token_uri, + scopes=None, + default_scopes=None, + subject=None, + project_id=None, + quota_project_id=None, + additional_claims=None, + always_use_jwt_access=False, + ): + """ + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + service_account_email (str): The service account's email. + scopes (Sequence[str]): User-defined scopes to request during the + authorization grant. + default_scopes (Sequence[str]): Default scopes passed by a + Google client library. Use 'scopes' for user-defined scopes. + token_uri (str): The OAuth 2.0 Token URI. + subject (str): For domain-wide delegation, the email address of the + user to for which to request delegated access. + project_id (str): Project ID associated with the service account + credential. + quota_project_id (Optional[str]): The project ID used for quota and + billing. + additional_claims (Mapping[str, str]): Any additional claims for + the JWT assertion used in the authorization grant. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be always used. + + .. note:: Typically one of the helper constructors + :meth:`from_service_account_file` or + :meth:`from_service_account_info` are used instead of calling the + constructor directly. + """ + super(Credentials, self).__init__() + + self._scopes = scopes + self._default_scopes = default_scopes + self._signer = signer + self._service_account_email = service_account_email + self._subject = subject + self._project_id = project_id + self._quota_project_id = quota_project_id + self._token_uri = token_uri + self._always_use_jwt_access = always_use_jwt_access + + self._jwt_credentials = None + + if additional_claims is not None: + self._additional_claims = additional_claims + else: + self._additional_claims = {} + + @classmethod + def _from_signer_and_info(cls, signer, info, **kwargs): + """Creates a Credentials instance from a signer and service account + info. + + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + info (Mapping[str, str]): The service account info. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.Credentials: The constructed credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + return cls( + signer, + service_account_email=info["client_email"], + token_uri=info["token_uri"], + project_id=info.get("project_id"), + **kwargs + ) + + @classmethod + def from_service_account_info(cls, info, **kwargs): + """Creates a Credentials instance from parsed service account info. + + Args: + info (Mapping[str, str]): The service account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.service_account.Credentials: The constructed + credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + signer = _service_account_info.from_dict( + info, require=["client_email", "token_uri"] + ) + return cls._from_signer_and_info(signer, info, **kwargs) + + @classmethod + def from_service_account_file(cls, filename, **kwargs): + """Creates a Credentials instance from a service account json file. + + Args: + filename (str): The path to the service account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.service_account.Credentials: The constructed + credentials. + """ + info, signer = _service_account_info.from_filename( + filename, require=["client_email", "token_uri"] + ) + return cls._from_signer_and_info(signer, info, **kwargs) + + @property + def service_account_email(self): + """The service account email.""" + return self._service_account_email + + @property + def project_id(self): + """Project ID associated with this credential.""" + return self._project_id + + @property + def requires_scopes(self): + """Checks if the credentials requires scopes. + + Returns: + bool: True if there are no scopes set otherwise False. + """ + return True if not self._scopes else False + + @_helpers.copy_docstring(credentials.Scoped) + def with_scopes(self, scopes, default_scopes=None): + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + scopes=scopes, + default_scopes=default_scopes, + token_uri=self._token_uri, + subject=self._subject, + project_id=self._project_id, + quota_project_id=self._quota_project_id, + additional_claims=self._additional_claims.copy(), + always_use_jwt_access=self._always_use_jwt_access, + ) + + def with_always_use_jwt_access(self, always_use_jwt_access): + """Create a copy of these credentials with the specified always_use_jwt_access value. + + Args: + always_use_jwt_access (bool): Whether always use self signed JWT or not. + + Returns: + google.auth.service_account.Credentials: A new credentials + instance. + """ + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + scopes=self._scopes, + default_scopes=self._default_scopes, + token_uri=self._token_uri, + subject=self._subject, + project_id=self._project_id, + quota_project_id=self._quota_project_id, + additional_claims=self._additional_claims.copy(), + always_use_jwt_access=always_use_jwt_access, + ) + + def with_subject(self, subject): + """Create a copy of these credentials with the specified subject. + + Args: + subject (str): The subject claim. + + Returns: + google.auth.service_account.Credentials: A new credentials + instance. + """ + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + scopes=self._scopes, + default_scopes=self._default_scopes, + token_uri=self._token_uri, + subject=subject, + project_id=self._project_id, + quota_project_id=self._quota_project_id, + additional_claims=self._additional_claims.copy(), + always_use_jwt_access=self._always_use_jwt_access, + ) + + def with_claims(self, additional_claims): + """Returns a copy of these credentials with modified claims. + + Args: + additional_claims (Mapping[str, str]): Any additional claims for + the JWT payload. This will be merged with the current + additional claims. + + Returns: + google.auth.service_account.Credentials: A new credentials + instance. + """ + new_additional_claims = copy.deepcopy(self._additional_claims) + new_additional_claims.update(additional_claims or {}) + + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + scopes=self._scopes, + default_scopes=self._default_scopes, + token_uri=self._token_uri, + subject=self._subject, + project_id=self._project_id, + quota_project_id=self._quota_project_id, + additional_claims=new_additional_claims, + always_use_jwt_access=self._always_use_jwt_access, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + default_scopes=self._default_scopes, + scopes=self._scopes, + token_uri=self._token_uri, + subject=self._subject, + project_id=self._project_id, + quota_project_id=quota_project_id, + additional_claims=self._additional_claims.copy(), + always_use_jwt_access=self._always_use_jwt_access, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithTokenUri) + def with_token_uri(self, token_uri): + + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + default_scopes=self._default_scopes, + scopes=self._scopes, + token_uri=token_uri, + subject=self._subject, + project_id=self._project_id, + quota_project_id=self._quota_project_id, + additional_claims=self._additional_claims.copy(), + always_use_jwt_access=self._always_use_jwt_access, + ) + + def _make_authorization_grant_assertion(self): + """Create the OAuth 2.0 assertion. + + This assertion is used during the OAuth 2.0 grant to acquire an + access token. + + Returns: + bytes: The authorization grant assertion. + """ + now = _helpers.utcnow() + lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS) + expiry = now + lifetime + + payload = { + "iat": _helpers.datetime_to_secs(now), + "exp": _helpers.datetime_to_secs(expiry), + # The issuer must be the service account email. + "iss": self._service_account_email, + # The audience must be the auth token endpoint's URI + "aud": _GOOGLE_OAUTH2_TOKEN_ENDPOINT, + "scope": _helpers.scopes_to_string(self._scopes or ()), + } + + payload.update(self._additional_claims) + + # The subject can be a user email for domain-wide delegation. + if self._subject: + payload.setdefault("sub", self._subject) + + token = jwt.encode(self._signer, payload) + + return token + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + # Since domain wide delegation doesn't work with self signed JWT. If + # subject exists, then we should not use self signed JWT. + if self._subject is None and self._jwt_credentials is not None: + self._jwt_credentials.refresh(request) + self.token = self._jwt_credentials.token + self.expiry = self._jwt_credentials.expiry + else: + assertion = self._make_authorization_grant_assertion() + access_token, expiry, _ = _client.jwt_grant( + request, self._token_uri, assertion + ) + self.token = access_token + self.expiry = expiry + + def _create_self_signed_jwt(self, audience): + """Create a self-signed JWT from the credentials if requirements are met. + + Args: + audience (str): The service URL. ``https://[API_ENDPOINT]/`` + """ + # https://google.aip.dev/auth/4111 + if self._always_use_jwt_access: + if self._scopes: + self._jwt_credentials = jwt.Credentials.from_signing_credentials( + self, None, additional_claims={"scope": " ".join(self._scopes)} + ) + elif audience: + self._jwt_credentials = jwt.Credentials.from_signing_credentials( + self, audience + ) + elif self._default_scopes: + self._jwt_credentials = jwt.Credentials.from_signing_credentials( + self, + None, + additional_claims={"scope": " ".join(self._default_scopes)}, + ) + elif not self._scopes and audience: + self._jwt_credentials = jwt.Credentials.from_signing_credentials( + self, audience + ) + + @_helpers.copy_docstring(credentials.Signing) + def sign_bytes(self, message): + return self._signer.sign(message) + + @property # type: ignore + @_helpers.copy_docstring(credentials.Signing) + def signer(self): + return self._signer + + @property # type: ignore + @_helpers.copy_docstring(credentials.Signing) + def signer_email(self): + return self._service_account_email + + +class IDTokenCredentials( + credentials.Signing, + credentials.CredentialsWithQuotaProject, + credentials.CredentialsWithTokenUri, +): + """Open ID Connect ID Token-based service account credentials. + + These credentials are largely similar to :class:`.Credentials`, but instead + of using an OAuth 2.0 Access Token as the bearer token, they use an Open + ID Connect ID Token as the bearer token. These credentials are useful when + communicating to services that require ID Tokens and can not accept access + tokens. + + Usually, you'll create these credentials with one of the helper + constructors. To create credentials using a Google service account + private key JSON file:: + + credentials = ( + service_account.IDTokenCredentials.from_service_account_file( + 'service-account.json')) + + + Or if you already have the service account file loaded:: + + service_account_info = json.load(open('service_account.json')) + credentials = ( + service_account.IDTokenCredentials.from_service_account_info( + service_account_info)) + + + Both helper methods pass on arguments to the constructor, so you can + specify additional scopes and a subject if necessary:: + + credentials = ( + service_account.IDTokenCredentials.from_service_account_file( + 'service-account.json', + scopes=['email'], + subject='user@example.com')) + + + The credentials are considered immutable. If you want to modify the scopes + or the subject used for delegation, use :meth:`with_scopes` or + :meth:`with_subject`:: + + scoped_credentials = credentials.with_scopes(['email']) + delegated_credentials = credentials.with_subject(subject) + + """ + + def __init__( + self, + signer, + service_account_email, + token_uri, + target_audience, + additional_claims=None, + quota_project_id=None, + ): + """ + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + service_account_email (str): The service account's email. + token_uri (str): The OAuth 2.0 Token URI. + target_audience (str): The intended audience for these credentials, + used when requesting the ID Token. The ID Token's ``aud`` claim + will be set to this string. + additional_claims (Mapping[str, str]): Any additional claims for + the JWT assertion used in the authorization grant. + quota_project_id (Optional[str]): The project ID used for quota and billing. + .. note:: Typically one of the helper constructors + :meth:`from_service_account_file` or + :meth:`from_service_account_info` are used instead of calling the + constructor directly. + """ + super(IDTokenCredentials, self).__init__() + self._signer = signer + self._service_account_email = service_account_email + self._token_uri = token_uri + self._target_audience = target_audience + self._quota_project_id = quota_project_id + + if additional_claims is not None: + self._additional_claims = additional_claims + else: + self._additional_claims = {} + + @classmethod + def _from_signer_and_info(cls, signer, info, **kwargs): + """Creates a credentials instance from a signer and service account + info. + + Args: + signer (google.auth.crypt.Signer): The signer used to sign JWTs. + info (Mapping[str, str]): The service account info. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.jwt.IDTokenCredentials: The constructed credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + kwargs.setdefault("service_account_email", info["client_email"]) + kwargs.setdefault("token_uri", info["token_uri"]) + return cls(signer, **kwargs) + + @classmethod + def from_service_account_info(cls, info, **kwargs): + """Creates a credentials instance from parsed service account info. + + Args: + info (Mapping[str, str]): The service account info in Google + format. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.service_account.IDTokenCredentials: The constructed + credentials. + + Raises: + ValueError: If the info is not in the expected format. + """ + signer = _service_account_info.from_dict( + info, require=["client_email", "token_uri"] + ) + return cls._from_signer_and_info(signer, info, **kwargs) + + @classmethod + def from_service_account_file(cls, filename, **kwargs): + """Creates a credentials instance from a service account json file. + + Args: + filename (str): The path to the service account json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + google.auth.service_account.IDTokenCredentials: The constructed + credentials. + """ + info, signer = _service_account_info.from_filename( + filename, require=["client_email", "token_uri"] + ) + return cls._from_signer_and_info(signer, info, **kwargs) + + def with_target_audience(self, target_audience): + """Create a copy of these credentials with the specified target + audience. + + Args: + target_audience (str): The intended audience for these credentials, + used when requesting the ID Token. + + Returns: + google.auth.service_account.IDTokenCredentials: A new credentials + instance. + """ + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + token_uri=self._token_uri, + target_audience=target_audience, + additional_claims=self._additional_claims.copy(), + quota_project_id=self.quota_project_id, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) + def with_quota_project(self, quota_project_id): + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + token_uri=self._token_uri, + target_audience=self._target_audience, + additional_claims=self._additional_claims.copy(), + quota_project_id=quota_project_id, + ) + + @_helpers.copy_docstring(credentials.CredentialsWithTokenUri) + def with_token_uri(self, token_uri): + return self.__class__( + self._signer, + service_account_email=self._service_account_email, + token_uri=token_uri, + target_audience=self._target_audience, + additional_claims=self._additional_claims.copy(), + quota_project_id=self._quota_project_id, + ) + + def _make_authorization_grant_assertion(self): + """Create the OAuth 2.0 assertion. + + This assertion is used during the OAuth 2.0 grant to acquire an + ID token. + + Returns: + bytes: The authorization grant assertion. + """ + now = _helpers.utcnow() + lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS) + expiry = now + lifetime + + payload = { + "iat": _helpers.datetime_to_secs(now), + "exp": _helpers.datetime_to_secs(expiry), + # The issuer must be the service account email. + "iss": self.service_account_email, + # The audience must be the auth token endpoint's URI + "aud": _GOOGLE_OAUTH2_TOKEN_ENDPOINT, + # The target audience specifies which service the ID token is + # intended for. + "target_audience": self._target_audience, + } + + payload.update(self._additional_claims) + + token = jwt.encode(self._signer, payload) + + return token + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + assertion = self._make_authorization_grant_assertion() + access_token, expiry, _ = _client.id_token_jwt_grant( + request, self._token_uri, assertion + ) + self.token = access_token + self.expiry = expiry + + @property + def service_account_email(self): + """The service account email.""" + return self._service_account_email + + @_helpers.copy_docstring(credentials.Signing) + def sign_bytes(self, message): + return self._signer.sign(message) + + @property # type: ignore + @_helpers.copy_docstring(credentials.Signing) + def signer(self): + return self._signer + + @property # type: ignore + @_helpers.copy_docstring(credentials.Signing) + def signer_email(self): + return self._service_account_email diff --git a/script.module.google-auth-library/lib/google/oauth2/sts.py b/script.module.google-auth-library/lib/google/oauth2/sts.py new file mode 100644 index 000000000..5cf06d4d4 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/sts.py @@ -0,0 +1,177 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""OAuth 2.0 Token Exchange Spec. + +This module defines a token exchange utility based on the `OAuth 2.0 Token +Exchange`_ spec. This will be mainly used to exchange external credentials +for GCP access tokens in workload identity pools to access Google APIs. + +The implementation will support various types of client authentication as +allowed in the spec. + +A deviation on the spec will be for additional Google specific options that +cannot be easily mapped to parameters defined in the RFC. + +The returned dictionary response will be based on the `rfc8693 section 2.2.1`_ +spec JSON response. + +.. _OAuth 2.0 Token Exchange: https://tools.ietf.org/html/rfc8693 +.. _rfc8693 section 2.2.1: https://tools.ietf.org/html/rfc8693#section-2.2.1 +""" + +import json + +from six.moves import http_client +from six.moves import urllib + +from google.oauth2 import utils + + +_URLENCODED_HEADERS = {"Content-Type": "application/x-www-form-urlencoded"} + + +class Client(utils.OAuthClientAuthHandler): + """Implements the OAuth 2.0 token exchange spec based on + https://tools.ietf.org/html/rfc8693. + """ + + def __init__(self, token_exchange_endpoint, client_authentication=None): + """Initializes an STS client instance. + + Args: + token_exchange_endpoint (str): The token exchange endpoint. + client_authentication (Optional(google.oauth2.oauth2_utils.ClientAuthentication)): + The optional OAuth client authentication credentials if available. + """ + super(Client, self).__init__(client_authentication) + self._token_exchange_endpoint = token_exchange_endpoint + + def _make_request(self, request, headers, request_body): + # Initialize request headers. + request_headers = _URLENCODED_HEADERS.copy() + + # Inject additional headers. + if headers: + for k, v in dict(headers).items(): + request_headers[k] = v + + # Apply OAuth client authentication. + self.apply_client_authentication_options(request_headers, request_body) + + # Execute request. + response = request( + url=self._token_exchange_endpoint, + method="POST", + headers=request_headers, + body=urllib.parse.urlencode(request_body).encode("utf-8"), + ) + + response_body = ( + response.data.decode("utf-8") + if hasattr(response.data, "decode") + else response.data + ) + + # If non-200 response received, translate to OAuthError exception. + if response.status != http_client.OK: + utils.handle_error_response(response_body) + + response_data = json.loads(response_body) + + # Return successful response. + return response_data + + def exchange_token( + self, + request, + grant_type, + subject_token, + subject_token_type, + resource=None, + audience=None, + scopes=None, + requested_token_type=None, + actor_token=None, + actor_token_type=None, + additional_options=None, + additional_headers=None, + ): + """Exchanges the provided token for another type of token based on the + rfc8693 spec. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + grant_type (str): The OAuth 2.0 token exchange grant type. + subject_token (str): The OAuth 2.0 token exchange subject token. + subject_token_type (str): The OAuth 2.0 token exchange subject token type. + resource (Optional[str]): The optional OAuth 2.0 token exchange resource field. + audience (Optional[str]): The optional OAuth 2.0 token exchange audience field. + scopes (Optional[Sequence[str]]): The optional list of scopes to use. + requested_token_type (Optional[str]): The optional OAuth 2.0 token exchange requested + token type. + actor_token (Optional[str]): The optional OAuth 2.0 token exchange actor token. + actor_token_type (Optional[str]): The optional OAuth 2.0 token exchange actor token type. + additional_options (Optional[Mapping[str, str]]): The optional additional + non-standard Google specific options. + additional_headers (Optional[Mapping[str, str]]): The optional additional + headers to pass to the token exchange endpoint. + + Returns: + Mapping[str, str]: The token exchange JSON-decoded response data containing + the requested token and its expiration time. + + Raises: + google.auth.exceptions.OAuthError: If the token endpoint returned + an error. + """ + # Initialize request body. + request_body = { + "grant_type": grant_type, + "resource": resource, + "audience": audience, + "scope": " ".join(scopes or []), + "requested_token_type": requested_token_type, + "subject_token": subject_token, + "subject_token_type": subject_token_type, + "actor_token": actor_token, + "actor_token_type": actor_token_type, + "options": None, + } + # Add additional non-standard options. + if additional_options: + request_body["options"] = urllib.parse.quote(json.dumps(additional_options)) + # Remove empty fields in request body. + for k, v in dict(request_body).items(): + if v is None or v == "": + del request_body[k] + + return self._make_request(request, additional_headers, request_body) + + def refresh_token(self, request, refresh_token): + """Exchanges a refresh token for an access token based on the + RFC6749 spec. + + Args: + request (google.auth.transport.Request): A callable used to make + HTTP requests. + subject_token (str): The OAuth 2.0 refresh token. + """ + + return self._make_request( + request, + None, + {"grant_type": "refresh_token", "refresh_token": refresh_token}, + ) diff --git a/script.module.google-auth-library/lib/google/oauth2/utils.py b/script.module.google-auth-library/lib/google/oauth2/utils.py new file mode 100644 index 000000000..593f03236 --- /dev/null +++ b/script.module.google-auth-library/lib/google/oauth2/utils.py @@ -0,0 +1,171 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""OAuth 2.0 Utilities. + +This module provides implementations for various OAuth 2.0 utilities. +This includes `OAuth error handling`_ and +`Client authentication for OAuth flows`_. + +OAuth error handling +-------------------- +This will define interfaces for handling OAuth related error responses as +stated in `RFC 6749 section 5.2`_. +This will include a common function to convert these HTTP error responses to a +:class:`google.auth.exceptions.OAuthError` exception. + + +Client authentication for OAuth flows +------------------------------------- +We introduce an interface for defining client authentication credentials based +on `RFC 6749 section 2.3.1`_. This will expose the following +capabilities: + + * Ability to support basic authentication via request header. + * Ability to support bearer token authentication via request header. + * Ability to support client ID / secret authentication via request body. + +.. _RFC 6749 section 2.3.1: https://tools.ietf.org/html/rfc6749#section-2.3.1 +.. _RFC 6749 section 5.2: https://tools.ietf.org/html/rfc6749#section-5.2 +""" + +import abc +import base64 +import enum +import json + +import six + +from google.auth import exceptions + + +# OAuth client authentication based on +# https://tools.ietf.org/html/rfc6749#section-2.3. +class ClientAuthType(enum.Enum): + basic = 1 + request_body = 2 + + +class ClientAuthentication(object): + """Defines the client authentication credentials for basic and request-body + types based on https://tools.ietf.org/html/rfc6749#section-2.3.1. + """ + + def __init__(self, client_auth_type, client_id, client_secret=None): + """Instantiates a client authentication object containing the client ID + and secret credentials for basic and response-body auth. + + Args: + client_auth_type (google.oauth2.oauth_utils.ClientAuthType): The + client authentication type. + client_id (str): The client ID. + client_secret (Optional[str]): The client secret. + """ + self.client_auth_type = client_auth_type + self.client_id = client_id + self.client_secret = client_secret + + +@six.add_metaclass(abc.ABCMeta) +class OAuthClientAuthHandler(object): + """Abstract class for handling client authentication in OAuth-based + operations. + """ + + def __init__(self, client_authentication=None): + """Instantiates an OAuth client authentication handler. + + Args: + client_authentication (Optional[google.oauth2.utils.ClientAuthentication]): + The OAuth client authentication credentials if available. + """ + super(OAuthClientAuthHandler, self).__init__() + self._client_authentication = client_authentication + + def apply_client_authentication_options( + self, headers, request_body=None, bearer_token=None + ): + """Applies client authentication on the OAuth request's headers or POST + body. + + Args: + headers (Mapping[str, str]): The HTTP request header. + request_body (Optional[Mapping[str, str]]): The HTTP request body + dictionary. For requests that do not support request body, this + is None and will be ignored. + bearer_token (Optional[str]): The optional bearer token. + """ + # Inject authenticated header. + self._inject_authenticated_headers(headers, bearer_token) + # Inject authenticated request body. + if bearer_token is None: + self._inject_authenticated_request_body(request_body) + + def _inject_authenticated_headers(self, headers, bearer_token=None): + if bearer_token is not None: + headers["Authorization"] = "Bearer %s" % bearer_token + elif ( + self._client_authentication is not None + and self._client_authentication.client_auth_type is ClientAuthType.basic + ): + username = self._client_authentication.client_id + password = self._client_authentication.client_secret or "" + + credentials = base64.b64encode( + ("%s:%s" % (username, password)).encode() + ).decode() + headers["Authorization"] = "Basic %s" % credentials + + def _inject_authenticated_request_body(self, request_body): + if ( + self._client_authentication is not None + and self._client_authentication.client_auth_type + is ClientAuthType.request_body + ): + if request_body is None: + raise exceptions.OAuthError( + "HTTP request does not support request-body" + ) + else: + request_body["client_id"] = self._client_authentication.client_id + request_body["client_secret"] = ( + self._client_authentication.client_secret or "" + ) + + +def handle_error_response(response_body): + """Translates an error response from an OAuth operation into an + OAuthError exception. + + Args: + response_body (str): The decoded response data. + + Raises: + google.auth.exceptions.OAuthError + """ + try: + error_components = [] + error_data = json.loads(response_body) + + error_components.append("Error code {}".format(error_data["error"])) + if "error_description" in error_data: + error_components.append(": {}".format(error_data["error_description"])) + if "error_uri" in error_data: + error_components.append(" - {}".format(error_data["error_uri"])) + error_details = "".join(error_components) + # If no details could be extracted, use the response data. + except (KeyError, ValueError): + error_details = response_body + + raise exceptions.OAuthError(error_details, response_body) From 49d42141d566e47ec3444402c9dfd723c3a43ea7 Mon Sep 17 00:00:00 2001 From: scott967 Date: Tue, 25 Apr 2023 07:33:12 -1000 Subject: [PATCH 031/145] [script.extendedinfo] 6.0.5 (#2420) Delete Tract.py [script.extendedinfo] 6.0.5 update commit from comments fix base64 encode decode --- script.extendedinfo/addon.xml | 7 +- script.extendedinfo/changelog.txt | 37 ++ script.extendedinfo/default.py | 61 +- script.extendedinfo/plugin.py | 48 +- .../resources/kutil131/__init__.py | 27 + .../resources/kutil131/abs_last_fm.py | 12 + .../resources/kutil131/actionhandler.py | 330 ++++++++++ .../resources/kutil131/busyhandler.py | 77 +++ .../resources/kutil131/confirmdialog.py | 61 ++ .../resources/kutil131/dialogbaselist.py | 434 +++++++++++++ .../resources/kutil131/favs.py | 82 +++ .../resources/kutil131/imagetools.py | 114 ++++ .../resources/kutil131/itemlist.py | 202 ++++++ .../resources/kutil131/kodiaddon.py | 139 ++++ .../resources/kutil131/kodijson.py | 134 ++++ .../resources/kutil131/kodilogging.py | 57 ++ .../resources/kutil131/listitem.py | 580 +++++++++++++++++ .../resources/kutil131/localdb.py | 526 +++++++++++++++ .../resources/kutil131/player.py | 64 ++ .../resources/kutil131/selectdialog.py | 65 ++ .../resources/kutil131/slideshow.py | 41 ++ .../resources/kutil131/strptime_patch.py | 80 +++ .../resources/kutil131/t9_search.py | 230 +++++++ .../resources/kutil131/utils.py | 606 ++++++++++++++++++ .../resources/kutil131/windows.py | 59 ++ .../resources/kutil131/youtube.py | 260 ++++++++ .../resource.language.bg_bg/strings.po | 4 + .../resource.language.cs_cz/strings.po | 4 + .../resource.language.en_gb/strings.po | 4 + .../resource.language.es_es/strings.po | 4 + .../resource.language.fr_fr/strings.po | 5 + .../resource.language.he_il/strings.po | 5 + .../resource.language.it_it/strings.po | 4 + .../resource.language.pl_pl/strings.po | 5 + .../lib/{BandsInTown.py => bandsintown.py} | 30 +- .../resources/lib/dialogs/DialogActorInfo.py | 64 -- .../resources/lib/dialogs/dialogactorinfo.py | 100 +++ .../{DialogBaseInfo.py => dialogbaseinfo.py} | 53 +- ...logEpisodeInfo.py => dialogepisodeinfo.py} | 21 +- ...{DialogMovieInfo.py => dialogmovieinfo.py} | 81 ++- ...ialogSeasonInfo.py => dialogseasoninfo.py} | 16 +- ...ialogTVShowInfo.py => dialogtvshowinfo.py} | 35 +- ...{DialogVideoInfo.py => dialogvideoinfo.py} | 18 +- ...{DialogVideoList.py => dialogvideolist.py} | 75 ++- ...logYoutubeList.py => dialogyoutubelist.py} | 18 +- .../resources/lib/{LastFM.py => lastfm.py} | 34 +- script.extendedinfo/resources/lib/omdb.py | 14 +- script.extendedinfo/resources/lib/process.py | 225 ++++--- .../lib/{TheAudioDB.py => theaudiodb.py} | 27 +- .../lib/{TheMovieDB.py => themoviedb.py} | 427 +++++++++--- .../resources/lib/{Trakt.py => trakt.py} | 136 +++- .../{WindowManager.py => windowmanager.py} | 99 +-- script.extendedinfo/resources/settings.xml | 28 + .../script-script.extendedinfo-DialogInfo.xml | 12 +- ...pt-script.extendedinfo-DialogVideoInfo.xml | 14 +- .../script-script.extendedinfo-VideoList.xml | 35 +- ...ript-script.extendedinfo-pictureviewer.xml | 74 +++ .../script-script.extendedinfo-t9search.xml | 166 +++++ .../skins/Default/media/DefaultVideo.png | Bin 0 -> 1200 bytes .../skins/Default/media/flags/audio/opus.png | Bin 0 -> 1351 bytes 60 files changed, 5618 insertions(+), 552 deletions(-) create mode 100644 script.extendedinfo/resources/kutil131/__init__.py create mode 100644 script.extendedinfo/resources/kutil131/abs_last_fm.py create mode 100644 script.extendedinfo/resources/kutil131/actionhandler.py create mode 100644 script.extendedinfo/resources/kutil131/busyhandler.py create mode 100644 script.extendedinfo/resources/kutil131/confirmdialog.py create mode 100644 script.extendedinfo/resources/kutil131/dialogbaselist.py create mode 100644 script.extendedinfo/resources/kutil131/favs.py create mode 100644 script.extendedinfo/resources/kutil131/imagetools.py create mode 100644 script.extendedinfo/resources/kutil131/itemlist.py create mode 100644 script.extendedinfo/resources/kutil131/kodiaddon.py create mode 100644 script.extendedinfo/resources/kutil131/kodijson.py create mode 100644 script.extendedinfo/resources/kutil131/kodilogging.py create mode 100644 script.extendedinfo/resources/kutil131/listitem.py create mode 100644 script.extendedinfo/resources/kutil131/localdb.py create mode 100644 script.extendedinfo/resources/kutil131/player.py create mode 100644 script.extendedinfo/resources/kutil131/selectdialog.py create mode 100644 script.extendedinfo/resources/kutil131/slideshow.py create mode 100644 script.extendedinfo/resources/kutil131/strptime_patch.py create mode 100644 script.extendedinfo/resources/kutil131/t9_search.py create mode 100644 script.extendedinfo/resources/kutil131/utils.py create mode 100644 script.extendedinfo/resources/kutil131/windows.py create mode 100644 script.extendedinfo/resources/kutil131/youtube.py rename script.extendedinfo/resources/lib/{BandsInTown.py => bandsintown.py} (71%) delete mode 100644 script.extendedinfo/resources/lib/dialogs/DialogActorInfo.py create mode 100644 script.extendedinfo/resources/lib/dialogs/dialogactorinfo.py rename script.extendedinfo/resources/lib/dialogs/{DialogBaseInfo.py => dialogbaseinfo.py} (88%) rename script.extendedinfo/resources/lib/dialogs/{DialogEpisodeInfo.py => dialogepisodeinfo.py} (83%) rename script.extendedinfo/resources/lib/dialogs/{DialogMovieInfo.py => dialogmovieinfo.py} (83%) rename script.extendedinfo/resources/lib/dialogs/{DialogSeasonInfo.py => dialogseasoninfo.py} (80%) rename script.extendedinfo/resources/lib/dialogs/{DialogTVShowInfo.py => dialogtvshowinfo.py} (82%) rename script.extendedinfo/resources/lib/dialogs/{DialogVideoInfo.py => dialogvideoinfo.py} (87%) rename script.extendedinfo/resources/lib/dialogs/{DialogVideoList.py => dialogvideolist.py} (90%) rename script.extendedinfo/resources/lib/dialogs/{DialogYoutubeList.py => dialogyoutubelist.py} (95%) rename script.extendedinfo/resources/lib/{LastFM.py => lastfm.py} (89%) rename script.extendedinfo/resources/lib/{TheAudioDB.py => theaudiodb.py} (93%) rename script.extendedinfo/resources/lib/{TheMovieDB.py => themoviedb.py} (77%) rename script.extendedinfo/resources/lib/{Trakt.py => trakt.py} (64%) rename script.extendedinfo/resources/lib/{WindowManager.py => windowmanager.py} (76%) create mode 100644 script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-pictureviewer.xml create mode 100644 script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-t9search.xml create mode 100644 script.extendedinfo/resources/skins/Default/media/DefaultVideo.png create mode 100644 script.extendedinfo/resources/skins/Default/media/flags/audio/opus.png diff --git a/script.extendedinfo/addon.xml b/script.extendedinfo/addon.xml index f1e7d2d52..cd738a793 100644 --- a/script.extendedinfo/addon.xml +++ b/script.extendedinfo/addon.xml @@ -1,10 +1,13 @@ - + - + + + + executable diff --git a/script.extendedinfo/changelog.txt b/script.extendedinfo/changelog.txt index a9298035d..c4cc25072 100644 --- a/script.extendedinfo/changelog.txt +++ b/script.extendedinfo/changelog.txt @@ -1,3 +1,40 @@ +v6.0.5 +- removed support for broken/obsolete addons artwork downloader, couch potato, sick rage, trakt helper +- removed support for youtube-dl +- renamed all files to lowercase +- various code refactoring to current python 3.8 standards +- remove dependency on kutils (incorporate mdoules within addon) +- addon.xml bump ver 6.0.5 +- add menucontrol to skin files +- add dependency on autocompletion (required due to changes in autocompletion library) +- for Kodi 20, use new listitem setter classes/methods +- add "known for" for actor info when tmdb actor search as multiple results +- skin -- rearrange some actor info labels +- default.py switch to f-strings + add/update docstrings + wrap try/finally to clear state property on exception +- plugin.py fix exception V19 ListItem args deprecated +- process.py add/update docstrings + make import paths absolute + wrap try/finally to clear state property on exception +- theaudiodb.py add/update docstrings + remove dead TADB api key (patreon subscription now required) +- themoviedb.py add/update docstrings + add/update PEP 484 type annotations + debug logging message changes + switch to f-strings + fix exception due to key missing in dict (use .get method) +- windowmanager.py make import paths absolute + add/update docstrings + add a "hidebusy" function call to clear stuck busy dialog +- dialogactorinfo.py add/update docstrings + add/update PEP 484 type annotations +- dialogbaseinfo.py add/update docstrings + +- trakt.py add docstrings + fix get_episodes getting more than 20 episodes +- various bug fix/better handling of query results when error returned + v6.0.1 - Move codebase to python3 - Kodi Matrix / Nexus changes diff --git a/script.extendedinfo/default.py b/script.extendedinfo/default.py index 6a74f8664..bdc856f17 100644 --- a/script.extendedinfo/default.py +++ b/script.extendedinfo/default.py @@ -1,31 +1,35 @@ -# -*- coding: utf-8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +"""Module called by Runscript() as executable in Kodi +""" + +from __future__ import annotations import sys -from typing import Dict, List, Optional -from kutils import addon, utils +from resources.kutil131 import addon +from resources.kutil131 import utils from resources.lib import process -def pass_list_to_skin(name, data, prefix="", limit: Optional[int] = False) -> None: +def pass_list_to_skin(name: str, data, prefix: str = "", limit: int = False) -> None: """Set home window properties from the data - SetProperty(prefixname.%d.data_item key,data_item value, home) for 1 to - limit number of items in data + SetProperty(prefixname.%d.data_item key,data_item value, home) for 1 to + limit number of items in data Args: - name (str): Type of data being returned. Used to construct - the skin window property key eg. topratedmovies from invocation - parameter info= - data (kutils.itemlist.ItemList): collection of ListItems + name (str): Type of data being returned derived from runscript info + parameter. Used to construct the skin window property key + eg. topratedmovies from invocation parameter info= + data (kutils.itemlist.ItemList): collection of ListItems (Video or Audio) - prefix (str, optional): Optional prefix for the name. Defaults to "". - limit (int, optional): Number of items to return. Defaults to False. + prefix (str, optional): Optional prefix for the name. May be set + as a param in runscript. Defaults to "". + limit (int, optional): Number of items to return. May be set as a param + in runscript. Defaults to False. Returns: None @@ -33,23 +37,21 @@ def pass_list_to_skin(name, data, prefix="", limit: Optional[int] = False) -> No if data and limit and int(limit) < len(data): data = data[:int(limit)] if not data: - addon.set_global('%s%s.Count' % (prefix, name), '0') + addon.set_global(f'{prefix}{name}.Count', '0') return None for (count, result) in enumerate(data): for (key, value) in result.get_infos().items(): - addon.set_global('%s%s.%i.%s' % - (prefix, name, count + 1, key), str(value)) + addon.set_global(f'{prefix}{name}.{count + 1}.{key}', str(value)) for key, value in result.get("properties", {}).items(): if not value: continue - addon.set_global('%s%s.%i.%s' % - (prefix, name, count + 1, key), str(value)) - addon.set_global('%s%s.Count' % (prefix, name), str(len(data))) + addon.set_global(f'{prefix}{name}.{count + 1}.{key}', str(value)) + addon.set_global(f'{prefix}{name}.Count', str(len(data))) class Main: """When called by Runscript provides all functionality. Multiple instances - of Main can be created. No class attributes or methods are provided + of Main can be created. No class attributes or methods are provided """ def __init__(self): @@ -60,7 +62,7 @@ def __init__(self): If started with no parameters, opens the video list dialog with movies from TMDB retrieved by popularity. """ - utils.log("version {} started".format(addon.VERSION)) + utils.log(f"version {addon.VERSION} started") addon.set_global("extendedinfo_running", "true") self._parse_argv() for info in self.infos: @@ -71,24 +73,27 @@ def __init__(self): limit=self.params.get("limit", 20)) if not self.infos: addon.set_global('infodialogs.active', "true") - from resources.lib.WindowManager import wm - wm.open_video_list() - addon.clear_global('infodialogs.active') + try: + from resources.lib.windowmanager import wm + wm.open_video_list() + finally: + addon.clear_global('infodialogs.active') addon.clear_global("extendedinfo_running") def _parse_argv(self) -> None: """gets arguments passed by Runscript call and passes them as - instance attributes of self.infos (invoked with info=) and self.params + instance attributes of self.infos list (invoked with info=) + and self.params dict """ - self.infos: List[str] = [] - self.params: Dict[str, str] = {"handle": None} + self.infos: list[str] = [] + self.params: dict[str, str] = {"handle": None} for arg in sys.argv[1:]: param = arg.replace('"', '').replace("'", " ") if param.startswith('info='): self.infos.append(param[5:]) else: try: - self.params[param.split("=")[0].lower()] = "=".join( + self.params[param.split('=', maxsplit=1)[0].lower()] = "=".join( param.split("=")[1:]).strip() except Exception: pass diff --git a/script.extendedinfo/plugin.py b/script.extendedinfo/plugin.py index 99514e036..def23c071 100644 --- a/script.extendedinfo/plugin.py +++ b/script.extendedinfo/plugin.py @@ -1,18 +1,19 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +"""Entry point when called as video plugin +""" + import os import sys import routing import xbmcgui import xbmcplugin +from resources.kutil131 import addon -from kutils import addon, utils - +from resources.kutil131 import utils from resources.lib import process MOVIEDB_IMAGE = os.path.join(addon.MEDIA_PATH, "moviedb.png") @@ -22,9 +23,14 @@ class Main: + """Handles plugin list / listitem creation + """ def __init__(self): - utils.log("version %s started" % addon.VERSION) + """Constructor gets actions from args to create the + plugin list + """ + utils.log(f"plugin version {addon.VERSION} started") addon.set_global("extendedinfo_running", "true") self._parse_argv() for info in self.infos: @@ -43,9 +49,13 @@ def _parse_argv(self): if args.startswith("---"): delimiter = "&" args = args[3:] + elif args.find("&---"): + delimiter = "&" else: delimiter = "&&" for arg in args.split(delimiter): + if arg.startswith("---"): + arg = arg[3:] param = arg.replace('"', '').replace("'", " ") if param.startswith('info='): self.infos.append(param[5:]) @@ -59,6 +69,8 @@ def _parse_argv(self): @plugin.route('/tmdb') def tmdb(): + """_sets category options for tmdb + """ xbmcplugin.setPluginCategory(plugin.handle, "TheMovieDB") items = [("incinemamovies", addon.LANG(32042)), ("upcomingmovies", addon.LANG(32043)), @@ -77,9 +89,9 @@ def tmdb(): if addon.setting("tmdb_username") and addon.setting("tmdb_password"): items += login for key, value in items: - li = xbmcgui.ListItem(label=value, - thumbnailImage="DefaultFolder.png") - url = 'plugin://script.extendedinfo?info=%s' % key + li = xbmcgui.ListItem(label=value) + li.setArt({'thumb': 'DefaultFolder.png'}) + url = f'plugin://script.extendedinfo?info={key}' xbmcplugin.addDirectoryItem(handle=plugin.handle, url=url, listitem=li, @@ -90,6 +102,8 @@ def tmdb(): @plugin.route('/trakt') def trakt(): + """sets category options form trakt + """ xbmcplugin.setPluginCategory(plugin.handle, "Trakt") items = [("trendingmovies", addon.LANG(32047)), ("traktpopularmovies", addon.LANG(32044)), @@ -107,9 +121,9 @@ def trakt(): ("airingepisodes", addon.LANG(32028)), ("premiereepisodes", addon.LANG(32029))] for key, value in items: - li = xbmcgui.ListItem(label=value, - thumbnailImage="DefaultFolder.png") - url = 'plugin://script.extendedinfo?info=%s' % key + li = xbmcgui.ListItem(label=value) + li.setArt({'thumb': 'DefaultFolder.png'}) + url = f'plugin://script.extendedinfo?info={key}' xbmcplugin.addDirectoryItem(handle=plugin.handle, url=url, listitem=li, @@ -120,11 +134,15 @@ def trakt(): @plugin.route('/') def root(): + """Sets root plugin folder for TMDB and Trakt + """ + traktitem = xbmcgui.ListItem(label="Trakt") + traktitem.setArt({'thumb': TRAKT_IMAGE}) + tmdbitem = xbmcgui.ListItem(label="TheMovieDB") + tmdbitem.setArt({'thumb': MOVIEDB_IMAGE}) items = [ - (plugin.url_for(trakt), xbmcgui.ListItem(label="Trakt", - thumbnailImage=TRAKT_IMAGE), True), - (plugin.url_for(tmdb), xbmcgui.ListItem(label="TheMovieDB", - thumbnailImage=MOVIEDB_IMAGE), True), + (plugin.url_for(trakt), traktitem, True), + (plugin.url_for(tmdb), tmdbitem, True), ] xbmcplugin.addSortMethod(plugin.handle, xbmcplugin.SORT_METHOD_LABEL) xbmcplugin.addDirectoryItems(plugin.handle, items) diff --git a/script.extendedinfo/resources/kutil131/__init__.py b/script.extendedinfo/resources/kutil131/__init__.py new file mode 100644 index 000000000..e6c907b3e --- /dev/null +++ b/script.extendedinfo/resources/kutil131/__init__.py @@ -0,0 +1,27 @@ +# Copyright (C) 2016 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +from resources.kutil131.kodiaddon import Addon + +addon = Addon() + +import sys + +from resources.kutil131.abs_last_fm import AbstractLastFM +from resources.kutil131.actionhandler import ActionHandler +from resources.kutil131.busyhandler import busyhandler as busy +from resources.kutil131.dialogbaselist import DialogBaseList +from resources.kutil131.itemlist import ItemList +from resources.kutil131.kodilogging import KodiLogHandler, config +from resources.kutil131.listitem import AudioItem, ListItem, VideoItem +from resources.kutil131.localdb import LocalDB +from resources.kutil131.player import VideoPlayer + +# PIL uses numpy if it is available. +# numpy can NOT be loaded multiple times in a sub-interpreter. +# Since numpy is optional, force it to NEVER be imported. + +sys.modules['numpy'] = None + +local_db: LocalDB = LocalDB(last_fm=AbstractLastFM()) +player = VideoPlayer() diff --git a/script.extendedinfo/resources/kutil131/abs_last_fm.py b/script.extendedinfo/resources/kutil131/abs_last_fm.py new file mode 100644 index 000000000..c210db726 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/abs_last_fm.py @@ -0,0 +1,12 @@ +""" +Created on 8/24/21 + +@author: Frank Feuerbacher +""" + + +class AbstractLastFM: + + @classmethod + def get_similar_artists(cls, artist_mbid): + pass \ No newline at end of file diff --git a/script.extendedinfo/resources/kutil131/actionhandler.py b/script.extendedinfo/resources/kutil131/actionhandler.py new file mode 100644 index 000000000..20673be72 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/actionhandler.py @@ -0,0 +1,330 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import xbmcgui + +ACTIONS = {"none": xbmcgui.ACTION_NONE, + "left": xbmcgui.ACTION_MOVE_LEFT, + "right": xbmcgui.ACTION_MOVE_RIGHT, + "up": xbmcgui.ACTION_MOVE_UP, + "down": xbmcgui.ACTION_MOVE_DOWN, + "pageup": xbmcgui.ACTION_PAGE_UP, + "pagedown": xbmcgui.ACTION_PAGE_DOWN, + "select": xbmcgui.ACTION_SELECT_ITEM, + "highlight": xbmcgui.ACTION_HIGHLIGHT_ITEM, + "parentdir": xbmcgui.ACTION_NAV_BACK, # backward compatibility + "parentfolder": xbmcgui.ACTION_PARENT_DIR, + "back": xbmcgui.ACTION_NAV_BACK, + "previousmenu": xbmcgui.ACTION_PREVIOUS_MENU, + "info": xbmcgui.ACTION_SHOW_INFO, + "pause": xbmcgui.ACTION_PAUSE, + "stop": xbmcgui.ACTION_STOP, + "skipnext": xbmcgui.ACTION_NEXT_ITEM, + "skipprevious": xbmcgui.ACTION_PREV_ITEM, + "fullscreen": xbmcgui.ACTION_SHOW_GUI, + "aspectratio": xbmcgui.ACTION_ASPECT_RATIO, + "stepforward": xbmcgui.ACTION_STEP_FORWARD, + "stepback": xbmcgui.ACTION_STEP_BACK, + "bigstepforward": xbmcgui.ACTION_BIG_STEP_FORWARD, + "bigstepback": xbmcgui.ACTION_BIG_STEP_BACK, + "chapterorbigstepforward": xbmcgui.ACTION_CHAPTER_OR_BIG_STEP_FORWARD, + "chapterorbigstepback": xbmcgui.ACTION_CHAPTER_OR_BIG_STEP_BACK, + "osd": xbmcgui.ACTION_SHOW_OSD, + "showsubtitles": xbmcgui.ACTION_SHOW_SUBTITLES, + "nextsubtitle": xbmcgui.ACTION_NEXT_SUBTITLE, + "cyclesubtitle": xbmcgui.ACTION_CYCLE_SUBTITLE, + "playerdebug": xbmcgui.ACTION_PLAYER_DEBUG, + "nextpicture": xbmcgui.ACTION_NEXT_PICTURE, + "previouspicture": xbmcgui.ACTION_PREV_PICTURE, + "zoomout": xbmcgui.ACTION_ZOOM_OUT, + "zoomin": xbmcgui.ACTION_ZOOM_IN, + "playlist": xbmcgui.ACTION_SHOW_PLAYLIST, + "queue": xbmcgui.ACTION_QUEUE_ITEM, + "zoomnormal": xbmcgui.ACTION_ZOOM_LEVEL_NORMAL, + "zoomlevel1": xbmcgui.ACTION_ZOOM_LEVEL_1, + "zoomlevel2": xbmcgui.ACTION_ZOOM_LEVEL_2, + "zoomlevel3": xbmcgui.ACTION_ZOOM_LEVEL_3, + "zoomlevel4": xbmcgui.ACTION_ZOOM_LEVEL_4, + "zoomlevel5": xbmcgui.ACTION_ZOOM_LEVEL_5, + "zoomlevel6": xbmcgui.ACTION_ZOOM_LEVEL_6, + "zoomlevel7": xbmcgui.ACTION_ZOOM_LEVEL_7, + "zoomlevel8": xbmcgui.ACTION_ZOOM_LEVEL_8, + "zoomlevel9": xbmcgui.ACTION_ZOOM_LEVEL_9, + "nextcalibration": xbmcgui.ACTION_CALIBRATE_SWAP_ARROWS, + "resetcalibration": xbmcgui.ACTION_CALIBRATE_RESET, + "analogmove": xbmcgui.ACTION_ANALOG_MOVE, + "rotate": xbmcgui.ACTION_ROTATE_PICTURE_CW, + "rotateccw": xbmcgui.ACTION_ROTATE_PICTURE_CCW, + "close": xbmcgui.ACTION_NAV_BACK, # backwards compatibility + "subtitledelayminus": xbmcgui.ACTION_SUBTITLE_DELAY_MIN, + "subtitledelay": xbmcgui.ACTION_SUBTITLE_DELAY, + "subtitledelayplus": xbmcgui.ACTION_SUBTITLE_DELAY_PLUS, + "audiodelayminus": xbmcgui.ACTION_AUDIO_DELAY_MIN, + "audiodelay": xbmcgui.ACTION_AUDIO_DELAY, + "audiodelayplus": xbmcgui.ACTION_AUDIO_DELAY_PLUS, + "subtitleshiftup": xbmcgui.ACTION_SUBTITLE_VSHIFT_UP, + "subtitleshiftdown": xbmcgui.ACTION_SUBTITLE_VSHIFT_DOWN, + "subtitlealign": xbmcgui.ACTION_SUBTITLE_ALIGN, + "audionextlanguage": xbmcgui.ACTION_AUDIO_NEXT_LANGUAGE, + "verticalshiftup": xbmcgui.ACTION_VSHIFT_UP, + "verticalshiftdown": xbmcgui.ACTION_VSHIFT_DOWN, + "nextresolution": xbmcgui.ACTION_CHANGE_RESOLUTION, + "audiotoggledigital": xbmcgui.ACTION_TOGGLE_DIGITAL_ANALOG, + "number0": xbmcgui.REMOTE_0, + "number1": xbmcgui.REMOTE_1, + "number2": xbmcgui.REMOTE_2, + "number3": xbmcgui.REMOTE_3, + "number4": xbmcgui.REMOTE_4, + "number5": xbmcgui.REMOTE_5, + "number6": xbmcgui.REMOTE_6, + "number7": xbmcgui.REMOTE_7, + "number8": xbmcgui.REMOTE_8, + "number9": xbmcgui.REMOTE_9, + "smallstepback": xbmcgui.ACTION_SMALL_STEP_BACK, + "fastforward": xbmcgui.ACTION_PLAYER_FORWARD, + "rewind": xbmcgui.ACTION_PLAYER_REWIND, + "play": xbmcgui.ACTION_PLAYER_PLAY, + "playpause": xbmcgui.ACTION_PLAYER_PLAYPAUSE, + "switchplayer": xbmcgui.ACTION_SWITCH_PLAYER, + "delete": xbmcgui.ACTION_DELETE_ITEM, + "copy": xbmcgui.ACTION_COPY_ITEM, + "move": xbmcgui.ACTION_MOVE_ITEM, + "screenshot": xbmcgui.ACTION_TAKE_SCREENSHOT, + "rename": xbmcgui.ACTION_RENAME_ITEM, + "togglewatched": xbmcgui.ACTION_TOGGLE_WATCHED, + "scanitem": xbmcgui.ACTION_SCAN_ITEM, + "reloadkeymaps": xbmcgui.ACTION_RELOAD_KEYMAPS, + "volumeup": xbmcgui.ACTION_VOLUME_UP, + "volumedown": xbmcgui.ACTION_VOLUME_DOWN, + "mute": xbmcgui.ACTION_MUTE, + "backspace": xbmcgui.ACTION_BACKSPACE, + "scrollup": xbmcgui.ACTION_SCROLL_UP, + "scrolldown": xbmcgui.ACTION_SCROLL_DOWN, + "analogfastforward": xbmcgui.ACTION_ANALOG_FORWARD, + "analogrewind": xbmcgui.ACTION_ANALOG_REWIND, + "moveitemup": xbmcgui.ACTION_MOVE_ITEM_UP, + "moveitemdown": xbmcgui.ACTION_MOVE_ITEM_DOWN, + "contextmenu": xbmcgui.ACTION_CONTEXT_MENU, + "shift": xbmcgui.ACTION_SHIFT, + "symbols": xbmcgui.ACTION_SYMBOLS, + "cursorleft": xbmcgui.ACTION_CURSOR_LEFT, + "cursorright": xbmcgui.ACTION_CURSOR_RIGHT, + "showtime": xbmcgui.ACTION_SHOW_OSD_TIME, + "analogseekforward": xbmcgui.ACTION_ANALOG_SEEK_FORWARD, + "analogseekback": xbmcgui.ACTION_ANALOG_SEEK_BACK, + "showpreset": xbmcgui.ACTION_VIS_PRESET_SHOW, + "nextpreset": xbmcgui.ACTION_VIS_PRESET_NEXT, + "previouspreset": xbmcgui.ACTION_VIS_PRESET_PREV, + "lockpreset": xbmcgui.ACTION_VIS_PRESET_LOCK, + "randompreset": xbmcgui.ACTION_VIS_PRESET_RANDOM, + "increasevisrating": xbmcgui.ACTION_VIS_RATE_PRESET_PLUS, + "decreasevisrating": xbmcgui.ACTION_VIS_RATE_PRESET_MINUS, + "showvideomenu": xbmcgui.ACTION_SHOW_VIDEOMENU, + "enter": xbmcgui.ACTION_ENTER, + "increaserating": xbmcgui.ACTION_INCREASE_RATING, + "decreaserating": xbmcgui.ACTION_DECREASE_RATING, + "togglefullscreen": xbmcgui.ACTION_TOGGLE_FULLSCREEN, + "nextscene": xbmcgui.ACTION_NEXT_SCENE, + "previousscene": xbmcgui.ACTION_PREV_SCENE, + "nextletter": xbmcgui.ACTION_NEXT_LETTER, + "prevletter": xbmcgui.ACTION_PREV_LETTER, + "jumpsms2": xbmcgui.ACTION_JUMP_SMS2, + "jumpsms3": xbmcgui.ACTION_JUMP_SMS3, + "jumpsms4": xbmcgui.ACTION_JUMP_SMS4, + "jumpsms5": xbmcgui.ACTION_JUMP_SMS5, + "jumpsms6": xbmcgui.ACTION_JUMP_SMS6, + "jumpsms7": xbmcgui.ACTION_JUMP_SMS7, + "jumpsms8": xbmcgui.ACTION_JUMP_SMS8, + "jumpsms9": xbmcgui.ACTION_JUMP_SMS9, + "filter": xbmcgui.ACTION_FILTER, + "filterclear": xbmcgui.ACTION_FILTER_CLEAR, + "filtersms2": xbmcgui.ACTION_FILTER_SMS2, + "filtersms3": xbmcgui.ACTION_FILTER_SMS3, + "filtersms4": xbmcgui.ACTION_FILTER_SMS4, + "filtersms5": xbmcgui.ACTION_FILTER_SMS5, + "filtersms6": xbmcgui.ACTION_FILTER_SMS6, + "filtersms7": xbmcgui.ACTION_FILTER_SMS7, + "filtersms8": xbmcgui.ACTION_FILTER_SMS8, + "filtersms9": xbmcgui.ACTION_FILTER_SMS9, + "firstpage": xbmcgui.ACTION_FIRST_PAGE, + "lastpage": xbmcgui.ACTION_LAST_PAGE, + "menu": xbmcgui.ACTION_MENU, + "guiprofile": xbmcgui.ACTION_GUIPROFILE_BEGIN, + "red": xbmcgui.ACTION_TELETEXT_RED, + "green": xbmcgui.ACTION_TELETEXT_GREEN, + "yellow": xbmcgui.ACTION_TELETEXT_YELLOW, + "blue": xbmcgui.ACTION_TELETEXT_BLUE, + "increasepar": xbmcgui.ACTION_INCREASE_PAR, + "decreasepar": xbmcgui.ACTION_DECREASE_PAR, + "volampup": xbmcgui.ACTION_VOLAMP_UP, + "volampdown": xbmcgui.ACTION_VOLAMP_DOWN, + "createbookmark": xbmcgui.ACTION_CREATE_BOOKMARK, + "createepisodebookmark": xbmcgui.ACTION_CREATE_EPISODE_BOOKMARK, + "settingsreset": xbmcgui.ACTION_SETTINGS_RESET, + "settingslevelchange": xbmcgui.ACTION_SETTINGS_LEVEL_CHANGE, # 3D movie playback/GUI + "stereomode": xbmcgui.ACTION_STEREOMODE_SELECT, # cycle 3D modes, for now an alias for next + "nextstereomode": xbmcgui.ACTION_STEREOMODE_NEXT, + "previousstereomode": xbmcgui.ACTION_STEREOMODE_PREVIOUS, + "togglestereomode": xbmcgui.ACTION_STEREOMODE_TOGGLE, + "stereomodetomono": xbmcgui.ACTION_STEREOMODE_TOMONO, # PVR actions + "channelup": xbmcgui.ACTION_CHANNEL_UP, + "channeldown": xbmcgui.ACTION_CHANNEL_DOWN, + "previouschannelgroup": xbmcgui.ACTION_PREVIOUS_CHANNELGROUP, + "nextchannelgroup": xbmcgui.ACTION_NEXT_CHANNELGROUP, + "playpvr": xbmcgui.ACTION_PVR_PLAY, + "playpvrtv": xbmcgui.ACTION_PVR_PLAY_TV, + "playpvrradio": xbmcgui.ACTION_PVR_PLAY_RADIO, + "record": xbmcgui.ACTION_RECORD, # Mouse actions + "leftclick": xbmcgui.ACTION_MOUSE_LEFT_CLICK, + "rightclick": xbmcgui.ACTION_MOUSE_RIGHT_CLICK, + "middleclick": xbmcgui.ACTION_MOUSE_MIDDLE_CLICK, + "doubleclick": xbmcgui.ACTION_MOUSE_DOUBLE_CLICK, + "longclick": xbmcgui.ACTION_MOUSE_LONG_CLICK, + "wheelup": xbmcgui.ACTION_MOUSE_WHEEL_UP, + "wheeldown": xbmcgui.ACTION_MOUSE_WHEEL_DOWN, + "mousedrag": xbmcgui.ACTION_MOUSE_DRAG, + "mousemove": xbmcgui.ACTION_MOUSE_MOVE, # Touch + "tap": xbmcgui.ACTION_TOUCH_TAP, + "longpress": xbmcgui.ACTION_TOUCH_LONGPRESS, + "pangesture": xbmcgui.ACTION_GESTURE_PAN, + "zoomgesture": xbmcgui.ACTION_GESTURE_ZOOM, + "rotategesture": xbmcgui.ACTION_GESTURE_ROTATE, + "swipeleft": xbmcgui.ACTION_GESTURE_SWIPE_LEFT, + "swiperight": xbmcgui.ACTION_GESTURE_SWIPE_RIGHT, + "swipeup": xbmcgui.ACTION_GESTURE_SWIPE_UP, + "swipedown": xbmcgui.ACTION_GESTURE_SWIPE_DOWN, + + # Do nothing / error action + "noop": xbmcgui.ACTION_NOOP + } + + +class ActionHandler(): + + def __init__(self): + self.clicks = {} + self.focus_actions = {} + self.action_maps = {} + self.context_actions = {} + self.info_actions = {} + self.clicks_by_type = {} + + def click(self, button_ids): + def decorator(f): + if isinstance(button_ids, list): + for button_id in button_ids: + self.clicks[button_id] = f + else: + self.clicks[button_ids] = f + return f + + return decorator + + def click_by_type(self, mediatypes): + def decorator(f): + if isinstance(mediatypes, list): + for mediatype in mediatypes: + self.clicks_by_type[mediatype] = f + else: + self.clicks_by_type[mediatypes] = f + return f + + return decorator + + def context(self, mediatypes): + def decorator(f): + if isinstance(mediatypes, list): + for mediatype in mediatypes: + self.context_actions[mediatype] = f + else: + self.context_actions[mediatypes] = f + return f + + return decorator + + def info(self, mediatypes): + def decorator(f): + if isinstance(mediatypes, list): + for mediatype in mediatypes: + self.info_actions[mediatype] = f + else: + self.info_actions[mediatypes] = f + return f + + return decorator + + def action(self, builtin_name, button_ids): + def decorator(f): + action_id = ACTIONS[builtin_name] + if action_id not in self.action_maps: + self.action_maps[action_id] = {} + if isinstance(button_ids, list): + for button_id in button_ids: + self.action_maps[action_id][button_id] = f + else: + self.action_maps[action_id][button_ids] = f + return f + + return decorator + + def focus(self, button_ids): + def decorator(f): + if isinstance(button_ids, list): + for button_id in button_ids: + self.focus_actions[button_id] = f + else: + self.focus_actions[button_ids] = f + return f + + return decorator + + def serve(self, control_id, wnd): + listitem = self.get_listitem(wnd, control_id) + if listitem: + media_type = listitem.getVideoInfoTag().getMediaType() + if media_type: + action = self.clicks_by_type.get(media_type) + if action: + action(wnd, control_id) + view_function = self.clicks.get(control_id) + if view_function: + return view_function(wnd, control_id) + + def serve_focus(self, control_id, wnd): + view_function = self.focus_actions.get(control_id) + if view_function: + return view_function(wnd, control_id) + + def serve_action(self, action: xbmcgui.Action, control_id, wnd): + action_id = action.getId() + wnd.action_id = action_id + if action_id in [ACTIONS["contextmenu"], ACTIONS["info"]]: + listitem = self.get_listitem(wnd, control_id) + if listitem: + media_type = listitem.getVideoInfoTag().getMediaType() + if media_type: + action = None + if action_id == ACTIONS["contextmenu"]: + action = self.context_actions.get(media_type) + else: + action = self.info_actions.get(media_type) + if action: + action(wnd, control_id) + if action_id not in self.action_maps: + return None + dct = self.action_maps[action_id] + all_func = dct.get("*") + if all_func: + all_func(wnd, control_id) + ctl_func = dct.get(control_id) + if ctl_func: + return ctl_func(wnd, control_id) + + def get_listitem(self, wnd, control_id): + try: + listitem = wnd.getControl(control_id).getSelectedItem() + if not listitem: + listitem = wnd.getListItem(wnd.getCurrentListPosition()) + return listitem + except Exception: + return None diff --git a/script.extendedinfo/resources/kutil131/busyhandler.py b/script.extendedinfo/resources/kutil131/busyhandler.py new file mode 100644 index 000000000..06440077c --- /dev/null +++ b/script.extendedinfo/resources/kutil131/busyhandler.py @@ -0,0 +1,77 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import traceback +from functools import wraps + +import xbmc +import xbmcgui + +from resources.kutil131 import utils + + +class BusyHandler: + """ + Class to deal with busydialog handling + """ + def __init__(self, *args, **kwargs): + self.busy = 0 + self.enabled = True + + def enable(self): + """ + Enables busydialog handling + """ + self.enabled = True + + def disable(self): + """ + Disables busydialog handling + """ + self.enabled = False + + def show_busy(self): + """ + Increase busycounter and open busydialog if needed + """ + if not self.enabled: + return None + if self.busy == 0: + xbmc.executebuiltin('ActivateWindow(busydialognocancel)') + self.busy += 1 + + def set_progress(self, percent): + pass + + def hide_busy(self): + """ + Decrease busycounter and close busydialog if needed + """ + if not self.enabled: + return None + self.busy = max(0, self.busy - 1) + if self.busy == 0: + # utils.log('Closing busydialognoancel') + xbmc.executebuiltin('Dialog.Close(busydialognocancel)') + + def set_busy(self, func): + """ + Decorator to show busy dialog while function is running + """ + @wraps(func) + def decorator(cls, *args, **kwargs): + self.show_busy() + result = None + try: + result = func(cls, *args, **kwargs) + except Exception: + utils.log(traceback.format_exc()) + utils.notify("Error", "please contact add-on author") + finally: + self.hide_busy() + return result + + return decorator + + +busyhandler = BusyHandler() diff --git a/script.extendedinfo/resources/kutil131/confirmdialog.py b/script.extendedinfo/resources/kutil131/confirmdialog.py new file mode 100644 index 000000000..bce52249e --- /dev/null +++ b/script.extendedinfo/resources/kutil131/confirmdialog.py @@ -0,0 +1,61 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import xbmc +import xbmcgui + +from resources.kutil131 import addon + +ID_BUTTON_YES = 11 +ID_BUTTON_NO = 10 +ID_BUTTON_EXTRA = 12 +ID_LABEL_HEADER = 1 +ID_LABEL_TEXT = 9 +ID_PROGRESS = 20 + + +class ConfirmDialog(xbmcgui.WindowXMLDialog): + """ + open yesnodialog, return -1 for cancelled, otherwise index (0-2) + """ + def __init__(self, *args, **kwargs): + xbmcgui.WindowXMLDialog.__init__(self, 'ConfirmDialog.xml', kwargs.get('path', '')) + self.yeslabel = kwargs.get('yeslabel') + self.nolabel = kwargs.get('nolabel') + self.header = kwargs.get('header') + self.text = kwargs.get('text') + self.extrabutton = kwargs.get('extrabutton') + self.index = -1 + + def onInit(self): + self.setFocusId(10) + self.getControl(ID_BUTTON_YES).setLabel(self.yeslabel) + self.getControl(ID_BUTTON_NO).setLabel(self.nolabel) + self.getControl(ID_LABEL_HEADER).setLabel(self.header) + self.getControl(ID_LABEL_TEXT).setText(self.text) + if self.extrabutton: + self.getControl(ID_BUTTON_EXTRA).setVisible(True) + self.getControl(ID_BUTTON_EXTRA).setLabel(self.extrabutton) + else: + self.getControl(ID_BUTTON_EXTRA).setVisible(False) + self.getControl(ID_PROGRESS).setVisible(False) + self.setFocusId(ID_BUTTON_NO) + + def onClick(self, control_id): + self.index = control_id - ID_BUTTON_NO + self.close() + + +def open(header="", text="", yeslabel=addon.LANG(107), nolabel=addon.LANG(106), extrabutton=False, path=""): + """ + open yesnodialog, return -1 for cancelled, otherwise index (0-2) + """ + xbmc.executebuiltin("Dialog.Close(busydialognocancel)") + w = ConfirmDialog('DialogConfirm.xml', path, + yeslabel=yeslabel, + nolabel=nolabel, + header=header, + text=text, + extrabutton=extrabutton) + w.doModal() + return w.index diff --git a/script.extendedinfo/resources/kutil131/dialogbaselist.py b/script.extendedinfo/resources/kutil131/dialogbaselist.py new file mode 100644 index 000000000..a248c3884 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/dialogbaselist.py @@ -0,0 +1,434 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import xbmc +import xbmcgui + +from resources.kutil131 import ActionHandler, addon, busy, utils +from resources.kutil131.t9_search import T9Search + +ch = ActionHandler() + +ID_BUTTON_SEARCH = 6000 +ID_BUTTON_RESETFILTERS = 5005 +ID_BUTTON_PREV_PAGE = 700 +ID_BUTTON_NEXT_PAGE = 600 +ID_BUTTON_TOGGLETYPE = 5007 + + +class DialogBaseList: + viewid = { + 'WALL 3D' : '67', + 'BANNER' : '52', + 'BANNER INFO' : '53', + 'COVERFLOW' : '58', + 'GAMES' : '50', + 'GLASS LIST' : '57', + 'LANDSCAPEX' : '64', + 'LOW LIST' : '55', + 'MID LIST' : '70', + 'MULTI-LIST' : '71', + 'MULTIPLEX' : '61', + 'PANEL' : '62', + 'PHOTOSHOW' : '79', + 'POSTER' : '54', + 'RIGHT LIST' : '59', + 'SETS' : '65', + 'SHELF' : '63', + 'SHELFCASE' : '69', + 'SHOWART' : '60', + 'SHOWCASE' : '66', + 'WALL' : '56', + 'WIDE' : '51', + 'List' : '50', + 'IconWall' : '52', + 'Shift' : '53', + 'InfoWall' : '54', + 'WideList' : '55', + 'Banner' : '501', + 'Fanart' : '502' + } + + + + """ + BaseList for MediaBrowsers (handles filtering, sorting) + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.search_str = kwargs.get('search_str', "") + self.filter_label = kwargs.get("filter_label", "") + self.mode = kwargs.get("mode", "filter") + self.order = kwargs.get('order', "desc") + self.sort = kwargs.get('sort', self.default_sort) + self.filters = [] + for item in kwargs.get('filters', []): + self.add_filter(key=item["type"], + value=item["id"], + label=item["label"], + reset=False) + self.page = 1 + self.listitems = None + self.column = None + self.set_sort(self.sort) + self.last_position = 0 + self.total_pages = 1 + self.total_items = 0 + self.page_token = "" + self.next_page_token = "" + self.prev_page_token = "" + self.listitems = kwargs.get('listitems') + if self.listitems: + self.listitems = self.listitems.create_listitems() + self.total_items = len(self.listitems) + else: + self.update_content(force_update=kwargs.get('force', False)) + + def onInit(self): + super().onInit() + viewtype = addon.setting("viewtype_selection") + self.cur_viewtype = DialogBaseList.viewid.get(xbmc.getInfoLabel('Container.Viewmode')) + if viewtype: + xbmc.executebuiltin("Container.SetViewMode(%s)" % viewtype) + self.update_ui() + if self.total_items > 0: + self.setFocusId(self.getCurrentContainerId()) + self.setCurrentListPosition(self.last_position) + else: + self.setFocusId(ID_BUTTON_SEARCH) + + def onClick(self, control_id): + ch.serve(control_id, self) + + def onAction(self, action: xbmcgui.Action): + ch.serve_action(action, self.getFocusId(), self) + + def onFocus(self, control_id): + if control_id == ID_BUTTON_NEXT_PAGE: + self.go_to_next_page() + elif control_id == ID_BUTTON_PREV_PAGE: + self.go_to_prev_page() + + @property + def sort_key(self): + """ + get key used for sorting + """ + return self.type + + def close(self): + """ + save viewtype and last focusposition + """ + addon.set_setting("viewtype_selection", str(self.getCurrentContainerId())) + self.last_position = self.getCurrentListPosition() + xbmc.executebuiltin("Container.SetViewMode(%s)" % self.cur_viewtype) + super().close() + + def set_sort(self, sort): + """ + set sort method to *sort + """ + self.sort = sort + self.verify_sort() + self.sort_label = self.SORTS[self.sort_key][self.sort] + + def verify_sort(self): + """ + check if sort is valid. If not, change to default. + """ + if self.sort not in [i for i in list(self.SORTS[self.sort_key].keys())]: + self.set_sort(self.default_sort) + + @ch.click(ID_BUTTON_TOGGLETYPE) + def toggle_type(self, control_id): + """ + toggle type + """ + self.filters = [] + self.type = self.TYPES[self.TYPES.index(self.type) - 1] + self.verify_sort() + self.reset() + + @ch.click(ID_BUTTON_RESETFILTERS) + def reset_filters(self, control_id): + """ + reset filters, show selectdialog if filtercount > 1 + """ + if len(self.filters) > 1: + listitems = ["%s: %s" % (f["typelabel"], f["label"]) for f in self.filters] + listitems.append(addon.LANG(32078)) + index = xbmcgui.Dialog().select(heading=addon.LANG(32077), + list=listitems) + if index == -1: + return None + elif index == len(listitems) - 1: + self.filters = [] + else: + del self.filters[index] + else: + self.filters = [] + self.reset() + + @ch.click(ID_BUTTON_SEARCH) + def open_search(self, control_id): + """ + open search dialog, update list with search results + """ + if addon.bool_setting("classic_search"): + result = xbmcgui.Dialog().input(heading=addon.LANG(16017), + type=xbmcgui.INPUT_ALPHANUM) + if result and result > -1: + self.search(result) + else: + T9Search(call=self.search, + start_value="", + history=self.__class__.__name__ + ".search") + if self.total_items > 0: + self.setFocusId(self.getCurrentContainerId()) + + @ch.action("parentdir", "*") + @ch.action("parentfolder", "*") + def previous_menu(self, control_id): + """ + close the currently active dialog + can also get overridden by skinners per control by setting a window prop + """ + onback = self.getProperty("%i_onback" % control_id) + if onback: + xbmc.executebuiltin(onback) + else: + self.close() + + @ch.action("previousmenu", "*") + def exit_script(self, control_id): + """ + completely exit script + """ + self.exit() + + @ch.action("left", "*") + @ch.action("right", "*") + @ch.action("up", "*") + @ch.action("down", "*") + def save_position(self, control_id): + """ + save position for any navigation keypress + """ + self.position = self.getCurrentListPosition() + + @ch.info("video") + # @ch.click_by_type("movie") + def open_video(self, control_id): + self.close() + xbmcgui.Dialog().info(self.FocusedItem(control_id)) + self.doModal() + + def search(self, label): + """ + set search string and update the container + """ + if not label: + return None + self.search_str = label + self.filters = [] + busy.disable() + self.reset("search") + busy.enable() + + def set_filter_label(self): + """ + build filter label for UI based on active filters + """ + filters = [] + for item in self.filters: + filter_label = item["label"].replace("|", " | ").replace(",", " + ") + filters.append("[COLOR FFAAAAAA]%s:[/COLOR] %s" % (item["typelabel"], filter_label)) + self.filter_label: str = " - ".join(filters) + + def update_content(self, force_update=False): + """ + fetch listitems and pagination info based on current state + """ + self.data = self.fetch_data(force=force_update) + if not self.data: + return None + self.listitems = self.data + self.total_pages = self.data.total_pages + self.total_items = self.data.totals + self.next_page_token = self.data.next_page_token + self.prev_page_token = self.data.prev_page_token + + def update_ui(self): + """ + add listitems to list, set focusposition, set window properties + """ + if not self.listitems and self.getFocusId() == self.getCurrentContainerId(): + self.setFocusId(ID_BUTTON_SEARCH) + self.clearList() + if self.listitems: + items = [] + for item in self.listitems: + item.set_label2(self.LABEL2[self.sort](item)) + items.append(item.get_listitem()) + self.addItems(items) + if self.column is not None: + self.setCurrentListPosition(self.column) + # self.setContent(self.listitems.content_type) + self.setProperty("TotalPages", str(self.total_pages)) + self.setProperty("TotalItems", str(self.total_items)) + self.setProperty("CurrentPage", str(self.page)) + self.setProperty("Filter_Label", self.filter_label) + self.setProperty("Sort_Label", self.sort_label) + self.setProperty("ArrowDown", "True" if self.page != self.total_pages else "") + self.setProperty("ArrowUp", "True" if self.page > 1 else "") + self.setProperty("Order_Label", addon.LANG(584 if self.order == "asc" else 585)) + self.setProperty("Type", self.TRANSLATIONS[self.type]) + + def reset(self, mode="filter"): + """ + resets the container to its default mode and updates + """ + self.page = 1 + self.mode = mode + self.verify_sort() + self.update() + + def go_to_next_page(self): + """ + go to the next page (for paginated results) + """ + self.get_column() + if self.page < self.total_pages: + self.page += 1 + self.prev_page_token = self.page_token + self.page_token = self.next_page_token + self.update() + + def go_to_prev_page(self): + """ + go to the previous page (for paginated results) + """ + self.get_column() + if self.page > 1: + self.page -= 1 + self.next_page_token = self.page_token + self.page_token = self.prev_page_token + self.update() + + def get_column(self): + """ + save the column of the currently focused item + """ + col = xbmc.getInfoLabel("Container(%s).Column" % self.getCurrentContainerId()) + self.column = int(col) if col != "" else None + + @busy.set_busy + def update(self, force_update=False): + """ + complete refresh of both content and ui + """ + self.update_content(force_update=force_update) + self.update_ui() + + def choose_sort_method(self, sort_key): + """ + open dialog and let user choose sortmethod + returns True if sorthmethod changed + """ + listitems = list(self.SORTS[sort_key].values()) + sort_strings = list(self.SORTS[sort_key].keys()) + preselect = listitems.index(self.sort_label) if self.sort_label in listitems else -1 + index = xbmcgui.Dialog().select(heading=addon.LANG(32104), + list=listitems, + preselect=preselect) + if index == -1 or listitems[index] == self.sort_label: + return False + self.sort = sort_strings[index] + self.sort_label = listitems[index] + return True + + def choose_filter(self, filter_code, header, options): + """ + open dialog and let user choose filter from *options + filter gets removed in case value is empty + filter_code: filter code from API + options: list of tuples with 2 items each: first is value, second is label + """ + values = [i[0] for i in options] + labels = [i[1] for i in options] + index = xbmcgui.Dialog().select(heading=addon.LANG(header), + list=labels) + if index == -1: + return None + if not values[index]: + self.remove_filter(filter_code) + self.add_filter(key=filter_code, + value=values[index], + label=labels[index]) + + def toggle_filter(self, filter_code): + """ + automatically add / remove filter with *filter_code + """ + index = self.find_filter_position(filter_code) + if index > -1: + del self.filters[index] + else: + pass # add filter... + + def find_filter_position(self, filter_code): + """ + find position of specific filter in filter list + """ + for i, item in enumerate(self.filters): + if item["type"] == filter_code: + return i + return -1 + + def remove_filter(self, filter_code): + """ + remove filter with specific filter_code from filter list + """ + index = self.find_filter_position(filter_code) + if index > -1: + del self.filters[index] + self.reset() + + def add_filter(self, key, value, label, typelabel="", force_overwrite=False, reset=True): + """ + add a filter to the filter list + a filter consists of a key and value (for api call), and label as well as + typelabel for displaying in UI. + *reset updates the container after modifying filters + *force_overwrite is used for filters which do not support ANDing + """ + if not value: + return False + new_filter = {"id": str(value), + "type": key, + "typelabel": typelabel, + "label": label} + if new_filter in self.filters: + return False + index = self.find_filter_position(key) + if index == -1: + self.filters.append(new_filter) + if reset: + self.reset() + return None + if force_overwrite: + self.filters[index]["id"] = str(value) + self.filters[index]["label"] = str(label) + if reset: + self.reset() + return None + self.filters[index]["id"] += ",%s" % value + self.filters[index]["label"] += ",%s" % label + ids = self.filters[index]["id"].split(",") + labels = self.filters[index]["label"].split(",") + self.filters[index]["id"] = ",".join(list(set(ids))) + self.filters[index]["label"] = ",".join(list(set(labels))) + if reset: + self.reset() diff --git a/script.extendedinfo/resources/kutil131/favs.py b/script.extendedinfo/resources/kutil131/favs.py new file mode 100644 index 000000000..ce5946fb6 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/favs.py @@ -0,0 +1,82 @@ +# Copyright (C) 2016 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +from resources.kutil131 import ItemList, ListItem, kodijson, utils + + +def get_favs_by_type(fav_type): + """ + returns dict list containing favourites with type *fav_type + """ + return [fav for fav in get_favs() if fav["type"] == fav_type] + + +def get_fav_path(fav): + """ + get builtin for fav according to type + *fav: dict from JSON API representing a favourite + """ + if fav["type"] == "media": + return "PlayMedia(%s)" % (fav["path"]) + elif fav["type"] == "script": + return "RunScript(%s)" % (fav["path"]) + elif "window" in fav and "windowparameter" in fav: + return "ActivateWindow(%s,%s)" % (fav["window"], fav["windowparameter"]) + else: + utils.log("error parsing favs") + + +def get_favs(): + """ + returns dict list containing favourites + """ + items = ItemList() + data = kodijson.get_favourites() + if "result" not in data or data["result"]["limits"]["total"] == 0: + return [] + for fav in data["result"]["favourites"]: + path = get_fav_path(fav) + item = ListItem(label=fav["title"], + path="plugin://script.extendedinfo/?info=action&&id=" + path) + item.set_artwork({'thumb': fav["thumbnail"]}) + item.set_properties({'type': fav["type"], + 'builtin': path}) + items.append(item) + return items + + +def get_icon_panel(number): + """ + get icon panel with index *number, returns dict list based on skin strings + """ + items = ItemList() + offset = number * 5 - 5 + for i in range(1, 6): + infopanel_path = utils.get_skin_string("IconPanelItem%i.Path" % (i + offset)) + item = ListItem(label=utils.get_skin_string("IconPanelItem%i.Label" % (i + offset)), + path="plugin://script.extendedinfo/?info=action&&id=" + infopanel_path) + item.set_artwork({'thumb': utils.get_skin_string("IconPanelItem%i.Icon" % (i + offset))}) + item.set_properties({'type': utils.get_skin_string("IconPanelItem%i.Type" % (i + offset)), + 'id': "IconPanelitem%i" % (i + offset)}) + items.append(item) + return items + + +def get_addons_by_author(author_name, installed="all"): + """ + get a list of addons from *author_name + *installed: "all", True, False + """ + repo_addons = kodijson.get_addons(installed=installed, + properties=["installed", "author", "name", "thumbnail", "fanart"]) + addons = [item for item in repo_addons if item["author"] == author_name] + items = ItemList() + for item in addons: + path = 'InstallAddon(%s)' % item["id"] + item = ListItem(label=item["name"], + path="plugin://script.extendedinfo/?info=action&&id=" + path) + item.set_artwork({'thumb': item["thumbnail"], + "fanart": item["fanart"]}) + item.set_properties({'installed': item["installed"]}) + items.append(item) + return items diff --git a/script.extendedinfo/resources/kutil131/imagetools.py b/script.extendedinfo/resources/kutil131/imagetools.py new file mode 100644 index 000000000..9027ae336 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/imagetools.py @@ -0,0 +1,114 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import os +import threading +import urllib.parse + +import PIL.Image +import PIL.ImageFilter +import xbmc +import xbmcvfs + +from resources.kutil131 import addon, utils + +THUMBS_CACHE_PATH = utils.translate_path("special://profile/Thumbnails/Video") +IMAGE_PATH = os.path.join(addon.DATA_PATH, "images") + + +def blur(input_img, radius=25): + if not input_img: + return {} + if not xbmcvfs.exists(IMAGE_PATH): + xbmcvfs.mkdir(IMAGE_PATH) + #input_img = utils.translate_path(urllib.parse.unquote(input_img)) + # input_img = input_img.replace("image://video@", "").rstrip("/") not working + #input_img = input_img.rstrip("/") + cachedthumb = xbmc.getCacheThumbName(input_img) + filename = "%s-radius_%i.png" % (cachedthumb, radius) + targetfile = os.path.join(IMAGE_PATH, filename) + vid_cache_file = os.path.join("special://profile/Thumbnails/Video", cachedthumb[0], cachedthumb) + cache_file = os.path.join("special://profile/Thumbnails", cachedthumb[0], cachedthumb[:-4] + ".jpg") + if xbmcvfs.exists(targetfile): + img = PIL.Image.open(targetfile) + return {"ImageFilter": targetfile, + "ImageColor": get_colors(img)} + try: + if xbmcvfs.exists(cache_file): + img = PIL.Image.open(utils.translate_path(cache_file)) + elif xbmcvfs.exists(vid_cache_file): + img = PIL.Image.open(utils.translate_path(vid_cache_file)) + else: + xbmcvfs.copy(input_img, targetfile) + img = PIL.Image.open(targetfile) + img.thumbnail((200, 200), PIL.Image.ANTIALIAS) + imgfilter = MyGaussianBlur(radius=radius) + img = img.convert('RGB').filter(imgfilter) + img.save(targetfile) + except Exception: + utils.log("Could not get image for %s" % input_img) + return {} + return {"ImageFilter": targetfile, + "ImageColor": get_colors(img)} + + +def get_cached_thumb(filename): + if filename.startswith("stack://"): + filename = filename[8:].split(" , ")[0] + cachedthumb = xbmc.getCacheThumbName(filename) + if not filename.endswith("folder.jpg"): + if ".jpg" in filename: + cachedthumb = cachedthumb.replace("tbn", "jpg") + elif ".png" in filename: + cachedthumb = cachedthumb.replace("tbn", "png") + return os.path.join(THUMBS_CACHE_PATH, cachedthumb[0], cachedthumb).replace("/Video", "") + + +def get_colors(img): + width, height = img.size + try: + pixels = img.load() + except Exception: + return "FFF0F0F0" + data = [] + for x in range(width // 2): + data += [pixels[x * 2, y * 2] for y in range(height // 2)] + pix_values = [(x[0], x[1], x[2]) for x in data if 150 < (x[0] + x[1] + x[2]) < 720] + if len(pix_values) == 0: + return "FFF0F0F0" + r_avg = int(sum([i[0] for i in pix_values]) / len(pix_values)) + g_avg = int(sum([i[1] for i in pix_values]) / len(pix_values)) + b_avg = int(sum([i[2] for i in pix_values]) / len(pix_values)) + avg = (r_avg + g_avg + b_avg) / 3 + min_brightness = 170 + if avg < min_brightness: + diff = min_brightness - avg + r_avg = int(min(r_avg + diff, 255)) + g_avg = int(min(g_avg + diff, 255)) + b_avg = int(min(b_avg + diff, 255)) + return f"FF{r_avg:02X}{g_avg:02X}{b_avg:02X}" + + +class FilterImageThread(threading.Thread): + + def __init__(self, image="", radius=25): + super().__init__() + self.image = image + self.radius = radius + self.info = {} + + def run(self): + try: + self.info = blur(self.image, self.radius) + except Exception: + pass + + +class MyGaussianBlur(PIL.ImageFilter.Filter): + name = "GaussianBlur" + + def __init__(self, radius=2): + self.radius = radius + + def filter(self, image): + return image.gaussian_blur(self.radius) diff --git a/script.extendedinfo/resources/kutil131/itemlist.py b/script.extendedinfo/resources/kutil131/itemlist.py new file mode 100644 index 000000000..f77e78574 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/itemlist.py @@ -0,0 +1,202 @@ +# Copyright (C) 2016 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import xbmcplugin + +from resources.kutil131 import addon, utils + +SORTS = {"none": xbmcplugin.SORT_METHOD_NONE, + "unsorted": xbmcplugin.SORT_METHOD_UNSORTED, + "label": xbmcplugin.SORT_METHOD_LABEL, + "label_ignore_the": xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE, + "label_ignore_folders": xbmcplugin.SORT_METHOD_LABEL_IGNORE_FOLDERS, + "date": xbmcplugin.SORT_METHOD_DATE, + "size": xbmcplugin.SORT_METHOD_SIZE, + "file": xbmcplugin.SORT_METHOD_FILE, + "drive_type": xbmcplugin.SORT_METHOD_DRIVE_TYPE, + "tracknum": xbmcplugin.SORT_METHOD_TRACKNUM, + "duration": xbmcplugin.SORT_METHOD_DURATION, + "video_title": xbmcplugin.SORT_METHOD_VIDEO_TITLE, + "title": xbmcplugin.SORT_METHOD_TITLE, + "title_ignore_the": xbmcplugin.SORT_METHOD_TITLE_IGNORE_THE, + "artist": xbmcplugin.SORT_METHOD_ARTIST, + "artist_ignore_the": xbmcplugin.SORT_METHOD_ARTIST_IGNORE_THE, + "album": xbmcplugin.SORT_METHOD_ALBUM, + "album_ignore_the": xbmcplugin.SORT_METHOD_ALBUM_IGNORE_THE, + "genre": xbmcplugin.SORT_METHOD_GENRE, + "year": xbmcplugin.SORT_METHOD_VIDEO_YEAR, + "rating": xbmcplugin.SORT_METHOD_VIDEO_RATING, + "program_count": xbmcplugin.SORT_METHOD_PROGRAM_COUNT, + "playlist_order": xbmcplugin.SORT_METHOD_PLAYLIST_ORDER, + "episode": xbmcplugin.SORT_METHOD_EPISODE, + "sorttitle": xbmcplugin.SORT_METHOD_VIDEO_SORT_TITLE, + "sorttitle_ignore_the": xbmcplugin.SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE, + "productioncode": xbmcplugin.SORT_METHOD_PRODUCTIONCODE, + "song_rating": xbmcplugin.SORT_METHOD_SONG_RATING, + "mpaa": xbmcplugin.SORT_METHOD_MPAA_RATING, + "video_runtime": xbmcplugin.SORT_METHOD_VIDEO_RUNTIME, + "studio": xbmcplugin.SORT_METHOD_STUDIO, + "studio_ignore_the": xbmcplugin.SORT_METHOD_STUDIO_IGNORE_THE, + "bitrate": xbmcplugin.SORT_METHOD_BITRATE, + "listeners": xbmcplugin.SORT_METHOD_LISTENERS, + "country": xbmcplugin.SORT_METHOD_COUNTRY, + "dateadded": xbmcplugin.SORT_METHOD_DATEADDED, + "fullpath": xbmcplugin.SORT_METHOD_FULLPATH, + "lastplayed": xbmcplugin.SORT_METHOD_LASTPLAYED, + "playcount": xbmcplugin.SORT_METHOD_PLAYCOUNT, + "channel": xbmcplugin.SORT_METHOD_CHANNEL, + "date_taken": xbmcplugin.SORT_METHOD_DATE_TAKEN, + "userrating": xbmcplugin.SORT_METHOD_VIDEO_USER_RATING} + + +class ItemList: + + def __init__(self, items=None, content_type: str ="", name="", sorts=None, totals=None, properties=None): + self.name = name + self.content_type: str = content_type + self.totals = totals + self.total_pages = 1 + self._items = items if items else [] + self.sorts = sorts if sorts else [] + self._properties = properties if properties else [] + self.local_first = True + self.sortkey = False + self.next_page_token = None + self.prev_page_token = None + + def __len__(self): + return len(self._items) + + def __iter__(self): + return iter(self._items) + + def __getitem__(self, key): + return self._items[key] + + def __cmp__(self, other): + return len(self) - len(other) + + def __bool__(self): + return len(self._items) > 0 + + def __repr__(self): + return "Itemlist with length %s. Content type: %s" % (len(self._items), self.content_type) + + def __add__(self, other): + return ItemList(items=self._items + list(other.items()), + content_type=self.content_type, + name=self.name, + sorts=self.sorts, + properties=self._properties) + + def __iadd__(self, other): + self._items += list(other.items()) + return self + + def prettify(self): + """ + log a formatted list of all items + """ + for item in self._items: + utils.log(item) + + def items(self): + return self._items + + def append(self, item): + self._items.append(item) + + def remove(self, index): + self._items.remove(index) + + def set_name(self, name): + self.name = name + + def set_content(self, content_type): + self.content_type = content_type + + def set_totals(self, totals): + self.totals = totals + + def set_total_pages(self, total_pages): + self.total_pages = total_pages + + def set_sorts(self, sorts): + self.sorts = sorts + + def set_properties(self, properties): + self._properties = properties + + def update_properties(self, properties): + self._properties.update({k: v for k, v in properties.items() if v}) + + def set_property(self, key, value): + self._properties[key] = value + + def get_property(self, key): + value = self._properties.get(key) + return value if value else "" + + def create_listitems(self): + """ + returns list with xbmcgui listitems + """ + return [item.get_listitem() for item in self._items] if self._items else [] + + def set_plugin_list(self, handle): + """ + populate plugin list with *handle, set sorts and content + """ + # these fixed sortmethods are only temporary + if self.content_type == "tvshows": + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_TITLE) + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_VIDEO_YEAR) + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_VIDEO_RATING) + elif self.content_type == "episodes": + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_TITLE) + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_VIDEO_YEAR) + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_VIDEO_RATING) + elif self.content_type == "movies": + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_TITLE) + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_VIDEO_YEAR) + xbmcplugin.addSortMethod(handle, xbmcplugin.SORT_METHOD_VIDEO_RATING) + for item in self.sorts: + xbmcplugin.addSortMethod(handle, SORTS[item]) + if self.content_type: + xbmcplugin.setContent(handle, self.content_type) + items = [(i.get_path(), i.get_listitem(), i.is_folder()) for i in self._items] + xbmcplugin.addDirectoryItems(handle=handle, + items=items, + totalItems=len(items)) + xbmcplugin.setPluginFanart(handle, addon.FANART) + xbmcplugin.endOfDirectory(handle) + + def sort(self): + """ + sort based on self.sortkey and self.localfirst + """ + self._items = sorted(self._items, + key=lambda k: k.get_info(self.sortkey), + reverse=True) + if self.local_first: + local_items = [i for i in self._items if i.get_info("dbid")] + remote_items = [i for i in self._items if not i.get_info("dbid")] + self._items = local_items + remote_items + + def reduce(self, key="job"): + """ + remove duplicate listitems (based on property "id") and merge their property with key *key + """ + ids = [] + merged_items = [] + for item in self._items: + id_ = item.get_property("id") + if id_ not in ids: + ids.append(id_) + merged_items.append(item) + else: + index = ids.index(id_) + if key in merged_items[index]: + merged_items[index][key] = merged_items[index][key] + " / " + str(item[key]) + self._items = merged_items + return self diff --git a/script.extendedinfo/resources/kutil131/kodiaddon.py b/script.extendedinfo/resources/kutil131/kodiaddon.py new file mode 100644 index 000000000..fe55df6a6 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/kodiaddon.py @@ -0,0 +1,139 @@ +# Copyright (C) 2016 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import base64 +import hashlib +import os +import uuid + +import xbmc +import xbmcaddon +import xbmcgui +import xbmcvfs + +HOME = xbmcgui.Window(10000) + + +class Addon: + """ + Wrapper for xbmcaddon.Addon() + """ + + def __init__(self, *args, **kwargs): + self.addon = xbmcaddon.Addon(*args) + self.ID = self.addon.getAddonInfo('id') + self.ICON = self.addon.getAddonInfo('icon') + self.NAME = self.addon.getAddonInfo('name') + self.FANART = self.addon.getAddonInfo('fanart') + self.AUTHOR = self.addon.getAddonInfo('author') + self.CHANGELOG = self.addon.getAddonInfo('changelog') + self.DESCRIPTION = self.addon.getAddonInfo('description') + self.DISCLAIMER = self.addon.getAddonInfo('disclaimer') + self.VERSION = self.addon.getAddonInfo('version') + self.PATH = self.addon.getAddonInfo('path') + self.PROFILE = self.addon.getAddonInfo('profile') + self.SUMMARY = self.addon.getAddonInfo('summary') + self.TYPE = self.addon.getAddonInfo('type') + self.MEDIA_PATH = os.path.join(self.PATH, "resources", "skins", "Default", "media") + self.DATA_PATH = xbmcvfs.translatePath("special://profile/addon_data/%s" % self.ID) + + def setting(self, setting_name): + """ + get setting with name *setting_name + """ + return self.addon.getSetting(setting_name) + + def set_setting(self, setting_name, string): + """ + set setting with name *setting_name to value *string + """ + self.addon.setSetting(str(setting_name), str(string)) + + def set_password_prompt(self, setting_name): + password = xbmcgui.Dialog().input(self.LANG(12326), option=xbmcgui.ALPHANUM_HIDE_INPUT) + if password: + self.set_password(setting_name, password) + + def set_password(self, setting_name, string): + self.addon.setSetting(setting_name, encode_string(string)) + + def get_password(self, setting_name): + mac = str(uuid.getnode()) + mac_hash = hashlib.md5(mac.encode()).hexdigest() + if not self.addon.getSetting("mac_hash"): + self.addon.setSetting("mac_hash", mac_hash) + elif self.addon.getSetting("mac_hash") != mac_hash: + xbmcgui.Dialog().notification("Error", "MAC id changed. Please enter password again in settings.") + self.addon.setSetting("mac_hash", mac_hash) + return None + setting = self.addon.getSetting(setting_name) + if setting: + return decode_string(setting) + + def bool_setting(self, setting_name): + """ + get bool setting (either True or False) + """ + return self.addon.getSetting(setting_name) == "true" + + def reload_addon(self): + self.addon = xbmcaddon.Addon(self.ID) + + def LANG(self, id_): + return self.addon.getLocalizedString(id_) if 31000 <= id_ <= 33000 else xbmc.getLocalizedString(id_) + + def set_global(self, setting_name: str, setting_value: str) ->None: + """sets xbmc Window SetProperty(setting_name,setting_value,home) + + Args: + setting_name (str): property key + setting_value (str): property value + """ + HOME.setProperty(setting_name, setting_value) + + def get_global(self, setting_name): + return HOME.getProperty(setting_name) + + def clear_global(self, setting_name): + HOME.clearProperty(setting_name) + + def clear_globals(self): + HOME.clearProperties() + + +def encode_string(clear: str) -> str: + """base64 encodes a string + + Args: + clear (str): string to be encoded + + Returns: + str: the url safe base64 encoding as bytes + """ + enc = [] + key = str(uuid.getnode()) + clear_enc = clear.encode() + for i in range(len(clear_enc)): + key_c = key[i % len(key)] + enc_c = chr((clear_enc[i] + ord(key_c)) % 256) + enc.append(enc_c) + return base64.urlsafe_b64encode("".join(enc).encode()).decode() + + +def decode_string(enc: str) -> str: + """return decoded string (encoded with uuid) + + Args: + enc (str): base64 string encoded by encode_string + + Returns: + str: the decoded string + """ + dec = [] + key = str(uuid.getnode()) + enc = base64.urlsafe_b64decode(enc.encode()).decode() + for i in range(len(enc)): + key_c = key[i % len(key)] + dec_c = ((256 + ord(enc[i]) - ord(key_c)) % 256).to_bytes(1, 'little') + dec.append(dec_c) + return bytes.join(b'', dec).decode() diff --git a/script.extendedinfo/resources/kutil131/kodijson.py b/script.extendedinfo/resources/kutil131/kodijson.py new file mode 100644 index 000000000..44233df12 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/kodijson.py @@ -0,0 +1,134 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import json +import xbmc + + +def play_media(media_type, dbid, resume=True): + ''' + Start playback of media item + *media_type: movie, episode, musicvideo, album, song + *dbid: DBID of media to play + *resume: Resume from last position (only movie/episode) + ''' + if media_type in ['movie', 'episode']: + return get_json(method="Player.Open", + params={"item": {"%sid" % media_type: int(dbid)}, "options": {"resume": resume}}) + elif media_type in ['musicvideo', 'album', 'song']: + return get_json(method="Player.Open", + params={"item": {"%sid" % media_type: int(dbid)}}) + + +def get_directory(path, media_type="files"): + """ + get list with items from directory *path. + """ + return get_json(method="Files.GetDirectory", + params={"directory": path, "media": media_type}) + + +def send_text(text, close_keyboard=True): + """ + SendText JSON message + """ + return get_json(method="Input.SendText", + params={"text": text, "done": "true" if close_keyboard else "false"}) + + +def get_artists(properties=None): + """ + return list of artists from database + """ + properties = properties if properties else [] + data = get_json(method="AudioLibrary.GetArtists", + params={"properties": properties}) + if "result" in data and "artists" in data["result"]: + return data["result"]["artists"] + return [] + + +def get_addons(properties=None, installed=True, enabled="all"): + ''' + Get a list of addons + *properties: list of properties + *installed: True, False or "all" + *enabled: True, False or "all" + ''' + params = {"properties": properties if properties else [], + "installed": installed, + "enabled": enabled} + data = get_json(method="Addons.GetAddons", + params=params) + if "result" in data and "addons" in data["result"]: + return data["result"]["addons"] + return [] + + +def get_movies(properties=None): + ''' + Get a list of movies + *properties: list of properties + ''' + properties = properties if properties else [] + data = get_json(method="VideoLibrary.GetMovies", + params={"properties": properties}) + if "result" in data and "movies" in data["result"]: + return data["result"]["movies"] + return [] + + +def get_tvshows(properties=None): + ''' + Get a list of TvShows + *properties: list of properties + ''' + properties = properties if properties else [] + data = get_json(method="VideoLibrary.GetTVShows", + params={"properties": properties}) + if "result" in data and "tvshows" in data["result"]: + return data["result"]["tvshows"] + return [] + + +def set_userrating(media_type, dbid, rating): + ''' + Set the userrating for media items + *media_type: movie, tv or episode + *dbid: DBID of media to get rated + *rating: Actual rating value: 1-10 + ''' + if media_type == "movie": + return get_json(method="VideoLibrary.SetMovieDetails", + params={"movieid": dbid, "userrating": rating}) + elif media_type == "tv": + return get_json(method="VideoLibrary.SetTVShowDetails", + params={"tvshowid": dbid, "userrating": rating}) + elif media_type == "episode": + return get_json(method="VideoLibrary.SetEpisodeDetails", + params={"episodeid": dbid, "userrating": rating}) + + +def get_favourites(): + """ + get list with favourites + """ + return get_json(method="Favourites.GetFavourites", + params={"type": None, "properties": ["path", "thumbnail", "window", "windowparameter"]}) + + +def set_art(media_type, art, dbid): + """ + set artwork via json + """ + return get_json(method="VideoLibrary.Set%sDetails" % media_type, + params={"art": art, + "%sid" % media_type.lower(): int(dbid)}) + + +def get_json(method, params): + """ + communicate with kodi JSON-RPC + """ + json_query = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "%s", "params": %s, "id": 1}' % (method, json.dumps(params))) + return json.loads(json_query) diff --git a/script.extendedinfo/resources/kutil131/kodilogging.py b/script.extendedinfo/resources/kutil131/kodilogging.py new file mode 100644 index 000000000..2f925189d --- /dev/null +++ b/script.extendedinfo/resources/kutil131/kodilogging.py @@ -0,0 +1,57 @@ +# +# Copyright (C) 2015 Thomas Amland +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + + +import logging + +import xbmc +import xbmcaddon + +from resources.kutil131 import addon + + +class KodiLogHandler(logging.StreamHandler): + + def __init__(self): + logging.StreamHandler.__init__(self) + addon_id = xbmcaddon.Addon().getAddonInfo('id') + prefix = b"[%s] " % addon_id + formatter = logging.Formatter(prefix + b'%(name)s: %(message)s') + self.setFormatter(formatter) + + def emit(self, record): + levels = { + logging.CRITICAL: xbmc.LOGFATAL, + logging.ERROR: xbmc.LOGERROR, + logging.WARNING: xbmc.LOGWARNING, + logging.INFO: xbmc.LOGINFO, + logging.DEBUG: xbmc.LOGDEBUG, + logging.NOTSET: xbmc.LOGNONE, + } + if addon.bool_setting('debug'): + try: + xbmc.log(self.format(record), levels[record.levelno]) + except UnicodeEncodeError: + xbmc.log(self.format(record), levels[record.levelno]) + + def flush(self): + pass + +def config(): + logger = logging.getLogger() + logger.addHandler(KodiLogHandler()) + logger.setLevel(logging.DEBUG) diff --git a/script.extendedinfo/resources/kutil131/listitem.py b/script.extendedinfo/resources/kutil131/listitem.py new file mode 100644 index 000000000..b04213398 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/listitem.py @@ -0,0 +1,580 @@ +# Copyright (C) 2016 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +from __future__ import annotations + +import xbmc +import xbmcgui + +from resources.kutil131 import utils + +INFOTAG_DISPATCHER = { + 'genre':'setGenres', + 'country':'setCountries', + 'year':'setYear', + 'episode':'setEpisode', + 'season':'setSeason', + 'sortepisode':'setSortEpisode', + 'sortseason':'setSortSeason', + 'episodeguide':'setEpisodeGuide', + 'showlink':'', + 'top250':'setTop250', + 'setid':'setSetId', + 'tracknumber':'setTrackNumber', + 'rating':'setRating', + 'userrating':'setUserRating', + 'watched':'', + 'playcount':'setPlaycount', + 'overlay':'', + 'cast':'setCast', + 'castandrole':'', + 'director':'setDirectors', + 'mpaa':'setMpaa', + 'plot': 'setPlot', + 'plotoutline':'setPlotOutline', + 'title':'setTitle', + 'originaltitle':'setOriginalTitle', + 'sorttitle':'setSortTitle', + 'duration':'setDuration', + 'studio':'setStudios', + 'tagline':'setTagLine', + 'writer':'setWriters', + 'tvshowtitle':'setTvShowTitle', + 'premiered':'setPremiered', + 'status':'setTvShowStatus', + 'set':'setSet', + 'setoverview':'setSetOverview', + 'tag':'setTags', + 'imdbnumber':'setUniqueID', + 'code':'setProductionCode', + 'aired':'setFirstAired', + 'credits':'', + 'lastplayed':'setLastPlayed', + 'album':'setAlbum', + 'artist':'setArtists', + 'votes':'setVotes', + 'path':'setPath', + 'trailer':'setTrailer', + 'dateadded':'setDateAdded', + 'mediatype':'setMediaType', + 'dbid':'setDbId' + } +KODI_MATRIX: bool = float(xbmc.getInfoLabel('System.BuildVersionCode')[:4]) < 19.9 + +class ListItem: + ICON_OVERLAY_NONE = 0 # No overlay icon + ICON_OVERLAY_RAR = 1 # Compressed *.rar files + ICON_OVERLAY_ZIP = 2 # Compressed *.zip files + ICON_OVERLAY_LOCKED = 3 # Locked files + ICON_OVERLAY_UNWATCHED = 4 # For not watched files + ICON_OVERLAY_WATCHED = 5 # For seen files + ICON_OVERLAY_HD = 6 # Is on hard disk stored + + def __init__(self, label="", label2="", path="", infos=None, properties=None, size="", artwork=None, ratings=None, ids=None): + """ + Kodi listitem, based on built-in datatypes + """ + # + # Define all instance variables + # + self.size = "" + self.videoinfo = [] + self.audioinfo = [] + self.subinfo = [] + self.cast = [] + self.specials = {} + self._is_folder = False + self.type: str = "video" + self.label: str = "" + self.label2 = "" + + self.set_label(label) + self.set_label2(label2) + self.path = path + self._properties = properties if properties else {} + self._artwork = artwork if artwork else {} + self._ratings: dict[str, str] = ratings if ratings else [] + self._ids = ids if ids else {} + self._infos = infos if infos else {} + + def __setitem__(self, key, value): + self._properties[key] = value + + def __getitem__(self, key): + if key in self._properties: + return self._properties[key] + elif key in self._artwork: + return self._artwork[key] + elif key in self._infos: + return self._infos[key] + elif key == "properties": + return self._properties + elif key == "infos": + return self._infos + elif key == "artwork": + return self._artwork + elif key == "label": + return self.label + elif key == "label2": + return self.label2 + elif key == "path": + return self.path + else: + raise KeyError(str(key)) + + def __repr__(self): + return "\n".join(["Label:", self.label, + "Label2:", self.label2, + "InfoLabels:", utils.dump_dict(self._infos), + "Properties:", utils.dump_dict(self._properties), + "Artwork:", utils.dump_dict(self._artwork), + "Specials:", utils.dump_dict(self.specials), + "", ""]) + + def __contains__(self, key): + if key in self._properties: + return True + elif key in self._artwork: + return True + elif key in self._infos: + return True + elif key in ["properties", "infos", "artwork", "label", "label2", "path"]: + return True + + def __delitem__(self, key): + if key in self._properties: + del self._properties[key] + + def get(self, key, fallback=None): + try: + return self.__getitem__(key) + except KeyError: + return fallback + + def update_from_listitem(self, listitem): + if not listitem: + return None + self.set_label(listitem.label) + self.set_label2(listitem.label2) + self.set_size(listitem.size) + self.update_properties(listitem.get_properties()) + self.update_artwork(listitem.get_artwork()) + self.update_infos(listitem.get_infos()) + + def set_label(self, label): + self.label = label + + def set_label2(self, label): + self.label2 = label + + def set_mimetype(self, mimetype): + self.specials["mimetype"] = mimetype + + def fix_at_top(self): + self.specials["specialsort"] = "top" + + def fix_at_bottom(self): + self.specials["specialsort"] = "bottom" + + def set_startoffset(self, value): + self.specials["startoffset"] = value + + def set_totaltime(self, value): + self.specials["totaltime"] = value + + def set_resumetime(self, value): + self.specials["resumetime"] = value + + def set_playable(self, value): + self.specials["isPlayable"] = value + + def is_playable(self): + return bool(self.specials.get("isPlayable")) + + def set_folder(self, value): + self._is_folder = value + + def is_folder(self): + return bool(self._is_folder) + +# playlist_starting_track isspecial item_start isplayable + + def set_size(self, size): + self.size = size + + def set_visible(self, condition): + self.specials["node.visible"] = condition + + def set_target(self, target): + self.specials["node.target"] = target + + def set_infos(self, infos): + self._infos = infos + + def set_artwork(self, artwork): + self._artwork = artwork + + def set_properties(self, properties): + self._properties = properties + + def update_properties(self, properties): + self._properties.update({k: v for k, v in properties.items() if v}) + + def update_artwork(self, artwork): + self._artwork.update({k: v for k, v in artwork.items() if v}) + + def update_infos(self, infos): + self._infos.update({k: v for k, v in infos.items() if v}) + + def set_art(self, key, value): + self._artwork[key] = value + + def set_property(self, key, value): + self._properties[key] = value + + def set_info(self, key, value): + self._infos[key] = value + + def get_path(self): + return self.path + + def get_art(self, key): + value = self._artwork.get(key) + return value if value else "" + + def get_info(self, key): + value = self._infos.get(key) + return value if value else "" + + def get_property(self, key): + value = self._properties.get(key) + return value if value else "" + + def get_artwork(self): + return {k: v for k, v in self._artwork.items() if v} + + def get_infos(self): + return {k: v for k, v in self._infos.items() if v} + + def get_properties(self): + return {k: v for k, v in self._properties.items() if v} + + def get_listitem(self) -> xbmcgui.ListItem: + #listitem: xbmcgui.ListItem + listitem = xbmcgui.ListItem(label=str(self.label) if self.label else "", + label2=str(self.label2) if self.label2 else "", + path=self.path) + props = {k: str(v) for k, v in self._properties.items() if v} + infos = {k.lower(): v for k, v in self._infos.items() if v} + infos["path"] = self.path + if "media_type" in infos: + infos["mediatype"] = infos["media_type"] + infos.pop("media_type") + if "file" in infos: + #infos["path"] = infos["file"] + infos.pop("file") + if "duration" in infos: + props['duration(h)'] = utils.format_time(infos["duration"], "h") + props['duration(m)'] = utils.format_time(infos["duration"], "m") + for key, value in props.items(): + listitem.setProperty(key, str(value)) + for key, value in self.specials.items(): + listitem.setProperty(key, str(value)) + artwork = {k: v for k, v in self._artwork.items() if v} + if artwork: + listitem.setArt(artwork) + if infos: + #Use setInfo for Matrix, Nexus complains so use videoinfo tag setters + if KODI_MATRIX: + listitem.setInfo(self.type, infos) + else: + vinfotag = listitem.getVideoInfoTag() + for k, v in infos.items(): + if k in ['genre','country','director','studio','writer']: v = v.split(' / ') + if k in ['year', 'votes', 'userrating']: v = int(v) + if k in ['file', 'media_type']: continue + getattr(vinfotag, INFOTAG_DISPATCHER[k])(v) + return listitem + + def to_windowprops(self, prefix="", window_id=10000): + window = xbmcgui.Window(window_id) + window.setProperty('%slabel' % (prefix), self.label) + window.setProperty('%slabel2' % (prefix), self.label2) + window.setProperty('%spath' % (prefix), self.path) + dct = utils.merge_dicts(self.get_properties(), + self.get_artwork(), + self.get_infos()) + for k, v in dct.items(): + window.setProperty('%s%s' % (prefix, k), str(v)) + + +class AudioItem(ListItem): + """ + Kodi audio listitem, based on built-in datatypes + """ + props = ["id", + "artist_instrument", + "artist_style", + "artist_mood", + "artist_born", + "artist_formed", + "artist_description", + "artist_genre", + "artist_died", + "artist_disbanded", + "artist_yearsactive", + "artist_born", + "artist_died", + "album_description", + "album_theme", + "album_mood", + "album_style", + "album_type", + "album_label", + "album_artist", + "album_genre", + "album_title", + "album_rating", + "album_userrating", + "album_votes", + "album_releasetype"] + + def __init__(self, *args, **kwargs): + self.type = "music" + super().__init__(*args, **kwargs) + + def from_listitem(self, listitem): + info = listitem.getAudioInfoTag() + self.label = listitem.getLabel() + self.path = info.getPath() + self._infos = {"dbid": info.GetDatabaseId(), + "mediatype": info.GetMediaType(), + "title": info.GetTitle(), + "votes": info.GetVotes(), + "rating": info.GetRating(), + "userrating": info.GetUserRating(), + "file": info.GetFile(), + "comment": info.getComment(), + "lyrics": info.getLyrics(), + "genre": info.getGenre(), + "lastplayed": info.getLastPlayed(), + "listeners": info.getListeners(), + "playcount": info.getPlayCount(), + "year": info.getReleaseDate()} + self._properties = {key: listitem.getProperty(key) for key in self.props} + + def from_infolabels(self): + self.label = xbmc.getInfoLabel("ListItem.Label") + self.path = xbmc.getInfoLabel("ListItem.Path") + self._infos = {"dbid": xbmc.getInfoLabel("ListItem.Label"), + "mediatype": xbmc.getInfoLabel("ListItem.DBType"), + "title": xbmc.getInfoLabel("ListItem.Title"), + "votes": xbmc.getInfoLabel("ListItem.Votes"), + "rating": xbmc.getInfoLabel("ListItem.Rating"), + "userrating": xbmc.getInfoLabel("ListItem.UserRating"), + "file": xbmc.getInfoLabel("ListItem.FileNameAndPath"), + "comment": xbmc.getInfoLabel("ListItem.Comment"), + "lyrics": xbmc.getInfoLabel("ListItem.Lyrics"), + "genre": xbmc.getInfoLabel("ListItem.Genre"), + "lastplayed": xbmc.getInfoLabel("ListItem.Label"), + "listeners": xbmc.getInfoLabel("ListItem.Listeners"), + "playcount": xbmc.getInfoLabel("ListItem.Playcount"), + "year": xbmc.getInfoLabel("ListItem.Year")} + self._properties = {key: xbmc.getInfoLabel("ListItem.Property({}".format(key)) for key in self.props} + + +class VideoItem(ListItem): + """Kodi video listitem, based on built-in datatypes + + Args: + ListItem (class): The Kutils ListItem class + """ + + def __init__(self, *args, **kwargs): + self.type = "video" + super().__init__(*args, **kwargs) + + def __repr__(self): + baseinfo = super().__repr__() + return "\n".join([baseinfo, + "Cast:", utils.dump_dict(self.cast), + "VideoStreams:", utils.dump_dict(self.videoinfo), + "AudioStreams:", utils.dump_dict(self.audioinfo), + "Ratings:", utils.dump_dict(self._ratings), + "Ids:", utils.dump_dict(self._ids), + "Subs:", utils.dump_dict(self.subinfo), + "", ""]) + + def from_listitem(self, listitem: xbmcgui.ListItem): + """ + xbmcgui listitem -> kodi65 listitem + """ + info = listitem.getVideoInfoTag() + self.label = listitem.getLabel() + self.path = info.getPath() + for provider in {"tmdb", "imdb", "trakt"}: + self._ratings[provider] = listitem.getRating(provider) + self._infos = {"dbid": info.getDbId(), + "mediatype": info.getMediaType(), + "plot": info.getPlot(), + "plotoutline": info.getPlotOutline(), + "tvshowtitle": info.getTVShowTitle(), + "title": info.getTitle(), + "votes": info.getVotes(), + "season": info.getSeason(), + "episode": info.getEpisode(), + "rating": info.getRating(), + "userrating": info.getUserRating(), + "pictureurl": info.getPictureURL(), + "cast": info.getCast(), + "file": info.getFile(), + "trailer": info.getTrailer(), + "originaltitle": info.getOriginalTitle(), + "tagline": info.getTagLine(), + "genre": info.getGenre(), + "director": info.getDirector(), + "writer": info.getWritingCredits(), + "lastplayed": info.getLastPlayed(), + "premiered": info.getPremiered(), + "firstaired": info.getFirstAired(), + "playcount": info.getPlayCount(), + "imdbnumber": info.getIMDBNumber(), + "year": info.getYear()} + + def update_from_listitem(self, listitem: ListItem): + if not listitem: + return None + super().update_from_listitem(listitem) + self.set_videoinfos(listitem.videoinfo) + self.set_audioinfos(listitem.audioinfo) + self.set_subinfos(listitem.subinfo) + self.set_cast(listitem.cast) + + def get_listitem(self) -> xbmcgui.ListItem: + listitem = super().get_listitem() + #Use listitem for Matrix, Nexus complains so use videoinfo tag setters + if KODI_MATRIX: + for item in self.videoinfo: + listitem.addStreamInfo("video", item) + for item in self.audioinfo: + listitem.addStreamInfo("audio", item) + for item in self.subinfo: + listitem.addStreamInfo("subtitle", item) + for item in self._ratings: + listitem.setRating(item["type"], item["rating"], item["votes"], item["default"]) + listitem.setUniqueIDs(self._ids) + listitem.setCast(self.cast) + else: + vinfotag = listitem.getVideoInfoTag() + for item in self.videoinfo: + vstream = xbmc.VideoStreamDetail() + for k, v in item.items(): + if k == 'aspect': + vstream.setAspect(v) + elif k == 'codec': + vstream.setCodec(v) + elif k == 'duration': + vstream.setDuration(v) + elif k == 'height': + vstream.setHeight(v) + elif k == 'stereomode': + vstream.setStereoMode(v) + elif k == 'language': + vstream.setLanguage(v) + elif k == 'width': + vstream.setWidth(v) + for item in self.audioinfo: + astream = xbmc.AudioStreamDetail() + for k, v in item.items(): + if k == 'channels': + astream.setChannels(v) + elif k == 'codec': + astream.setCodec(v) + elif k == 'language': + astream.setLanguage(v) + for item in self.subinfo: + substream = xbmc.SubtitleStreamDetail() + for k, v in item.items(): + if k == 'language': + substream.setLanguage(v) + vinfotag.setUniqueIDs(self._ids) + if self.cast: + castlist: list = [] + for actorinfo in self.cast: + actor = xbmc.Actor(actorinfo['name']) + for k, v in actorinfo.items(): + if k == 'role': + actor.setRole(v) + elif k == 'order': + actor.setOrder(v) + elif k == 'thumbnail': + actor.setThumbnail(v) + castlist.append(actor) + # listitem.setCast(self.cast) + vinfotag.setCast(castlist) + return listitem + + def add_videoinfo(self, info): + self.videoinfo.append(info) + + def add_audioinfo(self, info): + self.audioinfo.append(info) + + def add_subinfo(self, info): + self.subinfo.append(info) + + def add_cast(self, value): + self.cast.append(value) + + def set_cast(self, value): + self.cast = value + + def get_cast(self): + return self.cast + + def set_videoinfos(self, infos): + self.videoinfo = infos + + def set_audioinfos(self, infos): + self.audioinfo = infos + + def set_subinfos(self, infos): + self.subinfo = infos + + def get_rating(self, provider): + for item in self._ratings: + if item["provider"] == provider.lower(): + return item + return None + + def get_ratings(self): + return self._ratings + + def add_rating(self, provider, rating, votes=None, default=None): + self._ratings.append({"provider": provider.lower(), + "rating": rating, + "votes": int(votes), + "default": bool(default)}) + + def set_id(self, provider, uid): + self._ids[provider] = uid + + def get_id(self): + return self._ids + + def movie_from_dbid(self, dbid): + from resources.kutil131.localdb import LocalDB + if not dbid: + return None + self.update_from_listitem(LocalDB(last_fm=None).get_movie(dbid)) + + +class GameItem(ListItem): + """ + Kodi game listitem, based on built-in datatypes + """ + + def __init__(self, *args, **kwargs): + self.type = "game" + super().__init__(*args, **kwargs) + diff --git a/script.extendedinfo/resources/kutil131/localdb.py b/script.extendedinfo/resources/kutil131/localdb.py new file mode 100644 index 000000000..527400b7f --- /dev/null +++ b/script.extendedinfo/resources/kutil131/localdb.py @@ -0,0 +1,526 @@ +# Copyright (C) 2016 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import itertools +import json + +from resources.kutil131 import ItemList, VideoItem, addon, kodijson, utils +from resources.kutil131.abs_last_fm import AbstractLastFM + +PLUGIN_BASE = "plugin://script.extendedinfo/?info=" +MOVIE_PROPS = ["title", "genre", "year", "rating", "director", "trailer", + "tagline", "plot", "plotoutline", "originaltitle", "lastplayed", + "playcount", "writer", "studio", "mpaa", "cast", "country", + "imdbnumber", "runtime", "set", "showlink", "streamdetails", + "top250", "votes", "file", "sorttitle", + "resume", "setid", "dateadded", "tag", "art", "userrating", + "ratings", "uniqueid", "premiered"] +TV_PROPS = ["title", "genre", "year", "rating", "plot", + "studio", "mpaa", "cast", "playcount", "episode", + "imdbnumber", "premiered", "votes", "lastplayed", + "file", "originaltitle", + "sorttitle", "episodeguide", "season", "watchedepisodes", + "dateadded", "tag", "art", "userrating", "ratings", "uniqueid", "runtime"] + + +class LocalDB: + + def __init__(self, last_fm: AbstractLastFM, *args, **kwargs): + """ + + :param last_fm: reference to implementation of AbstractLastFM + :param args: + :param kwargs: + """ + self.info = {} + self.artists = [] + self.albums = [] + self.last_fm = last_fm + if last_fm is None: + self.last_fm = AbstractLastFM() + + def get_artists(self): + """ + get list of artists from db (limited metadata) + """ + self.artists = kodijson.get_artists(properties=["musicbrainzartistid", "thumbnail"]) + return self.artists + + def get_similar_artists(self, artist_id): + """ + get list of artists from db which are similar to artist with *artist_id + based on LastFM online data + """ + simi_artists = self.last_fm.get_similar_artists(artist_id) + if simi_artists is None: + utils.log('Last.fm didn\'t return proper response') + return None + if not self.artists: + self.artists = self.get_artists() + artists = ItemList(content_type="artists") + for simi_artist, kodi_artist in itertools.product(simi_artists, self.artists): + if kodi_artist['musicbrainzartistid'] and kodi_artist['musicbrainzartistid'] == simi_artist['mbid']: + artists.append(kodi_artist) + elif kodi_artist['artist'] == simi_artist['name']: + data = kodijson.get_json(method="AudioLibrary.GetArtistDetails", + params={"properties": ["genre", "description", "mood", "style", "born", "died", "formed", "disbanded", "yearsactive", "instrument", "fanart", "thumbnail"], "artistid": kodi_artist['artistid']}) + item = data["result"]["artistdetails"] + artwork = {"thumb": item['thumbnail'], + "fanart": item['fanart']} + artists.append({"label": item['label'], + "artwork": artwork, + "title": item['label'], + "genre": " / ".join(item['genre']), + "artist_description": item['description'], + "userrating": item['userrating'], + "born": item['born'], + "died": item['died'], + "formed": item['formed'], + "disbanded": item['disbanded'], + "yearsactive": " / ".join(item['yearsactive']), + "style": " / ".join(item['style']), + "mood": " / ".join(item['mood']), + "instrument": " / ".join(item['instrument']), + "librarypath": 'musicdb://artists/%s/' % item['artistid']}) + utils.log('%i of %i artists found in last.FM are in Kodi database' % (len(artists), len(simi_artists))) + return artists + + def get_similar_movies(self, dbid): + """ + get list of movies from db which are similar to movie with *dbid + based on metadata-centric ranking + """ + movie = kodijson.get_json(method="VideoLibrary.GetMovieDetails", + params={"properties": ["genre", "director", "country", "year", "mpaa"], "movieid": dbid}) + if "moviedetails" not in movie['result']: + return [] + comp_movie = movie['result']['moviedetails'] + genres = comp_movie['genre'] + data = kodijson.get_json(method="VideoLibrary.GetMovies", + params={"properties": ["genre", "director", "mpaa", "country", "year"], "sort": {"method": "random"}}) + if "movies" not in data['result']: + return [] + quotalist = [] + for item in data['result']['movies']: + item["mediatype"] = "movie" + diff = abs(int(item['year']) - int(comp_movie['year'])) + hit = 0.0 + miss = 0.00001 + quota = 0.0 + for genre in genres: + if genre in item['genre']: + hit += 1.0 + else: + miss += 1.0 + if hit > 0.0: + quota = float(hit) / float(hit + miss) + if genres and item['genre'] and genres[0] == item['genre'][0]: + quota += 0.3 + if diff < 3: + quota += 0.3 + elif diff < 6: + quota += 0.15 + if comp_movie['country'] and item['country'] and comp_movie['country'][0] == item['country'][0]: + quota += 0.4 + if comp_movie['mpaa'] and item['mpaa'] and comp_movie['mpaa'] == item['mpaa']: + quota += 0.4 + if comp_movie['director'] and item['director'] and comp_movie['director'][0] == item['director'][0]: + quota += 0.6 + quotalist.append((quota, item["movieid"])) + quotalist = sorted(quotalist, + key=lambda quota: quota[0], + reverse=True) + movies = ItemList(content_type="movies") + for i, list_movie in enumerate(quotalist): + if comp_movie['movieid'] is not list_movie[1]: + newmovie = self.get_movie(list_movie[1]) + movies.append(newmovie) + if i == 20: + break + return movies + + def get_movies(self, limit=10): + """ + get list of movies with length *limit from db + """ + data = kodijson.get_json(method="VideoLibrary.GetMovies", + params={"properties": MOVIE_PROPS, "limits": {"end": limit}}) + if "result" not in data or "movies" not in data["result"]: + return [] + return ItemList(content_type="movies", + items=[self.handle_movie(item) for item in data["result"]["movies"]]) + + def get_tvshows(self, limit=10): + """ + get list of tvshows with length *limit from db + """ + data = kodijson.get_json(method="VideoLibrary.GetTVShows", + params={"properties": TV_PROPS, "limits": {"end": limit}}) + if "result" not in data or "tvshows" not in data["result"]: + return [] + return ItemList(content_type="movies", + items=[self.handle_tvshow(item) for item in data["result"]["tvshows"]]) + + def handle_movie(self, movie:dict) -> VideoItem: + """ + convert movie data to listitems + """ + trailer = PLUGIN_BASE + "playtrailer&&dbid=%s" % movie['movieid'] + if addon.setting("infodialog_onclick") != "false": + path = PLUGIN_BASE + 'extendedinfo&&dbid=%s' % movie['movieid'] + else: + path = PLUGIN_BASE + 'playmovie&&dbid=%i' % movie['movieid'] + resume = movie['resume'] + if (resume['position'] and resume['total']) > 0: + resumable = "true" + played = int((float(resume['position']) / float(resume['total'])) * 100) + else: + resumable = "false" + played = 0 + db_movie = VideoItem(label=movie.get('label'), + path=path) + db_movie.set_infos({'title': movie.get('label'), + 'dbid': movie['movieid'], + 'file': movie.get('file'), + 'year': movie.get('year'), + 'premiered' : movie.get('premiered'), + 'tagline': movie.get('tagline'), + 'writer': " / ".join(movie['writer']), + 'mediatype': "movie", + 'set': movie.get("set"), + 'playcount': movie.get("playcount"), + 'setid': movie.get("setid"), + 'top250': movie.get("top250"), + 'imdbnumber': movie.get("uniqueid").get("imdb", ""), + 'userrating': movie.get('userrating'), + 'trailer': trailer, + 'rating': round(float(movie['rating']), 1), + 'director': " / ".join(movie.get('director')), + #'writer': " / ".join(movie.get('writer')), + #"tag": " / ".join(movie['tag']), + 'tag': movie.get('tag'), + "genre": " / ".join(movie['genre']), + 'plot': movie.get('plot'), + 'plotoutline': movie.get('plotoutline'), + 'studio': " / ".join(movie.get('studio')), + 'mpaa': movie.get('mpaa'), + 'originaltitle': movie.get('originaltitle')}) + db_movie.set_properties({'imdb_id': movie.get('uniqueid').get('imdb', ''), + 'showlink': " / ".join(movie['showlink']), + 'set': movie.get("set"), + 'setid': movie.get("setid"), + 'percentplayed': played, + 'resume': resumable}) + db_movie.set_artwork(movie['art']) + db_movie.set_videoinfos(movie['streamdetails']["video"]) + db_movie.set_audioinfos(movie['streamdetails']["audio"]) + stream_info = media_streamdetails(movie['file'].lower(), + movie['streamdetails']) + db_movie.update_properties(stream_info) + db_movie.set_cast(movie.get("cast")) + return db_movie + + def handle_tvshow(self, tvshow): + """ + convert tvshow data to listitems + """ + if addon.setting("infodialog_onclick") != "false": + path = PLUGIN_BASE + 'extendedtvinfo&&dbid=%s' % tvshow['tvshowid'] + else: + path = PLUGIN_BASE + 'action&&id=ActivateWindow(videos,videodb://tvshows/titles/%s/,return)' % tvshow['tvshowid'] + db_tvshow = VideoItem(label=tvshow.get("label"), + path=path) + db_tvshow.set_infos({'title': tvshow.get('label'), + 'dbid': tvshow['tvshowid'], + 'genre': " / ".join(tvshow.get('genre')), + 'rating': round(float(tvshow['rating']), 1), + 'mediatype': "tvshow", + 'mpaa': tvshow.get("mpaa"), + 'plot': tvshow.get("plot"), + 'votes': tvshow.get("votes"), + 'studio': " / ".join(tvshow.get('studio')), + 'premiered': tvshow.get("premiered"), + 'playcount': tvshow.get("playcount"), + 'imdbnumber': tvshow.get("imdbnumber"), + 'userrating': tvshow.get("userrating"), + 'duration': tvshow.get("duration"), + # "tag": " / ".join(movie['tag']), + 'year': tvshow.get('year'), + 'originaltitle': tvshow.get('originaltitle')}) + db_tvshow.set_properties({'imdb_id': tvshow.get('imdbnumber'), + 'file': tvshow.get('file'), + 'watchedepisodes': tvshow.get('watchedepisodes'), + 'totalepisodes': tvshow.get('episode')}) + db_tvshow.set_artwork(tvshow['art']) + db_tvshow.set_cast(tvshow.get("cast")) + return db_tvshow + + def get_movie(self, movie_id) -> VideoItem: + """ + get info from db for movie with *movie_id + """ + response = kodijson.get_json(method="VideoLibrary.GetMovieDetails", + params={"properties": MOVIE_PROPS, "movieid": movie_id}) + if "result" in response and "moviedetails" in response["result"]: + return self.handle_movie(response["result"]["moviedetails"]) + return {} + + def get_tvshow(self, tvshow_id): + """ + get info from db for tvshow with *tvshow_id + """ + response = kodijson.get_json(method="VideoLibrary.GetTVShowDetails", + params={"properties": TV_PROPS, "tvshowid": tvshow_id}) + if "result" in response and "tvshowdetails" in response["result"]: + return self.handle_tvshow(response["result"]["tvshowdetails"]) + return {} + + def get_albums(self): + """ + get a list of all albums from db + """ + data = kodijson.get_json(method="AudioLibrary.GetAlbums", + params={"properties": ["title"]}) + if "result" not in data or "albums" not in data['result']: + return [] + return data['result']['albums'] + + def get_compare_info(self, media_type="movie", items=None): + """ + fetches info needed for the locally-available check + Caches some info as window properties. + Hacky, but by far fastest way to cache between sessions + """ + infos = ["ids", "imdbs", "otitles", "titles"] + if not self.info.get(media_type): + self.info[media_type] = {} + dct = self.info[media_type] + # now = time.time() + dct["ids"] = addon.get_global("%s_ids.JSON" % media_type) + if dct["ids"] and dct["ids"] != "[]": + dct["ids"] = json.loads(dct["ids"]) + dct["otitles"] = json.loads(addon.get_global("%s_otitles.JSON" % media_type)) + dct["titles"] = json.loads(addon.get_global("%s_titles.JSON" % media_type)) + dct["imdbs"] = json.loads(addon.get_global("%s_imdbs.JSON" % media_type)) + else: + for info in infos: + dct[info] = [] + for item in items: + dct["ids"].append(item["%sid" % media_type]) + dct["imdbs"].append(item["imdbnumber"]) + dct["otitles"].append(item["originaltitle"].lower()) + dct["titles"].append(item["label"].lower()) + for info in infos: + addon.set_global("%s_%s.JSON" % (media_type, info), json.dumps(dct[info])) + + self.info[media_type] = dct + + def merge_with_local(self, media_type, items, library_first=True, sortkey=False): + """ + merge *items from online sources with local db info (and sort) + works for movies and tvshows + """ + get_list = kodijson.get_movies if media_type == "movie" else kodijson.get_tvshows + self.get_compare_info(media_type, + get_list(["originaltitle", "imdbnumber"])) + local_items = [] + remote_items = [] + info = self.info[media_type] + for item in items: + index = False + imdb_id = item.get_property("imdb_id") + title = item.get_info("title").lower() + otitle = item.get_info("originaltitle").lower() + if "imdb_id" in item.get_properties() and imdb_id in info["imdbs"]: + index = info["imdbs"].index(imdb_id) + elif "title" in item.get_infos() and title in info["titles"]: + index = info["titles"].index(title) + elif "originaltitle" in item.get_infos() and otitle in info["otitles"]: + index = info["otitles"].index(otitle) + if index: + get_info = self.get_movie if media_type == "movie" else self.get_tvshow + local_item = get_info(info["ids"][index]) + if local_item: + try: + diff = abs(int(local_item.get_info("year")) - int(item.get_info("year"))) + if diff > 1: + remote_items.append(item) + continue + except Exception: + pass + item.update_from_listitem(local_item) + if library_first: + local_items.append(item) + continue + remote_items.append(item) + if sortkey: + local_items = sorted(local_items, + key=lambda k: k.get_info(sortkey), + reverse=True) + remote_items = sorted(remote_items, + key=lambda k: k.get_info(sortkey), + reverse=True) + return ItemList(content_type=media_type + "s", + items=local_items + remote_items) + + def compare_album_with_library(self, online_list): + """ + merge *albums from online sources with local db info + """ + if not self.albums: + self.albums = self.get_albums() + for item in online_list: + for local_item in self.albums: + if not item.get_info("title") == local_item["title"]: + continue + data = kodijson.get_json(method="AudioLibrary.getAlbumDetails", + params={"properties": ["thumbnail"], "albumid": local_item["albumid"]}) + album = data["result"]["albumdetails"] + item.set_info("dbid", album["albumid"]) + item.set_path(PLUGIN_BASE + 'playalbum&&dbid=%i' % album['albumid']) + if album["thumbnail"]: + item.update_artwork({"thumb": album["thumbnail"]}) + break + return online_list + + def get_set_name(self, dbid): + """ + get name of set for movie with *dbid + """ + data = kodijson.get_json(method="VideoLibrary.GetMovieDetails", + params={"properties": ["setid"], "movieid": dbid}) + if "result" not in data or "moviedetails" not in data["result"]: + return None + set_dbid = data['result']['moviedetails'].get('setid') + if set_dbid: + data = kodijson.get_json(method="VideoLibrary.GetMovieSetDetails", + params={"setid": set_dbid}) + return data['result']['setdetails'].get('label') + + def get_artist_mbid(self, dbid): + """ + get mbid of artist with *dbid + """ + data = kodijson.get_json(method="MusicLibrary.GetArtistDetails", + params={"properties": ["musicbrainzartistid"], "artistid": dbid}) + mbid = data['result']['artistdetails'].get('musicbrainzartistid') + return mbid if mbid else None + + def get_imdb_id(self, media_type, dbid): + if not dbid: + return None + if media_type == "movie": + data = kodijson.get_json(method="VideoLibrary.GetMovieDetails", + params={"properties": ["uniqueid", "title", "year"], "movieid": int(dbid)}) + if "result" in data and "moviedetails" in data["result"]: + try: + return data['result']['moviedetails']['uniqueid']['imdb'] + except KeyError: + return None + elif media_type == "tvshow": + data = kodijson.get_json(method="VideoLibrary.GetTVShowDetails", + params={"properties": ["uniqueid", "title", "year"], "tvshowid": int(dbid)}) + if "result" in data and "tvshowdetails" in data["result"]: + try: + return data['result']['tvshowdetails']['uniqueid']['imdb'] + except KeyError: + return None + return None + + def get_tmdb_id(self, media_type, dbid): + if not dbid: + return None + if media_type == "movie": + data = kodijson.get_json(method="VideoLibrary.GetMovieDetails", + params={"properties": ["uniqueid", "title", "year"], "movieid": int(dbid)}) + if "result" in data and "moviedetails" in data["result"]: + return data['result']['moviedetails']['uniqueid'].get('tmdb', None) + elif media_type == "tvshow": + data = kodijson.get_json(method="VideoLibrary.GetTVShowDetails", + params={"properties": ["uniqueid", "title", "year"], "tvshowid": int(dbid)}) + if "result" in data and "tvshowdetails" in data["result"]: + return data['result']['tvshowdetails']['uniqueid'].get('tmdb', None) + return None + + def get_tvshow_id_by_episode(self, dbid): + if not dbid: + return None + data = kodijson.get_json(method="VideoLibrary.GetEpisodeDetails", + params={"properties": ["tvshowid"], "episodeid": dbid}) + if "episodedetails" not in data["result"]: + return None + return self.get_imdb_id(media_type="tvshow", + dbid=str(data['result']['episodedetails']['tvshowid'])) + + +def media_streamdetails(filename, streamdetails): + info = {} + video = streamdetails['video'] + audio = streamdetails['audio'] + if video: + # see StreamDetails.cpp + if video[0]['width'] + video[0]['height'] == 0: + info['VideoResolution'] = "" + elif video[0]['width'] <= 720 and video[0]['height'] <= 480: + info['VideoResolution'] = "480" + elif video[0]['width'] <= 768 and video[0]['height'] <= 576: + info['VideoResolution'] = "576" + elif video[0]['width'] <= 960 and video[0]['height'] <= 544: + info['VideoResolution'] = "540" + elif video[0]['width'] <= 1280 and video[0]['height'] <= 720: + info['VideoResolution'] = "720" + elif video[0]['width'] <= 1920 and video[0]['height'] <= 1080: + info['VideoResolution'] = "1080" + elif video[0]['width'] * video[0]['height'] >= 6000000: + info['VideoResolution'] = "4K" + else: + info['videoresolution'] = "" + info['VideoCodec'] = str(video[0]['codec']) + info["VideoAspect"] = select_aspectratio(video[0]['aspect']) + info["VideoHdrType"] = video[0].get('hdrtype', '') + if audio: + info['AudioCodec'] = audio[0]['codec'] + info['AudioChannels'] = audio[0]['channels'] + streams = [] + for i, item in enumerate(audio, start=1): + language = item['language'] + if language in streams or language == "und": + continue + streams.append(language) + streaminfo = {'AudioLanguage.%d' % i: language, + 'AudioCodec.%d' % i: item["codec"], + 'AudioChannels.%d' % i: str(item['channels'])} + info.update(streaminfo) + subs = [] + for i, item in enumerate(streamdetails['subtitle'], start=1): + language = item['language'] + if language in subs or language == "und": + continue + subs.append(language) + info.update({'SubtitleLanguage.%d' % i: language}) + return info + + +def select_aspectratio(aspect): + # see StreamDetails.cpp + aspect = float(aspect) + if aspect < 1.3499: # sqrt(1.33*1.37) + return "1.33" + elif aspect < 1.5080: # sqrt(1.37*1.66) + return "1.37" + elif aspect < 1.7190: # sqrt(1.66*1.78) + return "1.66" + elif aspect < 1.8147: # sqrt(1.78*1.85) + return "1.78" + elif aspect < 2.0174: # sqrt(1.85*2.20) + return "1.85" + elif aspect < 2.2738: # sqrt(2.20*2.35) + return "2.20" + elif aspect < 2.3749: # sqrt(2.35*2.40) + return "2.35" + elif aspect < 2.4739: # sqrt(2.40*2.55) + return "2.40" + elif aspect < 2.6529: # sqrt(2.55*2.76) + return "2.55" + else: + return "2.76" diff --git a/script.extendedinfo/resources/kutil131/player.py b/script.extendedinfo/resources/kutil131/player.py new file mode 100644 index 000000000..9d16a6e60 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/player.py @@ -0,0 +1,64 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import xbmc +import xbmcgui + +from resources.kutil131 import busy, utils + + +class VideoPlayer(xbmc.Player): + + def __init__(self, *args, **kwargs): + super().__init__() + self.stopped = False + self.started = False + + def onPlayBackEnded(self): + self.stopped = True + + def onPlayBackStopped(self): + self.stopped = True + + def onPlayBackError(self): + self.stopped = True + + def onAVStarted(self): + self.started = True + self.stopped = False + + @busy.set_busy + def youtube_info_by_id(self, youtube_id): + vid = utils.get_youtube_info(youtube_id) + if not vid: + return None, None + listitem = xbmcgui.ListItem(label=vid.title) + listitem.setArt({'thumb': vid.thumbnail}) + listitem.setInfo(type='video', + infoLabels={"genre": vid.sourceName, + "plot": vid.description}) + return vid.streamURL(), listitem + + def wait_for_video_end(self): + monitor: xbmc.Monitor = xbmc.Monitor() + while not monitor.waitForAbort(1.0): + if self.stopped: + break + + self.stopped = False + + def wait_for_video_start(self): + """Timer that checks if Youtube can play selected listitem + Hard coded to 15 sec + """ + monitor = xbmc.Monitor() + timeout = 15 + while not monitor.waitForAbort(1.0): #wait 10 sec to see if video starts + if monitor.abortRequested(): + break + timeout += -1 + if self.stopped or self.started: + break + if timeout == 0: + self.stopped = True + break diff --git a/script.extendedinfo/resources/kutil131/selectdialog.py b/script.extendedinfo/resources/kutil131/selectdialog.py new file mode 100644 index 000000000..902a24e9c --- /dev/null +++ b/script.extendedinfo/resources/kutil131/selectdialog.py @@ -0,0 +1,65 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import xbmc +import xbmcgui + +from resources.kutil131 import addon + +C_LABEL_HEADER = 1 +C_LIST_SIMPLE = 3 +C_LIST_DETAIL = 6 +C_BUTTON_GET_MORE = 5 +C_BUTTON_CANCEL = 7 + + +class SelectDialog(xbmcgui.WindowXMLDialog): + + def __init__(self, *args, **kwargs): + xbmcgui.WindowXMLDialog.__init__(self) + self.items = kwargs.get('listing') + self.header = kwargs.get('header') + self.detailed = kwargs.get('detailed') + self.extrabutton = kwargs.get('extrabutton') + self.listitems = [i.get_listitem() for i in self.items] if self.items else [] + self.index = -1 + self.list: xbmcgui.ControlList = None + + def onInit(self): + if not self.listitems: + self.index == -1 + self.close() + self.list: xbmcgui.ControlList = self.getControl(C_LIST_DETAIL) + self.getControl(C_LIST_DETAIL).setVisible(self.detailed) + self.getControl(C_LIST_SIMPLE).setVisible(not self.detailed) + self.getControl(C_BUTTON_GET_MORE).setVisible(bool(self.extrabutton)) + if self.extrabutton: + self.getControl(C_BUTTON_GET_MORE).setLabel(self.extrabutton) + self.getControl(C_LABEL_HEADER).setLabel(self.header) + self.list.addItems(self.listitems) + self.setFocus(self.list) + + def onClick(self, control_id): + if control_id in [C_LIST_SIMPLE, C_LIST_DETAIL]: + self.index = int(self.list.getSelectedPosition()) + self.close() + elif control_id == C_BUTTON_GET_MORE: + self.index = -2 + self.close() + elif control_id == C_BUTTON_CANCEL: + self.close() + + +def open(listitems, header: str, detailed=True, extrabutton=False) -> int: + """ + open selectdialog, return index (-1 for closing, -2 for extra button) + *listitems needs to be an iterable with ListItems (array, ItemList) + """ + xbmc.executebuiltin("Dialog.Close(busydialognocancel)") + w = SelectDialog('DialogSelect.xml', addon.PATH, + listing=listitems, + header=header, + detailed=detailed, + extrabutton=extrabutton) + w.doModal() + return w.index diff --git a/script.extendedinfo/resources/kutil131/slideshow.py b/script.extendedinfo/resources/kutil131/slideshow.py new file mode 100644 index 000000000..38197874b --- /dev/null +++ b/script.extendedinfo/resources/kutil131/slideshow.py @@ -0,0 +1,41 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import os + +import xbmcgui + +from resources.kutil131 import utils + + +class SlideShow(xbmcgui.WindowXMLDialog): + ACTION_PREVIOUS_MENU = [9, 92, 10] + ID_LIST_PICTURES = 5000 + + def __init__(self, *args, **kwargs): + self.images = kwargs.get('listitems') + self.index = kwargs.get('index') + self.image = kwargs.get('image') + self.action = None + + def onInit(self): + super().onInit() + if not self.images: + return None + self.getControl(self.ID_LIST_PICTURES).addItems(utils.create_listitems(self.images)) + self.getControl(self.ID_LIST_PICTURES).selectItem(self.index) + self.setFocusId(self.ID_LIST_PICTURES) + + def onAction(self, action): + if action in self.ACTION_PREVIOUS_MENU: + self.position = self.getControl(self.ID_LIST_PICTURES).getSelectedPosition() + self.close() + + +def open(listitems, index): + slideshow = SlideShow('script-script.extendedinfo-pictureviewer.xml', + os.path.join(os.path.dirname(__file__), "..", ".."), + listitems=listitems, + index=index) + slideshow.doModal() + return slideshow.position diff --git a/script.extendedinfo/resources/kutil131/strptime_patch.py b/script.extendedinfo/resources/kutil131/strptime_patch.py new file mode 100644 index 000000000..17c6c27ce --- /dev/null +++ b/script.extendedinfo/resources/kutil131/strptime_patch.py @@ -0,0 +1,80 @@ +""" +Created on 1/11/22 + +@author: Frank Feuerbacher +""" +import datetime +import time + + +class StripTimePatch: + """ + Contains a work around for a complex bug in datetime.strptime that only + impacts embedded Python, which Kodi uses. For more info on the defect, + see: : https://bugs.python.org/issue27400 + + One option is for you to replace every reference to datetime.strptime to use + strptime_patch here. This is less voodoo, but there is always the possibility + that some library code uses strptime and there will still be potential for + incorrect results or a Kodi crash. + + The other option is to call patch_strptime at your addon's startup. This + will Monkey-Patch striptime with the version here. It is voodoo like, + but that is done a bit in Python. + """ + + @staticmethod + def monkey_patch_strptime(): + # Check if problem exists (don't want to stomp on patch applied earlier) + try: + datetime.datetime.strptime('0', '%H') + except TypeError: + # Globally replace Python's datetime.datetime.strptime with + # the version here. + + datetime.datetime = StripTimePatch.strptime + + @staticmethod + def strptime(date_string: str, date_format: str) -> datetime.datetime: + """ + Monkey-Patch dattime.strptime with time.strptime in order to + work around a known embedded python problem. + + The patch works fairly well, as long as the format does not try + to parse sub-second values. Since Python's datetime.strptime and + time.strptime sit on top of libc's strptime. + + From Python documentation on datetime.strptime + (https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior): + + classmethod datetime.strptime(date_string, format) + + Return a datetime corresponding to date_string, parsed according + to format. + + Using datetime.strptime(date_string, format) is equivalent to: + + datetime(*(time.strptime(date_string, format)[0:6])) + + except when the format includes sub-second components or timezone + offset information, which are supported in datetime.strptime but + are discarded by time.strptime. + + ValueError is raised if the date_string and format can’t be parsed + by time.strptime() or if it returns a value which isn’t a time + tuple. For a complete list of formatting directives, see + strftime() and strptime() Behavior. + + + This Python bug has been around a long time, but not fixed due to + lack of funding for embedded systems. For more info on the defect, + see: : https://bugs.python.org/issue27400 + + :param date_string: + :param date_format: + :return: + """ + result: datetime.datetime + result = datetime.datetime(*(time.strptime(date_string, + date_format)[0:6])) + return result diff --git a/script.extendedinfo/resources/kutil131/t9_search.py b/script.extendedinfo/resources/kutil131/t9_search.py new file mode 100644 index 000000000..66c2d7604 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/t9_search.py @@ -0,0 +1,230 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import ast +import os +import time +from collections import deque +from threading import Timer + +import AutoCompletion +import xbmc +import xbmcgui + +from resources.kutil131 import ActionHandler, addon, utils + +ch = ActionHandler() + +# (1st label, 2nd label) +KEYS = (("1", "ABC1"), + ("2", "DEF2"), + ("3", "GHI3"), + ("4", "JKL4"), + ("5", "MNO5"), + ("6", "PQR6"), + ("7", "STU7"), + ("8", "VWX8"), + ("9", "YZ90"), + ("DEL", "<--"), + (" ", "___"), + ("KEYB", "CLASSIC")) + + +class T9Search: + + def __init__(self, call=None, start_value="", history="Default"): + dialog = T9SearchDialog('script-script.extendedinfo-t9search.xml', + os.path.join(os.path.dirname(__file__), "..", ".."), + call=call, + start_value=start_value, + history=history) + dialog.doModal() + self.search_str = dialog.search_str + + +class T9SearchDialog(xbmcgui.WindowXMLDialog): + """ + T9 Search dialog class.dialog + params for constructor: "call", "start_value", "history" + """ + def __init__(self, *args, **kwargs): + self.callback = kwargs.get("call") + self.search_str = kwargs.get("start_value", "") + self.previous = False + self.prev_time = 0 + self.timer = None + self.color_timer = None + self._closing = False + self.setting_name = kwargs.get("history") + setting_string = addon.setting(self.setting_name) + if self.setting_name and setting_string: + self.last_searches = deque(ast.literal_eval(setting_string), maxlen=10) + else: + self.last_searches = deque(maxlen=10) + + def onInit(self): + self._closing = False + self.get_autocomplete_labels_async() + self.update_search_label_async() + listitems = [] + for i, item in enumerate(KEYS): + li = {"label": "[B]%s[/B]" % item[0], + "label2": item[1], + "key": item[0], + "value": item[1], + "index": str(i) + } + listitems.append(li) + self.getControl(9090).addItems(utils.dict_to_listitems(listitems)) + self.setFocusId(9090) + self.getControl(600).setLabel("[B]%s[/B]_" % self.search_str) + + def onClick(self, control_id): + ch.serve(control_id, self) + + def onAction(self, action): + ch.serve_action(action, self.getFocusId(), self) + + @ch.click(9090) + def panel_click(self, control_id): + listitem = self.getControl(control_id).getSelectedItem() + self.set_t9_letter(letters=listitem.getProperty("value"), + number=listitem.getProperty("key"), + button=int(listitem.getProperty("index"))) + + @ch.click(9091) + def set_autocomplete(self, control_id): + listitem = self.getControl(control_id).getSelectedItem() + self.search_str = listitem.getLabel() + self.getControl(600).setLabel("[B]%s[/B]_" % self.search_str) + self.get_autocomplete_labels_async() + if self.timer: + self.timer.cancel() + self.timer = Timer(0.0, self.search, (self.search_str,)) + self.timer.start() + + @ch.action("parentdir", "*") + @ch.action("parentfolder", "*") + @ch.action("previousmenu", "*") + def close_dialog(self, control_id): + """ + save autocompletion and close dialog + """ + self._closing = True + self.save_autocomplete() + self.close() + + @ch.action("number0", "*") + def set_0(self, control_id): + """ + deal with 0 action (either via gui or via remotekeys) + """ + listitem = self.getControl(control_id).getListItem(10) + self.set_t9_letter(letters=listitem.getProperty("value"), + number=listitem.getProperty("key"), + button=int(listitem.getProperty("index"))) + + @ch.action("number1", "*") + @ch.action("number2", "*") + @ch.action("number3", "*") + @ch.action("number4", "*") + @ch.action("number5", "*") + @ch.action("number6", "*") + @ch.action("number7", "*") + @ch.action("number8", "*") + @ch.action("number9", "*") + def t_9_button_click(self, control_id): + """ + deal with number actions (either via gui or via remotekeys) + """ + item_id = self.action_id - xbmcgui.REMOTE_1 + listitem = self.getControl(control_id).getListItem(item_id) + self.set_t9_letter(letters=listitem.getProperty("value"), + number=listitem.getProperty("key"), + button=int(listitem.getProperty("index"))) + + @utils.run_async + def update_search_label_async(self): + + monitor: xbmc.Monitor = xbmc.Monitor() + while not monitor.waitForAbort(1.0): + if self._closing: + break + + # TODO: Blink every second (probably a better way to do this, like animation) + if int(time.time()) % 2 == 0: + self.getControl(600).setLabel("[B]%s[/B]_" % self.search_str) + else: + self.getControl(600).setLabel("[B]%s[/B][COLOR 00FFFFFF]_[/COLOR]" % self.search_str) + + @utils.run_async + def get_autocomplete_labels_async(self): + self.getControl(9091).reset() + if self.search_str: + listitems = AutoCompletion.get_autocomplete_items(self.search_str) + else: + listitems = list(self.last_searches) + self.getControl(9091).addItems(utils.dict_to_listitems(listitems)) + + def save_autocomplete(self): + """ + save last searches + """ + if not self.search_str: + return None + listitem = {"label": self.search_str} + if listitem in self.last_searches: + self.last_searches.remove(listitem) + self.last_searches.appendleft(listitem) + addon.set_setting(self.setting_name, str(list(self.last_searches))) + + def set_t9_letter(self, letters, number, button): + now = time.time() + time_diff = now - self.prev_time + if number == "DEL": + self.search_str = self.search_str[:-1] + elif number == " ": + if self.search_str: + self.search_str += " " + elif number == "KEYB": + self.use_classic_search() + elif self.previous != letters or time_diff >= 1: + self.prev_time = now + self.previous = letters + self.search_str += letters[0] + self.color_labels(0, letters, button) + elif time_diff < 1: + if self.color_timer: + self.color_timer.cancel() + self.prev_time = now + idx = (letters.index(self.search_str[-1]) + 1) % len(letters) + self.search_str = self.search_str[:-1] + letters[idx] + self.color_labels(idx, letters, button) + if self.timer: + self.timer.cancel() + self.timer = Timer(1.0, self.search, (self.search_str,)) + self.timer.start() + self.getControl(600).setLabel("[B]%s[/B]_" % self.search_str) + self.get_autocomplete_labels_async() + + def use_classic_search(self): + """ + open classic keyboard dialog and call callback when result is valid + """ + self.close() + result = xbmcgui.Dialog().input(heading=addon.LANG(16017), + type=xbmcgui.INPUT_ALPHANUM) + if result and result > -1: + self.search_str = result + self.callback(self.search_str) + self.save_autocomplete() + + def search(self, search_str): + self.callback(search_str) + + def color_labels(self, index, letters, button): + letter = letters[index] + label = "[COLOR=FFFF3333]%s[/COLOR]" % letter + self.getControl(9090).getListItem(button).setLabel2(letters.replace(letter, label)) + self.color_timer = Timer(1.0, utils.reset_color, (self.getControl(9090).getListItem(button),)) + self.color_timer.start() diff --git a/script.extendedinfo/resources/kutil131/utils.py b/script.extendedinfo/resources/kutil131/utils.py new file mode 100644 index 000000000..45cff0fd8 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/utils.py @@ -0,0 +1,606 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details +import datetime +import hashlib +import json +import os +import re +import sys +import threading +import time +import traceback +import urllib.error +import urllib.parse +import urllib.request +from functools import wraps +from io import StringIO + +import requests +import xbmc +import xbmcgui +import xbmcvfs + +#import YDStreamExtractor +from resources.kutil131 import addon + + +def youtube_info_by_id(youtube_id): + #vid = get_youtube_info(youtube_id) + vid = None #added + if not vid: + return None, None + url = vid.streamURL() + listitem = xbmcgui.ListItem(label=vid.title, path=url) + listitem.setArt({'thumb': vid.thumbnail}) + listitem.setInfo(type='video', + infoLabels={"genre": vid.sourceName, + "path": url, + "plot": vid.description}) + listitem.setProperty("isPlayable", "true") + return url, listitem + + +#def get_youtube_info(youtube_id): +# return YDStreamExtractor.getVideoInfo(youtube_id, +# quality=1) + + +def log(*args): + for arg in args: + message = '%s: %s' % (addon.ID, arg) + xbmc.log(msg=message, + level=xbmc.LOGDEBUG) + + +def dump_all_threads(delay: float = None) -> None: + """ + Dumps all Python stacks, including those in other plugins + + :param delay: + :return: + """ + if delay is None or delay == 0: + _dump_all_threads() + else: + dump_threads = threading.Timer(delay, _dump_all_threads) + dump_threads.setName('dump_threads') + dump_threads.start() + + +def _dump_all_threads() -> None: + """ + Worker method that dumps all threads. + + :return: + """ + addon_prefix = f'{addon.ID}/' + xbmc.log('dump_all_threads', xbmc.LOGDEBUG) + sio = StringIO() + sio.write('\n*** STACKTRACE - START ***\n\n') + code = [] + # Monitor.dump_wait_counts() + # for threadId, stack in sys._current_frames().items(): + for th in threading.enumerate(): + sio.write(f'\n# ThreadID: {th.name} Daemon: {th.isDaemon()}\n\n') + stack = sys._current_frames().get(th.ident, None) + if stack is not None: + traceback.print_stack(stack, file=sio) + + string_buffer: str = sio.getvalue() + '\n*** STACKTRACE - END ***\n' + sio.close() + msg = addon.ID + ' : dump_all_threads' + xbmc.log(msg, xbmc.LOGDEBUG) + xbmc.log(string_buffer, xbmc.LOGDEBUG) + + ''' + try: + dump_path = Constants.FRONTEND_DATA_PATH + '/stack_dump' + + dump_file = io.open(dump_path, mode='at', buffering=1, newline=None, + encoding='ascii') + + faulthandler.dump_traceback(file=dump_file, all_threads=True) + except Exception as e: + pass + ''' + + +def format_seconds(seconds): + if not seconds: + return None + hours, remainder = divmod(seconds, 3600) + minutes, seconds = divmod(remainder, 60) + return '%02d:%02d:%02d' % (hours, minutes, seconds) + + +def dump_dict(dct): + return json.dumps(dct, + ensure_ascii=False, + sort_keys=True, + indent=4, + separators=(',', ': ')) + + +def pp(string): + """ + prettyprint json + """ + log(dump_dict(string)) + + +def dictfind(lst, key, value): + """ + searches through a list of dicts, returns dict where dict[key] = value + """ + for i, dic in enumerate(lst): + if dic[key] == value: + return dic + return "" + + +def merge_dicts(*dict_args): + ''' + Given any number of dicts, shallow copy and merge into a new dict, + precedence goes to key value pairs in latter dicts. + ''' + result = {} + for dictionary in dict_args: + result.update(dictionary) + return result + + +def check_version(): + """ + check version, open TextViewer if update detected + """ + pass + # if not addon.setting("changelog_version") == addon.VERSION: + # xbmcgui.Dialog().textviewer(heading=addon.LANG(24036), + # text=read_from_file(addon.CHANGELOG, True)) + # addon.set_setting("changelog_version", addon.VERSION) + + +def get_skin_string(name): + """ + get String with name *name + """ + return xbmc.getInfoLabel("Skin.String(%s)" % name) + + +def set_skin_string(name, value): + """ + Set String *name to value *value + """ + xbmc.executebuiltin("Skin.SetString(%s, %s)" % (name, value)) + + +def run_async(func): + """ + Decorator to run a function in a separate thread + """ + @wraps(func) + def async_func(*args, **kwargs): + func_hl = threading.Thread(target=func, + args=args, + kwargs=kwargs) + func_hl.start() + return func_hl + + return async_func + + +def contextmenu(options): + """ + pass list of tuples (index, label), get index + """ + index = xbmcgui.Dialog().contextmenu(list=[i[1] for i in options]) + if index > -1: + return [i[0] for i in options][index] + + +def extract_youtube_id(raw_string): + """ + get youtube video id if from youtube URL + """ + vid_ids = None + if raw_string and 'youtube.com/v' in raw_string: + vid_ids = re.findall('http://www.youtube.com/v/(.{11})\??', raw_string, re.DOTALL) + elif raw_string and 'youtube.com/watch' in raw_string: + vid_ids = re.findall('youtube.com/watch\?v=(.{11})\??', raw_string, re.DOTALL) + if vid_ids: + return vid_ids[0] + else: + return "" + + +# def download_video(youtube_id): +# """ +# download youtube video with id *youtube_id +# """ +# vid = YDStreamExtractor.getVideoInfo(youtube_id, +# quality=1) +# YDStreamExtractor.handleDownload(vid) + + +def notify(header="", message="", icon=addon.ICON, time=5000, sound=True): + """ + show kodi notification dialog + """ + xbmcgui.Dialog().notification(heading=header, + message=message, + icon=icon, + time=time, + sound=sound) + + +def millify(n): + """ + make large numbers human-readable, return string + """ + millnames = [' ', ',000', ' ' + addon.LANG(32000), ' ' + addon.LANG(32001), ' ' + addon.LANG(32002)] + if not n or n <= 100: + return "" + n = float(n) + char_count = len(str(n)) + millidx = int(char_count / 3) - 1 + if millidx == 3 or char_count == 9: + return '%.2f%s' % (n / 10 ** (3 * millidx), millnames[millidx]) + else: + return '%.0f%s' % (n / 10 ** (3 * millidx), millnames[millidx]) + + +def get_year(year_string): + """ + return last 4 chars of string + """ + return year_string[:4] if year_string else "" + + +def format_time(time:int, time_format=None): + """ + get formatted time + time (int): duration in secs + time_format = h, m or None + """ + try: + intTime = int(time) + except Exception: + return time + #hour = str(intTime / 60) + #minute = str(intTime % 60).zfill(2) + minute, second = divmod(time, 60) + hour, minute = divmod(minute, 60) + if time_format == "h": + return str(hour) + elif time_format == "m": + return str(minute) + elif time_format == 's': + return str(second) + elif intTime >= 3600: + return hour + " h " + minute + " min" + else: + return minute + " min" + + +def input_userrating(preselect=-1): + """ + opens selectdialog and returns chosen userrating. + """ + index = xbmcgui.Dialog().select(heading=addon.LANG(38023), + list=[addon.LANG(10035)] + [str(i) for i in range(1, 11)], + preselect=preselect) + if index == preselect: + return -1 + return index + + +def save_to_file(content, filename, path): + """ + dump json and save to *filename in *path + """ + if not xbmcvfs.exists(path): + xbmcvfs.mkdirs(path) + text_file_path = os.path.join(path, filename + ".txt") + text_file = xbmcvfs.File(text_file_path, "w") + json.dump(content, text_file) + text_file.close() + return True + + +def read_from_file(path, raw=False): + """ + return data from file with *path + """ + if not xbmcvfs.exists(path): + return False + try: + with open(path) as f: + # utils.log("opened textfile %s." % (path)) + if not raw: + result = json.load(f) + else: + result = f.read() + return result + except Exception: + log("failed to load textfile: " + path) + return False + + +def create_listitems(data=None, preload_images=0): + """ + returns list with xbmcgui listitems + """ + return [item.get_listitem() for item in data] if data else [] + + +def translate_path(arg1, *args): + return xbmcvfs.translatePath(os.path.join(arg1, *args)) + + +def get_infolabel(name): + """ + returns infolabel with *name + """ + return xbmc.getInfoLabel(name) + + +def calculate_age(born, died=False): + """ + calculate age based on born / died + display notification for birthday + return death age when already dead + """ + if died: + ref_day = died.split("-") + elif born: + date = datetime.date.today() + ref_day = [date.year, date.month, date.day] + else: + return "" + actor_born = born.split("-") + base_age = int(ref_day[0]) - int(actor_born[0]) + if len(actor_born) > 1: + diff_months = int(ref_day[1]) - int(actor_born[1]) + diff_days = int(ref_day[2]) - int(actor_born[2]) + if diff_months < 0 or (diff_months == 0 and diff_days < 0): + base_age -= 1 + elif diff_months == 0 and diff_days == 0 and not died: + notify("%s (%i)" % (addon.LANG(32158), base_age)) + return base_age + + +def get_http(url, headers=False): + """ + fetches data from *url, returns it as a string + """ + succeed = 0 + if not headers: + headers = {'User-agent': 'Kodi/17.0 ( fbacher@kodi.tv )'} + while (succeed < 2) and (not xbmc.Monitor().abortRequested()): + try: + request = requests.get(url, headers=headers) + return request.text + except Exception as err: + log(f"get_http: could not get data from {url} exception {err}") + xbmc.sleep(1000) + succeed += 1 + return None + + +def post(url, values, headers): + """ + retuns answer to post request + """ + request = requests.post(url=url, + data=json.dumps(values), + headers=headers) + return json.loads(request.text) + + +def delete(url, values, headers): + """ + returns answer to delete request + """ + request = requests.delete(url=url, + data=json.dumps(values), + headers=headers) + return json.loads(request.text) + + +def get_JSON_response(url="", cache_days=7.0, folder=False, headers=False) -> dict: + """gets JSON response for *url, makes use of prop and file cache. + + Args: + url (str, optional): search query URL. Defaults to "". + cache_days (float, optional): Number of days to determine cache is stale. Defaults to 7.0. + folder (bool, optional): folder on local system to cache query results. Defaults to False. + headers (bool, optional): headers to use in https request. Defaults to False. + + Returns: + dict: a deserialized JSON query response or None + """ + now = time.time() + hashed_url = hashlib.md5(url.encode("utf-8", "ignore")).hexdigest() + cache_path = translate_path(addon.DATA_PATH, folder) if folder else translate_path(addon.DATA_PATH) + cache_seconds = int(cache_days * 86400.0) + if not cache_days: + addon.clear_global(hashed_url) + addon.clear_global(hashed_url + "_timestamp") + prop_time = addon.get_global(hashed_url + "_timestamp") + if prop_time and now - float(prop_time) < cache_seconds: + try: + prop = json.loads(addon.get_global(hashed_url)) + if prop: + return prop + except Exception: + # utils.log("could not load prop data for %s" % url) + pass + path = os.path.join(cache_path, hashed_url + ".txt") + if xbmcvfs.exists(path) and ((now - os.path.getmtime(path)) < cache_seconds): + results = read_from_file(path) + # utils.log("loaded file for %s. time: %f" % (url, time.time() - now)) + else: + response = get_http(url, headers) + try: + results = json.loads(response) + # utils.log("download %s. time: %f" % (url, time.time() - now)) + save_to_file(results, hashed_url, cache_path) + except Exception as err: + log(f"Exception: Could not get new JSON data from {url} with error {err}. Trying to fallback to cache") + #log(f'kutils131.utils.get_JSON_response {response}') + results = read_from_file(path) if xbmcvfs.exists(path) else [] + if not results: + return None + addon.set_global(hashed_url + "_timestamp", str(now)) + addon.set_global(hashed_url, json.dumps(results)) + return results + + +def dict_to_windowprops(data=None, prefix="", window_id=10000): + window = xbmcgui.Window(window_id) + if not data: + return None + for (key, value) in data.items(): + value = str(value) + window.setProperty('%s%s' % (prefix, key), value) + + +def get_file(url): + clean_url = translate_path(urllib.parse.unquote(url)).replace("image://", "") + clean_url = clean_url.rstrip("/") + cached_thumb = xbmc.getCacheThumbName(clean_url) + vid_cache_file = os.path.join("special://profile/Thumbnails/Video", cached_thumb[0], cached_thumb) + cache_file_jpg = os.path.join("special://profile/Thumbnails/", cached_thumb[0], cached_thumb[:-4] + ".jpg").replace("\\", "/") + cache_file_png = cache_file_jpg[:-4] + ".png" + if xbmcvfs.exists(cache_file_jpg): + log("cache_file_jpg Image: " + url + "-->" + cache_file_jpg) + return translate_path(cache_file_jpg) + elif xbmcvfs.exists(cache_file_png): + log("cache_file_png Image: " + url + "-->" + cache_file_png) + return cache_file_png + elif xbmcvfs.exists(vid_cache_file): + log("vid_cache_file Image: " + url + "-->" + vid_cache_file) + return vid_cache_file + try: + request = urllib.request.Request(clean_url) + request.add_header('Accept-encoding', 'gzip') + response = urllib.request.urlopen(request, timeout=3) + data = response.read() + response.close() + log('image downloaded: ' + clean_url) + except Exception: + log('image download failed: ' + clean_url) + return "" + if not data: + return "" + image = cache_file_png if url.endswith(".png") else cache_file_jpg + try: + with open(translate_path(image), "wb") as f: + f.write(data) + return translate_path(image) + except Exception: + log('failed to save image ' + url) + return "" + + +def fetch_musicbrainz_id(artist, artist_id=-1): + """ + fetches MusicBrainz ID for given *artist and returns it + uses musicbrainz.org + """ + base_url = "http://musicbrainz.org/ws/2/artist/?fmt=json" + url = '&query=artist:%s' % urllib.parse.quote_plus(artist.encode('utf-8')) + results = get_JSON_response(url=base_url + url, + cache_days=30, + folder="MusicBrainz") + if results and len(results["artists"]) > 0: + log("found artist id for %s: %s" % (artist, results["artists"][0]["id"])) + return results["artists"][0]["id"] + else: + return None + + +class FunctionThread(threading.Thread): + + def __init__(self, function=None, param=None): + super().__init__() + self.function = function + self.param = param + self.setName(self.function.__name__) + log("init " + self.function.__name__) + + def run(self): + self.listitems = self.function(self.param) + return True + + +def reset_color(item): + label = item.getLabel2() + label = label.replace("[COLOR=FFFF3333]", "").replace("[/COLOR]", "") + item.setLabel2(label) + + +def dict_to_listitems(data=None): + if not data: + return [] + itemlist = [] + for (count, result) in enumerate(data): + listitem = xbmcgui.ListItem('%s' % (str(count))) + for (key, value) in result.items(): + if not value: + continue + value = str(value) + if key.lower() in ["name", "label"]: + listitem.setLabel(value) + elif key.lower() in ["label2"]: + listitem.setLabel2(value) + elif key.lower() in ["path"]: + listitem.setPath(path=value) + listitem.setProperty('%s' % (key), value) + listitem.setProperty("index", str(count)) + itemlist.append(listitem) + return itemlist + + +def pretty_date(time=False): + """ + Get a datetime object or a int() Epoch timestamp and return a + pretty string like 'an hour ago', 'Yesterday', '3 months ago', + 'just now', etc + # https://stackoverflow.com/questions/1551382/user-friendly-time-format-in-python + """ + now = datetime.datetime.now() + if type(time) is int: + diff = now - datetime.datetime.fromtimestamp(time) + elif isinstance(time, datetime.datetime): + diff = now - time + elif not time: + diff = now - now + second_diff = diff.seconds + day_diff = diff.days + + if day_diff < 0: + return '' + + if day_diff == 0: + if second_diff < 10: + return "just now" + if second_diff < 60: + return str(second_diff) + " seconds ago" + if second_diff < 120: + return "a minute ago" + if second_diff < 3600: + return str(second_diff / 60) + " minutes ago" + if second_diff < 7200: + return "an hour ago" + if second_diff < 86400: + return str(second_diff / 3600) + " hours ago" + if day_diff == 1: + return "Yesterday" + if day_diff < 7: + return str(day_diff) + " days ago" + if day_diff < 31: + return str(day_diff / 7) + " weeks ago" + if day_diff < 365: + return str(day_diff / 30) + " months ago" + return str(day_diff / 365) + " years ago" diff --git a/script.extendedinfo/resources/kutil131/windows.py b/script.extendedinfo/resources/kutil131/windows.py new file mode 100644 index 000000000..425a4d3c2 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/windows.py @@ -0,0 +1,59 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +import xbmcgui + + +class WindowMixin: + + def __init__(self, *args, **kwargs): + super().__init__() + self.cancelled = False + + def FocusedItem(self, control_id): + try: + control = self.getControl(control_id) + listitem = control.getSelectedItem() + if not listitem: + listitem = self.getListItem(self.getCurrentListPosition()) + return listitem + except Exception as err: + return None + + def set_visible(self, control_id, condition): + try: + self.getControl(control_id).setVisible(bool(condition)) + return True + except Exception: + return False + + def check_visible(self, control_id): + try: + self.getControl(control_id) + return True + except Exception: + return False + + def exit(self): + self.cancelled = True + self.close() + + +class WindowXML(xbmcgui.WindowXML, WindowMixin): + + def __init__(self, *args, **kwargs): + super().__init__() + self.window_type = "window" + + def onInit(self): + self.window_id = xbmcgui.getCurrentWindowId() + + +class DialogXML(xbmcgui.WindowXMLDialog, WindowMixin): + + def __init__(self, *args, **kwargs): + super().__init__() + self.window_type = "dialog" + + def onInit(self): + self.window_id = xbmcgui.getCurrentWindowDialogId() diff --git a/script.extendedinfo/resources/kutil131/youtube.py b/script.extendedinfo/resources/kutil131/youtube.py new file mode 100644 index 000000000..b00640bf9 --- /dev/null +++ b/script.extendedinfo/resources/kutil131/youtube.py @@ -0,0 +1,260 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# This program is Free Software see LICENSE file for details + +from __future__ import annotations +import html +import itertools +import urllib.error +import urllib.parse +import urllib.request + +from resources.kutil131 import ItemList, VideoItem, utils + +BASE_URL = "https://www.googleapis.com/youtube/v3/" +PLUGIN_BASE = "plugin://script.extendedinfo/?info=" + + +def handle_videos(results:list[dict], extended=False, api_key=''): + """ + Process video api result to ItemList + + :param api_key: api_key to pass to YouTube + """ + videos = ItemList(content_type="videos") + for item in results: + snippet = item["snippet"] + thumb = snippet["thumbnails"]["high"]["url"] if "thumbnails" in snippet else "" + try: + video_id = item["id"]["videoId"] + except Exception: + video_id = snippet["resourceId"]["videoId"] + video = VideoItem(label=html.unescape(snippet["title"]), + path=PLUGIN_BASE + 'youtubevideo&&id=%s' % video_id) + video.set_infos({'plot': html.unescape(snippet["description"]), + 'mediatype': "video", + 'premiered': snippet["publishedAt"][:10]}) + video.set_artwork({'thumb': thumb}) + video.set_playable(True) + video.set_properties({'channel_title': html.unescape(snippet["channelTitle"]), + 'channel_id': snippet["channelId"], + 'type': "video", + 'youtube_id': video_id}) + videos.append(video) + if not extended: + return videos + params = {"part": "contentDetails,statistics", + "id": ",".join([i.get_property("youtube_id") for i in videos]), + "key": api_key} + ext_results = get_data(method="videos", + params=params) + if not ext_results or not 'items' in ext_results.keys(): + return videos + for item in videos: + for ext_item in ext_results["items"]: + if not item.get_property("youtube_id") == ext_item['id']: + continue + details = ext_item['contentDetails'] + stats = ext_item['statistics'] + likes = stats.get('likeCount') + dislikes = stats.get('dislikeCount') + item.update_infos({"duration": get_duration_in_seconds(details['duration'])}) + props = {"duration": details['duration'][2:].lower(), + "formatted_duration": get_formatted_duration(details['duration']), + "dimension": details['dimension'], + "definition": details['definition'], + "caption": details['caption'], + "viewcount": utils.millify(int(stats.get('viewCount', 0))), + "likes": likes, + "dislikes": dislikes} + item.update_properties(props) + if likes and dislikes: + vote_count = int(likes) + int(dislikes) + if vote_count > 0: + item.set_info("rating", round(float(likes) / vote_count * 10, 1)) + break + return videos + + +def get_duration_in_seconds(duration:str): + """ + convert youtube duration string to seconds int + """ + if not duration.endswith('S'): + duration = duration + '0S' + duration = duration[2:-1].replace("H", "M").split("M") + if len(duration) == 3: + return int(duration[0]) * 3600 + int(duration[1]) * 60 + int(duration[2]) + elif len(duration) == 2: + return int(duration[0]) * 60 + int(duration[1]) + else: + return int(duration[0]) + + +def get_formatted_duration(duration): + """ + convert youtube duration string to formatted duration + """ + duration = duration[2:-1].replace("H", "M").split("M") + if len(duration) == 3: + return "{}:{}:{}".format(duration[0].zfill(2), duration[1].zfill(2), duration[2].zfill(2)) + elif len(duration) == 2: + return "{}:{}".format(duration[0].zfill(2), duration[1].zfill(2)) + else: + return "00:{}".format(duration[0].zfill(2)) + + +def handle_playlists(results, api_key=''): + """ + process playlist api result to ItemList + + :param api_key: api_key to pass to YouTube + + """ + playlists = ItemList(content_type="videos") + for item in results: + snippet = item["snippet"] + thumb = snippet["thumbnails"]["high"]["url"] if "thumbnails" in snippet else "" + try: + playlist_id = item["id"]["playlistId"] + except Exception: + playlist_id = snippet["resourceId"]["playlistId"] + playlist = VideoItem(label=snippet["title"], + path=PLUGIN_BASE + 'youtubeplaylist&&id=%s' % playlist_id) + playlist.set_infos({'plot': snippet["description"], + "mediatype": "video", + 'premiered': snippet["publishedAt"][:10]}) + playlist.set_art("thumb", thumb) + playlist.set_properties({'youtube_id': playlist_id, + 'channel_title': snippet["channelTitle"], + 'type': "playlist", + 'live': snippet["liveBroadcastContent"].replace("none", "")}) + playlists.append(playlist) + params = {"id": ",".join([i.get_property("youtube_id") for i in playlists]), + "part": "contentDetails", + "key": api_key} + ext_results = get_data(method="playlists", + params=params) + for item, ext_item in itertools.product(playlists, ext_results["items"]): + if item.get_property("youtube_id") == ext_item['id']: + item.set_property("itemcount", ext_item['contentDetails']['itemCount']) + return playlists + + +def handle_channels(results, api_key=''): + """ + process channel api result to ItemList + + :param api_key: api_key to pass to YouTube + + """ + channels = ItemList(content_type="videos") + for item in results: + snippet = item["snippet"] + thumb = snippet["thumbnails"]["high"]["url"] if "thumbnails" in snippet else "" + try: + channel_id = item["id"]["channelId"] + except Exception: + channel_id = snippet["resourceId"]["channelId"] + channel = VideoItem(label=html.unescape(snippet["title"]), + path=PLUGIN_BASE + 'youtubechannel&&id=%s' % channel_id) + channel.set_infos({'plot': html.unescape(snippet["description"]), + 'mediatype': "video", + 'premiered': snippet["publishedAt"][:10]}) + channel.set_art("thumb", thumb) + channel.set_properties({"youtube_id": channel_id, + "type": "channel"}) + channels.append(channel) + channel_ids = [item.get_property("youtube_id") for item in channels] + params = {"id": ",".join(channel_ids), + "part": "contentDetails,statistics,brandingSettings", + "key": api_key} + ext_results = get_data(method="channels", + params=params) + for item, ext_item in itertools.product(channels, ext_results["items"]): + if item.get_property("youtube_id") == ext_item['id']: + item.set_property("itemcount", ext_item['statistics']['videoCount']) + item.set_art("fanart", ext_item["brandingSettings"]["image"].get("bannerTvMediumImageUrl")) + return channels + + +def get_data(method, params=None, cache_days=0.5): + """ + fetch data from youtube API + """ + params = params if params else {} +# params["key"] = YT_KEY + params = {k: str(v) for k, v in iter(params.items()) if v} + url = "{base_url}{method}?{params}".format(base_url=BASE_URL, + method=method, + params=urllib.parse.urlencode(params)) + return utils.get_JSON_response(url=url, + cache_days=cache_days, + folder="YouTube") + + +def search(search_str="", hd="", orderby="relevance", limit=40, extended=True, + page="", filters=None, media_type="video", api_key="") -> ItemList: + """ + returns ItemList according to search term, filters etc. + + :param api_key: api_key to pass to YouTube + """ + params = {"part": "id,snippet", + "maxResults": limit, + "type": media_type, + "order": orderby, + "pageToken": page, + "hd": str(hd and not hd == "false"), + "q": search_str.replace('"', ''), + "key" : api_key} + results = get_data(method="search", + params=utils.merge_dicts(params, filters if filters else {})) + if 'error' in results.keys(): + utils.log('youtube get_data ERROR: {error}'.format(error=results.get('error').get('message'))) + if not results or 'items' not in results.keys(): + return None + + # Give initial value to keep IDE happy as well as in case we drop through all + # choices + + listitems: ItemList = ItemList() + if media_type == "video": + listitems = handle_videos(results["items"], extended=extended, api_key=api_key) + elif media_type == "playlist": + listitems = handle_playlists(results["items"], api_key=api_key) + elif media_type == "channel": + listitems = handle_channels(results["items"], api_key=api_key) + listitems.total_pages = results["pageInfo"]["resultsPerPage"] + listitems.totals = results["pageInfo"]["totalResults"] + listitems.next_page_token = results.get("nextPageToken", "") + listitems.prev_page_token = results.get("prevPageToken", "") + return listitems + + +def get_playlist_videos(playlist_id=""): + """ + returns ItemList from playlist with *playlist_id + """ + if not playlist_id: + return [] + params = {"part": "id,snippet", + "maxResults": "50", + "playlistId": playlist_id} + results = get_data(method="playlistItems", + params=params) + if not results: + return [] + return handle_videos(results["items"]) + + +def get_user_playlists(username=""): + """ + returns ItemList with user uploads from *username + """ + params = {"part": "contentDetails", + "forUsername": username} + results = get_data(method="channels", + params=params) + if not results["items"]: + return None + return results["items"][0]["contentDetails"]["relatedPlaylists"] diff --git a/script.extendedinfo/resources/language/resource.language.bg_bg/strings.po b/script.extendedinfo/resources/language/resource.language.bg_bg/strings.po index 6d50482de..2dc91cb72 100644 --- a/script.extendedinfo/resources/language/resource.language.bg_bg/strings.po +++ b/script.extendedinfo/resources/language/resource.language.bg_bg/strings.po @@ -724,3 +724,7 @@ msgstr "" msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" diff --git a/script.extendedinfo/resources/language/resource.language.cs_cz/strings.po b/script.extendedinfo/resources/language/resource.language.cs_cz/strings.po index 84dbcc1ac..30140f3b9 100644 --- a/script.extendedinfo/resources/language/resource.language.cs_cz/strings.po +++ b/script.extendedinfo/resources/language/resource.language.cs_cz/strings.po @@ -775,3 +775,7 @@ msgstr "" msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" diff --git a/script.extendedinfo/resources/language/resource.language.en_gb/strings.po b/script.extendedinfo/resources/language/resource.language.en_gb/strings.po index 5747ed245..0abe25cb5 100644 --- a/script.extendedinfo/resources/language/resource.language.en_gb/strings.po +++ b/script.extendedinfo/resources/language/resource.language.en_gb/strings.po @@ -772,3 +772,7 @@ msgstr "" msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" diff --git a/script.extendedinfo/resources/language/resource.language.es_es/strings.po b/script.extendedinfo/resources/language/resource.language.es_es/strings.po index 6570694c0..eb2b1c1c1 100644 --- a/script.extendedinfo/resources/language/resource.language.es_es/strings.po +++ b/script.extendedinfo/resources/language/resource.language.es_es/strings.po @@ -772,3 +772,7 @@ msgstr "" msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" diff --git a/script.extendedinfo/resources/language/resource.language.fr_fr/strings.po b/script.extendedinfo/resources/language/resource.language.fr_fr/strings.po index 99fb4fe57..5e0699ddd 100644 --- a/script.extendedinfo/resources/language/resource.language.fr_fr/strings.po +++ b/script.extendedinfo/resources/language/resource.language.fr_fr/strings.po @@ -772,3 +772,8 @@ msgstr "" msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" + diff --git a/script.extendedinfo/resources/language/resource.language.he_il/strings.po b/script.extendedinfo/resources/language/resource.language.he_il/strings.po index 7e9dfc46e..28294a3b1 100644 --- a/script.extendedinfo/resources/language/resource.language.he_il/strings.po +++ b/script.extendedinfo/resources/language/resource.language.he_il/strings.po @@ -776,3 +776,8 @@ msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" + diff --git a/script.extendedinfo/resources/language/resource.language.it_it/strings.po b/script.extendedinfo/resources/language/resource.language.it_it/strings.po index cd545c889..829e9b630 100644 --- a/script.extendedinfo/resources/language/resource.language.it_it/strings.po +++ b/script.extendedinfo/resources/language/resource.language.it_it/strings.po @@ -772,3 +772,7 @@ msgstr "" msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" diff --git a/script.extendedinfo/resources/language/resource.language.pl_pl/strings.po b/script.extendedinfo/resources/language/resource.language.pl_pl/strings.po index 708d2aedb..e66614763 100644 --- a/script.extendedinfo/resources/language/resource.language.pl_pl/strings.po +++ b/script.extendedinfo/resources/language/resource.language.pl_pl/strings.po @@ -776,3 +776,8 @@ msgctxt "#32174" msgid "OMDb API Key" msgstr "" + +msgctxt "#32184" +msgid "ExtendedInfo Script" +msgstr "" + diff --git a/script.extendedinfo/resources/lib/BandsInTown.py b/script.extendedinfo/resources/lib/bandsintown.py similarity index 71% rename from script.extendedinfo/resources/lib/BandsInTown.py rename to script.extendedinfo/resources/lib/bandsintown.py index 869dfe7ac..faa01157d 100644 --- a/script.extendedinfo/resources/lib/BandsInTown.py +++ b/script.extendedinfo/resources/lib/bandsintown.py @@ -1,11 +1,9 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details """Obtains local events from BandsInTown -The current API TOU does not permit getting an API key for this addon. This +The current API TOU does not permit getting an API key for this addon. This module is inop, but retained in case there is a change in the future. """ @@ -14,14 +12,24 @@ import urllib.parse import urllib.request -from kutils import ItemList, VideoItem, utils +from resources.kutil131 import ItemList + +from resources.kutil131 import VideoItem, utils # TVRAGE_KEY = 'VBp9BuIr5iOiBeWCFRMG' API_KEY = '' BASE_URL = "http://api.bandsintown.com/events/search?format=json&api_version=2.0&app_id=%s&" % API_KEY -def handle_events(results): +def handle_events(results: list) -> ItemList: + """converts a list of BandsinTown events to a kutils ItemList + + Args: + results (list): list of event dicts + + Returns: + ItemList: a kutils ItemList of VideoItems + """ events = ItemList() for event in results: venue = event['venue'] @@ -39,12 +47,20 @@ def handle_events(results): return events -def get_near_events(artists): # not possible with api 2.0 +def get_near_events(artists: str) -> ItemList: # not possible with api 2.0 + """Queries BandsInTown for events + + Args: + artists (str): _description_ + + Returns: + ItemList: A kutils ItemList of VideoItems for artist events + """ arts = [urllib.parse.quote(art['artist'].encode("utf-8")) for art in artists[:50]] artist_str = 'artists[]=' + '&artists[]='.join(arts) url = BASE_URL + \ - 'location=use_geoip&radius=50&per_page=100&%s' % (artist_str) + f'location=use_geoip&radius=50&per_page=100&{artist_str}' results = utils.get_JSON_response(url, folder="BandsInTown") if results: return handle_events(results) diff --git a/script.extendedinfo/resources/lib/dialogs/DialogActorInfo.py b/script.extendedinfo/resources/lib/dialogs/DialogActorInfo.py deleted file mode 100644 index 380750109..000000000 --- a/script.extendedinfo/resources/lib/dialogs/DialogActorInfo.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf8 -*- - -# Copyright (C) 2015 - Philipp Temminghoff -# Modifications copyright (C) 2022 - Scott Smart -# This program is Free Software see LICENSE file for details - -import xbmcgui -from kutils import ActionHandler, addon, imagetools -from resources.lib import TheMovieDB as tmdb - -from .DialogBaseInfo import DialogBaseInfo - -ID_CONTROL_PLOT = 132 - -ch = ActionHandler() - - -class DialogActorInfo(DialogBaseInfo): - """creates a dialog window for actor info - - Args: - DialogBaseInfo (_type_): handles common window details - """ - TYPE = "Actor" - LISTS = [(150, "movie_roles"), - (250, "tvshow_roles"), - (450, "images"), - (550, "movie_crew_roles"), - (650, "tvshow_crew_roles"), - (750, "tagged_images")] - - def __init__(self, *args, **kwargs) -> None: - """Constructs the dialog window with actor info from tmdb - slef.info is a ListItem for the actor - self.lists is a list of ListItems for the actor's movies and tv shows - - Arguments: - *args: dialog xml filename - this addon path (for cache) - **kwargs: id[str]: the tmdb actor id - - Returns: - None: if no tmdb extended actor info available - """ - super(DialogActorInfo, self).__init__(*args, **kwargs) - data = tmdb.extended_actor_info(actor_id=kwargs.get('id')) - if not data: - return None - self.info, self.lists = data - self.info.update_properties( - imagetools.blur(self.info.get_art("thumb"))) - - def onInit(self): - self.get_youtube_vids(self.info.label) - super(DialogActorInfo, self).onInit() - - def onClick(self, control_id): - super(DialogActorInfo, self).onClick(control_id) - ch.serve(control_id, self) - - @ch.click(ID_CONTROL_PLOT) - def show_plot(self, control_id): - xbmcgui.Dialog().textviewer(heading=addon.LANG(32037), - text=self.info.get_property("biography")) diff --git a/script.extendedinfo/resources/lib/dialogs/dialogactorinfo.py b/script.extendedinfo/resources/lib/dialogs/dialogactorinfo.py new file mode 100644 index 000000000..bd4e6be9e --- /dev/null +++ b/script.extendedinfo/resources/lib/dialogs/dialogactorinfo.py @@ -0,0 +1,100 @@ +# Copyright (C) 2015 - Philipp Temminghoff +# Modifications copyright (C) 2022 - Scott Smart +# This program is Free Software see LICENSE file for details + +"""Provides the DialogActorInfo class that implements a dialog +XML window. The Actor Info is added to the window properties +from a kutils VideoItem. Panels of VideoItems are added from +kutils ItemLists and a Youtube list. + +The class hierarchy is: + xbmcgui.Window + -------------- + xbmcgui.WindowXML / xbmcgui.WindowDialogMixin + --------------- + xbmc.WindowDialogXML / kutils.windows.WindowMixin + --------------- + kutils.windows.DialogXML + --------------- + DialogBaseInfo + --------------- + DialogActorInfo + +""" + +import xbmcgui +from resources.kutil131 import ActionHandler, ItemList, addon + +from resources.kutil131 import VideoItem, imagetools, utils +from resources.lib import themoviedb as tmdb + +from .dialogbaseinfo import DialogBaseInfo + +ID_CONTROL_PLOT = 132 + +ch = ActionHandler() + + +class DialogActorInfo(DialogBaseInfo): + """creates a dialog XML window for actor info + + Args: + DialogBaseInfo: handles common window details + """ + TYPE = "Actor" + LISTS = [(150, "movie_roles"), + (250, "tvshow_roles"), + (450, "images"), + (550, "movie_crew_roles"), + (650, "tvshow_crew_roles"), + (750, "tagged_images")] + + def __init__(self, *args, **kwargs): + """Constructs the dialog window with actor info from tmdb + self.info is a ListItem for the actor + self.lists is a list of ListItems for the actor's movies and tv shows + if TMDB actor id is provided, gets extended info from TMDB + + Arguments: + *args: dialog xml filename + this addon path (for cache) + **kwargs: id(int): the tmdb actor id + Returns: + None: if no tmdb extended actor info available + self.info and self.lists are set from extended actor info + """ + super().__init__(*args, **kwargs) + data: tuple = tmdb.extended_actor_info(actor_id=kwargs.get('id')) + if not data: + return None + self.info, self.lists = data + self.info.update_properties( + imagetools.blur(self.info.get_art("thumb"))) + + def onInit(self, *args, **kwargs): + """callback function from Kodi when window is opened + Also calls onInit in parent classes to set all info in the + dialog window + """ + self.get_youtube_vids(self.info.label) + super().onInit() + + def onClick(self, control_id): + """callback function from Kodi when control in window is + clicked + + Args: + control_id (int): id of window control that was clicked + """ + super().onClick(control_id) + ch.serve(control_id, self) + + @ch.click(ID_CONTROL_PLOT) + def show_plot(self, control_id): + """Opens info dialog textbox in a textviewer + + Args: + control_id (int): window control id that was clicked + """ + xbmcgui.Dialog().textviewer(heading=addon.LANG(32037), + text=self.info.get_property("biography")) diff --git a/script.extendedinfo/resources/lib/dialogs/DialogBaseInfo.py b/script.extendedinfo/resources/lib/dialogs/dialogbaseinfo.py similarity index 88% rename from script.extendedinfo/resources/lib/dialogs/DialogBaseInfo.py rename to script.extendedinfo/resources/lib/dialogs/dialogbaseinfo.py index 469d1d724..3ed1b5789 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogBaseInfo.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogbaseinfo.py @@ -1,17 +1,17 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +import traceback + import xbmc import xbmcgui +from resources.kutil131 import (ActionHandler, addon, kodijson, selectdialog, slideshow, + windows) -from kutils import (ActionHandler, VideoItem, addon, kodijson, selectdialog, - slideshow, utils, windows, youtube) - -from resources.lib import TheMovieDB as tmdb -from resources.lib.WindowManager import wm +from resources.kutil131 import VideoItem, utils, youtube +from resources.lib import themoviedb as tmdb +from resources.lib.windowmanager import wm ch = ActionHandler() @@ -36,29 +36,32 @@ class DialogBaseInfo(windows.DialogXML): ACTION_EXIT_SCRIPT = [13, 10] def __init__(self, *args, **kwargs): - super(DialogBaseInfo, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.logged_in: bool = tmdb.Login.check_login() self.bouncing = False self.last_focus = None self.lists = None self.states = False self.yt_listitems = [] - self.info = VideoItem() + self.info = VideoItem() # kutils listitem self.last_control = None self.last_position = None def onInit(self, *args, **kwargs): - super(DialogBaseInfo, self).onInit() + super().onInit() # self.set_buttons() - self.info.to_windowprops(window_id=self.window_id) #kutils sets home window - #properties from the info listitem + self.info.to_windowprops(window_id=self.window_id) #kutils sets dialog window + #properties from the info VideoItem(listitem) for container_id, key in self.LISTS: try: self.getControl(container_id).reset() - items = [i.get_listitem() for i in self.lists[key]] + items = [i.get_listitem() for i in self.lists[key]] # lists is a dict of ItemList get_listitem gets xbmc listitem from VideoItem self.getControl(container_id).addItems(items) + except (IndexError, KeyError) as err: + utils.log(f'Notice: No container with id {container_id} key {key} available due to {err}') except Exception as err: - utils.log(f'Notice: No container with id {container_id} available and {err}') + utils.log(f'Notice: No container with id {container_id} key {key} available due to {err}') + utils.log(f'traceback for this exception\n{traceback.format_exc()}') if self.last_control: self.setFocusId(self.last_control) if self.last_control and self.last_position: @@ -68,6 +71,7 @@ def onInit(self, *args, **kwargs): except Exception: pass addon.set_global("ImageColor", self.info.get_property('ImageColor')) + addon.set_global("ImageFilter", self.info.get_property('ImageFilter')) addon.set_global("infobackground", self.info.get_art('fanart_small')) self.setProperty("type", self.TYPE) self.setProperty("tmdb_logged_in", "true" if self.logged_in else "") @@ -75,8 +79,8 @@ def onInit(self, *args, **kwargs): def onAction(self, action): ch.serve_action(action, self.getFocusId(), self) - def onClick(self, control_id): - super(DialogBaseInfo, self).onClick(control_id) + def onClick(self, control_id: int): + super().onClick(control_id) ch.serve(control_id, self) def onFocus(self, control_id): @@ -97,7 +101,7 @@ def close(self): self.last_position = None addon.set_global("infobackground", "") self.last_control = self.getFocusId() - super(DialogBaseInfo, self).close() + super().close() @utils.run_async def bounce(self, identifier): @@ -123,8 +127,8 @@ def play_youtube_video(self, control_id): @ch.click_by_type("artist") def open_actor_info(self, control_id): - wm.open_actor_info(actor_id=self.FocusedItem( - control_id).getProperty("id")) + wm.open_actor_info(actor_id=self.FocusedItem(control_id).getProperty("id"), + name=self.FocusedItem(control_id).getLabel()) @ch.click_by_type("movie") def open_movie_info(self, control_id): @@ -171,8 +175,9 @@ def thumbnail_options(self, control_id): def video_context_menu(self, control_id): index = xbmcgui.Dialog().contextmenu(list=[addon.LANG(33003)]) if index == 0: - utils.download_video(self.FocusedItem( - control_id).getProperty("youtube_id")) + #utils.download_video(self.FocusedItem( + # control_id).getProperty("youtube_id")) + pass @ch.context("movie") def movie_context_menu(self, control_id): @@ -259,14 +264,16 @@ def previous_menu(self, control_id): def exit_script(self, *args): self.exit() - @utils.run_async + # @utils.run_async def get_youtube_vids(self, search_str): try: youtube_list = self.getControl(ID_LIST_YOUTUBE) - except Exception: + except Exception as err: + utils.log(f'DialogBaseInfo.get_youtube_vids threw exception {err}') return None if not self.yt_listitems: user_key = addon.setting("Youtube API Key") + search_str = search_str.replace('-', '') self.yt_listitems = youtube.search( search_str, limit=15, api_key=user_key) if not self.yt_listitems: diff --git a/script.extendedinfo/resources/lib/dialogs/DialogEpisodeInfo.py b/script.extendedinfo/resources/lib/dialogs/dialogepisodeinfo.py similarity index 83% rename from script.extendedinfo/resources/lib/dialogs/DialogEpisodeInfo.py rename to script.extendedinfo/resources/lib/dialogs/dialogepisodeinfo.py index efe60337b..bcc65a90d 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogEpisodeInfo.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogepisodeinfo.py @@ -1,16 +1,15 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details import xbmc +from resources.kutil131 import ActionHandler, addon, busy -from kutils import ActionHandler, addon, busy, imagetools -from resources.lib import TheMovieDB as tmdb -from resources.lib.WindowManager import wm +from resources.kutil131 import imagetools +from resources.lib import themoviedb as tmdb +from resources.lib.windowmanager import wm -from .DialogVideoInfo import DialogVideoInfo +from .dialogvideoinfo import DialogVideoInfo ID_BUTTON_RATED = 6006 @@ -27,7 +26,7 @@ class DialogEpisodeInfo(DialogVideoInfo): @busy.set_busy def __init__(self, *args, **kwargs): - super(DialogEpisodeInfo, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.tvshow_id = kwargs.get('tvshow_id') tv_info = tmdb.get_tvshow(self.tvshow_id, light=True) data = tmdb.extended_episode_info(tvshow_id=self.tvshow_id, @@ -41,16 +40,16 @@ def __init__(self, *args, **kwargs): self.info.update_properties(image_info) def onInit(self): - super(DialogEpisodeInfo, self).onInit() + super().onInit() search_str = '{} "Season {}" "Episode {}"'.format(self.info.get_info("tvshowtitle"), self.info.get_info( 'season'), self.info.get_info('episode')) self.get_youtube_vids(search_str) - super(DialogEpisodeInfo, self).update_states() + super().update_states() def onClick(self, control_id): - super(DialogEpisodeInfo, self).onClick(control_id) + super().onClick(control_id) ch.serve(control_id, self) @ch.click(ID_BUTTON_RATED) @@ -72,7 +71,7 @@ def update_states(self): episode=self.info.get_info("episode"), cache_days=0) self.states = info.get("account_states") - super(DialogEpisodeInfo, self).update_states() + super().update_states() def get_manage_options(self): return [(addon.LANG(1049), "Addon.OpenSettings(script.extendedinfo)")] diff --git a/script.extendedinfo/resources/lib/dialogs/DialogMovieInfo.py b/script.extendedinfo/resources/lib/dialogs/dialogmovieinfo.py similarity index 83% rename from script.extendedinfo/resources/lib/dialogs/DialogMovieInfo.py rename to script.extendedinfo/resources/lib/dialogs/dialogmovieinfo.py index a94be6ebf..adc809209 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogMovieInfo.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogmovieinfo.py @@ -1,21 +1,21 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +from __future__ import annotations + import threading -from typing import Optional, Union import xbmc import xbmcgui +from resources.kutil131 import ActionHandler, addon, busy, kodijson -from kutils import ActionHandler, addon, busy, imagetools, kodijson, utils -from resources.lib import TheMovieDB as tmdb +from resources.kutil131 import imagetools, utils +from resources.lib import themoviedb as tmdb from resources.lib import omdb -from resources.lib.WindowManager import wm +from resources.lib.windowmanager import wm -from .DialogVideoInfo import DialogVideoInfo +from .dialogvideoinfo import DialogVideoInfo ID_LIST_SIMILAR = 150 ID_LIST_SETS = 250 @@ -44,6 +44,14 @@ class DialogMovieInfo(DialogVideoInfo): + """ Class that creates a new movie info dialog + + Args: + DialogVideoInfo: The super class + + Returns: + DialogMmovieInfo: an instance + """ TYPE = "Movie" TYPE_ALT = "movie" LISTS = [(ID_LIST_ACTORS, "actors"), @@ -63,9 +71,17 @@ class DialogMovieInfo(DialogVideoInfo): # BUTTONS = [ID_BUTTON_OPENLIST, # ID_BUTTON_ADDTOLIST] - def __init__(self, *args, **kwargs): - super(DialogMovieInfo, self).__init__(*args, **kwargs) - data: Optional[dict] = tmdb.extended_movie_info(movie_id=kwargs.get('id'), + def __init__(self, *args, **kwargs) -> DialogMovieInfo: + """Creates a new instance of DialogMovieInfo + + kwargs: + id(int): the tmdb movie id + dbid(int): the local Kodi dbid + + Returns: dialogmovieinfo + """ + super().__init__(*args, **kwargs) + data: tuple | None = tmdb.extended_movie_info(movie_id=kwargs.get('id'), dbid=kwargs.get('dbid')) if not data: return None @@ -82,25 +98,26 @@ def __init__(self, *args, **kwargs): self.info.get_art("poster"))) sets_thread.join() self.info.update_properties( - {"set.%s" % k: v for k, v in list(sets_thread.setinfo.items())}) + {f"set.{k}": v for k, v in list(sets_thread.setinfo.items())}) set_ids = [item.get_property("id") for item in sets_thread.listitems] - self.lists["similar"] = [i for i in self.lists["similar"] - if i.get_property("id") not in set_ids] + if self.lists and self.lists.get('similar'): + self.lists["similar"] = [i for i in self.lists["similar"] + if i.get_property("id") not in set_ids] self.lists["sets"] = sets_thread.listitems def onInit(self): - super(DialogMovieInfo, self).onInit() - super(DialogMovieInfo, self).update_states() + super().onInit() + super().update_states() self.get_youtube_vids("%s %s, movie" % (self.info.label, self.info.get_info("year"))) self.set_omdb_infos_async() def onClick(self, control_id): - super(DialogMovieInfo, self).onClick(control_id) + super().onClick(control_id) ch.serve(control_id, self) def set_buttons(self): - super(DialogMovieInfo, self).set_buttons() + super().set_buttons() condition = self.info.get_info("dbid") and int( self.info.get_property("percentplayed")) > 0 self.set_visible(ID_BUTTON_PLAY_RESUME, condition) @@ -230,15 +247,8 @@ def get_manage_options(self): options = [] movie_id = self.info.get_info("dbid") imdb_id = self.info.get_property("imdb_id") - # if movie_id: - # call = "RunScript(script.artwork.downloader,mediatype=movie,dbid={}%s)".format(movie_id) - # options += [(addon.LANG(413), call % ",mode=gui"), - # (addon.LANG(14061), call % ""), - # (addon.LANG(32101), call % ",mode=custom,extrathumbs"), - # (addon.LANG(32100), call % ",mode=custom")] - # else: - options += [(addon.LANG(32165), "RunPlugin(plugin://plugin.video.couchpotato_manager/movies/add?imdb_id=%s)" % imdb_id), - (addon.LANG(32170), "RunPlugin(plugin://plugin.video.trakt_list_manager/watchlist/movies/add?imdb_id=%s)" % imdb_id)] + #options += [(addon.LANG(32165), "RunPlugin(plugin://plugin.video.couchpotato_manager/movies/add?imdb_id=%s)" % imdb_id), + # (addon.LANG(32170), "RunPlugin(plugin://plugin.video.trakt_list_manager/watchlist/movies/add?imdb_id=%s)" % imdb_id)] options.append( (addon.LANG(1049), "Addon.OpenSettings(script.extendedinfo)")) return options @@ -248,7 +258,7 @@ def update_states(self): info = tmdb.get_movie(movie_id=self.info.get_property("id"), cache_days=0) self.states = info.get("account_states") - super(DialogMovieInfo, self).update_states() + super().update_states() @utils.run_async def set_omdb_infos_async(self) -> None: @@ -261,14 +271,21 @@ def set_omdb_infos_async(self) -> None: class SetItemsThread(threading.Thread): + """Thread fetches movies in set from tmdb + + Args: + threading.Thead (super class): python thread class + """ - def __init__(self, set_id=""): + def __init__(self, set_id="") -> SetItemsThread: + """Creates a new SetItemsThread instance to run async + returns: SetItemsThread instance + """ threading.Thread.__init__(self) self.set_id = set_id + self.listitems = [] + self.setinfo = {} def run(self): - if self.set_id: + if self.set_id and self.set_id != 0: self.listitems, self.setinfo = tmdb.get_set_movies(self.set_id) - else: - self.listitems = [] - self.setinfo = {} diff --git a/script.extendedinfo/resources/lib/dialogs/DialogSeasonInfo.py b/script.extendedinfo/resources/lib/dialogs/dialogseasoninfo.py similarity index 80% rename from script.extendedinfo/resources/lib/dialogs/DialogSeasonInfo.py rename to script.extendedinfo/resources/lib/dialogs/dialogseasoninfo.py index 600f3d8e2..f04715ad3 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogSeasonInfo.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogseasoninfo.py @@ -1,13 +1,13 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details -from kutils import ActionHandler, addon, imagetools, utils -from resources.lib import TheMovieDB as tmdb +from resources.kutil131 import ActionHandler, addon + +from resources.kutil131 import imagetools, utils +from resources.lib import themoviedb as tmdb -from .DialogVideoInfo import DialogVideoInfo +from .dialogvideoinfo import DialogVideoInfo ch = ActionHandler() @@ -22,7 +22,7 @@ class DialogSeasonInfo(DialogVideoInfo): (1350, "backdrops")] def __init__(self, *args, **kwargs): - super(DialogSeasonInfo, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.tvshow_id = kwargs.get('id') data = tmdb.extended_season_info(tvshow_id=self.tvshow_id, season_number=kwargs.get('season')) @@ -38,10 +38,10 @@ def __init__(self, *args, **kwargs): def onInit(self): self.get_youtube_vids("%s %s tv" % (self.info.get_info( "tvshowtitle"), self.info.get_info('title'))) - super(DialogSeasonInfo, self).onInit() + super().onInit() def onClick(self, control_id): - super(DialogSeasonInfo, self).onClick(control_id) + super().onClick(control_id) ch.serve(control_id, self) def get_manage_options(self): diff --git a/script.extendedinfo/resources/lib/dialogs/DialogTVShowInfo.py b/script.extendedinfo/resources/lib/dialogs/dialogtvshowinfo.py similarity index 82% rename from script.extendedinfo/resources/lib/dialogs/DialogTVShowInfo.py rename to script.extendedinfo/resources/lib/dialogs/dialogtvshowinfo.py index cd52cde9f..898ccef12 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogTVShowInfo.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogtvshowinfo.py @@ -1,17 +1,16 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details import xbmc import xbmcgui +from resources.kutil131 import ActionHandler, addon -from kutils import ActionHandler, addon, imagetools, utils -from resources.lib import TheMovieDB as tmdb -from resources.lib.WindowManager import wm +from resources.kutil131 import imagetools, utils +from resources.lib import themoviedb as tmdb +from resources.lib.windowmanager import wm -from .DialogVideoInfo import DialogVideoInfo +from .dialogvideoinfo import DialogVideoInfo ID_LIST_SIMILAR = 150 ID_LIST_SEASONS = 250 @@ -50,7 +49,7 @@ class DialogTVShowInfo(DialogVideoInfo): (ID_LIST_BACKDROPS, "backdrops")] def __init__(self, *args, **kwargs): - super(DialogTVShowInfo, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) data = tmdb.extended_tvshow_info(tvshow_id=kwargs.get('tmdb_id'), dbid=kwargs.get('dbid')) if not data: @@ -64,11 +63,11 @@ def __init__(self, *args, **kwargs): def onInit(self): self.get_youtube_vids("%s tv" % (self.info.get_info("title"))) - super(DialogTVShowInfo, self).onInit() - super(DialogTVShowInfo, self).update_states() + super().onInit() + super().update_states() def onClick(self, control_id): - super(DialogTVShowInfo, self).onClick(control_id) + super().onClick(control_id) ch.serve(control_id, self) def set_buttons(self): @@ -124,17 +123,9 @@ def get_manage_options(self): options = [] title = self.info.get_info("tvshowtitle") dbid = self.info.get_info("dbid") - if dbid: - call = "RunScript(script.artwork.downloader,mediatype=tv,dbid={}%s)".format( - dbid) - options += [(addon.LANG(413), call % (",mode=gui")), - (addon.LANG(14061), call % ("")), - (addon.LANG(32101), call % - (",mode=custom,extrathumbs")), - (addon.LANG(32100), call % (",mode=custom"))] - else: - options += [(addon.LANG(32166), - "RunPlugin(plugin://plugin.video.sickrage?action=addshow&show_name=%s)" % title)] + #if not dbid: + # options += [(addon.LANG(32166), + # "RunPlugin(plugin://plugin.video.sickrage?action=addshow&show_name=%s)" % title)] options.append( (addon.LANG(1049), "Addon.OpenSettings(script.extendedinfo)")) return options @@ -160,4 +151,4 @@ def update_states(self): info = tmdb.get_tvshow(tvshow_id=self.info.get_property("id"), cache_days=0) self.states = info.get("account_states") - super(DialogTVShowInfo, self).update_states() + super().update_states() diff --git a/script.extendedinfo/resources/lib/dialogs/DialogVideoInfo.py b/script.extendedinfo/resources/lib/dialogs/dialogvideoinfo.py similarity index 87% rename from script.extendedinfo/resources/lib/dialogs/DialogVideoInfo.py rename to script.extendedinfo/resources/lib/dialogs/dialogvideoinfo.py index e9799d886..0ff42769a 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogVideoInfo.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogvideoinfo.py @@ -1,16 +1,15 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details import xbmc import xbmcgui +from resources.kutil131 import ActionHandler, addon -from kutils import ActionHandler, addon, utils -from resources.lib import TheMovieDB as tmdb +from resources.kutil131 import utils +from resources.lib import themoviedb as tmdb -from .DialogBaseInfo import DialogBaseInfo +from .dialogbaseinfo import DialogBaseInfo BUTTONS = {8, 9, 10, 6001, 6002, 6003, 6005, 6006} @@ -23,12 +22,17 @@ class DialogVideoInfo(DialogBaseInfo): + """ + + Args: + DialogBaseInfo (_type_): _description_ + """ def __init__(self, *args, **kwargs): - super(DialogVideoInfo, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def onClick(self, control_id): - super(DialogVideoInfo, self).onClick(control_id) + super().onClick(control_id) ch.serve(control_id, self) def set_buttons(self): diff --git a/script.extendedinfo/resources/lib/dialogs/DialogVideoList.py b/script.extendedinfo/resources/lib/dialogs/dialogvideolist.py similarity index 90% rename from script.extendedinfo/resources/lib/dialogs/DialogVideoList.py rename to script.extendedinfo/resources/lib/dialogs/dialogvideolist.py index 29e7a87d2..13ad8c75f 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogVideoList.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogvideolist.py @@ -1,16 +1,16 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +from __future__ import annotations + import xbmc import xbmcgui -from kutils import (ActionHandler, DialogBaseList, addon, busy, confirmdialog, - selectdialog, utils) -from resources.lib import TheMovieDB as tmdb -from resources.lib.WindowManager import wm +from resources.kutil131 import (ActionHandler, DialogBaseList, addon, busy, + confirmdialog, selectdialog, utils) +from resources.lib import themoviedb as tmdb +from resources.lib.windowmanager import wm ID_BUTTON_SORT = 5001 ID_BUTTON_GENREFILTER = 5002 @@ -22,18 +22,25 @@ ID_BUTTON_COMPANYFILTER = 5010 ID_BUTTON_RUNTIMEFILTER = 5011 ID_BUTTON_VOTECOUNTFILTER = 5012 +ID_BUTTON_LANGUAGEFILTER = 5013 ID_BUTTON_ACCOUNT = 7000 +LANGUAGES = ['en', 'ja', 'ko', 'de', 'es', + 'ar', 'bn', 'bg', 'zh', 'da', + 'nl', 'fr', 'el', 'he', 'hu', + 'it', 'kn', 'no', 'pl', 'pt', + 'ru', 'sv', 'tr', 'uk'] + ch = ActionHandler() include_adult: bool = addon.setting("include_adults").lower() def get_window(window_type): - """[summary] + """Wrapper gets new DialogVideoList instance Args: - window_type (class instance): xbmc XML dialog window or + window_type (class instance): xbmc XML dialog window or xbmc XML window objects Returns: @@ -41,6 +48,13 @@ def get_window(window_type): """ class DialogVideoList(DialogBaseList, window_type): + """Dialog Video List class + + Args: + DialogBaseList: Super class for dialog windows + window_type (kutils.windows class): Super class for Kodi xbmc.WindowXML + + """ TYPES = ["movie", "tv"] @@ -55,7 +69,8 @@ class DialogVideoList(DialogBaseList, window_type): "first_air_date": addon.LANG(20416), "with_runtime": xbmc.getLocalizedString(2050), "primary_release_date": addon.LANG(345), - "vote_count": addon.LANG(32111)} + "vote_count": addon.LANG(32111), + "with_original_language": xbmc.getLocalizedString(308)} TRANSLATIONS = {"movie": addon.LANG(20338), "tv": addon.LANG(20364), @@ -89,18 +104,18 @@ def __init__(self, *args, **kwargs): self.type = kwargs.get('type', "movie") self.list_id = kwargs.get("list_id", False) self.logged_in = tmdb.Login.check_login() - super(DialogVideoList, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def onClick(self, control_id): - super(DialogVideoList, self).onClick(control_id) + super().onClick(control_id) ch.serve(control_id, self) def onAction(self, action): - super(DialogVideoList, self).onAction(action) + super().onAction(action) ch.serve_action(action, self.getFocusId(), self) def update_ui(self): - super(DialogVideoList, self).update_ui() + super().update_ui() self.getControl(ID_BUTTON_CERTFILTER).setVisible(self.type != "tv") self.getControl(ID_BUTTON_ACTORFILTER).setVisible( self.type != "tv") @@ -202,7 +217,7 @@ def add_filter(self, **kwargs): kwargs["label"] = "< %s" % kwargs["label"] if kwargs["key"].endswith(".gte"): kwargs["label"] = "> %s" % kwargs["label"] - super(DialogVideoList, self).add_filter(force_overwrite=kwargs["key"].endswith((".gte", ".lte")), + super().add_filter(force_overwrite=kwargs["key"].endswith((".gte", ".lte")), **kwargs) @ch.click(ID_BUTTON_ORDER) @@ -240,11 +255,10 @@ def open_account_menu(self, control_id): self.reset("favorites") else: self.close() - dialog = wm.open_video_list(filters=[], + wm.open_video_list(filters=[], mode="list", list_id=account_lists[index - 2]["id"], filter_label=account_lists[index - 2]["name"]) - dialog.doModal() @ch.click(ID_BUTTON_GENREFILTER) def set_genre_filter(self, control_id): @@ -279,7 +293,8 @@ def set_vote_count_filter(self, control_id): ret = confirmdialog.open(header=addon.LANG(32151), text=addon.LANG(32106), nolabel=addon.LANG(32150), - yeslabel=addon.LANG(32149)) + yeslabel=addon.LANG(32149), + path=addon.PATH) if ret == -1: return None result = xbmcgui.Dialog().input(heading=addon.LANG(32111), @@ -294,7 +309,8 @@ def set_year_filter(self, control_id): ret = confirmdialog.open(header=addon.LANG(32151), text=addon.LANG(32106), nolabel=addon.LANG(32150), - yeslabel=addon.LANG(32149)) + yeslabel=addon.LANG(32149), + path=addon.PATH) if ret == -1: return None result = xbmcgui.Dialog().input(heading=addon.LANG(345), @@ -312,7 +328,8 @@ def set_runtime_filter(self, control_id): ret = confirmdialog.open(header=addon.LANG(32151), text=addon.LANG(32106), nolabel=addon.LANG(32150), - yeslabel=addon.LANG(32149)) + yeslabel=addon.LANG(32149), + path=addon.PATH) if ret == -1: return None result = xbmcgui.Dialog().input(heading=xbmc.getLocalizedString(2050), @@ -419,20 +436,30 @@ def set_certification_filter(self, control_id): value=cert, label=cert) + @ch.click(ID_BUTTON_LANGUAGEFILTER) + def set_language_filter(self, control_id): + index = xbmcgui.Dialog().select(heading=f'ISO-639-1 {xbmc.getLocalizedString(304)}', + list=LANGUAGES) + if index == -1: + return None + language = LANGUAGES[index] + self.add_filter(key="with_original_language", + value=language, + label=language) + def fetch_data(self, force=False): # TODO: rewrite sort_by = self.sort + "." + self.order temp = "tv" if self.type == "tv" else "movies" - #utils.log('DialogVideoList fetch_data args: sort_by {} temp {} mode {}'.format(sort_by, temp, self.mode)) #debug if self.mode == "search": self.filter_label = addon.LANG( 32146) % self.search_str if self.search_str else "" return tmdb.multi_search(search_str=self.search_str, page=self.page, cache_days=0 if force else 2) - elif self.mode == "list": + if self.mode == "list": return tmdb.get_list_movies(list_id=self.list_id, force=force) - elif self.mode == "favorites": + if self.mode == "favorites": self.filter_label = addon.LANG( 32144) if self.type == "tv" else addon.LANG(32134) return tmdb.get_fav_items(media_type=temp, @@ -445,14 +472,14 @@ def fetch_data(self, force=False): # TODO: rewrite sort_by=sort_by, page=self.page, cache_days=0) - else: + else: #self.mode == "filter" self.set_filter_label() params = {"sort_by": sort_by, "language": addon.setting("LanguageID"), "page": self.page, "include_adult": include_adult} filters = {item["type"]: item["id"] for item in self.filters} - response = tmdb.get_data(url="discover/%s" % (self.type), + response = tmdb.get_data(url=f"discover/{self.type}", params=utils.merge_dicts( params, filters), cache_days=0 if force else 2) diff --git a/script.extendedinfo/resources/lib/dialogs/DialogYoutubeList.py b/script.extendedinfo/resources/lib/dialogs/dialogyoutubelist.py similarity index 95% rename from script.extendedinfo/resources/lib/dialogs/DialogYoutubeList.py rename to script.extendedinfo/resources/lib/dialogs/dialogyoutubelist.py index 2044d9bc6..cc3206ef9 100644 --- a/script.extendedinfo/resources/lib/dialogs/DialogYoutubeList.py +++ b/script.extendedinfo/resources/lib/dialogs/dialogyoutubelist.py @@ -1,5 +1,3 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details @@ -7,10 +5,10 @@ import datetime import xbmcgui +from resources.kutil131 import ActionHandler, DialogBaseList, addon, busy, windows -from kutils import (ActionHandler, DialogBaseList, addon, busy, utils, windows, - youtube) -from resources.lib.WindowManager import wm +from resources.kutil131 import utils, youtube +from resources.lib.windowmanager import wm ch = ActionHandler() @@ -72,14 +70,14 @@ class DialogYoutubeList(DialogBaseList, window_type): @busy.set_busy def __init__(self, *args, **kwargs): self.type = kwargs.get('type', "video") - super(DialogYoutubeList, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def onClick(self, control_id): - super(DialogYoutubeList, self).onClick(control_id) + super().onClick(control_id) ch.serve(control_id, self) def onAction(self, action): - super(DialogYoutubeList, self).onAction(action) + super().onAction(action) ch.serve_action(action, self.getFocusId(), self) @ch.click_by_type("video") @@ -196,7 +194,7 @@ def update_ui(self): self.getControl(ID_BUTTON_DURATIONFILTER).setVisible(is_video) self.getControl(ID_BUTTON_CAPTIONFILTER).setVisible(is_video) self.getControl(ID_BUTTON_DEFINITIONFILTER).setVisible(is_video) - super(DialogYoutubeList, self).update_ui() + super().update_ui() @property def default_sort(self): @@ -204,7 +202,7 @@ def default_sort(self): def add_filter(self, **kwargs): kwargs["typelabel"] = self.FILTERS[kwargs["key"]] - super(DialogYoutubeList, self).add_filter(force_overwrite=True, + super().add_filter(force_overwrite=True, **kwargs) def fetch_data(self, force=False): diff --git a/script.extendedinfo/resources/lib/LastFM.py b/script.extendedinfo/resources/lib/lastfm.py similarity index 89% rename from script.extendedinfo/resources/lib/LastFM.py rename to script.extendedinfo/resources/lib/lastfm.py index 8ee346cfa..7bd73f1d8 100644 --- a/script.extendedinfo/resources/lib/LastFM.py +++ b/script.extendedinfo/resources/lib/lastfm.py @@ -1,28 +1,36 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details -"""Uses LastFM API to query data from LastFM. +"""Uses LastFM API to query data from LastFM. The get_* functions are called to query LastFM API. """ import re -from typing import Optional import urllib.error import urllib.parse import urllib.request +from typing import Optional + +from resources.kutil131 import ItemList -from kutils import ItemList, utils +from resources.kutil131 import utils LAST_FM_API_KEY = 'd942dd5ca4c9ee5bd821df58cf8130d4' GOOGLE_MAPS_KEY = 'AIzaSyBESfDvQgWtWLkNiOYXdrA9aU-2hv_eprY' BASE_URL = 'http://ws.audioscrobbler.com/2.0/?' -def _handle_albums(results) -> ItemList: +def _handle_albums(results: dict) -> ItemList: + """Converts TADB query results to kutils131 ItemList + + Args: + results (dict): TADB albums for an artist + + Returns: + ItemList: a kutils131 ItemList od dicts + """ albums = ItemList(content_type="albums") if not results: return albums @@ -39,6 +47,14 @@ def _handle_albums(results) -> ItemList: def _handle_artists(results) -> ItemList: + """Converts TADB artist query to kutils ItemList + + Args: + results (_type_): _description_ + + Returns: + ItemList: a kutils131 ItemList of artist info as dicts + """ artists = ItemList(content_type="artists") if not results: return artists @@ -59,7 +75,7 @@ def get_top_artists() -> ItemList: """Queries LastFM api chart.getTopArtists method for top 100 artists Returns: - ItemList: a kutils object that wraps a list of artist + ItemList: a kutils131 object that wraps a list of artist info dicts """ results: Optional[dict] = get_data(method="chart.getTopArtists", @@ -76,7 +92,7 @@ def get_artist_albums(artist_mbid: str) -> ItemList: artist_mbid (str): The musicbrainz id for the artist Returns: - ItemList: a kutils object that wraps a list of albums + ItemList: a kutils131object that wraps a list of albums info dicts """ if not artist_mbid: @@ -108,7 +124,7 @@ def get_similar_artists(artist_mbid: str) -> ItemList: def get_track_info(artist_name="", track="") -> dict: - """ Queries LastFM api + """ Queries LastFM api Args: artist_name (str, optional): The artist name. Defaults to "". diff --git a/script.extendedinfo/resources/lib/omdb.py b/script.extendedinfo/resources/lib/omdb.py index bbc2a2fab..d930cb15c 100644 --- a/script.extendedinfo/resources/lib/omdb.py +++ b/script.extendedinfo/resources/lib/omdb.py @@ -1,5 +1,3 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details @@ -9,24 +7,26 @@ """ -from typing import Optional +from __future__ import annotations + +from resources.kutil131 import addon -from kutils import addon, utils +from resources.kutil131 import utils BASE_URL = "http://www.omdbapi.com/?tomatoes=true&plot=full&r=json&" -def get_movie_info(imdb_id: str) -> Optional[dict]: +def get_movie_info(imdb_id: str) -> dict | None: """gets tomato data from OMDb Args: imdb_id (str): imbd id Returns: - Optional[dict]: Json.loads response from OMDb + dict | None: Json.loads response from OMDb or None if not available """ omdb_key: str = addon.setting('OMDb API Key') - url = 'apikey={0}&i={1}'.format(omdb_key, imdb_id) + url = f'apikey={omdb_key}&i={imdb_id}' results = utils.get_JSON_response(BASE_URL + url, 20, "OMDB") if not results: return None diff --git a/script.extendedinfo/resources/lib/process.py b/script.extendedinfo/resources/lib/process.py index 83b0601c6..3dd6e260f 100644 --- a/script.extendedinfo/resources/lib/process.py +++ b/script.extendedinfo/resources/lib/process.py @@ -1,43 +1,45 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details """When addon is called with RunScript, executes required action +When called as plugin, sets listitems to container -Action to run is passed in the call, along with any associated parameters +Public functions: + start_info_actions(info, params): takes in invocation info action + and optional param key/value pairs and exexutes the info action """ +from __future__ import annotations + import os import shutil import time -from typing import Dict import xbmc import xbmcgui import xbmcplugin +from resources.kutil131 import addon, busy, kodijson -from kutils import addon, busy, favs, kodijson, local_db, utils, youtube -from resources.lib import LastFM -from resources.lib import TheAudioDB as AudioDB -from resources.lib import TheMovieDB as tmdb -from resources.lib import Trakt +from resources.kutil131 import favs, local_db, utils, youtube +from resources.lib import lastfm +from resources.lib import theaudiodb as AudioDB +from resources.lib import themoviedb as tmdb +from resources.lib import trakt +from resources.lib.windowmanager import wm -from .WindowManager import wm - -def start_info_actions(info: str, params: Dict[str, str]) -> list: +def start_info_actions(info: str, params: dict[str, str]): """executes an action from infos (info= list) using any params See README for list of possible actions Args: info (str): one of a defined infos list of possible actions - params (Dict[str,str]): Optional parameters for the action + params (dict[str,str]): Optional parameters for the action Returns: - [type]: [description] + [ItemList]: a kodi utils ItemList of VideoItems/Music """ if "artistname" in params: params["artistname"] = params.get( @@ -45,7 +47,7 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: if not params.get("artist_mbid"): params["artist_mbid"] = utils.fetch_musicbrainz_id( params["artistname"]) - utils.log(f'start_info_actions: {info}') + utils.log(f'process start_info_actions info: {info} params:') utils.pp(params) if "prefix" in params and not params["prefix"].endswith('.'): params["prefix"] = params["prefix"] + '.' @@ -54,14 +56,14 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: if info == 'discography': discography = AudioDB.get_artist_discography(params["artistname"]) if not discography: - discography = LastFM.get_artist_albums(params.get("artist_mbid")) + discography = lastfm.get_artist_albums(params.get("artist_mbid")) return discography elif info == 'mostlovedtracks': return AudioDB.get_most_loved_tracks(params["artistname"]) elif info == 'trackdetails': return AudioDB.get_track_details(params.get("id", "")) elif info == 'topartists': - return LastFM.get_top_artists() + return lastfm.get_top_artists() # The MovieDB elif info == 'incinemamovies': return tmdb.get_movies("now_playing") @@ -79,9 +81,10 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: account_lists = tmdb.handle_lists(tmdb.get_account_lists()) for item in account_lists: item.set_property("directory", True) + item.set_folder(True) return account_lists elif info == 'listmovies': - return tmdb.get_movies_from_list(params["id"]) + return tmdb.get_movies_from_list(params["id"]) if params.get('id') else [] elif info == 'airingtodaytvshows': return tmdb.get_tvshows("airing_today") elif info == 'onairtvshows': @@ -181,7 +184,7 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: movie_id = local_db.get_imdb_id("movie", params["dbid"]) else: movie_id = params["id"] - return Trakt.get_similar("movie", movie_id) + return trakt.get_similar("movie", movie_id) elif info == 'traktsimilartvshows': if params.get("id") or params.get("dbid"): if params.get("dbid"): @@ -193,56 +196,56 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: dbid=params["dbid"]) else: tvshow_id = params["id"] - return Trakt.get_similar("show", tvshow_id) + return trakt.get_similar("show", tvshow_id) elif info == 'airingepisodes': - return Trakt.get_episodes("shows") + return trakt.get_episodes("shows") elif info == 'premiereepisodes': - return Trakt.get_episodes("premieres") + return trakt.get_episodes("premieres") elif info == 'trendingshows': - return Trakt.get_shows("trending") + return trakt.get_shows("trending") elif info == 'popularshows': - return Trakt.get_shows("popular") + return trakt.get_shows("popular") elif info == 'anticipatedshows': - return Trakt.get_shows("anticipated") + return trakt.get_shows("anticipated") elif info == 'mostcollectedshows': - return Trakt.get_shows_from_time("collected") + return trakt.get_shows_from_time("collected") elif info == 'mostplayedshows': - return Trakt.get_shows_from_time("played") + return trakt.get_shows_from_time("played") elif info == 'mostwatchedshows': - return Trakt.get_shows_from_time("watched") + return trakt.get_shows_from_time("watched") elif info == 'trendingmovies': - return Trakt.get_movies("trending") + return trakt.get_movies("trending") elif info == 'traktpopularmovies': - return Trakt.get_movies("popular") + return trakt.get_movies("popular") elif info == 'mostplayedmovies': - return Trakt.get_movies_from_time("played") + return trakt.get_movies_from_time("played") elif info == 'mostwatchedmovies': - return Trakt.get_movies_from_time("watched") + return trakt.get_movies_from_time("watched") elif info == 'mostcollectedmovies': - return Trakt.get_movies_from_time("collected") + return trakt.get_movies_from_time("collected") elif info == 'mostanticipatedmovies': - return Trakt.get_movies("anticipated") + return trakt.get_movies("anticipated") elif info == 'traktboxofficemovies': - return Trakt.get_movies("boxoffice") + return trakt.get_movies("boxoffice") elif info == 'similarartistsinlibrary': return local_db.get_similar_artists(params.get("artist_mbid")) # LastFM elif info == 'trackinfo': - addon.clear_global('%sSummary' % params.get("prefix", "")) + addon.clear_global(f'{params.get("prefix", "")}Summary') if params["artistname"] and params["trackname"]: - track_info = LastFM.get_track_info(artist_name=params["artistname"], + track_info = lastfm.get_track_info(artist_name=params["artistname"], track=params["trackname"]) - addon.set_global('%sSummary' % params.get( - "prefix", ""), track_info["summary"]) + addon.set_global(f'{params.get("prefix", "")}Summary', + track_info["summary"]) # Bands in town API no longer provides event access # elif info == 'topartistsnearevents': # artists = local_db.get_artists() - # from . import BandsInTown - # return BandsInTown.get_near_events(artists[0:49]) + # from . import bandsintown + # return bandsintown.get_near_events(artists[0:49]) # Youtube elif info == 'youtubesearchvideos': - addon.set_global('%sSearchValue' % params.get( - "prefix", ""), params.get("id", "")) + addon.set_global(f'{params.get("prefix", "")}SearchValue', + params.get("id", "")) user_key = addon.setting("Youtube API Key") if params.get("id"): return youtube.search(search_str=params.get("id", ""), @@ -285,33 +288,32 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: if xbmc.getCondVisibility("System.HasActiveModalDialog"): container_id = "" else: - container_id = "Container(%s)" % utils.get_infolabel( - "System.CurrentControlId") - dbid = utils.get_infolabel("%sListItem.DBID" % container_id) - db_type = utils.get_infolabel("%sListItem.DBType" % container_id) + container_id = f'Container({utils.get_infolabel("System.CurrentControlId")})' + dbid = utils.get_infolabel(f'{container_id}ListItem.DBID') + db_type = utils.get_infolabel(f'{container_id}ListItem.DBType') if db_type == "movie": params = {"dbid": dbid, - "id": utils.get_infolabel("%sListItem.Property(id)" % container_id), - "name": utils.get_infolabel("%sListItem.Title" % container_id)} + "id": utils.get_infolabel(f'{container_id}ListItem.Property(id)'), + "name": utils.get_infolabel(f'{container_id}ListItem.Title')} + utils.log(f'process.start_info_actions call exendedinfo with {params}') start_info_actions("extendedinfo", params) elif db_type == "tvshow": params = {"dbid": dbid, - "tvdb_id": utils.get_infolabel("%sListItem.Property(tvdb_id)" % container_id), - "id": utils.get_infolabel("%sListItem.Property(id)" % container_id), - "name": utils.get_infolabel("%sListItem.Title" % container_id)} + "tvdb_id": utils.get_infolabel(f'{container_id}ListItem.Property(tvdb_id)'), + "id": utils.get_infolabel(f'{container_id}ListItem.Property(id)'), + "name": utils.get_infolabel(f'{container_id}ListItem.Title')} start_info_actions("extendedtvinfo", params) elif db_type == "season": - params = {"tvshow": utils.get_infolabel("%sListItem.TVShowTitle" % container_id), - "season": utils.get_infolabel("%sListItem.Season" % container_id)} + params = {"tvshow": utils.get_infolabel(f'{container_id}ListItem.TVShowTitle'), + "season": utils.get_infolabel(f'{container_id}ListItem.Season')} start_info_actions("seasoninfo", params) elif db_type == "episode": - params = {"tvshow": utils.get_infolabel("%sListItem.TVShowTitle" % container_id), - "season": utils.get_infolabel("%sListItem.Season" % container_id), - "episode": utils.get_infolabel("%sListItem.Episode" % container_id)} + params = {"tvshow": utils.get_infolabel(f'{container_id}ListItem.TVShowTitle'), + "season": utils.get_infolabel(f'{container_id}ListItem.Season'), + "episode": utils.get_infolabel(f'{container_id}ListItem.Episode')} start_info_actions("extendedepisodeinfo", params) elif db_type in ["actor", "director"]: - params = {"name": utils.get_infolabel( - "%sListItem.Label" % container_id)} + params = {"name": utils.get_infolabel(f'{container_id}ListItem.Label')} start_info_actions("extendedactorinfo", params) else: utils.notify("Error", "Could not find valid content type") @@ -319,23 +321,22 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: if xbmc.getCondVisibility("System.HasModalDialog"): container_id = "" else: - container_id = "Container(%s)" % utils.get_infolabel( - "System.CurrentControlId") - dbid = utils.get_infolabel("%sListItem.DBID" % container_id) - db_type = utils.get_infolabel("%sListItem.DBType" % container_id) + container_id = f'Container({utils.get_infolabel("System.CurrentControlId")})' + dbid = utils.get_infolabel(f'{container_id}ListItem.DBID') + db_type = utils.get_infolabel(f'{container_id}ListItem.DBType') if db_type == "movie": params = {"dbid": dbid, - "id": utils.get_infolabel("%sListItem.Property(id)" % container_id), + "id": utils.get_infolabel(f'{container_id}ListItem.Property(id)'), "type": "movie"} start_info_actions("ratemedia", params) elif db_type == "tvshow": params = {"dbid": dbid, - "id": utils.get_infolabel("%sListItem.Property(id)" % container_id), + "id": utils.get_infolabel(f'{container_id}ListItem.Property(id)'), "type": "tv"} start_info_actions("ratemedia", params) if db_type == "episode": - params = {"tvshow": utils.get_infolabel("%sListItem.TVShowTitle" % container_id), - "season": utils.get_infolabel("%sListItem.Season" % container_id), + params = {"tvshow": utils.get_infolabel(f'{container_id}ListItem.TVShowTitle'), + "season": utils.get_infolabel(f'{container_id}ListItem.Season'), "type": "episode"} start_info_actions("ratemedia", params) elif info == 'youtubebrowser': @@ -344,62 +345,74 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: if addon.get_global('infodialogs.active'): return None addon.set_global('infodialogs.active', "true") - search_str = params.get("id", "") - if not search_str and params.get("search"): - result = xbmcgui.Dialog().input(heading=addon.LANG(16017), - type=xbmcgui.INPUT_ALPHANUM) - if result and result > -1: - search_str = result - else: - addon.clear_global('infodialogs.active') - return None - wm.open_video_list(search_str=search_str, - mode="search") - addon.clear_global('infodialogs.active') - elif info == 'extendedinfo': + try: + search_str = params.get("id", "") + if not search_str and params.get("search"): + result = xbmcgui.Dialog().input(heading=addon.LANG(16017), + type=xbmcgui.INPUT_ALPHANUM) + if result and result > -1: + search_str = result + else: + addon.clear_global('infodialogs.active') + return None + wm.open_video_list(search_str=search_str, + mode="search") + finally: + addon.clear_global('infodialogs.active') + elif info == 'extendedinfo': # called with movie if addon.get_global('infodialogs.active'): return None addon.set_global('infodialogs.active', "true") - wm.open_movie_info(movie_id=params.get("id"), - dbid=params.get("dbid"), - imdb_id=params.get("imdb_id"), - name=params.get("name")) - addon.clear_global('infodialogs.active') + try: + wm.open_movie_info(movie_id=params.get("id"), + dbid=params.get("dbid"), + imdb_id=params.get("imdb_id"), + name=params.get("name")) + finally: + addon.clear_global('infodialogs.active') elif info == 'extendedactorinfo': if addon.get_global('infodialogs.active'): return None addon.set_global('infodialogs.active', "true") - wm.open_actor_info(actor_id=params.get("id"), - name=params.get("name")) - addon.clear_global('infodialogs.active') + try: + wm.open_actor_info(actor_id=params.get("id"), + name=params.get("name")) + finally: + addon.clear_global('infodialogs.active') elif info == 'extendedtvinfo': if addon.get_global('infodialogs.active'): return None addon.set_global('infodialogs.active', "true") - wm.open_tvshow_info(tmdb_id=params.get("id"), - tvdb_id=params.get("tvdb_id"), - dbid=params.get("dbid"), - imdb_id=params.get("imdb_id"), - name=params.get("name")) - addon.clear_global('infodialogs.active') + try: + wm.open_tvshow_info(tmdb_id=params.get("id"), + tvdb_id=params.get("tvdb_id"), + dbid=params.get("dbid"), + imdb_id=params.get("imdb_id"), + name=params.get("name")) + finally: + addon.clear_global('infodialogs.active') elif info == 'seasoninfo': if addon.get_global('infodialogs.active'): return None addon.set_global('infodialogs.active', "true") - wm.open_season_info(tvshow=params.get("tvshow"), - dbid=params.get("dbid"), - season=params.get("season")) - addon.clear_global('infodialogs.active') + try: + wm.open_season_info(tvshow=params.get("tvshow"), + dbid=params.get("dbid"), + season=params.get("season")) + finally: + addon.clear_global('infodialogs.active') elif info == 'extendedepisodeinfo': if addon.get_global('infodialogs.active'): return None addon.set_global('infodialogs.active', "true") - wm.open_episode_info(tvshow=params.get("tvshow"), - tvshow_id=params.get("tvshow_id"), - dbid=params.get("dbid"), - episode=params.get("episode"), - season=int(params.get("season"))) - addon.clear_global('infodialogs.active') + try: + wm.open_episode_info(tvshow=params.get("tvshow"), + tvshow_id=params.get("tvshow_id"), + dbid=params.get("dbid"), + episode=params.get("episode"), + season=int(params.get("season"))) + finally: + addon.clear_global('infodialogs.active') elif info == 'albuminfo': if params.get("id"): album_details = AudioDB.get_album_details(params.get("id")) @@ -464,8 +477,8 @@ def start_info_actions(info: str, params: Dict[str, str]) -> list: try: if os.path.isdir(path): shutil.rmtree(path) - except Exception as e: - utils.log(e) + except Exception as err: + utils.log(f'Failed to remove cache due to {err}') utils.notify("Cache deleted") elif info == 'tmdbpassword': addon.set_password_prompt("tmdb_password") diff --git a/script.extendedinfo/resources/lib/TheAudioDB.py b/script.extendedinfo/resources/lib/theaudiodb.py similarity index 93% rename from script.extendedinfo/resources/lib/TheAudioDB.py rename to script.extendedinfo/resources/lib/theaudiodb.py index 6d3ca9258..ecdd45d6e 100644 --- a/script.extendedinfo/resources/lib/TheAudioDB.py +++ b/script.extendedinfo/resources/lib/theaudiodb.py @@ -1,25 +1,24 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details -"""Modules with get_* functions to query TADB +"""Module with get_* functions to query TADB Requires user API key (subscription basis) to access -TODO: handle user api key """ +from __future__ import annotations + import urllib.error import urllib.parse import urllib.request -from typing import Union import xbmc +from resources.kutil131 import ItemList, addon -from kutils import AudioItem, ItemList, VideoItem, addon, local_db, utils +from resources.kutil131 import AudioItem, VideoItem, local_db, utils -AUDIO_DB_KEY = '58353d43204d68753987fl' #key no longer accepted +AUDIO_DB_KEY = '2' #key no longer accepted - this is demo key BASE_URL = 'https://www.theaudiodb.com/api/v1/json' PLUGIN_BASE = 'plugin://script.extendedinfo/?info=' @@ -144,7 +143,6 @@ def extended_artist_info(results: dict) -> dict: 'Artist_Formed': artist.get('intFormedYear'), 'Artist_Died': artist.get('intDiedYear'), 'Artist_Disbanded': artist.get('strDisbanded'), - 'Artist_Mood': artist.get('strMood'), 'Artist_Description': description, 'Artist_Genre': artist.get('strGenre'), 'Artist_Style': artist.get('strStyle'), @@ -175,7 +173,7 @@ def get_artist_discography(search_str) -> ItemList: return _handle_albums(results) -def get_artist_details(search_str) -> Union[ItemList, dict]: +def get_artist_details(search_str) -> ItemList | dict: """gets artist details from TADB Args: @@ -188,10 +186,13 @@ def get_artist_details(search_str) -> Union[ItemList, dict]: return ItemList(content_type="artists") params = {"s": search_str} results = get_data("search", params) - return extended_artist_info(results) + if results: + return extended_artist_info(results) + else: + utils.notify("No artist info from TheAudioDb") -def get_most_loved_tracks(search_str="", mbid="") -> Union[ItemList, list]: +def get_most_loved_tracks(search_str="", mbid="") -> ItemList | list: """ highest rated TADB soings for artist Args: @@ -234,7 +235,7 @@ def get_musicvideos(audiodb_id): return _handle_musicvideos(results) -def get_track_details(audiodb_id: str) -> Union[ItemList, list]: +def get_track_details(audiodb_id: str) -> ItemList | list: """gets TADB info for a track Args: @@ -261,6 +262,8 @@ def get_data(url: str, params: dict) -> dict: dict: TADB api response """ tadb_key: str = addon.setting('TADB API Key') + if tadb_key is None or tadb_key == '': + tadb_key = AUDIO_DB_KEY #limited function key params: dict = {k: str(v) for k, v in params.items() if v} url: str = "{0}/{1}/{2}.php?{3}".format(BASE_URL, tadb_key, url, urllib.parse.urlencode(params)) diff --git a/script.extendedinfo/resources/lib/TheMovieDB.py b/script.extendedinfo/resources/lib/themoviedb.py similarity index 77% rename from script.extendedinfo/resources/lib/TheMovieDB.py rename to script.extendedinfo/resources/lib/themoviedb.py index 3a6204217..99369d590 100644 --- a/script.extendedinfo/resources/lib/TheMovieDB.py +++ b/script.extendedinfo/resources/lib/themoviedb.py @@ -1,17 +1,89 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +"""functions and classes to retrieve info from TMDB api v3 +see: https://developers.themoviedb.org/3/getting-started + +Public variables: + Login(LoginProvider): a TMDB session instance that logs into TMDB on + creation + +Public functions: + set_rating: sets local videodb userrating or TMDB user rating (called from button in dialogvideoinfo) + change_fav_status: sets TMDB user favorite (called from button in dialogvideoinfo) + create_list: creates a new user list on TMDB + remove_list_dialog: opens a Kodi select dialog to allow user to select + a TMDB list for removal + change_list_status: Adds or removes a video item from user's TMDB list + get_account_lists: gets the user's TMDB lists + get_certification_list: gets the TMDB certifications ("MPAA") + handle_movies/tvshows/episodes: creates a kutils ItemList instance + of kutils VideoItems instances with Kodi listitem properties for the + video media type to display as Kodi container content items + handle_lists: adds user TMDB lists to kutils ItemList instance for display + in Kodi cantainer content + handle_seasons: adds seasons to kutils ItemList instance + handle_videos: adds video clips as kutils VideoItems to kutils ItemList instance + search_companies: gets the TMDB company ID for company (studio) name string + multi_search: performs TMDB multisearch "Multi search currently supports + searching for movies, tv shows and people in a single request." + get_list_movies: query TMDB movie list for TMDB id + get_person_info: query TMDB actors/crew details for person name(s) + get_keywords: query TMDB keywords by keyword string for TMDB id + get_set_id: query TMDB sets by string for TMDB id + get_data: query TMDB with various search terms + get_company_data: query TMDB for company data using TMDB id + get_credit_info: query TMDB for credit data using TMDB id + get_account_props: provide various TMDB account related info as a dict + get_movie_tmdb_id: queries TMDB for TMDB video id if IMDB id is in + local videodb + get_show_tmdb_id: queries TMDB for TMDB tvshow id if TVDB id is in + local videodb + get_movie_videos: queries TMDB for movie trailers + extended_movie_info: sets Kodi listitem properties as a kutils + VideoItem instance and additionally returns a dict of kutil itemlists + instances + get_tvshow: queries TMDB for tvshow details as dict + extended_tvshow_info: sets Kodi listitem properties as a kutils + VideoItem instance and additionally returns a dict of kutil itemlists + instances + extended_season_info: sets Kodi listitem properties as a kutils + VideoItem instance and additionally returns a dict of kutil itemlists + instances + get_episode: queries TMDB for episode details as dict + extended_episode_info: sets Kodi listitem properties as a kutils + VideoItem instance and additionally returns a dict of kutil itemlists + instances + extended_actor_info: sets Kodi listitem properties as a kutils + VideoItem instance and additionally returns a dict of kutil itemlists + instances + get_movie_lists: gets kutils ItemList instance for movie lists + get_rated_media_items: queries TMDB for user media ratings + get_fav_items: queries TMDB for user favorites + get_movies_from_list: queries TMDB for movie list + get_popular_actors: queries TMDB for popular actors + get_movie: queries TMDB for movie given TMDB id + get_similar_movies: queries TMDB for similar movies + get_similar_tvshows: queries TMDB for similar tvshows + get_tvshows/movies: queries TMDB for tvshows/movies matching type + get_set_movies: queries TMDB for itemlist of movies in set + get_person_movies: queries TMDB for itemlist of movies for actor + search_media: generalized TMDB query + +""" + +from __future__ import annotations + import re +import traceback import urllib.error import urllib.parse import urllib.request -from typing import List, Optional, Union, Tuple -from kutils import (ItemList, VideoItem, addon, kodijson, local_db, - selectdialog, utils) +from resources.kutil131 import ItemList, addon, kodijson, selectdialog + +from resources.kutil131 import VideoItem, local_db, utils TMDB_KEY = '34142515d9d23817496eeb4ff1d223d0' POSTER_SIZES = ["w92", "w154", "w185", "w342", "w500", "w780", "original"] @@ -58,7 +130,12 @@ class LoginProvider: logs into TMDB for user or guest and gets corresponding session or guest session id """ - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> LoginProvider: + """Creates a new session for user at tmdb + + Returns: + LoginProvider: session for user + """ self.session_id = None self.logged_in = False self.account_id = None @@ -147,7 +224,7 @@ def set_rating(media_type, media_id, rating, dbid=None): ''' media_type: movie, tv or episode media_id: tmdb_id / episode ident array - rating: ratung value (1 - 10, 0 for deleting) + rating: rating value (1 - 10, 0 for deleting) dbid: dbid for syncing userrating of db item ''' if not media_type or not media_id or rating == -1: @@ -180,7 +257,6 @@ def send_request(url, params, values, delete=False): params["api_key"] = TMDB_KEY params = {k: str(v) for k, v in params.items() if v} url = "%s%s?%s" % (URL_BASE, url, urllib.parse.urlencode(params)) - #utils.log(url) if delete: return utils.delete(url, values=values, headers=HEADERS) else: @@ -258,16 +334,35 @@ def get_account_lists(cache_days=0): return response["results"] -def get_certification_list(media_type): - response = get_data(url="certification/%s/list" % media_type, +def get_certification_list(media_type:str) -> dict[str,list]: + """Gets the known certifications and meanings from tmdb + The list is cached since it doesn't change (much?) + + Args: + media_type (str): movie/tv + + Returns: + dict[str,list]: a dict keys are ISO-1366-1 countries + values are list of certs and their descriptions + """ + response = get_data(url=f"certification/{media_type}/list", cache_days=999999) return response.get("certifications") -def merge_with_cert_desc(input_list, media_type): +def merge_with_cert_desc(input_list: ItemList, media_type: str) -> ItemList: + """adds the tmdb text description of certification + + Args: + input_list (ItemList): the ItemList of releases (with country and cert) + media_type (str): movie or tv + + Returns: + ItemList: the input ItemList with cert meanings appended to the VideoItems + """ cert_list = get_certification_list(media_type) for item in input_list: - iso = item.get_property("iso_3166_1").upper() + iso = item.get_property("iso_3166_1") if iso not in cert_list: continue hit = utils.dictfind(lst=cert_list[iso], @@ -277,6 +372,27 @@ def merge_with_cert_desc(input_list, media_type): item.set_property("meaning", hit["meaning"]) return input_list +def get_best_release(co_releases:list) -> dict: + """Gets a single release for a country with multiple releases + Ensures the release has a cert. Best release is release with + "lowest" tmdb release type value + + Args: + co_releases (list): _description_ + + Returns: + dict: _description_ + """ + best_release = {} + for release in co_releases: + if not release.get('certification'): + continue + if not best_release: + best_release = release + elif int(release.get('type')) < int(best_release.get('type')): + best_release = release + return best_release + def handle_multi_search(results): listitems = ItemList(content_type="videos") @@ -290,8 +406,12 @@ def handle_multi_search(results): return listitems -def handle_movies(results: List[dict], local_first=True, sortkey="year") ->ItemList: - """takes a list of movies (dicts) and adds local db data then sorts as an ItemList +def handle_movies(results: list[dict], local_first=True, sortkey="year") ->ItemList: + """takes a list of movies (dicts) and adds local db data and then sorts as an ItemList + The tmdb movie keys are converted to extendedinfo keys and genre ids converted + to localized text strings, then a VideoItem is created for each movie. The + Kodi videodb is searched for any matching local movies and these are added to + the ItemList as VideoItems. Args: results (List[dict]): a list of movies, each movie is a dict @@ -304,8 +424,8 @@ def handle_movies(results: List[dict], local_first=True, sortkey="year") ->ItemL response: dict = get_data(url="genre/movie/list", params={"language": addon.setting("LanguageID")}, cache_days=30) - ids: List[int] = [item["id"] for item in response["genres"]] - labels: List[str] = [item["name"] for item in response["genres"]] + ids: list[int] = [item["id"] for item in response["genres"]] + labels: list[str] = [item["name"] for item in response["genres"]] movies = ItemList(content_type="movies") path = 'extendedinfo&&id=%s' if addon.bool_setting( "infodialog_onclick") else "playtrailer&&id=%s" @@ -342,7 +462,7 @@ def handle_movies(results: List[dict], local_first=True, sortkey="year") ->ItemL sortkey=sortkey) -def handle_tvshows(results, local_first=True, sortkey="year"): +def handle_tvshows(results:list[dict], local_first=True, sortkey="year"): tvshows = ItemList(content_type="tvshows") response = get_data(url="genre/tv/list", params={"language": addon.setting("LanguageID")}, @@ -415,19 +535,40 @@ def handle_episodes(results): return listitems -def handle_release_dates(results): +def handle_release_dates(results:list[dict]) -> ItemList: + """Creates ItemList of video mpaa cert and dates as VideoItems + + Args: + results (list[dict]): a list of dicts with TMDB releases + + Returns: + ItemList: ItemList of releases/certs + """ listitems = ItemList() for item in results: - ref = item["release_dates"][0] - if not ref.get("certification"): - continue - listitem = VideoItem(label=item.get('name')) - listitem.set_properties({'certification': ref.get('certification'), - 'iso_3166_1': item.get('iso_3166_1', "").lower(), - 'note': ref.get('note'), - 'iso_639_1': ref.get('iso_639_1'), - 'release_date': ref.get('release_date'), - 'type': RELEASE_TYPES.get(ref.get('type'))}) + if len(item["release_dates"]) == 1: + ref:dict = item["release_dates"][0] #only handles the first listed release per country + if not ref.get("certification"): + continue + #listitem = VideoItem(label=item.get('name')) #no key 'name' + listitem = VideoItem(label='') + listitem.set_properties({'certification': ref.get('certification'), + 'iso_3166_1': item.get('iso_3166_1', ""), + 'note': ref.get('note'), + 'iso_639_1': ref.get('iso_639_1'), + 'release_date': ref.get('release_date'), + 'type': RELEASE_TYPES.get(ref.get('type'))}) + else: + ref:dict = get_best_release(item["release_dates"]) + if not ref: + continue + listitem = VideoItem(label='') + listitem.set_properties({'certification': ref.get('certification'), + 'iso_3166_1': item.get('iso_3166_1', ""), + 'note': ref.get('note'), + 'iso_639_1': ref.get('iso_639_1'), + 'release_date': ref.get('release_date'), + 'type': RELEASE_TYPES.get(ref.get('type'))}) listitems.append(listitem) return listitems @@ -454,7 +595,15 @@ def handle_reviews(results): return listitems -def handle_text(results): +def handle_text(results:list[dict]) -> ItemList[VideoItem]: + """Converts list of textual info (genres, countries) to ItemList + + Args: + results (list[dict]): a list of related text info + + Returns: + ItemList: an ItemList of the text info as VideoItems + """ listitems = ItemList() for item in results: listitem = VideoItem(label=item.get('name')) @@ -463,7 +612,15 @@ def handle_text(results): return listitems -def handle_lists(results): +def handle_lists(results:list[dict]) -> ItemList[VideoItem]: + """Converts various tmdb user movie lists to ItemList + + Args: + results (list[dict]): list of user movie collections each item is a collection + + Returns: + ItemList: ItemList of collections as VideoItems type of 'set' + """ listitems = ItemList(content_type="sets") for item in results: listitem = VideoItem(label=item.get('name'), @@ -496,7 +653,15 @@ def handle_seasons(results): return listitems -def handle_videos(results): +def handle_videos(results:list[dict]) -> ItemList[VideoItem]: + """Creates an ItemList of video clips/trailers as VideoItems + + Args: + results (list[dict]): list of clips/trailers + + Returns: + ItemList: ItemList of VideoItems of the clips/trailers + """ listitems = ItemList(content_type="videos") for item in results: listitem = VideoItem(label=item.get('name'), @@ -513,12 +678,28 @@ def handle_videos(results): return listitems -def handle_people(results): +def handle_people(results: list[dict], select: bool = False) -> ItemList[VideoItem]: + """converts list of tmdb people into kutils videoitems + The VideoItem properties are tmdb query results + + Args: + results (list[dict]): a list of dicts, each dict is tmdb data for a person + select (bool): True if people are to be added to select dialog listing + + Returns: + ItemList: A kutils ItemList of VideoItems for tmdb persons + """ people = ItemList(content_type="actors") for item in results: - person = VideoItem(label=item['name'], - path="%sextendedactorinfo&&id=%s" % ( - PLUGIN_BASE, item['id']), + name_ext: str = '' + if item.get('adult'): + name_ext = name_ext + ' Adult' + if item.get('known_for_department'): + name_ext = name_ext + f' {item["known_for_department"]}' + if name_ext != '': + name_ext = f' -{name_ext}' + person = VideoItem(label=item['name'] if not select else f'{item["name"]}{name_ext}', + path=f"{PLUGIN_BASE}extendedactorinfo&&id={item['id']}", infos={'mediatype': "artist"}, artwork=get_image_urls(profile=item.get("profile_path"))) person.set_properties({'adult': item.get('adult'), @@ -534,22 +715,31 @@ def handle_people(results): 'credit_id': item.get('credit_id'), 'deathday': item.get('deathday'), 'placeofbirth': item.get('place_of_birth'), - 'homepage': item.get('homepage')}) + 'homepage': item.get('homepage'), + 'known_for_department': item.get('known_for_department')}) people.append(person) return people -def handle_images(results): +def handle_images(results:list[dict]) -> ItemList[VideoItem]: + """creates VideoItems of images and returns an ItemList + + Args: + results (list[dict]): image list + + Returns: + ItemList: kutils itemlist of the images as VideoItems type 'music'? + """ images = ItemList(content_type="images") for item in results: - artwork = get_image_urls(poster=item.get("file_path")) + artwork = get_image_urls(poster=item.get("file_path")) #artwork is a dict key imagetype value path to image image = VideoItem(artwork=artwork) image.set_properties({'aspectratio': item['aspect_ratio'], 'type': "poster" if item['aspect_ratio'] < 0.7 else "fanart", 'rating': item.get("vote_average"), 'votes': item.get("vote_count"), 'iso_639_1': item.get("iso_639_1")}) - if item.get("media"): + if item.get("media") and item["media"].get("title"): #tmdb has 2 media returns: movie and tv image.set_label(item["media"].get("title")) image.set_property("movie_id", item["media"].get("id")) poster_path = item["media"].get("poster_path") @@ -561,7 +751,15 @@ def handle_images(results): return images -def handle_companies(results): +def handle_companies(results:list[dict]) -> ItemList[VideoItem]: + """Converts list of studios from tmdb to ItemList of VideoItems + + Args: + results (list[dict]): tmdb "production comapnies" list + + Returns: + ItemList: ItemList of studio VideoItems + """ companies = ItemList(content_type="studios") for item in results: company = VideoItem(label=item['name'], @@ -579,14 +777,13 @@ def handle_companies(results): def search_companies(company_name): - regex = re.compile('\(.+?\)') + regex = re.compile(r'\(.+?\)') response = get_data(url="search/company", params={"query": regex.sub('', company_name)}, cache_days=10) if response and "results" in response: return handle_companies(response["results"]) else: - utils.log("Could not find company ID for %s" % company_name) return None @@ -618,7 +815,28 @@ def get_list_movies(list_id, force): return itemlist -def get_person_info(person_label, skip_dialog=False): +def get_person_info(person_label:str, skip_dialog=False) -> dict: + """takes an actor name and returns actor info for it + + Args: + person_label (str): the actor name, or names with ' / ' as separator + skip_dialog (bool, optional): Option to show user select dialog for + mulitple tmdb names. Defaults to False. + If true first actor in response is returned + + Returns: + dict: a dict of info for the named actor -- keys + 'adult' : bool + 'gender' : int enum + 'id' : int + 'known_for' : list of dicts of media info + 'known_for_department' : str enum + 'name' : str + 'popularity' : float + 'profile_path' : str of image path/filename + False: if no response + + """ if not person_label: return False params = {"query": person_label.split(" / ")[0], @@ -628,10 +846,10 @@ def get_person_info(person_label, skip_dialog=False): cache_days=30) if not response or "results" not in response: return False - people = [i for i in response["results"] if i["name"] == person_label] + people: list[dict] = [i for i in response["results"] if i["name"] == person_label] if len(people) > 1 and not skip_dialog: index = selectdialog.open(header=f'{addon.LANG(32151)} TMDB People', - listitems=handle_people(people)) + listitems=handle_people(people, select=True)) return people[index] if index > -1 else False elif people: return people[0] @@ -647,7 +865,6 @@ def get_keywords(search_label): params=params, cache_days=30) if not response or not response.get("results"): - utils.log("could not find Keyword ID") return False return response["results"] @@ -663,18 +880,18 @@ def get_set_id(set_name): return response["results"][0]["id"] -def get_data(url: str = "", params: Optional[dict] = None, cache_days: float = 14) -> Optional[dict]: +def get_data(url: str = "", params: dict = None, cache_days: float = 14) -> dict: """Queries tmdb api v3 or local cache Args: url (str, optional): tmdb query terms for the search apiv3. Defaults to "". - params (Optional[dict], optional): Dict of optional parameters for + params (dict, None): Dict of optional parameters for query. Defaults to None. cache_days (float, optional): Days to check for cached values. Defaults to 14. Returns: - dict: A dict of JSON.loads response from TMDB or None if no + response(dict): A dict of JSON.loads response from TMDB or None if no TMDB response """ params = params if params else {} @@ -683,10 +900,11 @@ def get_data(url: str = "", params: Optional[dict] = None, cache_days: float = 1 url = "%s%s?%s" % (URL_BASE, url, urllib.parse.urlencode(params)) response = utils.get_JSON_response(url, cache_days, "TheMovieDB") if not response: - utils.log("No response from TMDB") + utils.log("tmdb.get_data No response from TMDB") + return None + if "status_code" in response and response.get("status_code") != 1: + utils.log(f'tmdb.get_data FAIL TMDB status code: {response.get("status_code")} {traceback.format_stack(limit=-3)}') return None - elif "status_code" in response: - utils.log("TMDB status code: %s" % response.get("status_code")) return response @@ -708,14 +926,14 @@ def get_credit_info(credit_id): cache_days=30) -def get_account_props(states): +def get_account_props(states) -> dict: return {"FavButton_Label": addon.LANG(32155) if states.get("favorite") else addon.LANG(32154), "favorite": "True" if states.get("favorite") else "", "rated": int(states["rated"]["value"]) if states["rated"] else "", "watchlist": states["watchlist"] if "watchlist" in states else ""} -def get_image_urls(poster=None, still=None, fanart=None, profile=None): +def get_image_urls(poster=None, still=None, fanart=None, profile: str =None) -> dict: ''' get a dict with all available images for given image types ''' @@ -744,12 +962,21 @@ def get_image_urls(poster=None, still=None, fanart=None, profile=None): return images -def get_movie_tmdb_id(imdb_id=None, name=None, dbid=None): +def get_movie_tmdb_id(imdb_id:str=None, name:str=None, dbid:int=None): + """Gets tmdb id for movie + + + Args: + imdb_id (str, optional): the movie imbd id. Defaults to None. + name (str, optional): the movie title. Defaults to None. + dbid (int, optional): the kodi db movie id should be > 0. Defaults to None. + + Returns: + str: tmdb id for local movie get local imdb_id and use for query + or fall back to title + """ if dbid and (int(dbid) > 0): - movie_id = local_db.get_imdb_id("movie", dbid) - if movie_id: - utils.log("IMDB Id from local DB: %s" % (movie_id)) - return movie_id + imdb_id = local_db.get_imdb_id("movie", dbid) if imdb_id: params = {"external_source": "imdb_id", "language": addon.setting("LanguageID")} @@ -757,7 +984,7 @@ def get_movie_tmdb_id(imdb_id=None, name=None, dbid=None): params=params) if response and response["movie_results"]: return response["movie_results"][0]["id"] - return search_media(name) if name else None + return search_media(media_name = name) if name else None def get_show_tmdb_id(tvdb_id=None, source="tvdb_id"): @@ -793,7 +1020,7 @@ def get_movie_videos(movie_id): return None -def extended_movie_info(movie_id=None, dbid=None, cache_days=14) -> Optional[dict]: +def extended_movie_info(movie_id=None, dbid=None, cache_days=14) -> tuple[VideoItem, dict[str, ItemList], dict] | None: """get listitem with extended info for movie with *movie_id merge in info from *dbid if available @@ -803,17 +1030,19 @@ def extended_movie_info(movie_id=None, dbid=None, cache_days=14) -> Optional[dic cache_days (int, optional): Days to use cached info. Defaults to 14. Returns: - Optional[dict]: A dict of movie information + tuple: kutils VideoItem of movie info + dict of key str value kutils ItemList + dict of account states """ if not movie_id: return None - info: Union[dict, None] = get_movie( + info: dict | None = get_movie( movie_id=movie_id, cache_days=cache_days) - if not info: - utils.notify("Could not get movie information") - return {} + if not info or info.get('success') is False: + utils.notify("Could not get tmdb movie information") + return (None, None, None) mpaa = "" - studio = [i["name"] for i in info["production_companies"]] + studio = [i["name"] for i in info.get("production_companies")] authors = [i["name"] for i in info['credits'] ['crew'] if i["department"] == "Writing"] directors = [i["name"] for i in info['credits'] @@ -824,7 +1053,7 @@ def extended_movie_info(movie_id=None, dbid=None, cache_days=14) -> Optional[dic mpaa = us_cert['release_dates'][0]["certification"] elif info['release_dates']['results']: mpaa = info['release_dates']['results'][0]['release_dates'][0]['certification'] - movie_set = info.get("belongs_to_collection") + movie_set:dict = info.get("belongs_to_collection") movie = VideoItem(label=info.get('title'), path=PLUGIN_BASE + 'youtubevideo&&id=%s' % info.get("id", "")) movie.set_infos({'title': info.get('title'), @@ -857,9 +1086,9 @@ def extended_movie_info(movie_id=None, dbid=None, cache_days=14) -> Optional[dic fanart=info.get("backdrop_path"))) videos = handle_videos(info["videos"]["results"] ) if "videos" in info else [] - account_states = info.get("account_states") + account_states: dict = info.get("account_states") if dbid: - local_item = local_db.get_movie(dbid) + local_item: dict = local_db.get_movie(dbid) movie.update_from_listitem(local_item) else: movie = local_db.merge_with_local("movie", [movie])[0] @@ -868,7 +1097,7 @@ def extended_movie_info(movie_id=None, dbid=None, cache_days=14) -> Optional[dic info['vote_average'], 1) if info.get('vote_average') else "") releases = merge_with_cert_desc(handle_release_dates( info["release_dates"]["results"]), "movie") - listitems = {"actors": handle_people(info["credits"]["cast"]), + listitems: dict[str, ItemList] = {"actors": handle_people(info["credits"]["cast"]), "similar": handle_movies(info["similar"]["results"]), "lists": sort_lists(handle_lists(info["lists"]["results"])), "studios": handle_companies(info["production_companies"]), @@ -1045,38 +1274,39 @@ def extended_episode_info(tvshow_id, season, episode, cache_days=7): return (handle_episodes([response])[0], answer, response.get("account_states")) -def extended_actor_info(actor_id) -> Tuple[VideoItem, dict]: +def extended_actor_info(actor_id: int) -> tuple[VideoItem, dict[str, ItemList]]: """gets ListItem and lists with extended info for actor with actor_id data is a dict from JSON returned by tmdb for an actor lists is a dict of "append_to_response" queries extracted from data info is a Kodi video listitem instance with properties set from data Args: - actor_id (str): the tmdb actor id + actor_id (int): the tmdb actor id Returns: - VideoItem: a populated Kodi listitem - dict: the lists of ListItems items for which actor has role and actor images + info[VideoItem]: a populated Kodi listitem + lists[dict]: a dict of kutils Itemlists (one per category) Itemlist is sequence + of kutils VideoItems None: if no results from tmdb """ if not actor_id: return None - data = get_data(url="person/%s" % (actor_id), + data: dict = get_data(url="person/%s" % (actor_id), params={"append_to_response": ALL_ACTOR_PROPS}, cache_days=1) if not data: utils.notify("Could not find actor info") return None - lists = {"movie_roles": handle_movies(data["movie_credits"]["cast"]).reduce("character"), + # extract info from data dict as list of ItemLists + lists: dict[str, ItemList] = {"movie_roles": handle_movies(data["movie_credits"]["cast"]).reduce("character"), "tvshow_roles": handle_tvshows(data["tv_credits"]["cast"]).reduce("character"), "movie_crew_roles": handle_movies(data["movie_credits"]["crew"]).reduce(), "tvshow_crew_roles": handle_tvshows(data["tv_credits"]["crew"]).reduce(), "tagged_images": handle_images(data["tagged_images"]["results"]) if "tagged_images" in data else [], "images": handle_images(data["images"]["profiles"])} info = VideoItem(label=data['name'], - path="%sextendedactorinfo&&id=%s" % ( - PLUGIN_BASE, data['id']), - infos={'mediatype': "artist"}) + path=f"{PLUGIN_BASE}extendedactorinfo&&id={data['id']}", + infos={'mediatype': "artist"}) # kutils VideoItem subclass of ListItem a kodi-like class info.set_properties({'adult': data.get('adult'), 'alsoknownas': " / ".join(data.get('also_known_as', [])), 'biography': data.get('biography'), @@ -1092,6 +1322,7 @@ def extended_actor_info(actor_id) -> Tuple[VideoItem, dict]: 'deathday': data.get('deathday'), 'placeofbirth': data.get('place_of_birth'), 'homepage': data.get('homepage'), + 'totalmovies': len(lists["movie_roles"]), "DBMovies": len([d for d in lists["movie_roles"] if "dbid" in d])}) info.set_artwork(get_image_urls(profile=data.get("profile_path"))) return (info, lists) @@ -1104,7 +1335,7 @@ def translate_status(status): return STATUS.get(status.lower(), status) -def get_movie_lists(movie_id): +def get_movie_lists(movie_id) -> ItemList: data = get_movie(movie_id) return handle_lists(data["lists"]["results"]) @@ -1180,7 +1411,7 @@ def get_movies_from_list(list_id, cache_days=5): ''' get movie dict list from tmdb list. ''' - data = get_data(url="list/%s" % (list_id), + data = get_data(url=f"list/{list_id}", params={"language": addon.setting("LanguageID")}, cache_days=cache_days) return handle_movies(data["items"], False, None) if data else [] @@ -1204,13 +1435,13 @@ def get_actor_credits(actor_id, media_type): return handle_movies(response["cast"]) -def get_movie(movie_id, light=False, cache_days=30) -> Union[dict, None]: +def get_movie(movie_id, light=False, cache_days=30) -> dict | None: """gets details from tmdb for a moview with tmdb movie-id Args: movie_id (str): tmdb movie id light (bool, optional): return limited info. Defaults to False. - cache_days (int, optional):days to use cache vice new query. + cache_days (int, None):days to use cache vice new query. Defaults to 30. Returns: @@ -1268,7 +1499,7 @@ def get_tvshows(tvshow_type): return handle_tvshows(response["results"], False, None) -def get_movies(movie_type: str) -> Union[list, dict]: +def get_movies(movie_type: str) -> list | dict: """gets list with movies of movie_type from tmdb Args: @@ -1277,7 +1508,7 @@ def get_movies(movie_type: str) -> Union[list, dict]: Returns: list: [description] """ - response = get_data(url="movie/%s" % (movie_type), + response = get_data(url=f'movie/{movie_type}', params={"language": addon.setting("LanguageID")}, cache_days=0.3) if not response.get("results"): @@ -1285,10 +1516,16 @@ def get_movies(movie_type: str) -> Union[list, dict]: return handle_movies(response["results"], False, None) -def get_set_movies(set_id): - ''' - return list with movies which are part of set with *set_id - ''' +def get_set_movies(set_id:str) -> tuple[ItemList,dict]: + """Creates an ItemList of movie VideoItems for movies in set + + Args: + set_id (str): the tmdb collection id + + Returns: + tuple[ItemList,dict]: an ItemList of movies as VideoItems + a dict of set info + """ params = {"append_to_response": "images", "language": addon.setting("LanguageID"), "include_image_language": "en,null,%s" % addon.setting("LanguageID")} @@ -1319,7 +1556,15 @@ def get_person_movies(person_id): return handle_movies(response["crew"]) -def sort_lists(lists): +def sort_lists(lists: ItemList) -> ItemList: + """sorts an itemlist by finding tmdb movie in account list + + Args: + lists (ItemList): an itemlist of movies + + Returns: + ItemList: the itemlist ordered by account list first + """ if not Login.check_login(): return lists ids = [i["id"] for i in get_account_lists(10)] diff --git a/script.extendedinfo/resources/lib/Trakt.py b/script.extendedinfo/resources/lib/trakt.py similarity index 64% rename from script.extendedinfo/resources/lib/Trakt.py rename to script.extendedinfo/resources/lib/trakt.py index 8b78d724c..c05502d7b 100644 --- a/script.extendedinfo/resources/lib/Trakt.py +++ b/script.extendedinfo/resources/lib/trakt.py @@ -1,42 +1,74 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +"""Trakt module obtains data on TV Shows and Movies from Trakt.tv using +apiV2 If Trakt provides a TMDB id, additional data is retrieved from +TMDB + +Public functions: + get_episodes(content) gets upcoming episodes content shows or + premiering shows content premieres + returns a kutils ItemList + get_shows(show_type) gets tvshows for showtype trending/popular/anticipated + returns a kutils ItemList + get_shows_from_time(show_type, period) gets tvshos for showtype collected/played/ + watched for previous month + returns a kutils ItemList + get_movies(movie_type) gets movies for movietype trending/popular/anticipated + returns a kutils ItemList + get_movies_from_time(movie_type, period) gets movies forf movietype collected/ + played/watched for previous month + get_similar(media_type, imdb_id) gets related mediatype show(s)/movie(s) from + an imdb id. +""" import datetime import urllib.error import urllib.parse import urllib.request -from kutils import ItemList, VideoItem, addon, local_db, utils -from resources.lib import TheMovieDB as tmdb +from resources.kutil131 import ItemList, addon + +from resources.kutil131 import VideoItem, local_db, utils +from resources.lib import themoviedb as tmdb TRAKT_KEY = 'e9a7fba3fa1b527c08c073770869c258804124c5d7c984ce77206e695fbaddd5' -BASE_URL = "https://api-v2launch.trakt.tv/" +BASE_URL = "https://api.trakt.tv/" HEADERS = { 'Content-Type': 'application/json', 'trakt-api-key': TRAKT_KEY, - 'trakt-api-version': 2 + 'trakt-api-version': '2' } PLUGIN_BASE = "plugin://script.extendedinfo/?info=" def get_episodes(content): + """gets upcoming/premiering episodes from today + + Args: + content (str): enum shows (upcoming) or premieres (new shows) + + Returns: + ItemList: a kutils ItemList instance of VideoItems + """ shows = ItemList(content_type="episodes") url = "" if content == "shows": - url = 'calendars/shows/%s/14' % datetime.date.today() + url = f'calendars/shows/{datetime.date.today()}/14' elif content == "premieres": - url = 'calendars/shows/premieres/%s/14' % datetime.date.today() + url = f'calendars/shows/premieres/{datetime.date.today()}/14' results = get_data(url=url, params={"extended": "full"}, cache_days=0.3) count = 1 if not results: return None + #results is a dict. Each key is an ISO date string (day) with value as a + #list of episodes for that date (episode), episode is a dict with keys airs-at, + #episode (ep), and show (tv) Get the first 20 episodes and create an ItemList + #for each episode as VideoItem for day in results.items(): - for episode in day[1]: + for episode in day[1]: #dict of episode ep = episode["episode"] tv = episode["show"] title = ep["title"] if ep["title"] else "" @@ -69,16 +101,27 @@ def get_episodes(content): 'homepage': tv["homepage"]}) if tv["ids"].get("tmdb"): art_info = tmdb.get_tvshow(tv["ids"]["tmdb"], light=True) - show.set_artwork(tmdb.get_image_urls(poster=art_info.get("poster_path"), - fanart=art_info.get("backdrop_path"))) + if art_info: + show.set_artwork(tmdb.get_image_urls(poster=art_info.get("poster_path", ""), + fanart=art_info.get("backdrop_path", ""))) shows.append(show) count += 1 if count > 20: break + if count > 20: + break return shows def handle_movies(results): + """helper function creates kutils VideoItems and adds to an ItemList + + Args: + results (list): a list of dicts, each dict is Trakt data for movie + + Returns: + ItemList: a kutils ItemList of VideoItems + """ movies = ItemList(content_type="movies") path = 'extendedinfo&&id=%s' if addon.bool_setting( "infodialog_onclick") else "playtrailer&&id=%s" @@ -108,7 +151,8 @@ def handle_movies(results): 'language': item.get("language"), 'homepage': item.get("homepage")}) art_info = tmdb.get_movie(item["ids"]["tmdb"], light=True) - movie.set_artwork(tmdb.get_image_urls(poster=art_info.get("poster_path"), + if art_info: + movie.set_artwork(tmdb.get_image_urls(poster=art_info.get("poster_path"), fanart=art_info.get("backdrop_path"))) movies.append(movie) movies = local_db.merge_with_local(media_type="movie", @@ -119,6 +163,14 @@ def handle_movies(results): def handle_tvshows(results): + """helper function creates kutils VideoItems and adds to an ItemList + + Args: + results (list): a list of dicts, each dict is Trakt data for show + + Returns: + ItemList: a kutils ItemList of VideoItems + """ shows = ItemList(content_type="tvshows") for i in results: item = i["show"] if "show" in i else i @@ -151,7 +203,8 @@ def handle_tvshows(results): 'airshorttime': airs.get("time"), 'watchers': item.get("watchers")}) art_info = tmdb.get_tvshow(item["ids"]["tmdb"], light=True) - show.set_artwork(tmdb.get_image_urls(poster=art_info.get("poster_path"), + if art_info: + show.set_artwork(tmdb.get_image_urls(poster=art_info.get("poster_path"), fanart=art_info.get("backdrop_path"))) shows.append(show) shows = local_db.merge_with_local(media_type="tvshow", @@ -162,30 +215,73 @@ def handle_tvshows(results): def get_shows(show_type): + """gets Trakt full data for shows of enumerated type + + Args: + show_type (str): enum trending/popular/anticipated + + Returns: + ItemList: a kutils ItemList of VideoItems + """ results = get_data(url='shows/%s' % show_type, params={"extended": "full"}) return handle_tvshows(results) if results else [] def get_shows_from_time(show_type, period="monthly"): + """gets Trakt full data for shows of enumerated type for enumerated period + + Args: + show_type (str): enum collected/played/watched + period (str, optional): enum daily/weekly/monthly/yearly/all Defaults to "monthly" + + Returns: + ItemList: a kutils ItemList of VideoItems + """ results = get_data(url='shows/%s/%s' % (show_type, period), params={"extended": "full"}) return handle_tvshows(results) if results else [] def get_movies(movie_type): + """gets Trakt full data for movies of enumerated type + + Args: + movie_type (str): enum trending/popular/anticipated + + Returns: + ItemList: a kutils ItemList of VideoItems + """ results = get_data(url='movies/%s' % movie_type, params={"extended": "full"}) return handle_movies(results) if results else [] def get_movies_from_time(movie_type, period="monthly"): + """gets Trakt full data for movies of enumerated type for enumerated period + + Args: + movie_type (str): enum collected/played/watched + period (str, optional): enum daily/weekly/monthly/yearly/all Defaults to "monthly" + + Returns: + ItemList: a kutils ItemList of VideoItems + """ results = get_data(url='movies/%s/%s' % (movie_type, period), params={"extended": "full"}) return handle_movies(results) if results else [] def get_similar(media_type, imdb_id): + """gets related movies or shows from imbd id + + Args: + media_type (str): enum show/movie + imdb_id (str): the imbd id for show or movie + + Returns: + ItemList: a kutils ItemList of VideoItems + """ if not imdb_id or not media_type: return None results = get_data(url='%ss/%s/related' % (media_type, imdb_id), @@ -199,6 +295,20 @@ def get_similar(media_type, imdb_id): def get_data(url, params=None, cache_days=10): + """helper function builds query and formats result. First attempts to + retrieve data from local cache and then issues a ResT GET to the api if cache + data not available + + Args: + url (str): the url for GET operation on api + params (dict, optional): GET query (?) Defaults to None. + cache_days (int, optional): Max age of cached data before requesting new. + Defaults to 10. + + Returns: + dict: a dict from the deserialized JSON response from api or None + Note: kutils does not return the GET failure code (ie if not 200) + """ params = params if params else {} params["limit"] = 10 url = "%s%s?%s" % (BASE_URL, url, urllib.parse.urlencode(params)) diff --git a/script.extendedinfo/resources/lib/WindowManager.py b/script.extendedinfo/resources/lib/windowmanager.py similarity index 76% rename from script.extendedinfo/resources/lib/WindowManager.py rename to script.extendedinfo/resources/lib/windowmanager.py index 05ac58459..2199645b3 100644 --- a/script.extendedinfo/resources/lib/WindowManager.py +++ b/script.extendedinfo/resources/lib/windowmanager.py @@ -1,29 +1,33 @@ -# -*- coding: utf8 -*- - # Copyright (C) 2015 - Philipp Temminghoff # Modifications copyright (C) 2022 - Scott Smart # This program is Free Software see LICENSE file for details +# pylint: disable=line-too-long,import-outside-toplevel + +"""Module handles all actions to display dialogs +""" + +from __future__ import annotations + import os import re -from typing import Optional import xbmc import xbmcgui import xbmcvfs +from resources.kutil131 import addon, busy, player, windows -from kutils import addon, busy, local_db, player, utils, windows +from resources.kutil131 import local_db, utils +from resources.lib import themoviedb as tmdb -from . import TheMovieDB as tmdb - -INFO_XML_CLASSIC = 'script-%s-DialogVideoInfo.xml' % (addon.ID) -LIST_XML_CLASSIC = 'script-%s-VideoList.xml' % (addon.ID) -ACTOR_XML_CLASSIC = 'script-%s-DialogInfo.xml' % (addon.ID) +INFO_XML_CLASSIC = f'script-{addon.ID}-DialogVideoInfo.xml' +LIST_XML_CLASSIC = f'script-{addon.ID}-VideoList.xml' +ACTOR_XML_CLASSIC = f'script-{addon.ID}-DialogInfo.xml' if addon.bool_setting("force_native_layout") and addon.setting("xml_version") != addon.VERSION: addon.set_setting("xml_version", addon.VERSION) - INFO_XML = 'script-%s-DialogVideoInfo-classic.xml' % (addon.ID) - LIST_XML = 'script-%s-VideoList-classic.xml' % (addon.ID) - ACTOR_XML = 'script-%s-DialogInfo-classic.xml' % (addon.ID) + INFO_XML = f'script-{addon.ID}-DialogVideoInfo-classic.xml' + LIST_XML = f'script-{addon.ID}-VideoList-classic.xml' + ACTOR_XML = f'script-{addon.ID}-DialogInfo-classic.xml' path = os.path.join(addon.PATH, "resources", "skins", "Default", "1080i") xbmcvfs.copy(strSource=os.path.join(path, INFO_XML_CLASSIC), strDestination=os.path.join(path, INFO_XML)) @@ -38,6 +42,10 @@ class WindowManager: + """Class provides all operations to create/manage a Kodi dialog + window + + """ window_stack = [] def __init__(self): @@ -49,12 +57,12 @@ def __init__(self): # self.monitor = SettingsMonitor() self.monitor = xbmc.Monitor() - def open_movie_info(self, movie_id=None, dbid=None, name=None, imdb_id=None): + def open_movie_info(self, movie_id:str=None, dbid:str=None, name:str=None, imdb_id:str=None): """ - opens movie info dialog, deal with window stack + opens movie video info dialog, deal with window stack """ busy.show_busy() - from .dialogs.DialogMovieInfo import DialogMovieInfo + from .dialogs.dialogmovieinfo import DialogMovieInfo dbid = int(dbid) if dbid and int(dbid) > 0 else None if not movie_id: movie_id = tmdb.get_movie_tmdb_id(imdb_id=imdb_id, @@ -73,7 +81,7 @@ def open_tvshow_info(self, tmdb_id=None, dbid=None, tvdb_id=None, imdb_id=None, """ busy.show_busy() dbid = int(dbid) if dbid and int(dbid) > 0 else None - from .dialogs.DialogTVShowInfo import DialogTVShowInfo + from .dialogs.dialogtvshowinfo import DialogTVShowInfo if tmdb_id: pass elif tvdb_id: @@ -97,13 +105,13 @@ def open_tvshow_info(self, tmdb_id=None, dbid=None, tvdb_id=None, imdb_id=None, busy.hide_busy() self.open_infodialog(dialog) - def open_season_info(self, tvshow_id=None, season: Optional[int] = None, tvshow=None, dbid=None): + def open_season_info(self, tvshow_id=None, season: int = None, tvshow=None, dbid=None): """ open season info, deal with window stack needs *season AND (*tvshow_id OR *tvshow) """ busy.show_busy() - from .dialogs.DialogSeasonInfo import DialogSeasonInfo + from .dialogs.dialogseasoninfo import DialogSeasonInfo if not tvshow_id: params = {"query": tvshow, "language": addon.setting("language")} @@ -134,7 +142,7 @@ def open_episode_info(self, tvshow_id=None, season=None, episode=None, tvshow=No open season info, deal with window stack needs (*tvshow_id OR *tvshow) AND *season AND *episode """ - from .dialogs.DialogEpisodeInfo import DialogEpisodeInfo + from .dialogs.dialogepisodeinfo import DialogEpisodeInfo if not tvshow_id and tvshow: tvshow_id = tmdb.search_media(media_name=tvshow, media_type="tv", @@ -147,14 +155,14 @@ def open_episode_info(self, tvshow_id=None, season=None, episode=None, tvshow=No dbid=int(dbid) if dbid and int(dbid) > 0 else None) self.open_infodialog(dialog) - def open_actor_info(self, actor_id: str=None, name: str=None): + def open_actor_info(self, actor_id: int=None, name: str=None): """opens info dialog window for an actor, deals with window stack - A new dialog instance of DialogActorInfo is created and the xml window - (DialogInfo.xml) is opened + If a tmdb actor_id is passed, it is passed to a new dialog instance of + DialogActorInfo class. If actor name is passed, attempts to get the actor_id. Args: actor_id (str, optional): tmdb actor id. Defaults to None. - name (str, optional): a string of name or name[ separator name]. + name (str, optional): a string of name or name [separator name]*. if name is a multiple a select dialog is presented to user to get a single actor. If name is provided, attempts to get a tmdb for it. Defaults to None. @@ -162,21 +170,23 @@ def open_actor_info(self, actor_id: str=None, name: str=None): Returns: None: if no tmdb actor id could be found """ - from .dialogs.DialogActorInfo import DialogActorInfo - if not actor_id: - name = name.split(" %s " % addon.LANG(20347)) + from resources.lib.dialogs.dialogactorinfo import DialogActorInfo + if name and not actor_id: #use name to get person from tmdb for actor_id + name = name.split(f" {addon.LANG(20347)} ") names = name[0].strip().split(" / ") if len(names) > 1: ret = xbmcgui.Dialog().select(heading=addon.LANG(32027), - list=names) + list=names) #"Select person" if ret == -1: return None name = names[ret] else: name = names[0] busy.show_busy() - actor_info = tmdb.get_person_info(name) + actor_info = tmdb.get_person_info(name) # a dict of info or False + # no TMDB info if not actor_info: + busy.hide_busy() return None actor_id = actor_info["id"] else: @@ -193,7 +203,7 @@ def open_video_list(self, listitems=None, filters=None, mode="filter", list_id=F Args: listitems (dict, optional): [description]. Defaults to None. - filters ([type], optional): [description]. Defaults to None. + filters (list, optional): [description]. Defaults to None. mode (str, optional): [description]. Defaults to "filter". list_id (bool, optional): [description]. Defaults to False. filter_label (str, optional): [description]. Defaults to "". @@ -201,9 +211,8 @@ def open_video_list(self, listitems=None, filters=None, mode="filter", list_id=F media_type (str, optional): [description]. Defaults to "movie". search_str (str, optional): [description]. Defaults to "". """ - # utils.log('wm open_video_list listitems: {}'.format(listitems)) #debug - from .dialogs import DialogVideoList - Browser = DialogVideoList.get_window(windows.DialogXML) + from .dialogs import dialogvideolist + Browser = dialogvideolist.get_window(windows.DialogXML) dialog = Browser(LIST_XML, addon.PATH, listitems=listitems, @@ -220,22 +229,34 @@ def open_youtube_list(self, search_str="", filters=None, filter_label="", media_ """ open video list, deal with window stack """ - from .dialogs import DialogYoutubeList - YouTube = DialogYoutubeList.get_window(windows.DialogXML) - dialog = YouTube('script-%s-YoutubeList.xml' % addon.ID, addon.PATH, + from .dialogs import dialogyoutubelist + YouTube = dialogyoutubelist.get_window(windows.DialogXML) + dialog = YouTube(f'script-{addon.ID}-YoutubeList.xml', + addon.PATH, search_str=search_str, filters=[] if not filters else filters, type=media_type) self.open_dialog(dialog) def open_infodialog(self, dialog): + """opens the info dialog + + Args: + dialog (DialogActorInfo): a DialogActorinfo instance of a Kodi dialog + self.info is a kutils.VideoItem or AudioItem to display in dialog + """ if dialog.info: self.open_dialog(dialog) else: self.active_dialog = None - utils.notify(addon.LANG(32143)) + utils.notify(addon.LANG(32143)) #Could not find item at MovieDB def open_dialog(self, dialog): + """Opens a Kodi dialog managing a stack of dialogs + + Args: + dialog (DialogActorInfo): a Kodi xml dialog window + """ if self.active_dialog: self.window_stack.append(self.active_dialog) self.active_dialog.close() @@ -273,8 +294,10 @@ def play_youtube_video(self, youtube_id="", listitem=None): xbmc.executebuiltin("RunPlugin(plugin://plugin.video.youtube/play/?video_id=" + youtube_id + "&screensaver=true&incognito=true)") if self.active_dialog and self.active_dialog.window_type == "dialog": - player.wait_for_video_end() - self.active_dialog.doModal() + player.wait_for_video_start() #30 sec timeout + player.wait_for_video_end() #method returns when video ends + if not self.monitor.abortRequested(): + self.active_dialog.doModal() wm = WindowManager() diff --git a/script.extendedinfo/resources/settings.xml b/script.extendedinfo/resources/settings.xml index b8ff7336e..c85574644 100644 --- a/script.extendedinfo/resources/settings.xml +++ b/script.extendedinfo/resources/settings.xml @@ -14,6 +14,12 @@ false + + 0 + false + true + + 0 RunScript(script.extendedinfo,info=deletecache) @@ -52,6 +58,28 @@ 32174 + + 0 + false + + + true + + + 582 + + + + 0 + false + + + true + + + 560 + + diff --git a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogInfo.xml b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogInfo.xml index 6cb854087..99f9b2cfa 100644 --- a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogInfo.xml +++ b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogInfo.xml @@ -23,7 +23,7 @@ 0 0 - - + -5000 SetFocus(132) noop @@ -32,7 +32,7 @@ 0 0 - - + -5000 noop Control.HasFocus(20001) @@ -131,7 +131,7 @@ 25 FF999999 font12 - + !String.isEmpty(Window.Property(Birthday)) @@ -182,7 +182,7 @@ !String.isEmpty(Window.Property(Homepage)) - + 255 @@ -205,7 +205,7 @@ 150 buttons/button-fo.png buttons/button-nofo.png - + 55 diff --git a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogVideoInfo.xml b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogVideoInfo.xml index 054235dda..f199dd760 100644 --- a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogVideoInfo.xml +++ b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-DialogVideoInfo.xml @@ -24,7 +24,7 @@ 0 0 - - + -5000 SetFocus(132) noop @@ -33,7 +33,7 @@ 0 0 - - + -5000 noop Control.HasFocus(20001) @@ -69,7 +69,7 @@ SetFocus(20000) buttons/button-fo.png buttons/button-nofo.png - + 55 @@ -200,10 +200,10 @@ 400 - - + icons/heart.png icons/heart.png - - + 0 0 280 @@ -290,7 +290,7 @@ 44 44 !String.IsEmpty(Window.Property(tmdb_logged_in)) - !String.IsEqual(Window.Property(type),season) + !String.IsEqual(Window.Property(type),episode) + !String.IsEqual(Window.Property(type),season) + !String.IsEqual(Window.Property(type),episode) + !String.IsEqual(Window.Property(type),tvshow) @@ -3030,7 +3030,7 @@ 1100 scale common/black.png - thumbs/homewidget_shadow.png + overlays/shadow.png 10 diff --git a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-VideoList.xml b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-VideoList.xml index f73ccf1d1..ff88ba62a 100644 --- a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-VideoList.xml +++ b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-VideoList.xml @@ -6,6 +6,7 @@ SetProperty(WindowColor,$VAR[AreaColorVar],home) --> ClearProperty(WindowColor,home) 500 + 9000 common/white.png @@ -92,13 +93,13 @@ 30 396 200 - common/black.png - 3 + common/black.png + 4 222 - scale + keep - 270 + 275 40 395 300 @@ -108,7 +109,7 @@ 40 - 320 + 255 135 26 Conditional @@ -120,7 +121,7 @@ 395 500 justify - + true font12 FFDDDDDD @@ -589,7 +590,7 @@ 25 font13 315 - + FFBBBBBB FFFAFAFA 200 @@ -619,7 +620,7 @@ [COLOR FFFAFAFA]$INFO[Window.Property(Type)][/COLOR] 438 - 70 + 55 40 315 left @@ -635,7 +636,7 @@ [COLOR FFFAFAFA]$INFO[Window.Property(Sort_Label)][/COLOR] 438 - 70 + 55 40 30 315 @@ -651,7 +652,7 @@ [COLOR FFFAFAFA]$INFO[Window.Property(Order_Label)][/COLOR] 438 - 70 + 55 40 30 315 @@ -786,6 +787,20 @@ FFBBBBBB FFFAFAFA + + + 438 + 55 + 40 + 315 + left + center + lists/focus.png + lists/separator.png + font12 + FFBBBBBB + FFFAFAFA + 438 diff --git a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-pictureviewer.xml b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-pictureviewer.xml new file mode 100644 index 000000000..38a3059a2 --- /dev/null +++ b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-pictureviewer.xml @@ -0,0 +1,74 @@ + + + 5000 + no + + + 0 + 0 + 1920 + 1080 + 500 + common/black.png + WindowOpen + WindowClose + + + 910 + 503 + 100 + 100 + !Container(5000).OnScrollPrevious + !Container(5000).OnScrollNext + Visible + Conditional + spinner.png + Conditional + + + 925 + 518 + 70 + 70 + !Container(5000).OnScrollPrevious + !Container(5000).OnScrollNext + Visible + Conditional + spinner.png + Conditional + + + -90 + 0 + 2100 + 1080 + 5000 + 5000 + 9001 + WindowOpen + WindowClose + 400 + Horizontal + + + 90 + 0 + 1920 + 1080 + keep + 200 + $INFO[ListItem.Art(original)] + + + + + 90 + 0 + 1920 + 1080 + keep + 200 + $INFO[ListItem.Art(original)] + + + + + diff --git a/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-t9search.xml b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-t9search.xml new file mode 100644 index 000000000..ad67dd13d --- /dev/null +++ b/script.extendedinfo/resources/skins/Default/1080i/script-script.extendedinfo-t9search.xml @@ -0,0 +1,166 @@ + + + 9090 + + + + + + + + + + + 20 + 0 + + -112 + 600 + 1080 + lists/panel.png + + + 15 + -31 + 447 + 708 + 9090 + Action(Close) + Control.SetFocus(9091,999) + Control.SetFocus(9091,0) + noop + vertical + 200 + + + 0 + 27 + 140 + 133 + buttons/button-nofo.png + + + 0 + 7 + 140 + 133 + center + center + font12 + + + + 0 + 37 + 140 + 133 + center + center + font10 + + + + + + 0 + 27 + 140 + 133 + buttons/button-fo.png + + + 0 + 7 + 140 + 133 + center + center + font12 + + + + 0 + 37 + 140 + 133 + center + center + font10 + + + + + + 15 + 500 + 390 + 708 + 9091 + Action(Close) + 9090 + 9090 + noop + vertical + 200 + + + 0 + -5 + 380 + 85 + buttons/button-nofo.png + + + 25 + -9 + 330 + 85 + center + center + font12 + + + + + + 0 + -5 + 380 + 85 + buttons/button-nofo.png + !Control.HasFocus(9091) + + + 0 + -5 + 380 + 85 + buttons/button-fo.png + Control.HasFocus(9091) + + + 25 + -9 + 330 + 85 + center + center + font12 + + + + + + 15 + 455 + 380 + 50 + center + 15 + white + true + 20 + + + + diff --git a/script.extendedinfo/resources/skins/Default/media/DefaultVideo.png b/script.extendedinfo/resources/skins/Default/media/DefaultVideo.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f633d3d973d9080ace3300355e463983be5b4d GIT binary patch literal 1200 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5J2-$OL-(&leg+1Xa!(h>kcwMxZ`tQZhf1(N zsO#+Z)JBqgLFOCBvONox+=nU)NksVMt>u z^kOsq3KTqJ*Ax7?U|XK4Y{Sg07RuSiUsrK5@;o}j^D6W*;|@{bqUC--shx8@gL|K? z4i{#UIC6w%RX9*;n|0&Wc&fbzpx3zhiu}m{TT0jQ;+8 zd;j_AwQjDLIQ6e^$BU^ys^q_~3Jbm^6s^1eeCWbimzKRa!g?-aU6tw5+>f^>FZ;E~ z&s4F&bN1f**H){sT(JGUXLa=YSpp7*zaPJJ{%a7u9mp>H`NjDC>90WNiX44AIp6k< zWjs*NqgN09e~)7eKOgPOu|T8hd%VoNmq-7`2?Jf)wdiuZT;98P@89R~O;?YbtQ`wf zau<{u8&=wI>a2V3YJ4*~{*4;@h7T6A&OB}v7Q6L+yTpRqZ~h2MAHUE1ng3XQ?X|du z-4{#V$<;RU|Lf?ue~Wv=J&OasE|%X|-zz)AjH}>r>XFmZt}m7Eb6HxwDgXa>Ln%YF zpy2tgMIFzIf0XX)na1=-R`6rmD~9?1E{8QV+h?z0kbmcPjUjxSQg*}lYfAYI>w)Gnr6en{)`eyGAQ&-Y`Z24_R_@rN;teYFxu z>3YKH#~-#Z?%JQicj1@r#+A$>^83%pEZFhWthnLP>pP5A_tW_v-X8yB RtZzZC^mO%eS?83{1OVe0p)LRb literal 0 HcmV?d00001 diff --git a/script.extendedinfo/resources/skins/Default/media/flags/audio/opus.png b/script.extendedinfo/resources/skins/Default/media/flags/audio/opus.png new file mode 100644 index 0000000000000000000000000000000000000000..df856a6d57653e665bc2ab5b65738cf320c38674 GIT binary patch literal 1351 zcmZvcdpMH|9LL{WPK%Qok=Wxnq@Cl^R5-mX-KKX-uF1+}xt55|Hr5!Da<}1OE9Y2p z$uaknxr~sUMmX+rZMCS4h+N zuL_ER&%uka*Nm^<1X3`&7lF-H`<_0Q?`)<-f(+D2?xseRfqs z)g=LcE9q|jLRo&@%MKr5X5V%&=7Qq4g>?Cis{*#MYX6UcS@U{_;XO-QZ!AKi^ANYb zk8W{fm}LgFn>iV*5fsh~`1?;M$&F#im*yT=%sk|U)Y?s2l{&5<88mIf$}&#bi24t1 zMT`hS0^;Lc&0mhb93z>%R~pkJ!P>)01z|TbrihAk9GEYZsx=IXLCbAAp-vdKE#<0w*6B~dF;{l96ZD~c4EoS9 z*emjH%xw3uAj@T4#D_-|{{WBpacMnxZsj=&;$SCa@rB@n`6ubV0#;c5u@JN&t5Ymz zmr+n&q>Zd3dC1|=7dzn;Jf*Z|%XJFcL`) zELkx&>hD37OS_Wr&VzkJ1&ES|9l~=AZ4`rmrTuk=!@4}ctY8^Rz{muI4le7Ww8UJy zmhXL_aX%}(BFKdGxI?(j{K_c3q`App_EZoMm_{o8bB^0AhLfgEMGD86MAvw35t=ij zM-qQvV>a{DJA^kv?<2@+U1vG>OYxvZQ@5`XEpejeC)El>9dZr5niJvb!+9-lRoNmm z9`rk%|IE<&JM`t|SV8A<%+!5YfhMSD7k4p84kWR=T_1P8XtYg-hwI9&fJ^$wS)d8Q9Py_gww3M7q>+E^*H zoO6-bEz9gO8vcN;BL;KpW@L=;DfQrSsmxOl%}qv2F3=T>p!&?Hz~F8l4+NG@nqfcl z6&X$yCPKDgQCn2jm_27Q4Dq`0R=YZeLE(map!CR;YiVj)X>NmW=gh+e0ZXlNO#R6V zuZnk!*5em>BK&lX!5&G$NsEGg6E>}C6$t#j*lMQ*1EpS@^Fa}OdFKYL14|3X8I31k zLwk#@Lj01oqLZU5F`K>V+K;Gw>Ga2jQEU&Abv$ZIuH`b8+0QSnv*)-C*V~#l%??g4hBqV|xC&t0txG zq4O-wNIy)>V~3A~kG^qzTHV=fGMg#+XbWjP`h+yE!^95oUd;IMMAA0fA*bGLbe=L< zpS#BS`Aw=TW2RQgKYg~D;akxJjiu@2-KGf!JcnB&2)T&G5Yl3=b*mwS-Sl6{Y&3=S zzPE8hTjMa(z!8 Date: Sun, 7 May 2023 16:24:17 +0100 Subject: [PATCH 032/145] Test command for git diff --- .github/workflows/addon-checker.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/addon-checker.yml b/.github/workflows/addon-checker.yml index c6b940d8c..b9743d3da 100644 --- a/.github/workflows/addon-checker.yml +++ b/.github/workflows/addon-checker.yml @@ -27,7 +27,8 @@ jobs: shell: bash run: | - echo "addon=$(git diff --diff-filter=d --name-only HEAD~ | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT + echo addon=$(git --no-pager diff --name-only ..origin/master${{ github.event.pull_request.base.ref }} + echo "addon=$(git --no-pager diff --name-only ..origin/master${{ github.event.pull_request.base.ref }} | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT id: extract_vars - name: Addon-Check From a0df51265b58fbb0c3a0ba3cdfb65cad216e4b0c Mon Sep 17 00:00:00 2001 From: Miguel Borges de Freitas <92enen@gmail.com> Date: Sun, 7 May 2023 16:24:49 +0100 Subject: [PATCH 033/145] Update addon-checker.yml --- .github/workflows/addon-checker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/addon-checker.yml b/.github/workflows/addon-checker.yml index b9743d3da..49118b82b 100644 --- a/.github/workflows/addon-checker.yml +++ b/.github/workflows/addon-checker.yml @@ -27,7 +27,7 @@ jobs: shell: bash run: | - echo addon=$(git --no-pager diff --name-only ..origin/master${{ github.event.pull_request.base.ref }} + echo "addon=$(git --no-pager diff --name-only ..origin/master${{ github.event.pull_request.base.ref }}" echo "addon=$(git --no-pager diff --name-only ..origin/master${{ github.event.pull_request.base.ref }} | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT id: extract_vars From 21dab055f0881e03a4dfe6ccdc614ef66cc88be8 Mon Sep 17 00:00:00 2001 From: Miguel Borges de Freitas <92enen@gmail.com> Date: Sun, 7 May 2023 16:27:00 +0100 Subject: [PATCH 034/145] Update addon-checker.yml --- .github/workflows/addon-checker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/addon-checker.yml b/.github/workflows/addon-checker.yml index 49118b82b..f7a6d2a3b 100644 --- a/.github/workflows/addon-checker.yml +++ b/.github/workflows/addon-checker.yml @@ -27,8 +27,8 @@ jobs: shell: bash run: | - echo "addon=$(git --no-pager diff --name-only ..origin/master${{ github.event.pull_request.base.ref }}" - echo "addon=$(git --no-pager diff --name-only ..origin/master${{ github.event.pull_request.base.ref }} | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT + echo "addon=$(git --no-pager diff --name-only ..origin/${{ github.event.pull_request.base.ref }})" + echo "addon=$(git --no-pager diff --name-only ..origin/${{ github.event.pull_request.base.ref }} | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT id: extract_vars - name: Addon-Check From 60390a400675376327f35981ff00332167b9457c Mon Sep 17 00:00:00 2001 From: Miguel Borges de Freitas <92enen@gmail.com> Date: Sun, 7 May 2023 16:34:52 +0100 Subject: [PATCH 035/145] Update addon-checker.yml --- .github/workflows/addon-checker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/addon-checker.yml b/.github/workflows/addon-checker.yml index f7a6d2a3b..260a14a55 100644 --- a/.github/workflows/addon-checker.yml +++ b/.github/workflows/addon-checker.yml @@ -27,7 +27,7 @@ jobs: shell: bash run: | - echo "addon=$(git --no-pager diff --name-only ..origin/${{ github.event.pull_request.base.ref }})" + gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path' echo "addon=$(git --no-pager diff --name-only ..origin/${{ github.event.pull_request.base.ref }} | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT id: extract_vars From 3cad9b84dfba8775d1bdad3105c3d672aa891aca Mon Sep 17 00:00:00 2001 From: Miguel Borges de Freitas <92enen@gmail.com> Date: Sun, 7 May 2023 16:39:12 +0100 Subject: [PATCH 036/145] Update addon-checker.yml --- .github/workflows/addon-checker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/addon-checker.yml b/.github/workflows/addon-checker.yml index 260a14a55..2a2b6e592 100644 --- a/.github/workflows/addon-checker.yml +++ b/.github/workflows/addon-checker.yml @@ -27,7 +27,7 @@ jobs: shell: bash run: | - gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path' + git --no-pager diff --name-only HEAD^ echo "addon=$(git --no-pager diff --name-only ..origin/${{ github.event.pull_request.base.ref }} | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT id: extract_vars From 53b4dead884278b4c96a9779f68505efc4373225 Mon Sep 17 00:00:00 2001 From: Miguel Borges de Freitas <92enen@gmail.com> Date: Sun, 7 May 2023 16:50:20 +0100 Subject: [PATCH 037/145] Update addon-checker.yml --- .github/workflows/addon-checker.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/addon-checker.yml b/.github/workflows/addon-checker.yml index 2a2b6e592..e0fd1bfcd 100644 --- a/.github/workflows/addon-checker.yml +++ b/.github/workflows/addon-checker.yml @@ -22,6 +22,12 @@ jobs: run: | python -m pip install --upgrade pip pip3 install --user kodi-addon-checker + + - name: List all changed files + run: | + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + echo "$file was changed" + done - name: Extract job variables shell: bash From 5e91554fc36ce5d3e2c7904d0052354ccdad6108 Mon Sep 17 00:00:00 2001 From: Miguel Borges de Freitas <92enen@gmail.com> Date: Sun, 7 May 2023 16:52:43 +0100 Subject: [PATCH 038/145] Update addon-checker.yml --- .github/workflows/addon-checker.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/addon-checker.yml b/.github/workflows/addon-checker.yml index e0fd1bfcd..8f5e03518 100644 --- a/.github/workflows/addon-checker.yml +++ b/.github/workflows/addon-checker.yml @@ -22,19 +22,11 @@ jobs: run: | python -m pip install --upgrade pip pip3 install --user kodi-addon-checker - - - name: List all changed files - run: | - for file in ${{ steps.changed-files.outputs.all_changed_files }}; do - echo "$file was changed" - done - - name: Extract job variables shell: bash run: | - git --no-pager diff --name-only HEAD^ - echo "addon=$(git --no-pager diff --name-only ..origin/${{ github.event.pull_request.base.ref }} | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT + echo "addon=$(git diff --diff-filter=d --name-only HEAD~ | grep / | cut -d / -f1 | sort | uniq)" >> $GITHUB_OUTPUT id: extract_vars - name: Addon-Check From ad2b2aaf176d70b4a84af61c3dda7c3a76797c0b Mon Sep 17 00:00:00 2001 From: Connor McLeod Date: Sun, 7 May 2023 17:11:03 +0100 Subject: [PATCH 039/145] [service.subtitles.pipocas] 1.0.2 (#2445) - Cleaning unused functions - Improve performance - Enhance readability - Fix bug on regex --- service.subtitles.pipocas/README.md | 2 +- service.subtitles.pipocas/addon.xml | 10 +- service.subtitles.pipocas/changelog.txt | 6 + service.subtitles.pipocas/icon.png | Bin 71880 -> 5925 bytes .../resources/lib/pipocas.py | 81 +- service.subtitles.pipocas/service.py | 730 +++++++++++------- 6 files changed, 494 insertions(+), 335 deletions(-) diff --git a/service.subtitles.pipocas/README.md b/service.subtitles.pipocas/README.md index 2228f3d81..da91397d6 100644 --- a/service.subtitles.pipocas/README.md +++ b/service.subtitles.pipocas/README.md @@ -3,4 +3,4 @@ service.subtitles.pipocas Pipocas.tv subtitle service plugin for Kodi Matrix+. -HiGhLaNdeR +HiGhLaNdeR & Leinad4Mind diff --git a/service.subtitles.pipocas/addon.xml b/service.subtitles.pipocas/addon.xml index 346513a53..eff0516d1 100644 --- a/service.subtitles.pipocas/addon.xml +++ b/service.subtitles.pipocas/addon.xml @@ -1,5 +1,5 @@ - + @@ -15,7 +15,11 @@ Para bugs, pedidos ou perguntas, contacte: highlander@teknorage.com pt en - - v1.0.1 (2022-01-04) - Matrix READY! + - v1.0.2 (2023-03-22) + - Cleaning unused functions + - Improve performance + - Enhance readability + - Fix bug on regex all @@ -23,7 +27,7 @@ GPL-2.0-only https://forum.kodi.tv/forumdisplay.php?fid=143 - https://www.pipocas.tv + https://pipocas.tv pipocas [dot] tv [at] gmail [dot] com https://github.com/highlandr/service.subtitles.pipocas diff --git a/service.subtitles.pipocas/changelog.txt b/service.subtitles.pipocas/changelog.txt index 70f25235d..b994579b9 100644 --- a/service.subtitles.pipocas/changelog.txt +++ b/service.subtitles.pipocas/changelog.txt @@ -1,3 +1,9 @@ +1.0.2 (Thanks Leinad4Mind) +- Cleaning unused functions +- Improve performance +- Enhance readability +- Fix bug on regex +- Add notifications errors 1.0.1 Matrix Ready! 1.0.0 (Thanks Leinad4Mind) - Refactor extract function diff --git a/service.subtitles.pipocas/icon.png b/service.subtitles.pipocas/icon.png index 40381287df3554c1d83007189309e4cffbaec3c4..89c136a6d75a0b86c0551c2ad47d7bbfeced4d74 100644 GIT binary patch literal 5925 zcmV+=7ux8FP)1r@V5%}x(WTl20lA8(4i9Itqso3&i}v#{K5vo!N55A5&ymn|Gx&t#>J_I8}7CX^0^8;Ix|p6FUXt|+o=!t z_x3|SGEGG)P7cNJ24OP%Och75BUeLP0=KN;zazDuHSv-l`7$!vg=p0r2qd>FMXy)zm;eGKg;? zx{?>*tPbX|4OUDojBz2Hd>y})75c*kIEv$$dtgNehdwN|_EGH)?m6VfAOiO56GP8{s zsi>xQc63ERF^O>~mwF_mgCMVo8S?V*nwgkLM@Nu$CgiUTx3{)gP&STpA+U@cw2vHc zaBo>ySDk+&zm^$)YbziiAGnbll6D}hh#s-9t`I=2L;wI3>q$gGRCwC#)S(doAPfY- z2qcdFdj-kFNBwRIC$0bh00000000000001{ou<;P_yA3%*-vx;_#{s7vR?+b4Z|=L zTqi5kBdut*ZM(Yx1^F}C-bg!K#Drx+R(8?={QzIrC6_`( zZ3P3(+*OUo*lAt+#yia<-ly+&b4cU}$O9d7i0lOz6S8&!)Joq{4@nhifv6%pTCiXy z1XyLP49t|>_H~8q4Fo)Vu~R=U2}D60z~}jhd2cm)M$sk&#v@pR0t<_Z45E^9gCILt z5EL3EL{uINGmOF#SNbU)tib-xY$K597uaFJ{mgj|-_uD=i1IMI5}j}!9ZHUOU_HHB-^@^eyz81D3w1*y z?vVS^$yTr5>GyTH1#9M#v{!yZwJ^)hb4D8$KzbU}t`B&p>!C z*h1-xI6tG*VWRX{B0hqJL_+iAD{QP6e)E`N#OKzZRH&ySS2jHZ?cpG;3Es%_{7xYPqb%DsGXE=M$2lQTH}nIrQZ{&YtMo*1h|;&-#(M{}!_x zbV3O12a8ymB|ivg@U`g_XNnRa>8xjmF25us7V6FdS;FaWk5b25+KYp$xmx}@bW>s( ztl^be^Zsobh~oGiCpZsmYzqWfGBTKDq_D#>dnAkmkdm-L*^sc4va*^&OA^#F1Z9^g z_&Yf}aczhRKN=B@90_tG2l;Xvl^1zxOdQo?X1o709lVkS|xjE27goBNol zi&7Z%G9KCCcT#|+?}Pt=xhsAN_>zZ9_wQf&(4~k=J>%b`%A*`-#1dm4Vpg1kIcB=7 z7dQE`9$xhjlg(L{3O82YfSs>m$t5m^eTR^<{tq8f#^VI!crLC+FsXBO`xvJX&=S_SpRZ zcyq6-g)6|Xtfm?q%Q*q=+N6@!{uK*qE>FW=2{>^lpUwv=d}w_~2qoLpP%o!2uTmMI4~W$Q@oH?99tc?=j?y&(j(i110148Gw=)rc(wo z*xaTyR{XI#S<~wsjUF+Z!s^7DGozMxxC(FXsS1Sv;+Omj~DnRzi!_ z{dZmFrc4ZUXFww()-aW?5@jefG=7v*p8swRK(R=xo~WktU&@p80`u4LlW}C}>FYA1 zLLNelKLa0`w+Gtn0s~mM8=9Q!S3xQwi9gADu~R`3&%6km&IqVlMpVMcTLZ`>{AJ7> z5JPnpV&Z_=Bigtz zSki~uEm#-LM(CvhNc=Ko{VYPM2v3yrxR8(APc;_?0a=`acm(*yTW9Aj@(!ihczAVc|Mx za|`^5Ezsl|aPx+lkXg${6spWHDbXQBsA`ib@r5>;u#6*TAwm?PPXh?OGfGNgiNV|F zYc=H307GKMF~+wpa2wiC3&0;(+Z`9S0ymGSVNNm3RiD9H5k}Q7#dxR^4Ck3*BA?;H zww~WqV;&h`yMyS4uE-gN9?rFfXE+w4Ul_zAKq@X7%D_K=VQdRfcPth}bjr`uqGlQ=HRV83<+ z&K&^muy6i1R&NBJT!0pLft%A&K0hvUfzeDu3{@)6gDG0zv-R;}z03uAV)orSp@>RW_3y2dWlj%V*p2djb0FR@;K|f43*7gZr?XST zg4U@kvaH;s`RL~*P!OQd#5}GBYzL4c357z$3(mL{H;j1D6p!zQX@5X&FpO@=NiQj8 zhFR%Fhk0`f_{DZ;bF91F+iV?<0xzz0o5ioy_^fHZ={FJ;sN7Vx!wAi7VD6`vL-)VE zTG@=eX2ZRh$3=y}hGVD~-6Sg!SkVaUxs+*tB2B3o_jRElj!u-JhJD;ypSO>)kvd+fr6aB8yOfD{2jvV@($rQX|tLD}d3_n`MT^ zkbx?XX`GV7q2~oe+JkdhX5}o5`n4`Sya-x6v=$B*osQ7Yk>%Z`=wd)P2~BQ;Kk${$ z1xU!nP%s!G5)j}%v_7!1mG_cvlvG~jd4|HxD5hx~eS`T7rz?Ti0e7Q#u84I=Zv*}? zZ;N{maMWIloB{ppg3chk##s*zWN}j+OX#d3k*F&yt8-;u{qS0pbv?i(YJw1r62l{( zU#&U5;nS+QbKYa7QRTuDHD^pJptvNHN%$-9iEWFVx}JM*(6#tFw76kaJLPN!2J(c4 zB~H{$u?rBJ(-g)Oo~oskfRv{B`*YVU_`1tAb-cq2{UJ-&ku4je65^CZn!zi9UtCxZ z*Wc->`EI8r_Ob7>Yh1Xu+mVBTtbIf?<+j4f1THm2?lkYCG{fgRnUWZ!)&x3w;I2B;4#evzq|D+l4>gK-0JnS?w6Jwc1 zo}q{4f>%$PSm1eKYY?yea z&0)Ty_by(&diARC*FS&z_1C}s{M2X(+F*+>33J3O8U!;GbH4h3Bu@Wc)S0Nn;ZA{H zzIrNr{F?CTm%qy-el}nI`6_ew(*FG8Z$AITNE4rb^V#cLRl?IJFHXS@S4jC`&NkmM zec@OGlVglTQiZ!Y{K4O!KY#x6-x4gP^VP?Hef!fNKYaTg8u#j+eD${swg@8Sf@$G$ zAce#z-6;07^M0HLY!;~#c!%Q8o__Y}mrq_Vkk9`4^Ve5hu*oq}CI0Av{Q7=9>ckmZ znUn_SXv)C5B)|OeqfbA2^5pw2*y#W#l+NVgGsiv+=kZeM1Wm{AHo_%WAO!b{y?pWP z#jg_BY8@vcZh){qt>HcPd5@432g{TEV@*L})NsM7F$ch@cD+fwUxOA-tebe9YZr@+ zTo@LJrH~T(60DX3a{%@eXi+U7)jQ7n`+TKzn;QucPSY(U^bFibIzo$$*`+X?^Ik~s zXpV8#Zmkgv_?<`%SzAaq{`3+ON*wZ+Xe#i?mcZbSxn!VZ4^Fv-39($t3{`Ms5wQ)A z<_f3iH!+fgQ`UJeCrONurwo|+@Bl4RA`og@_nd;;6G7B-Z0j{GDw3qo$c~Ii8~bR} z`LXzsYqebx5N)I)O;#@VEv2*0>j!HUky&Y31~XzQ4+Ikkki`=PB|mB3`rwCBS`jw1r*{Soh5NX*=d5o-Os@n4V+e! zfO6>Q0ehKsO|}E3?ucb9653u%2l)aG3eH&PB~t%{#B|Jwhruk1`v5R3DHKM#NCd4N zs0P?d&d%Kh6zfPu%V5|e>w<#~05du|O0q}^?N0{s)EI!snJa;u7N5JC5cTGp4t1Rj z#I>~nvjcW=c;@d393mBQ0a3TyliEVA*aQfT$?~3euj^zU9msT{5YS>9xB(iD9IOoC zLGP}TLns@CJ$xSW?a|C;MM|dyHg_Ka592Ha)WOh{+%=tQ5-L%DkTFYS?@_T1)OM;$EmS+NGp6A(U~DMhjfkPd}d9}W9yg?1~CAegvhVI z$ym;bGP_9WAzP6O6e}9hkN;NZ|vTU6?Z?n*^rLsCts+$eIM( z7;GUK;oFLX)WeCbbu{VjH?_@f^6eIHABY~3DQ=7r*_ehAc z#=Lsa^{^g8OtEbt$eZi&HqO`)VVW0b2pK3lCx5ArzKA)xhV$bVAwD@<)f_;W`^pQL z2({>`e6ET_-z+;Ln_z>WIRK6pTGcWzOX9QLNAmuqgA7V9Oj?Aku9?tAWiY5Zi6c64 z%8=*X1Y1wdPsX}FbKH4pFa{ft8Lzdy>7s&M@=Stxp)3;73m8wHO-zxl$X0{|06RPN z$VR!G#7O|a_DuU+ZSl+5F7j(z`_7ruX`fwlAcymk>mhg}b$sd6d_f0Y5)Mf)_tyrB z5eKqm3!xt!)sbB+bC6NVI$*+I=TGXd;*_9uaVmlhSbLL6@W-F0x@9ojlDSUOd@XC; z>6JBPSRuKGhSa7k$<3e#iPlZ z5hS!)RKdIXx>L2Ha0Rv)()qXay-{{B;-ysp7WxigVmt=gBFl7(B~O4W6%ch5Y~uD- zdMzcP;Di?z^V2VMrx3OM09bYQFO5OT`trbRpvA@^&f6;kr>5-gk$zEjtH0)=XHei_LsM|UW<;Z z(ONrTZNvA15X(k&&z3|IXju~F?r^S4%2Z}n(4f+jFPmADUk=}USwL7kCxPtphI&E@rVb{rFs)}z*Kg^e5 zh2)S(E_z|o({DNNoQ$LRe~+P^*C%EY^>!=RqJOPTGf!QnBL2fLwJ006p0I%HEdVe zZ6Jy5hw@|+?`pkb`d~Y*hT#sPLpg@W7hpGstxngo0#dhh>*Q2PRTSI` zxKBe8EG5**-+DB>(<)q~y+UHsdXsZw7r8V5lq2j*-d-rMy;D!zaT|LD4A2l~+q6a$ ztqSD1#}94Xb^U|7g0psD736e`901|!XVD^Zesod-LsLPliSRI`vq}M{T)|3^Gfh$& z2aCulsiTVyFo$H*@L=(S6mqTADGFZ;=*aZi!R8uRtsOZl61)RqeqTW<2dgBA6II{f zjoY@e4DZM=O^SqM9#)Dwf#@vWY=_|e>v$_00~Jbg| literal 71880 zcmbq)by!s2*Dr|DA=0g)AT1zWB8`NIbV^D~H>09-cc+weHv5CcODF*7i8 z{l34r_qqSR``PDN`<&ft?X~w>=W|ZvJ1rG5Vn$*d92_z=RmJx>IJke4xHyFPe~GC_ zx!qrK-}8;y2g1K0h|nhD?>*6HRU=Ov9Fj->T)4AqA-8`YvUw>Pdg;2^dHH_yu*K2* zXzk(VVr%2@@v*Xlhpn%hhm+@H@#asnet+v6e)iBe@XHxA4IJjsV*pI?B{h@0x1#>e z(X^{PlO``#Z>cL3<@(`~i{V@K7UK7bhKdeNhH958`SLD4%`Mr=QS%%>!djj;@3Jku zPvTnduxB_xm`?dmj{8IJt}e3AHX0%0Il@r?kg3b@O#kk)zB_cPHCw|iQPueX!|CIn}H<#p%Ro_k&orYB~vsoSsX zUxP-^a1S~)C*$v-2&Yw4{Nz?n@A#*QJZ||5oW7XzbO9;6S`jjuHx@VuhfJu?K_}Hd zVZq&N0A2uu5N^-7E|6S`jXI0VLDfw&T`cPSSfI_j2ze3Uczf zf`US?MHw!%4*;P#K;nJQ*HiaUNvAVm=fU**6t97z=UZ*Lui0K%`x56TGj`>3Ti2vs zT_>l7VVd;JH0@;EU-P&Vd98zL>RujSfd=QqEU`oB#*o5aTw#kf7DtCZ z+|zmy5`)jM6Bh=jYdBt1(y^rSEsil>#|zq- zQsvqki+f&lL+d{;0qu7#opt}T+rDxdvh@8DFpk0E1O&wak<&aFJ`ViSNUS^B;OJWO z%}RPv^;c?wTThUJVl>}KA2Hel!xpdfN;tRWvM8Lk$i@1~V7-l8uGWoBlDJQS#65RE zvGbbTjnH+Ic}?6EtBupG0JA7m6aOI!wbmx7kjq;nfS+>E;X$D3pT3-JUuQ>pFl=5RlgtDPmm#GLe#W#O$>@?T0t(>?~?JPF*0?_mn8$;Ced?l)eKg!y?4;YDQsRUIbd+nE&eHQ^!g zC`cVe_f4G5mm*oGqt`WXlPh29q(p^59r2-(E4TWodyTkJX~c$fmgeG4XV;WTlx0r@ zSf3lyZ`d~(A!z~<$A&^8-<>LEt%Bs|B|G>YI<{{;v-}EWcxEF{;A||ZD)ZX!BOF4)NUUeznE*fI zBIT;#Ena_bPRWnaCpTYq6ygn_oVx_d^P_-YA)<=Fb z7=AxDKXDk8BRdOtSVi%fIh1+Qq}qnc;RF}|8SVykKTbb$;43+!mP~B!4>z8oto-?h zStOKJ>Mb0&UBYks-bLMfqa!`OWuuq1e`3$x8*QOZTP|e%{z2W)53^~-=>E?v7395_ zb%g-x-UkyRmjNoH7L)gauhjJOwi2G~{K#KabKV$XGP$AQQffUFxQ<5E!#JoI_51<0dXaC8$FPb*{j+VXVP5xRvuMmE)tlx#k^fva1)7%!uU#)sF zxqGfe_V?i%fj|%CIhEqPJ9n~>%8Bc5K)vZu#8rdtUHa20$AXwKbM`KarL(}YAE_x4 zm+#w?_hTOA^bw`YQnXLe=?y=c9}T?%@K1X`1wna<8$-%g&FG~xAJ`>wV}Dqt7?4I_ z_WYDSF0qFMX@|iH;Jt4Q-=%Psf4CouFCY;qdH#?UUQAr9HuSNB)?j3mP>F~ID7E0z z(p<>G3z`O-$+LjC?aZ>RK~{76os95gx9)zDR;Z=;CEKqb@9HFzRz5`E|P@I34}%lQe7U@HT=gBYp2<9`=>MEV95Ro#PzrOQE#bnY?T$^b zsToYsR`UxPNV>zPB?AXPk^3Eecg9pytQ1GL%(LmaHf$oqlVzu(d#xXg+7eS+*-Sfn8}`x>VmemDcwgr(Yreu~FmpO;NFd;X5Mr%FVd8{%WbeOb*PN`Lq}5yC)9a05FJvS#qCta1)NsA#XA?*J7^>KAN45cADzPPFG;>rb`E z2EEU+^NfpSj_V7GmsB~mosaK#zH@jF?q&gmd+a_8PDv8*g!1JT*nVhT@XX0ng~^HY zqjsyd-H6XtD(P_6=Iq)2JouRxV6vCPKgwO!vN^%`L8`$A-NuGR8(*oAZCLBso$Qzy z)&=(I?I7YOoOr=e*dOyi7KJN@a9)K=Z^Fpk@eJ`0UhSU>=Ul5=pfVbgCt(KA{1&2?e}kF&(le8KEvH-DdIfIAnr&e{3tF$( zPOuZ9=4b4XsYkbKsjQe5~UdJ*!5)#$2Q189Vqfi3Krq>HAqUqMy2WlwK&2a#!RuOjVH&f?A?`y_ z?l&fr(X1Q{Q?v}ewe;bECh5`|LOnV*%;;SHN0>b?7nX|yDYTfksZ{*ReFoo%m_YrQ zeu#jD=xjVNT$XL$(x4UnU?q`4eh4~ZnqEU64y1sz{-gj)gm;{^IAR1P&G&Bh{`L|G z=V1cRkYCp%Xs=v|z1ZH~!8qy1tgO^)FFR?UjG7|@mbqnk*;lE0YAYd{E&IZ+<@U|c zhaZQ-$$)p#A)y{yZdc^h^r1k$wuKzv&CA`nmKo+~xZVjaF}pQC?8f&dU>zHb3RrAASL{Lz=_OTB*`ORc14{eI`+ho|Vl2j-TZ)^AzW^tU#*fN+U2rpMFHrb=e} zz3THeV$+|3pa@_7wJ!kzCI-=ypM86#Z#U)Q_DIZXHBCEZue3Wl*WX-P)Ng_NTUw{9 zvjCsPt=Pf><66s)Fw+uw{kYY^`~BP4Tlv<&=1*iBU{_DC`gg3{*0x1mI>u3zrY}5g zx7b)O3owH7`ETxU=ks}VZB-85990Nigdbz*J6%|H;F|V5FYQ_&j%<^3rI5qRy=VsN zcgH9``*?B>Nk1k&=$D@6jw(O3!4pcjWvv1voL#bIuE;I-35`nCEJJTS6;Q+~mVE&| z{E_aU9%JafIH1G2S^fdI2L3F5+!MFfgvO^~DW5N#Hu`9}3GLlmA{JHH)j;0&*0n9w zsEtl&K@vV#-p1k2^YCXmo{?^B!h8ZNs&pFN85MbI-cbs27s>m^%vi_iP@PH;JTpE; zQx#msSzjhtHxIldV`28apO-aqT6m=qm8#B}_gPVtB)$FpS9U zbK=kgeWgei{D4?;5!cG+jjrD z2ST3_z|NMTEs@b#@EN{oU(@xV&2+c;TnjmlyB76gm*6I-G^gZS#hFnhL%V~8t|qcc zPq(zXMCe&0#Y45J2^mjsDY3M$YGGb77i0QP1d&<3&_0Yv!L@}W{Een?dVpHP7=e+| z7Yy!&SDeZqju0Pyf+(%m*!IH;(qgq`MWyE91-_>Pgj&O;5ma1%$Z(o}nQSWZNy&## zOO_G^Wc{);w(bsSF)t1f4!9x%?HklRNPq8j_$`V^OC`%9tZe9X2F}c8KWznrH|eWl zbt1r0=Lehxf?sk9G&^m?63^wJMS*eYrP@Cuh`w9oQyXwK4n6jiup62mcaa*?R&OhC zZ6{TIB{G=E{19nzFAGlcNw%f7^N8|daKs#s@cjte4jUQzHC{0uWTd($?EWk_ zsUSaB6p#feTrbWtc#-x8Ejl!=&eL<}oeUPN5Em+toM$>aWG?cuX6Zz{6S_{ce|jW( z{r<&^k;t^dvFTreO^&41jM<|xIA{HfRHZ`88JqIB%s{ek8UrLByNZ=CH4~|l$IR0g zzrac}HZO!|l7D|{CsmPopz?Ot;S2s0-YfAW(=$iY3rD+08C4wjIK*=YQ#|eqvwV1u ztRCi_EJ;On*|!_d+9)f?m`h<3zZOa`<4D99Guj0<{AtuoMzWk)NSo0(jL0067<~^+ zsF_tStxVEEX+^!yeiUf^xo@uQGI&r8_&i7XWjyp@o-?=B(6ak7vAZN*{LVQoRlkGu zLPo~(&{wXHKH$fW7U(d%;to}wAezvvAU^w(v2{oV4Y<5Au$UblwjwkleR5=+68w7R zNKY9NU|~Qnu5MXR#1Y+RBbZ@|pFC#iQPKk-=+`uMWq1NsO*vp*tz{_z$xWnONY@xr zg5?|S{Arm!I3!s3jgGJooJ=m0a%W3movWWn2qwj?;Xcn;KU18OvZ@sK*%x`g{D}Q= zQYoXSjnQh;*04G!`+?PZOj}^_;%+#1M&jDTA{!;D3pc8zn1L$qr!IWfh({wondTbH zEr8?C3d__pp9SjUOu1RRVh#eptDgKeM5Sl6r4EF&Tl5c(n8@|n(n-Y?S3dg1_0W{A zG<5N_!uIaR*fm%ReV-O0{PFDr6Bk0=vSL@&-jdJXkePSQuAV|kQj>U573nBKi_9>5 zFDXdX52Yj(wEmtg!+fr5c9L4MLTHd>Iflz+*YG~gj)Nah4_ct*^#mxoEAiB>P57zC zJ2U*s3HN4(I;w13sm)$3XF+oiMgN9^^S8#*Q-uUeMpAzbNoIU5Eqf6&PAa8@pPe)} zu@3whv9msa;grm9)Vkd++8ekRVFL7QxiZb^d*DTRfV;4g}BP(hex zdG~j?zy_7%Aw7c~zeg2a<0VSdX@K|TMW^Ksq#xTiAIr)`V*kQf%}a1?EAq!Za=Q?! zWRe$IWy65VmIpH0&hCbp6tlgi@Ng!Iy-#&+cIeY*z-;qRt(hCa9w<+S1b)0(bNBi7 zBZf5>TD(`p8&u>QwL3H8H?z+U3hD|H1p?V&D8K}5`^R=nl0g;NUrbIobbOH{+0 z_QrmQj_TcK3%iS0($5s3OnD_Ygrtr2GAS+N#cfjl9xB4lZg|~%j>j9%MYfbhIRX3G zZb3TqRK6Y5ts-zD6W~hz@Zx(mSQBSN??d{N;iB_T)YSYfky6j_dYC;Z&>G0cr_Zwr zbO-x2jXu@b(mSS&ysR1&^dfm}n0#0`U-9uR(6%egr2*9kX5Oy$-M!-v!XXbRO z$r8&rMy+G`s4B5F?W1~~9ls4IS>9B64tt;8%;Uw}pE>R$GZ#VCL ztRZ;Hl`zDY6_2F(t>dyfaBTa7OF{66tz*S2?9`w`s_gBiRgOPZI zzn-co?YzxCXn95#)a&d;nbVRkF3;Si?K%lRh)^Tb=uwHkH{9f$o2^O~BbuC8=u?>> zLoSoy+oZ-gN8XrPef`wAxxtCt7^BzwQeV(P5%+V~ZzUJ%=+P=fjerJeQ?-yJN|bG<@|RkoV&4==o`@BwzY-er7uq;Mz>Ryg88M zs7sZ@<*{5G7G>K7LTgRdq%GNS_pXQV}S4chuT2FE?BGg@Sc*rCG2w(Gd3x0I1yxn_{CwpUUvZ`l(2 zrB&~{cMlV5BrOPGhm6SXH9ibtls~0V--5j>EqWQ2LeG0z=M+(#$)cWa&em%v5l&h3 zY~UyVQi4`?Q2EoFhrB@2HsQ$DVOksZ^^!J^jORbt+NnbdX=;g%L%ItF32ZFKDdD_C zrQ*4DDi!D4Eh(B?QG9;7DUK$)NpD!o`#cr#wW}4>On(njHM`;Q=NJkl|D-YEZrtXv z-G`%dUD1v+k+N{;S%Cxo?(-j7ZnyzECl{Z;`Q38iEeV1o;x@MqU-nAINJ)~GO|m-p z+b@k5EN z9p`g^LWiIF1HRNM9@L5Dl_RF&UpdHA0T_r|x_^saqV7ID?;!yF5+_>;J5p#Nqd_0}D^rVPtwK#MYxbe(^P?6LwZ22_@LsBP0ZZ)I&%nC)40PRyBL`b?=q zv@?sn%A{$T*{5fVz2pNcak|T+YLnJU7gl)aG>R%E9&x(OjyO75<+x_h?6OCHM%_mZ z?g!l4732<&8q0)~gqxiyC*~VUa>h$F?B>+%cBS>wKlvi1yFdm-p{VWeD395OjHW7e zW80r11#Pa6{MSCd?vuZBe-kX>@F%nBFtuq^^~hlPiv-D;AAN_K(=DV+G z-ZB->`ls;f=1AE&$60iy|J<2P2l4S5=|{5n?P=o70S3FNkK?kaNs0?a=WmV=eWo1` zZ>ZcvstdfGV`J-S-Ku}6&H(+aWu(0&``Ne%TcYGDi&ncfA*qbg+m0`P64+lk0NGhr zipcnM@P%#It??ot9nH*4n0#?(hVHd_r4!arTiXX9QaI+i1AFRrePt6ePUJ(Bb82jT2()ai68%X$8gZt)0X_SQ2NS_BM!}|3WABVp)fzY!&Q@uA1BKp z8$F4_%VGf)2&Ct}TceC+cVUM<`&ZM$S%=TDAt%H?%P7IV8r0ru@#)c7FLF13IWB%0 z+z~d_y9_hY&f0u^ByzTDyj*daqATLA*iLw8PJykVw#w#F-0>crPAeoFpV4^pNJfpa z@_AA-BMDxK>QWjH@r7E7Xgx!)9jg*IG&(=W|!0tz6UTog-+C zH|Kmt39T*Ov!uhr@^jpjvV3nFwrk1b%0Y9^hU<^YFIi?w?MShIU8<<{7gW4DQ@^2} zrn|EcCUJx4s}ojCfZFZRw1T#76xkcUyQ>p{zxw~;@Emk)ZGXbWDsvKBwN{)S!@}(n zvIpQMDbcDHQ3_?#n@OcR^}i=_Lv&P%D5YaMJe>Yr^KmB8`=(l+B;>-{V6F6Q%MiVx zh7stL1n%Lrv7*xGUWye#rN1U>%`lXK&<9`j5Ap8VhU@`}u3NeXD5**E9Xmd(pIHNc zcT%D(SXp5DGWKzrep+Vr-#xRaA6xc5ycKEIWn5Ac=TH#e{zBcQ1l_mjvms>{tULKV)BMqhCWiEd7&!PA^C=(O6K z4C!Nz1%ApG#iZH)FjS5cyFZXW+js@Mm^T;tMj31&f9iiK{aghu?LP2Sa>}Z4_u-@^ z1>-o9r)9~=!V_!X;=zx$Hv1wwZj)}Ov#_YtmDiU6nVan=eTI&-dU>^VD6!iU>hAR0 z2qxG>->O<7^`kS{%$LVwT@@Jv*6#hpBlNq99Zw>nQCIpLh|>Tt)4&usmH2B@5}kSU2*2YqJMPbh12W~_;YM4je-HG znV{F;G!tlgh;C$hrINIIpGL)i+05N*aE1vqvqv{FBOhn2YNEkI(P0IR%H{D{m-cDt zQS~ABU{>g*uMN+7_fP$Q8tQf+HA6pTKm|@tlOtHV2BKNCJGW@AIGK4SYs5RZU{Q@? zv5l7kNsV~5lE0V!->#SOg`4j8IYP|_CuyV%U_rG@Mmwt$Oa85jyOJ=|KM%f-e@IJC@zMNL|)!EYh#)N*Ov)gBU5 z8o1s2^_4N!y>}+9MS)*sj|aR;%1<8fJk43Ft#A@~a?%a#2)i-?hA-Q>)wRg%F4H#a z7Kxz}j+pjHdlf3L7;5|IXxP)`Dml5A+efLowe!kbX26bEx1vKz*3&XTmh7P8N_ z<11`i$mdge>itWQ7P1O%Z)#qT&$tpR$Qhki2x;!_+Y9=vJ>mNZczhiE%ylJB=8~?d zTF9Fga)`K&b+%-R2!9=zXySdNqtG)bDUGi}y&tJbdaN@aR&_*Y*P8Vb+|b_NMR&nn z>&iJ%@k-{En>@vCfUYtg8z{iozGswsU)XS!>U5akwRR!790#+7d3a^eA5FhvN=0m!-Gg<(~U}u6p&FgyWRy4#a@WxjOJbK#>I!=#Cyg`~B z3{8v(|7G~-EBic{9fJLBkvpG1X_oW@Z46bcALnnbK8pj#N80)FCSp4W(T@VYu3En7 zR1pkUUM=cd%jP+Yn7I7?oczsI=5OpirKo<}?!B7(o@reTVymoOPr6m3`179U2u4 zt31>BD8UV%g2C8K;5qMV+$H~Hw@u3V#6qHh^5EHV#Qv z7GU!;5>E`uuGGNJKR7e*EU*^{eHV%d|C5EW|n(T*iud2Akm7 z`?^deuyQS*58E9V-#pxOOE@B3IidR-sswK*sL@oD))!wr#5(`<-e%CJ+j%~tjrH5gkm&kioYVRct#Qb?)uZ3UAts?(zBN} zQ%;;>YL7gaxAy@oHBW_L>5#FFYWZvx{XS9yjc>!9ITj6SeggGxL4G_p}8lXEVTeg53#rpjmeJS7HvJ2bMm4yPXt5RIIsW4B(3Em1o>uR~gdqaD( zCma4TMvgL&13T|Jm}jHLXLhKq<|;oB6dY;tSTLK{o9v`nS$}Z*tX55Ux_Grgxs#Z8 z+3XA2cm~>dKxjaDF+9b^Q$JqIyW7wa0%=Q)8L^;JN$E1#5N#Mcm>r+}{sinX4ym#} zVaH=?N)8jO)4E&vNz}G%lgP0_daX)Vx)Yr-fX_OC8L1w>gZCq2eObW*f^1hbF)#T? z*d9$`I8$oQWm~?T(VVYVe|nSkYEERc{@l2ab4#vDo`mt1NYv(wafbDu5%TRh7wauN zn;6Dw+1N-DY2)}=E}rN-pn&2Yc59o5yAnDpd@#g`O^@!QSd^AM5cSg4Lqm~A1`E0QCg5QDml zi?QEw3}ezse)uwZvz~laww$Y>W@!($XCnOLixb%*<VY*& zo|iFJh{tj*YH(tfQLxrik*B>)i*_8#Vbq;#`_>^iJ8^Gg(yghEYP6wZ$Emv@O%O8i z5l58K9|l{(Z)z59SlmyJ)CZTGb${(79ZIKwXV1*D{oF=0P>>q z)u{Gom{Qw4hH9RE5mu%5F<{QsDMv-0y#|&Q?qQUxuQOzx*oGQ-qu&3_+33&1RT1jb z*!uGUp2_VgE_?qJ8JC>|xMzUlx3xYABhDsbDR2rZCFoERX-Jk75NlPTtZ`@^)xsoL zv5jSA;Tc-Xes(EczFy5Ar0u^q74!jyjGa1N+L`TTDGoGMDbkKAB$&!G;AM+kNpZ`Z zA+=v`(?n*Li8mVZO=7^ z0kNN`#n(HNC!yu zu=|-3Tca?Wn`i^Mc7*=wV<)H^Z`8uutYf^9hv(wzOI={)ii@I_+4GG9-vBvO5 z%kV~YeU!@jBM^#1h7R4^cbr*1o}^>NLVXv-Vll{S`QZhVCe#^zmuDJfPI%%Jq~HMq zQ@cCPCEyhHF4@nPyqP!2o6A@3@-MpMSBR?Ko5>;mzwplI5pxQBoChB|L&lbhLvzTR zB?vw=b$nO~_w3^AKg6`sGTn zOHWmOSD==-Oy@8C4{ zq*&N_?n(a>Cn?K8B3jJ;Pw!?z{-&v9(z3_r=?2jj1fOH7Q3PGg619bLG_uUU%T>aU zkwqt(n(_&UI$wEn(qhr4}Rlh*CqEw0N}->S)u$q z%v}d|p6NXzD<8zCCrIO*w~5e;6^Gd1(|F|X-?JYr&{gysNOZ0OFXm)JkUu35c0|~T z?wosS*@^cCL5L5QINTI4|9ZWP_1NF&>jA>O&Q5DQW0bOK%)-An9wAN(y3GjS7yGIG z%lj*R5neFMfpcP)hBI*!Kv|Mc6PlBS;HxC8d9&b&cHwvmRwtx1-)tAVaV@C%%QJwG z6JjyZsTV;R#c@zjGe3*lI%oQYu8*tQzl)JD63L87$WnOzJ$-m-wC{O?t)ZBdA zAyleV7c{0xskP7bU=Q%_9ySyrvy@YxhfuXuR(M3EdVkk*w$um+mUvQvb=%)9eghb4 zo_qQzcW$W+qchcI+*^w*+SA>ve`EcFoBEy4sb9uen)ZY8sr4EDv|^5#rBA0kw4CLP z(~DByr~*_XIQ>%A3<@IG_IL`8($V76+fU}CWu-blhvus}1!z1E?0jXvtfA}MIjk1A z2s(M|yngiUJ=@h)e^hcvIBTHY1DR9jMo=!_SlP(QK~TerbHmD6`^oYzD8YsKTxlP) zzM}p1LgP=_r(Y_X8RsuS6u&DC!pemdTdg9D`*9iaDVc%+-;3FvRx(|7IAvP{=H8&()Ga;ZI+dXED>i8Tj@lYS?n$@AI@kV8pt1mMikudbaubhdcH|&RGT0 z)Nxis6YJ@^P~h}4nStpMn7rmu;bZb?(CNdM{AF$3GenCldV`ghA7X!f$R*aa{h{o_ zSUIof6QFGmI+Scd^_#WDeq8D6aJByqnzvLZYb#}qd#Cb+8_gc}&XV>D#S%ibVcSs`e1X0Gy|aW>Kmi*H^&Z2)Aj_QoU;YrRU&?`k zod;CezAct1h0jc5z1Uz^mE_wAFLWd2jZYtxm0B1*KE7}G_gmr@e`oRmHTf6#54kt< zze4^0UHLEIKU3)V?IV5I$L!Fr?scy|vwpXoXxVtO$Q$;xPT}Qp6^|5YvL8+~tswn^ zOz2b@&#(Y7+lqJpA4qtsp1Q-G=hRHR!)*#0Vb-U`9~dDYGj7XfD{xRe8uIQR;&$+k-CU@zfiCTB2HOo`=%WlYIpIj3M zV~aoaAE(qOb1?#vNC4&*2^PK7#`3kNkS0h7S;;{^V1}tP!5C*cgwy16xmK#>d%H|m zupJAb^PAfJohiYcH-Ki+M9*fLYoi^I$cAi>WSA_@sI`nBY-t2rh0#X(!b$i2cgz8m ze2>A)ExdQ*h9i&woPBg^o_GJWrzVmeoTO)VB&%w1ozd%mW0VB)>3Fgdc^R{7;WFSr zihb|Bh4E}+Gn+8XabYX7ut#$l8Le|spj`IM!2Z1H4OK47j|0L4M-H?8%}YNedJrU8 zr4C$%y>JtN8=bGASWOR|Iz%sP{JxLvA3G9E?b)m5o~B*(bf#Tj{M~R5 z?~1@NWVs~$yp?TBXXW)MBt(?WQ;sV*a+0_GF_Uu-44Q)=S+qBN%ntK;0M&suQ6yj4 zx3VmgUcbr9q&+`@EoGXILc9^>+h1$2c;277H+o#;;(`OsVy5{+hJ&YlEUvNYQb&GJ zw{d&*t0RPwS<-sr5#V*p0UkfBk}Gr5%^jeSb_-0F3x>$P2B8h}dnX|o=bU`EI6HGA z*caUfiE>j{sO*ONu4u&I3LO-+et?gNTp{Wh?4b9-45a|4j&`(jMl%ubF*#slKgI`U z@>b47KDb1V@6Pw?c(-}pW#&)fU9hyuu=VcS@2Nn+;E1j=@7*)MJ&l0%QdU+yO#e&L zf8sl96Ik}Gv@FoxROadngEf$?CHSmSvnQIQn+DK-+i!1gKX-V$u|Tv>4*CvV?M3jt zF+aL+vapvMKQE|Nmdhz_tbB}3T?6~P3<_F|n`T-B$biaJf$xS+R_vjku-0t>&?mOV z#4|NAkk{R62pu>u@f?bBH7^VP+5$J;yP@dtSIj#~znFrxUWn{R9AKe_BY+aDfzK(T zq)eNIiR<_&y59QbB=eY$(MIy(APFfJYJ3h43fXA4crGyYfOirB_-y)RY^2?PvhHt= z!1Tz0lz?9t-NNRi=jE-%0e-859G0c>-S}#)$XciAu}Sx~f6)5UJ^Fs=?)=o+ zO};(O4jMQ%TCWkfBlkaic}WVTx7ctJ?&*bw$u=cz-`vY*T3H>Uy9wA~tQ@(yXAzov z3!=NZHPyvzlLSfEaAB>2zQzxZLdAM||FfuF`I}R{j>4Ef0v^dZ4_uooY^OpfeVnSR z7Q5MNHvTfh7M*ayg>4d+7B&YHtT45-|8_d9vT;UQ1Nt~x9pCa~=j^%xp4y(Hr1`f; z^DMLb4$WT(2aKOjUF~}l=l7L5ukeU=q98s^C)v`OVc>`Twc%tvPGV+Q0p~euCKJm$ z?d2=vv}>7_|VH9I7WHK2iJRI>7HbCa|4j5%dK8!?rzuA5(GLd6#=TM>jwCbf$LZ_$L5C z*1jfqOTBQh(|4v~55^t`^32BLwI%_;tj=g(Y1})RV3oCQ*s}6ad4f5Li|sP^YYQwu zjpg%>3NZDSq;~r)45w-#XEJaiaA^c$I}9g5XQ`wD5(R}0Kr7X?Q|`58nGW7Ac68~< zvOs>|AIw^CRn5fFc}`78-bdJfBvzMY;@t$y<~bF+(e-h!>W9Pj7OJoOCx1YRS-R!c zza;|VgXvoecXJpGkx<{`!Is2jpK&?JZXKlJ^jh&0`!ybEypnv%=Pr;Y2WdQ$0Uk~C3_Yv`Kvd6y^%AcfopRU$lZulF&l|2?h(H~hw8GED~o>rrdy z!_O>!&=$Fu;OH(ocC1JqWaB1a4>S{>8EOqQD{X8j^dmP%9Xf}fcNL^kOoLuff$fm> zSjiB!{L-6Q^)+c zO9+|tVCFjtNIQ1h~D{Y5(N?Z)5>{gQD>#ejd@=2X4w9Xx)Rq@8MJ0dRk+}AIX1ZH*3 zl?*&OX|ou884h`pAaY;juJuUOQc`0$h|d>Q|kB` z5-D*$Rj&iDuQ93tE4PcM9RVmQwB&X}q$Fk3rPJXn5KJK-%nRqNV<5?2OMaaRbYS0! zQNY9znQo%B?zRj^-yWuWa&aD*zs1^{hHOEFg0n@BgXbH8t($PJcGgu_Gwn{a$2yBS z)A)6xV|Yl|)7Fzfw$FR*TSy@Z-!Gym%zp%?`I++r_w)0-w0aC#N#75=Wi>8xDg)qhk zkpL8Ltn~(`2EG}}WB0LW=&s_L^9g@OBI^gk0rJ4Ibwnp3ab0Te#25a(vi=K5BE5<# zV8k=P0GNVSt;xB7UFe5@^b^M76nsNH-T*!?#=#*6|6c<(>Fa-t(EknnmjTPnMf!s! zg3A3d`9P%jLxL?u=3(=LLs@XAz1r)kDU4yQqoaMN!^1~})1i6k>3xNS*_=TzUx4n!*=gR>w*Ma+dvv)UV+t=NGVIAcH zB#M&VtOvr1m^_a2h^}@z+e&j)I`F0cVSxj?fVK(?BH%W5>K7IS`N!t|3xZ3cJvD7- z&e=6nri6|1*=4SU(4C|@c`Jn3AjouPX(T+x#MDzpi81#=yeU{o_NNNnaK*uglbZsP z<%Urf@CUYE_I&wg!C(w(oTlm)pl`Q;Jpkl(eI3Ufx|Qqd`@)z5^n+*kw?YM`Wy?dp zO6z<0bi9@weIj>FqnCS!Oqd#jFks<=bZvu}eQ6Z?<;hM7CiO0uWvjPkQ3j)I^7!u* zL&B;MI?K^-E(*0W`A=Ks0eK7o1> zyml9VD0@b!NC6d&g*TMn zN~TvJ4mw!=vrHt#uhZ866X$MyGHu^^#Q82>1rM&|{kGm6C^4L}asL`zqx`G@$j?1lgn_zq=qqWnRYP;eB=+*nFg+zx(GF zLj=_;k>kSZ%T~`OUxZC^p;#Y4{Stlz<=`0|RLy=JqUp3}bpRl?b4&;Q9ahb)_w-P6 z=Wd&G+%lBKB)yHlFP>bCVg`;s(55!d8I|BQ%X!$H+hee!tXWiOgPe5Fh0$((<|S9; z{3Un3{u0}XA(DNUS_V6=JiK}b_=PuBnFL7ZF)3uM+)ze@4EjG%tu)n05BZ+~PioJG z7sq^}K#1h6H3Q=q@~%D*lwAR74&62wQ+#WKbnWPB(5roO`6&RN{DlLq#@0zG2D&EL zxH9f8ZDW&^q#qgjXmJE|y~QOEp{+Yf;@@zjhf4lu^g`>Cws@ml`nJNHzBMV(M0*wc z%s3giI;O__zq(00&=Y~o`R4uDDMOF<*IO#j6&4JXbum%oiz}&OJFaT&tyODLV|h@96Nm2H z>!`q!bi}xPsc_x_LJe>s9tQfVbJe@I5Bgl(WwBbAc&ZzP7_=f(~r;6W+|A*tynU|)txp~@qvbGra(c~E>J zB+4EJvp4`iohgy1vN1aU>ASe8SxnyGR^z!$ZEoXtz05zCEdIhWd5@W}sU`?fi(_>A zGFI43@6KZE1O{hD{K7h|n_+AB0A^Tl!@t^Icf@{)chs$s)yX(Dc;9qT1HCk0uJ8Kib{2%4v-d{D9GZ61pDNY&#v$5e$ZQV2K zM6-_nk^FWyJEcftUwLKSV=o;|GJYk*)6n+iWa-Zxmh;GMV z`qZ~gdiH}8Vv;|T6=7Q7@iVo@b(cwd0}cNps|SnEpbD`LXa68qe8y9Al;?j15A4!G z{^pJ6HP3ZdW)UzPMEi($@Gn%@Q*DBUgO7*Xw(e=aLjqv&q#>@)w?F9-tgE~tFN5B^ zut5LtbPX~H{$S7HXKsCjNaj^OzWdPvLekXr&s4XOpI0K9dA6fSr29s(>^#8&+j_p@ zZzkV=vX~l$@5}^s3JX7>a7ptp71NW5aXEy%2ppWr{hXWG<72zJd(U_Jzyw`|@~b@} zS1E@#kE4Kb5Hl>KUd~?Xk{9X0N6T(faSxGo`ICZ; z_6-uB_03aNnnPqWO)UPFZ`0Cl)xBn6$fpth&so?7=!Nbt!*$w{T6;{kS>Zk4#a<#G zTY$DHwUfCx&O%CjIi8O+?vb%oKu2xE3V|tZ+$J@nHtcgrT6PgU>cC^<`3xy=^~8-V7uu-Y^CWf_-8GX6ntFV1g#1}klEBUeoCGCYQ( za$n&#=Y!Z};I4G!B-Yl5?A^!;2ZnYGs4b3f+gBdX76DYw_MsO*&Cj05}+rt@)k zJgf@!$@ntd@XV3QpbVhOsXB{xo5JWWo`D%Mjm9rdkiRh#-dsQ-VWE^iU0<<9)_tdc z=MKW)UIIq9xqN0{K+CraMiYalU_cX<-TP-q7T@xm{1Z^eJ(d;3b|BwYs2if2c~zIi z2Apa!mIt2%hmK-ygm&jyq#QnQc$9tV_pg zG2RJ1Jho*TW|fcNlMCPAxNh?1@zA;xDH)abg^hAKI0rtk+IrdrDd}rkg#WkJ$8NOo z&$LbinV?M(GLn#zcPIMWG`M-*`Nh&rpvTf2mAAk{;kT9kR0PK+t5Id4k!PPP^80uAqCIN;_d}iLY#bd*E*BCW*B2ugi;z*vY>C!`gcQH5t8s zz5)U&Dk=g>6+vkNO7B4tQE4gy(vd1%dI=#QN|7#2T0#*JrT3Nq(rf618l(kj0Rki; z?dG?0cmH$m?Ck8Fy_rmsN#3+`-t(06`JU$(Q=r~8(lC#?Wj9YMG9Fpd7gFus;F;Y( zFTCnyyIa0jFc~|v@11Mo0N&kpaIB`XCvM4KddU3KE%+PM=kc<24Naz0wa+>cs8Bt# z+gK>JZv=|pFMm^U4|`i2*3_<9!B$3UU$91BY@CONzOW#_KAjD%b_J7|f=UsB){Rsb zPv+34K}H*_9Tir;&LB2&)I!L|xEAIO4x(%Gew1fDK=}vH^iTzPK(p^^ee-_6+yFDU zf&?AfQ3p)w_#-xyA2(32AT8y_{!#1S9z5c}af%idotM zzpuFv8C19jW zVbO*vCQY$}RM$9bgw8l36e0PCns1S%f|av!uX zs;2LTXf&`c*wuC;U={39B?RNMm7vvLcIH+)ni11jNKY{23m8#+!pxI)FMlJ8dmNgcA~wPJCnp&#iS*F7UY{!rN#I#3Lo4MfD)pagb{7T@E;qlA zP$PjIsR`yGkyIS(3C^b~c>fhz^tSfa#@1ZtFA&gd_RFZu@7hccg&r3Q=SQLmwtY0f zal`i%)1=iNfFPjE`(U#w5x6haR2w(If47?d-O2qYpE$t%y$&3oBOWJrhO$x1PGPlu z6Da5FHlDhtL7&zAJWIP!&K6!VyE@nq5cLA)+ypC80Wx6d@251PjoUjc-K}i5`vVs| zo%^TW_yFPJc~E{706dwFJmb3-HN(AB6QxT$Pf+{qZnCv~)GzI4{o^#gjH-yNOyBqi zb@7A%TIacIT*1pjPtWiuRCWF-*u5>1Ob%e4Qa|pxx+_?b2P$0{;+Q>Y)KV_nHCV_u zP*J6pQGIerK^fWm`BR{5y7_FlYYZs#EN;JgI;39jTO>wU@wVn$PD(|7nWy+qa}&tf zr{U8$7(UV{bG;OUd7XJe_7*mKpSK1XRPH;> z5>hvlVGD_;E93)T-IW|ed8n6-CUtMvg~yRxCzCEX^l!0>mIO>cVxj)qd%jmmvBYJi zpkv4<7I*hdhK83dH)wS;%9#Xlq!5{wu{TkpDkPZU6gwX(?`2jQh^RYmAov4@MIW zkjLApx;>w(w#R2NU-nH}tsc_6TaOYiN`3QE^glP`SsV^W+1YV@`2`hG!=ilk~WjYzpJ_<9<@*7sHtvjpr)4x3d_+j!&eelsspC4aMoQ6j+Sw(-j0g&c4$&v6^$LO@bKn4k@%{BwOJ?>M70>kd_(= zG!K4@0(IV`?y7(wx-aonyYKey_q`o_g_9w_T^6i7M*ZY4$42S*hE#rIZX_0zlMzN2rFtGnnb<%$LpZq`jOb>#}R^|L4wW#JboFUzv2n6Ef z_JqhC#PiPM#ethQsZOfBLPvK;tl;<5wn>%$t*0P{88k(mFUCQNFq67-C!^{;hSZx$Z$5o&#`xxsgGNiPvOQT<=ADQM+h`SKZO3CR;22kmKRY2|iwgu&(%$*p& z#1qGvth1IkUvSDZFkNwXlfL8INhVf>d?nq%_i!&VVEaYV(8B!;H_t)}!i>AY5de3U zJvC`t?336MEW?&x1Q<*0X4qL#8wGFz*MPVEhU*9GjEd*5Tyu?7w#PZ+?Lk@|B>0iSq|dlG)l#~lae_wi0V`c5T)?_xzx zh)dL3Y3Oe|3Zj`;+mxP`!>p9P&foYz3b>T{J8!99+3ZSR9fn(T>t<5 zlB}}MAC-~dGN+P|Lxbyv|7C=VzWjGX@_%wqGeR?eog-{+M!shDy3Xu%jnnJee;!n~ zg|jpk3sApaM2Bl;8xVK&+(r$*3BCA#UHQkoc+hZ+0a|IOJ^dk*9YD;{ znuhYuy8e%!c82>;HM9S{3tj_oiBQ(`W?qa|`iyJsznb?a>;K*d{I8Gt&ot)6Cib4R zzLd=2E&H0dwYbbUp{x&YW%~<0JrFzpy5P?1xaaoq7bKs4OV;X+_7Z4{5{Z`9NWGBU z9~SZT6MaEVVN>DjJ5A?hYJT2{u55kNzQ2HMuv{uRJKY09y9n@hMBh$@x=~5%_SD=q z%ga)!-A=y$ah-a2I)OAiO0CmQYb08jy1mZ2(qm52aBIxwY`_)8MzEx z+kPE7#Vg1yi;$^Y@f%#M&T-RC8in<}8LoL!z@!B5q@v!MSUiD?Th{;Q(H1Bk;JjEg zZnDC8kH4k8`)1&nQ#j~f&wJ~NMp$^IHK zf4k2q3RXvnCYdkS8QInJ2E4(SNh#_M;T+>1Xa; zwY1C9VxR7dgY|zkJSfBiC4TpEIc01f@o@>eJVbyE*UnbB0h{0LlIkambU4vDKBHd2 z$6K!zY&y=BxXxDi#d9n8bIG}^!}yDEHZ{GWj4)<*S-uD6Ptr=XWhsV6)|+%mShslI zM_58|yc`K|G=*xLZ1!<-+C^6H+a;=Pw&7P}{jwE2{e8LpxD`AWrCn#rcsZ>C^Od)M z7FujZPN-DX{5hhw^vVs+cJ8oL2b7(vR+%_Upd@g{87+5EZA=;@(Op3i8W|CXgygwCsqoM zbVpX@w;TU3pd}?hxC2&2RIf?4C)ppwG!#@51DCpF*Xx6{}9UPsNgbI8Kq`@Z&Wp9o?+^bM%W(9URI`NXnl z^xIef2nTB;$fGKlwzZ22S{1e*eogvl8HZ9e2@S*t#|=j(O$8f#&!jdmQ4=2$#GbLX z0g?bjf_O#KAJEyq5;cMh25>TE7~=zeMo{sD6C63LVqk$!9{PKIrZouNnrNplUHh&m z6?V>QpJj+T?^=0f9pl0~W?F5_c*>oaui6fVf$KI>FzUZ8oglv?h+@^6n2UH1lXFsR zPmW9qwG)j62w2Ic&Ur`*33g)L=-#!akjihJ@@3z!Cq%p9yYLF=EnSEON53_OI4w78 zffXg}fHcbVDs>61Z1;7Oj-qyJwu6x#lSA;7V8KF zGaLzv0J8a89hnr7+d~sRE9?eS#c!1;w$z4Ii!--hJO0aSMDSx-z>sXH0jn{>%08RJ zuZJ?E0>;VJb6wB%k8qn5Mivf5y)4;*9qt&xRXNSe*s{0kjs2->2akq>R@dlUIFge&OL+-#Z-dt+hE{UR7#NZ%{Ynl}l5 zur&!bN{W(7vjxsnQ5s#Q2ep_LkH<7~We}=t?eM~OFgk)&U1XNB_AjK(;0m|AZw36! zML1k|b-xz>5%A_j9OB^_-*=wO^*SGoDcqpELY|iVJ>Ho`)Y9>V9CUghAZknZbkY?) z+sXdT%6T}7Zm#mQ`_#{5Y%jNG6BFd1#PI}$vds7TCA80eyz}dlYGZgh@oNWqw$9nG zgl2L^yJOgv9EQ@b_q|r|+07lGxax)sDvkPgQW$pQ>L^JE^x@i;mLN2swe*h=m6C zY~Y}1$u$gSJK*K*iYR_JY~rQfyy$9Cu4D51$NW*7_+kF@!Pc~&y_lk}JOJ9tkGgrt zXGYl{l4^HLZ5QkLxC7&c1K0fSsjzx=dC+`J4uwoqF@uucMm;&|YiQPa$mG?ne%Pv% zpf}#}j8K*b<=nszr-$ce1X^}La!&ZI`K$RB8a+`G=Imdw)4}1jjw4(F%WXlD)hN=V z_mvpcv#r8)kkZ-ht2i6YJ5oP?XfvHrFFdB|$qM#)l`{S0tr0Cs?4I!-I?O~()PU8# zGi1rRZd!N`+=GxfrL1;)&i-P=_o&f0zhjI2Hk#M5(!CX=ex_V!c4#&Fg#dTymGp^JGHsA2FbJt^N|~;mYg7A#fkG{tR=#P`bn@Ei}qe z*>CC^!U`seM2joY3~}ywp>}I<`@dm`+QN8npXnz`_H!|<`$t5ZW)O8jho~pzS*MpR??J1=n|qa4`MI05*V9D{!^eP1 zjyk{Kd%Y$XV#WuYb-Gqp(0+na>%)*eq+Q|(+;qLC9m|`-*=sQl1L9iDJ(`O= zMst*qv27<$z(b==UTZnD*dj=2c`NN6SlZ8K-Z^gKUGW0)1@F1}sdvI#V4mx&sg4+8 zc~yC~xGdcHPO-2aE+W+IG2d0OX~)-pPwwJ4Z9 z@L(4CHtV-SMo7exEWGS6_uJ?@&NjjR?6z2)XQm)vQbngwT&^iANZrQ90 zt}1Qfw<1Kyck|Vbn$yi1Oza^J=e*x7-#ln|Rn+(JuFsJ*N@S_aaaS~+O{|}K-3-1f z5L)=C{;fioALU&BA_H<8T$b?ym=Ar|z{Xx{tNOn6XF0Y*6*G zi)cu1V3LNj|AD#0{HKR6p-FwW-mN~P^NiDp`Yitwkem*fs=NfMr8`ugFbi=tIx>sa zuQEd#Ym~8Tp(AZ#&r-q^avWbM>DV#4$4NAKn%)@*50iZ197UUNP+x}|ZFyP?c)qA1 zGT)2krr5EcIkCY1$*T0Li7n~RYCYt8Z<}}k6FWAs#YTKPZ5kH%7TlBad#wEdzCoJ! zI4J6#--)}Ami&c<5wnOVhz*2C%JU<H2wK6 z@%#1Mh142@Vd>5K&n4$+QI{*rW}<~bOz0rrGqZ@Y!Xxy+$3@xT_hw6XLRh;~Kkn1{ zML}POx->qh{!&Y4t`a2A z6?ndSjpaE?oo_yjdehaAcw`rWzgi+{ZQ@{=$8_l=f55M%)HFKR57vX!@G;t(HMkIl z5^^lk#yftZ4|n@gRf$y{4*h2luRfX?UW#(Vp4yn=1a$ zg#u6HjJab72c^WA3oQn)KEw@Dl0$nku4LSMDQy1F0^g}sk`9~!E zEwkN6I0>?q`y9iz{X#!KNJNn)Y6=VNjOW13-pF_DjgR@!@b3E)G&K8|=X15e9BksL{s#Z_pz!wgL zaK-jYKbcts#Vm0s<3r_td$PSF%}?$rXh+T+jZKS2ceQC=X2E7HwZIe!GG&!W~x5!eyrxX#2`~{I1u{trOmTURW_a2a#;C> z&wx~Y%=@b%q76X(LD&tHgIUgPtSt7vj~@r@Ud&i!%a4PMMt4HS?I5lFVG{{yRkrMQ zp>&0pv1z8BcKQZq9Dfzu+rI$rj-cYepWbDc)lW};ct;OLmO0%csj(=VAN45=<#@fl zji^(bykd*VTnB1o=p8v6EEV_oB~#@TzObIcCIWvvNPS!T@%g_j)eS_en;pX)>MtJf z*{fKmFU}e-TXQ6`-ZCdQ3rct-he{0hTU+@?d`0g)J$bQc200Su7`zV+gdL$WA0P@G zjc5uzZRCXsx8m+YAwn$w&4WIiwZ2~c!}sF%^y4h<+OqusE;eQLAbfK{JrbG zw9e;LZE`)sy%iDl)6>}u+jT2-LO-zGgC2w2y{!5y=6lCatL}N9h?V6#jZ9YW>;^_+ z=NFHX)UYqomFW+>zi-rj52(dY9Y{Rivn@27Z!s8SI%A&`}G!cb}7m0ud{!q_0--nd{MqHa^2OYX1q_JoNrh4y~?EY0oS$Aj=K8m+#9xC zT-)9%eIt3Ulfy4IaN9mrU9aslZ_isMkDlm1;1+P>s%4|tp%oUBAQ;pr) z6x$Eg?_Z8OC)`l~Qz=}R{rTdj)A7BDqkMP7#2x)9d)CLC8d4)Sv~_tHh+mrO=l$Ih zj6-)JF=N_DD9pAK)f4HI%>S+EzS^l$Hj*SF1Q*&|lBK=`=)e)Ob(5w8wi*Rb-RLP^ zr@DPV@d15~7J&*WZdrJ0c4|d^Oi;q_O2x4bPp)#7!zA|grRSs<&cQ|9RPJj;(w6e` zT}Ab@2dH!Kg98PP3auR2u%pGi7`EvE^H)atp3`sUoApC+HBAb->(KS<%zeQ^1MFRi zV-Gh&kGkJ!y1A_M>>1QTS_hZg-G4}I`}PftI$C_&z1tpdk?p9-!iG^elXYDrbKt&Q zgeg_tdVcCZVZm{1(wjx%48gaxervh*-mF+X8=dx6hpzQ@^XbkNurQybi;Cjp$8ulY zem#Y0{{qRkb@zD)>GBxBBUA%njZPq<&`91i+s3YS1E`5g-fnySb>{6(`7ri@dRIp! z81gr(>3i{hq-)XIW7X6F;TtC647pwQ*@G$3lRuxv$NMuLT+Nr+;}4eHi5Vzdl`&{aQi`21)udpq25j`}jD`Ab{&%T0i8=^ZMamTO$*>CA3;Yh*>?sf~sH zP5;cMkZ!(6|028hS+04@k-#yf8i;86)2-Ot2Z4x7B&`P5pzjBs_scI1AO6L^KYFh# zKmAcsg!tJsa)+rD5C6U^GEsdCGM4yrpYt3_pMxJ3Q^o$?P*m8lo5S6xL6woDfVW6l zJ;R4~`P-+Asy_OYGEnh!IBP&EJoILUp)hZh^}XW=*p2F|!wy^JcTdl$=f=g^ipy#Y)>exOdb*%@8QNFxt34=%TsnJa5z^*+nd$y< z;hWFor~pyd+%VN}7&tfF;MBYggN%URXvQ3Vrs!R??91YfhoW0AjXwV~6R7jV9Q!ty zcd1Faa)M$97`BZk^^tZGWA>4Iy=E1W*NuO=(npwQ-V6knN00=bvE zyZjRF5%hs}FORg|o|gIna#9ypkb3cCw{<9nxk65efbI&S^h>p<7Y6*;cv}d4>B7#0 zf4v@>4X;wDKisj;*O3VNU_ZM%m8zoP`UaR?#8(#9!>en7@%O>&Nk+Wv^j4@WV zsm&|si8YwFCE>&_tw%9mJaX?@LsP|+embz)2x_(ZcvZMsU^hD|eZ104llmF{%tsc% z8OPe-;l>m+rN;-+-HAl4!oSQNI@W6!|j+{BDx2=3~hki+l08tuPX z^tctF_(#&XT={-bgj(SM)JN~ifyvG2E7gb0CAo5j)=8;4!G`~NYV2PLSFb=qbfvg( zWTml&MT#f@6heDJDB7#0TA(-=X2RbA^!%Egyq*k#bi6}$f2MK4f28^|dc%tDUtBBY zAMzIF@rK${=MWozQVpKLkLlz(tjCk4j98+ZaCgb%Gz}Zq*c)db`?yvrKk!uUp3-Y| zpS``oDRf+}o_m-q>}I=g@5I>UHb8f4!P6zI-6f3Y5qGu?k!wXs{HL(}*Es=?A6wW& zSH=vkUZI4Vb+6e=(Myk}d+%i|zKuA-UR?${FKK#zO&PT-cUV~fJi{@+yd8HPS&tKM_b)13)?{V?+VuhXW_)vx+}#?jBvUw*WBmzdUdnLS>< zcF3@P+3iMxIgb%g_fOJHN@4rSqi3YPLDfD>;U*~PJo?WyL8yt9Lw%pn*Ul$!S0(*h zPzMV=nd6+1NXje2hoTvou$mu|X%a@jvH}~AY|)kMkhTIuq5=J*aZoDQ<09Io_9{Q8 zPp+sxL~*;xOqx#jL}jqZCDEKm5%I!1{T3ly@At5{-|Of@D~>LHG~g*(#E|#uG8!tR z>J$se#e z;gND?91|--d}cSIr)_Go*Iz9Kf-B6tkJ>)`_MimyS}n8)b}Tw*g>8svzPgy;6RNV` z$2C>C;I5W4A-tx{tEB|w4)|Oxf*z(02MNW`HqX7-)!z{n#dJyp?|cUobCnuS2vFH z{!fqp|M=v8s3kM)*s6q(28y}>`Eb}rn zSg{E$7dJ~araR?7MX)gTUL=`lu!kGbuQ8f&bnq&w&5ezj(_4iHsdIk6Gp1)ly~O)g z#qGXRXlBQs5WEs?Vq1>KyI;WdT)Ph>!m+{UqcC+?mj%&~;aSgQ&f*d}Xr#S~ zg+~NU%8D)Nx~if}RXylnm|g~A_85qm_I9bjBW`)OEq)qAqR=t(tYB&p>LJBY8IAw9|OhtQ_>J={814bO20Gp?wz|`SPU}J}EcriQI&o_z+570{B&Jrp7 zSfDa-x0Vc10|skGUOw!L=SJ&&f7l76;jx;oC{|oBZhx=d6SbUyAprNAoxUfYSo~QF zg$19G))E2B7*u<^LeP;tbwmMmybPw2cNd#|VA}kkDSp`xNnjc&d}4RW%!W^sdFzWj z?Tc@0Wg3iPS~2jI$(_aKTHKf>E8#zsqOzURa>GKDLOvRja$P}H!q0wD2gNG`X=LS8 zUu91=9-zap!g^bPv}YNx-xfc21HGk3wfmVS? zHuWjhGbokR$BdSO;|sFXK`j9Hd0Fb56ZFJs`1@ZLidrX3*!M3CJE}tY#K_Y2g@rSi z_OIUDMWt;q>uJ+3(-z2pBCI!v@FP_zsqaoCT8npb%Q#+kJ>&%)yN+pC@St?D0?H0YMLy%6_>zAwEcaa*GgLSa22Th-58L7*(d3YENl5HIPye{;Ub&NmH|KCK>iq(Qwe=@DL zrn!}UKfH!WJ!2?{NF6TPh%xnSzeLfA9NE~l@^w%Txr9Rb%~~Sux4&>&y+Qz}ZRscd zI9h)MOHkwjXYm7$wG?Ev9hr6p8LwT0a1t;}KnyH~pnl%0I9mUZTh8S(#^$6WgC1Nl zrt#vVS^qK?H}5KiiRAV;u%>ZbP8_74&YomOiXG-u!WhudQ#<)|0hVH*K8Nz^<0aE* z!`18&6&hS7l^T{5_ki{-b?GFgE3Hw}3?uTdNYr~haIi26w6FpCh-z>*XEk5$5AlTw zdv`R}sIls|(R%j}w`yROFeOL0?IH%qtL%G_cQOAqdvT_0$Bm~EFTF;a9{Skx zl|7V(4%|Wx1n0VDxbIvMVJji){ee+?y2oWHJ)79|%dkE^pzdF^08R_-6f?m7jVO0< z5SeA!;yeDxR*<0rb?wm8Ezgi`AC|VW!WBMkFZ%?Z+6Db)QcsAe54$FEh<77SxMGd!DxQ3fS2}TZ)Hfk1z zF3&UF4B80y%yt#>7sx}Le@HCswMjflW$JIOp>EVr72zxQkA}zT`AtbI2zzeX4^_dd z-7zjRWu{!zgK63j&;aYLDczvj{tjN@CfPCj?#x`Vo(9rPM4OHjEHzLjG+vr8yfmZ9 zb&w_RKFG&;i2}B?0Ru8n{CCGpY#<%16{x7Pn@}~Cprdsj$~c)uHY@k=I0u+AQyA%& zNhO3PZ)nPq5^EXaeq{SOLHichol(NjjSn_B-B-}aQJx1MlRG-;zl^pj3oQJ2!FB-9 zJb+?+Ts-+Mqfc^zFXhJeVW6_k-+J1kNY>1F6!hWyPZd}0l!$mIwLSG1Nx#}}RPQ!7 z(Ho1<36lvCb4f6cvi-pU89HAdD>q2}q_PEm&PU=GbTwbExUCceWkm*GGVhaf9KIz7 zJavl)uTyE(yAn|&zYRXULL-z0@2RmBIH{Jc0y*2%I1HSq|GqDdN9kJ*6A>zjt_r%G zLl$KFW!TkVe>G*u7nDFppFMSrH>rdXZ21I}L3M;TkUUmZklhp`6U&X5att?cpqDa5 z6FiiIz}Y(j7?aq;N&>b^0M=!NmrH&v|`&5)z3tT$CCy? zTUQs=;h))W{aj_Q`!mqV;MWIx z0xF#V0;R!y;SD<9Clm>maU4D{uCOpQKQy>HR$C3Q_onfc>C**I45ke`x+RaHNpBAS z1DCgNu%BE)MixI)64MX-#myP+NmCuD9_-I3A9&IW&Xqud2VIxjlJ}Og7lF?U?jUD zHuizXfp8Kb9V19f)))?vP@fm}3kln;N~X?QbZ~o~&(wk~^Cf zi_QipLx+wuuJ0GuQOXTdL1cQ`pQuZJYEI^qM0DrrY`?9w_55&FNHN_!s8ac9PQtZQ z_mZu(I28TYUb5+km{PMJkFB;QqOTx4}7X)=2kQ^M#N+!lLJ>x#yy zromENvL9^L4Dp@w`-P!><0z%(rL)uNF0C-Gc7h)m0;;%XqVI zD!J{5)k)@gj{b{1Q)Hz0@#R1sY+YPr8{#BtqMs$9K2dXWn7jG!^Fewd{q1uoyR-;v zs)fNaEJ2wjHv?_3*1e)eQ+i!J9x%=C@zBoMvQ z8BsbuT*4W0CZEKxMISiXVlJ4n-3`vdmMGBbH-4g;d%}$RorHwpE9f`Wqvu3p?VgN52=ta3YB zGf?@#K2f~>cc@y{Q2?6qMuP3@9%ABLh^7?h3H#Jk>R_zgxp_(`aj#L1`d%Rm`|7^_ zw;j&_@4wxcDnG-&sO{V!>?R={M@KSQ-R`bj0jB_##U-ePLp>g~6zC1OQMdaFwJ=eg z%S@29fQZ{F;cSO)WwEYL0u7`M^Df)2(p^a-|*VJ~e+$ zt=lywJ7%fy#OD%eCtxi_FsdAbAXXO=kN*|Ajr>|6=cf`hEE%HWgei7MVP>;Km^ywD zWt8h=alEIi$^m+H^%_aAip}!Fc&#^H4w{Ac#HJpCc}v)DqiOyh1W6WE zmVX(VK}y7XhnDE)`aZa2Dk&{`3Xi)y^hV~-{4C>gV~xqEPynU-NvGPe_|Yq3&^qoQ zYRW(pY;gL*DyOYj1(253^( zpXx5Akpxc5p=csO)Bi`Xf5@! zEVR0!d?(|DJ1ahlI?nQ9Ju4!^f;4s&9pG%c(X5o5y$Y=4$X3&lD#a$qZ9UFZdA}Tl z<_(@YnDusj4;EN-HNSOxj3(AK7cO*V?)O2furR6TZNcBE7U=Rseiwr`#;1*GMo2u4 zzppIJHno1;m1LRe61LcS#Nqf!9XXfIROJ+t!OA83d??TPv4OQ)h-ucdj2kkMl}W#c z!$G3dQAyL9r^I*ft#tp$(8RFS4R!|x>!g}bwGZ05RGPG-15$LV5tU~3FNsxC0Z^KB zWxdfaf!Q3@qZYP=SVTUQM?bN=?8QfFyFj=x`|NISo}KPi&}!UbnlE-lVW*Wf30Dko z_|n$ub=$T5+URIpwcHkf|+%OWN_JJwEidA6R!&u$GLX^rd|Wc z$CEEV^nar8QZD-!t!U0!{Z({w3i|#oHB;LZc$;)M36GFr2fm!VaNHMMwf7Stu>2zQ z#zK}~b5m4%zQA$e9-B153$gqn`Hhpa%4Bz6t!;z@O}3_|Cy&9pyF>mO1X7cv*T5`u={h%pdEx#nwx^=&}Q=bQ$fa+o*8`)gsp(cW6^H%L6C$DiQhJ zU0wMhb}jZp$Rkb|bN;&*SMwNsIqN!rfy^-I6!pTD4{9S>yYorB_}~=?=?iiZ-W+im zcni?*BhZ_U#HKUr{gIaFDlbQt$6OBE-}>#hZIDD)l9tJI)EVv}F-bF6c0d)m_5zl# zyVeWUVs8yJC1aJ&;iH1RCS|@&*00AV%d9sK%tda{0hDCcFC9UepH|>|jcdGy>OXXx z9pIJMEBbx@F5ICuXEWuV&%KN8k9w2nw^u*wvgAsZ*e+NB+Z&lJw$?}^G=#kaBKHe7 zBz5dkBG~rlm5aYR+qB31Gw&R|4$z)cQPTxOi>DR6=a0lAd>9Py(%qTO3yDg9Q4irs zOZ{By%mkC!gqsWcD7t9yOGxG|qilJ1)$vStOtLtT`O3NY_w8)0#qt}`f(c`X`Xp`w zTwB%XgT*Y-AG2&ZbUq|-*L{K8#Z4VU6E#lxy6wjBxTnvRjFX=1U6H=d8?fNs=uFCP zLbPU11dp%&(a+4|vz%;;r*@bJeYo>R|Mwk8J_h_myDI{D%@#mV*{e%IfD8=O2|wVR z(yRy<=;YRyGUW6A^Gi@s8oyamJ?v%!83q)(AJHPXq@4|YQ?i=v=9KB$Z!c(0c}d+# z&XnW=GM7OK+~3^zecpzbO>6&xr9&xNp`q~9C%2_~O149FRWtCJl=GZ#54*_+U`N@% zA7b5rfHFYJqX6KmNg0)(tX}QNf)*Ly3RdDVwxt< z+z)=UPkKKWA0KuVP3(7EY7f+)g)eY|i zG>Xj$2@(_at|o|qC^Pts>M+I~R%WO`{&g1Px~un zeY9nh&(wmCJJ1gU&fT-;AA;$X~l558{V zkfXBN1sm**+I|q0*jh?xP8-OVyQZjX6ZI(@gPbD!mexA6Er z6@_8$3vJ$BFkM4!hPgesmbtb9m2)@!f-flsRj8@B-8(+#osF++-m#NVau?u79Rb}Q zhIH1BD(fuRNLJ`Vzu+ptWE~VWp47po;NP5nB}YL?WHY~*WnR|H^{f~ z%(MP_iy6%6IC}#TyWGmUSQ}&`OsbA5~a51O#SGu6(el3WpsGUK*I0} zt26X7{Bb5~UP{Vgkc}aMo?`r`F@dC+IKh@b8v{=`YPGzR5V>5!(L|H(!b|gQmicA$ z6IDa6sx^;s$-@pzjY-f4)yf|}wR7HSs8V;ucl7)3=a+307f#a&87;?ONq0G2_q1mO z;n59-tDF526@UHqUz99=qDq<82yrIfRgWD0u|Hc%3@zhYJ=a0lhg65>fkGq?QK~N5 zReDL`9MRUT)F`KX>yOVtKg*#>gslw0nUA*jo1zqOd_JrO6|9%$Yn%PoBa8ThI4mtK z1N`#2i_w!(z5YTO1(@3~m6 zNc}EWV<>SNw!C&a%Dn657C^FhiCCFb2c6k#0k+^pG=ZdJGa{n}u+AvQc)-%+v(2%i z0z@K^_NXX#A0iHfY~52DIUjKC%J5q%d9QusJQ(qn54=BO=D2&+y>A6LhKSjJqJ2?v zfDK91mAlp|#Qa!_>yX!$w)A3*HIze{74jI;_y>;kK%4 z`^uWY$Gl=5xOCdA0%va+(r278NU-}}J^s%fzld}vS$x0f4JE1N<^B$$5>`BWt-Af! zJ%o4-Y%ou#Uz^mGb8nr;3!PqAsm)^@h#E5qlhC1F3B3mY*q6ZThms4Ktguwch58*) zoLwmsPk1${wdZRpcrFk8v9Qd+-VX8B)NS=+DV%KPwA037X_B6RG-FN+TLL}Fkh?qg zE?(!<>U?&_YRSkR8|%(kzUIDq@PQi!Nw>luINYg*V@)l@0VG}lpFn=bCU>phKyx+2 z$NGDNBK23CNEIiCSLIl?zQm;S=h0F4Zu@CWnb@&?^0DPFPVX-)!A%(&oVZ&Dyu*C4 zeT`J=n?1rVAh+x&5PFTmt`mUO4;BdeF;U!o2jqD>}I2+*CyWCPtB5Cyq_mSPdM z#YYO02Uk=-gH)&c7Y0$%mI~*{zBdRTJ?Bs=xtS%nx@mHnr3lj0hQ z_vx(qr5+*hLuEC03G~?|^9v-c6$E{IDdWxy`tG~L+nJ-NN8~BIv~?Dht*dm~g3`j2 zeSt^fp~ebrBTvRbW7r5wA3^aJ_uOZFl2hv6OXr>mCZ&-=3>tyco% zLi~4>b402hvP$ak_9udVeJF3gvGs$VR_T1-^L*0^>27%ZZ+y-#wyM%lzC$JDmP`$m z@D!sCmZCPaF8gs?Dp2*cJ^4Mp@RG0gvlYc~V|u;wr`PZi*u|CTfc@+hP(3>ri>k;$ zO@|D9-)D7{*2?wpqI?)w?BNR=+<8pPJEJT6w=EPcO8SYNCQ{)8^p&Myi6&8-geQz` zq4gTB><1z6>X&Jw4E1y?0i-g_6JkMFDLly0GaSdVi%Otgl8rxvV^b#+Gd{k0b(q;< z%RcsZmJzZbjsPkc((wuZ`qT74wjd-q>aBDT8&gPz-kT7Bgl-JdTpK&QzO^=RC9v{! zI4)1HwJ%3lHR;7{smA^3*K{Mcz&)24d>i(`akazNQhza3{BWtK_ujALT1-B@bwJK9 zC39&P3yG@cj*KAn9l?)ZJ4j;~l(B1{gV_aDqjgIH(-~9d(av397~lchZT^dH=JxJi@|-?Yq`b^25j!+^;7BWD!0QfgFYNf8kEklD%BW^bPJF*)=0@9A zTmH$L*5KMPDo{AYbHYpe&xxs`24la@AGCmHx#ACjKJsjnsi4k%UkelDx z9|cTxRJy$TqyFck-KPNCR*kN$=xVVlC&HTCTr|dp&Hm*(PT4cx50aAa7F#X@B{?bi zeb^DS_RT;hNUyN+^A)%H2J*W>4Md%Y7r&&%udjXo7kgh76~`C6iMxAn3-0c2!66Xb zHMqME8ay}zhu|J8xVyW1aCe=5|DN_?Uv}U2VbAFUoEfIOZ{4b|s;2M#zIai!U^GE- zSPqs-vtfRv_$QIN!`k*JXx{w{WMQl(9UCa{llkx|boP|a5^z98)qp zG_{!*xK@vnZqXm(pbhLr+l!Xs&_G&flg z$JysxyG9V7QU#1FYD{{xpETAAx`Rq1qrgA-XdK|E}uHSJh_cXoHLiS+IT@vY{{uLlyg2p>H5xQd8A3*CCZ zQoeRJqWB&Wv4d+vU3c*Pu-Uf^*bk32%(tFpvO;Z{;i+dVo{i0O{Jka(9a!qEh^**v zuT+p1FuE)BsDIVi_v_ZZ?hSvSNk8aY8|%F@?D)({)ZlD|X{8>lz+V@dO>mk~Jt%Y@ zB_yB5_iDX{x*kMNv_gxPDJSxmM#~XidJLr?F8#uDkiXt=LhD2GV?HGlHQN3J=a;p3 zNupuwaAWhu8qxrOQBdtg^kL_-#g91Cf5w`?+P2Yh# zdCWdwnCFF)w+Z1NZu7&a6M0Gy;JxFnE5D3B8zKRjR_7;7@pJWv%fE?r+b2*prspx$uf0 zl{(>J)V;a2&M}wv2!RQS0KIi_#gTtZPZ`uS*rZp6#92Q*jX|juDoKQ+676EyUY+`L zFHlcEzPvg|G0!?iw7a;<3=hjqLl+*itLmy&>KO61PB!6Nce=Z5_~duRanEvxJRSIv0J*=Wf2*^e z4(nf%B3L{N>G|BfR#Mij49Yp00bAgIh+qIGFk5|aHiUs2YrM&VA}FC1zARWD+EFM#ACnO`6F z5n#)kk@YM`vf&$XRUeb>T6{+P!`tO(m9yu4qEeP2H91?Ng!+WW5Q%f zCiMe_s5#4IQ3_RE;JjgMf~+tj>xgy1~pr$4i@(P@<{AO%hH%!xQ?!=a`Ho>%A3rn0 zN9A~r>?s{p{5%a}&cDe#!_~z%*=+m}JRn+R)h!AUB#b=8P!a#9<`}Ic#Z1bc*8>-x zzIFZS-sNd|{y=R=Q7HU{;iR?YHX>c(=SRJ}y-=mig~(J9gkg&$Jh6)v8vC~kQi^X) zu?!!N-MdiF?52))0@sh)rM@L;@yjgEv_1`a>=($}lL-=!R8@?iH<5cwZuc5r{k-P3 zrseuBw!<+0iR?f9Pi0wB)#RYaEzN~3)QWO(rSJRzVPZJiG~F}8Ny$hJcA@xWXJPs8 z+=gGEmpSS{vKpxCU_yNxp|Z!KYB&;!i!ugRgZ@fxk40pUm*%*IwX&A&_0y%?b!4+!tP z7YEmO!O-vFn^YM%PLvQ34EX!$rwiz_CYxr48Yn#Y=s5%-I|hY2P0uXHX#vB=TP@}ZX~VLh4x%e__@Aa zOFBZNWNnBuE;w^Gb=s-m;%s|mi|x=Ivt60A)-Z}bB4XvOYcLfV#X{Hc2DiBCXRmEe zr5j4vvD3dvV&10AqN6j;+pf`F$apJL^4+JJt4fX=@#788im1S`(b!dRwZwn1XZ*N0 zbx82MSd+z%cNwUCip|)D6jCb(IU}Oa;2<*Aq}7MXCHbSg)zG2Ly!Z z(X$kCn}MQum=<4J2D*Df?9p;aVBA&mo-RxIo%EmP-i26+&{;*>-*X|lW0Ht;Mx?v;D^GmFG;<&huA1hxVMh_+eE-R<_l z{LAQXhfoY9?!lS^ejKIYE1v~tE-{0%Do9!kWOhuJe$r1Nm#a&EmeVq0Q?h~{6lr^+ zXLb8-on)DQzkoQ?q8%sIq&UDQ4;L0_y(;c|To#nG_dL>#^ zAWwF+{h&`I^ht$S>9YzI9q&HRwm=D-sB+om6 zHkMA;gwPItxhO`dj-xe1kW3E#8ygSrPH+_&kG#xvnylVc7_6rUedZLeC=>C%m}eYP zES!VV_R#MQZ2NK8QCktw`=b%XRhvun23+9VdGyuKo*>=G?>;gbUU0z}ccIjn!8Nw3 z4}4kD%?b85Plz_+DjC=FOD~&26*<*J3eQR~aiZ8^9%Fz#PKtMYh$&F(ag!6}oajhbd z!Pp~Fqa#%S_Ub(T*51ep9V|s^Wk()+`CwFte3O6lYofOkdl~uA^$DZJ5=Q^^_;T-E@VE0zpz{w9*Ql@ z^atnQD8b*on&;#CziwS>Ny334kW7fYgF|qQTW#-WCx@=6{UQl_1)NV!mz(Q6dcS9^ zQcBZM)D>fwW6MjQF{?!Jo9R$uX*@SrcqOR7q?TETu!Qf%6#lGVoFWW}ZD?%_)hS^?zp@lPr3P{9nMf)=RZJbK^O=V*Q)Ki{NJuv_PAUUah~fF2|oU?`?$NIRYo-lH}5ZyN8{SS;K`(mLK1B@+ z=}Jbtg$QlLEsR}%u0uQ|p-#nYOX)1D$~^+9=PS=EEkyYqRmjCm@Fla%*ldVhSF zZ(fN%<5Td|k550Ch$@fvjTjsR>JCxIvh_f5tga@x zRxMv}@ud+s4w!tPXW3Wr-GYe(e%dMy&K*wnz~xVz6Axz~pdS=Q%hLZNp7+J#9d*0{ z9^9IjJ{27`U+tv$in-jYri)+<+V*$5~y)1Hqc0y*-4I{+@Yr1Fg z3@1JIefym?SKD&HCasXj%i!1iPGC^uoBhViEu()t-_-WvqqdBj=R>g*G6aw4jw=@= zasj^m?e3IWzxr^mu~OLP$f-&n`SeF`+i-zrZ*lc@&zPJ!)0_rthe5dMbAR`!rOr>G zF2kRoo3s6K-f8k?T*rK3A-#n zA~sr~E|uWBOXFlK5=_7M=;mq*I)#883t$j3}(S3)Gs%&I1s$3qR^Y9 zyDDdNIxeUy<`zRpQzJ5Pqxh%?8HlqlGsWOkmw{!uR1C7Q9+R`7p|$*@ViAHt3<#$D zl$IJ!a5RzBnJz+ftMv8gU^V2dv-8#2GOrU+uxJZtIA&9!5-#C!;4|8A33ad_`fj@@ z>APB`3qdSTgOe&WuW`FcMtIAyp>QaC==+HJVUrPl_aX*r!NJh)bO%X?MUIh4_p4U=Bk=k?)m$30T# zj(LD4r6m5So3cO$15udvOZfXF35f5i`G~-`EyF&NNRc%lv^D+{sF&g+e&`jD;O4tjmf)pR>f*JVPo+yqgaeyP(f7K2W>6 z!O^HS{f|1cdja1g_me@Y)ew=+7^J7}G`w`7u*A=rf)Y^qKkdkUWKO-7;@}#B3!;^> z9>;Ewnfz2OQNGb&%*NhvUSi6<>#c3s=O}v zF0NJ#6n~lUJiHD*BFS&VtB$8KM#J~VH_5fdR9D^w=h3DGe9@%nwY|}T3<_3^ z$ZpQLv z=$@>wtMyL5`Bvfp*8iutyWFFCeo-DK+$0plg4O9``URm9*#&Z`5N`yEN_4Zp@cF3T zqdkxNxyM7?#*iRq+`mTQ;kOG?F9A(u9C*_4H>vQPIxPZ_k4zeg`7cnXgrKKJy=jj2=2y)DGu-|23=$dI(h#G=$y#FvJbeHmmK33xYI( zBs}tfmX(8br`$P2W&d$&tGuM}t`Q>26uENf0usJhj|MOe6sPcZvV135qTBw2H-=yHOli*nRR{+p6bM|ZZ?zgHNQ!_d5)>(hz0oGrpjFYwb1=@S)WzoNXt-)ja``c!XgNk8bNZvV zo4(*yN)PdAk34;GS?EXND#cD^@XmQRC7TM29&4W?WTlEi^{U;NSr;7SPzUT;9u0ZF z`)P4Ug?H+_!1^+2Azd@>))1k@7UmAMEwgy9gl@kxkEu8^mxCbUZHazL68=$uZY4o5 zjaZFSq~n8YhyLYr9!fw>ELkRqd z2bte-6{($;3)QW=DkA9qluch`>j+IxrL{9W@io(-+DyH}>n_<>uiI7IgT1JdpF0ZE zsFJXfP2rf}zK7rkX466j@2W@+goaZ-cSLl{%AX=TLeAo^Z^cou8ZrAR>hXr8JL zu-Tr~N#3Z$B}mNwGfPb>%KalH&mPY0#68l0JmPblSlr`Am;f4=HQySjB|X2*&HW6Y zvs>^5X);lzh+Ul3CAtfyGXoZhXb^Ksoq@X>NNHnd-`8nus9mtyZRGI%1 z+Y+JmLCV2_3tdvgsH|zIT!X?tjc6+C;L%N(>E`n@CK}|~poBVz(S~H-G73WXfu+Sj zy^vupdu*GDe-*8L(Kdv-K^7MfWk)E07hE2p}_`6fYo50CQZq2ho=_Gt=6=Ic#J z`v}TC++fj3?dABUny;{}HE%{YzS2QWx2Lw+v(uZt$K^!QqzWsziDlqn^|}@5E>@Yd zc|uM>{c6PShe9f4mNN0TbPwHQ29N#zXZl?4_V&xf*K z>QDTpp0emKg5DSLx1wawd~SMhAiZOXMC6y^MrtOq$!f)_W{XtHcvzp`2cN%ehKrxr zu8-qms_)xTaJs+nZLbD4+gxUA}xCH?Nmq-5ONbk9b3L0 z`4-!-OSUR~OBy3~&UEpba?n>3jn?t#C~X_bd>DV3#N28dABOuDLKN40oe=(fN_iuT zVqIn!Q>2W=F*ou?A-fFBwPoVEK$aa(eV;Lv5@G6@VsW&^qI{PU4EN(r)nmaWZj@S- zJjWORm5aGg74?1S-?1I|ttM(JH~-6GaP%dhw(@NBJ54lCq);;3|sn2le)1v{2xD2XSF!&BV|GgxiPEL`%`!zzIEv?Dm45^RhyPnmZ} zTMEB(oK&bdiZy>mkt6)Q8A>PhQWI7KjLG5c%Q(5x<=&eS9mI2RJKCo!!e2iLF0Q!g zd9dVIAMVF>CfFld$m`V9|HasnF*%GazG};LRKbl#U7;m{M#n^PM8E`@=9Wn?kcTup z4S{cO9fs0@xbms?(O5X;$8MX$zQvMhjaePzl9f74uZ)MVQ4N0p%Y!h~}~Y0cNq%%180_!P8^@ z7sPK*vce5oPk|JWE#$^I=qqI;-g!UU1yTgax z1w5(!Y8`cgele>V2w{&_OsrDuP#om6zFx^pkvfZE_;Xt3t3Q1vX-kiF#O()87FRe8 z=Takee{=nT&N!y*ccwF;^Oh0E^KL_w<^s(=!;Wjq_4M+cR(s^rnKA8X~?6e^NA#84Tttxj#KNw{q3k6-8I#@n=GTGRn?OA}34L53yaT zgxP$`v2&XYwX1Q>ix#k_if%3$#=9RN#$0 zI|fd4Q5*$fXu`BWX7piaN;lul9wB<&bqazzzeStkOd<*0h%w|XSbGq-!U!AN1oib9 z0yJ-xQ<=^Zt$YkUu}9WHvR*M{wK^Zb=5j3dc;75;d??^8Loc5b||jC?acR%_1X~jVX_!Vi{HZ&)9Nj`{6^_e*Qy@ zLJLB!ebF!b?4H4`*glu&><)ljTQaGtDD$nIBMJ$D>@je0hYHl^L`(fgCSj~gjAGW8 zEeHQwDCTb+t+M4_M~f<^vLCeN(Q>qZyB>`XUEbLzcUO;aK~$L&fPbogO(opGz}ER2 zzZLjXSAt~Py5BF=tG-$8Rt%MAO~>cE7MWeBry6z-3MTQ6e~7m;I=<_6)ma0DaYX}J zfHzeEvkJim@5BTfSaqp??;FdX)Jx(29eYljCLVVZFh|xG!g=N0R{Z3mU=D zOJn$EpHAY@ge8NC*5#~G1Pv{cye*qUaa2K#REyV9{A(a`vOcR^()##_6v~b}^rSPo zZmRxjj4b0pN~1P%;F)f*hKLU>ChxOaM6fevR%mNnXX{AJITV$`t~$#Nt7K9e{I|t* zt0A?e;mXp30peH^m`LqtkA9nE)(K|rQ1|gLFgL#-Ix08lOlO-YYp0MkP5WpHw1b>O$ zJpbuPRwr>LB(5J9lc~=WZ+><3F7tcanQVJ1e{r zG>;o8aeb7CXvPG_He?-IAgA2VS?;B@qXTM+f)u8S1n!5Ha%`u%m*?W--1b%wncL!X)vt zwwAbun9|<|>o(XC2%Mt0?zE$|lJnIgaCdjh-)D*hfWQ9<{uP`seVhJ8D8V-S9Idwr zHFBkB&#>U@l2@i)^bvghqAOZZm8=wg%MM=m9$h#DV^kWYbYW|QoWo+cxKY-QzDzB$ z?sLb=r_ZzFMA1L{XGJ%`T*i$sm6e{^OQc4=E4=x{#8|Buly@6!6*}i|*VST4mj3C* zO(WpL0aa<68vEf@4}nXyVN#OFE||;NO&8_P8a>bPyKJ9rhKITz+{6gcW}*c)WVzr2 zg5=6%%WU4p#xzj{qZvZg>={}na#vkCM-5cJ#FM@xedf<6N69~5twVpFd4qbM25v|7 z5zQ1>@e#*LbY$n-RuewLW3gs@Xv`>47>4MWwq^p?!Oh<1(z(ubncnc}diU-1#LmVC zCV9Nt{p}mu0T|$(kD^ZX>f&kEehXJ@pY{3VR}?107A?>q1)Ok5JK< zxnuBnQ=&VTGKsbCx)nb9?Te_Jb9qjr{W;S?fqQ}8qfYPbs-qhiE}!u(2#2D=+H&=f zg~Q-%qg6D5Cgqo>_>OwypH7*+{?5~;PE1XUs*no!&+pmhQ)6~eL=E4cf}>YIoIlc( zTxkw@GPJWi@tA2QN%3^fJHt5XimNhY`4cOB&6a}47b}N=eDH5Wu&|)&nAl_U>Lth_ zm@;h=0rK3mk))L#rb7s{)H$(!9bsW~#omNV^7hN==;-m#|FMFd{cb~sDsf9k8x-t> zTjY#GXpjc%bq4A?CcWOz3^c^~aCKrJ5~+5}+rHUW@racSOV?zSjxnZE(56V&2dB;y z@q7wCg5aS5m9?~D~W@e>{yxQR)7x0``Glp^uYtG`sBvfGX$1eb|YvSB_L~R5sPqd_?p|&Fxo@eUyjtn55D8wQ*jA*U`+| zZUCy1DFUi11l|&ks z_}_wX2^W%gzZ`)|qR@U0n_p)9VIVO!=UwqQ2Ew==_(1|uAkdsWky3X>g_=>p>+$>e zPvJ|~^aJ^pkDz(0-;u*8umM}&_0)Z6!wK3m;Rj`LbEs-O64U%wMT$kW0-VTdT&MCx zbHKI@o8pg43VkjEjr{|YwqmJYuKYv{y{=qaMBnunu8f(ah>rH}$A3bW#nb}N?Q7tV zv$de{QtS3X;C5|;( zeBN=jS&nn|G@zD=DD)==7vQ#eSD-E}y)u~+&@LR+Do0Fy2+upVJ}lnNvoRsvmkxpd zw(SO_4k|^Hg8E;PbW+s+L=|)G@-R}wC;N*9xJTI3nz?05&cAHmtFjE}(7k(sm*V2{ zI+lDIMR~E<2DP+h)(blwiJ)VMI+|;uIepNggMS3EAq3XqRb%v+@s+9gN8(>x`7x(V%QgNe@etfFM)YS>(i2U^w63&~D3V?9`3m4+mkzh=V@H3lir zO^hkNYra*7?VAge$jX=$!JH|S))%Q8a+#m((H-Ya2B zT_w7Xekw3&rh21d^EE^58ScLN+~_W)B`E=kU91}AZVS?|4 z?0FtK6>TW?JvLMiES1_Q7XAaHUhHn@(^qX)^RuL39KM)F3auR`iuOA%*V9+rG5HSS zt>pM~8oApn6Du_W-bVQ6TgFh2)+D_&L>^!3LyQ6;__b&Bgi?oE~uRp zta-b!a}w9R`t$jx_Pj2hpj)+?Xef5w<0A=L&aHRGr7b(-V1qkPFNt17+4$m7ILeOH zeTErV*Wj~pF96;dt(aGZcF4= z$du->cSMAQpd~V;PQrKLMX3^G;n7{0<7w48C4RqmxTf*{v+gU#q-%mTXv&r>r(YTu2N!@Vc5hA%{ zRqn|nkJW!Iy1%VZFLoPxMN2pFLmB*DIzAy1rNNS^b^r)Q`75wigom4hWrncCQf;TQ)^Vg!Eq{9xL zpt_k;hr@Rlg=a~P7pOThkvMH%{5w95E=?s%46>s2)~=8` z0J}$g)%v@iG4w--meQBogQ`EP{NE0iq%5BxShI;4Nj>C$n;h$5;&=YvB$z-B| zy-g`%2Ue8y<>%#xWv=>*8aKOlzMGII6_%VAhOo+larYYp@DFz@=KfG*r*8SBI zym~ZSkFnu?u_~>-Z9@0=?gR^GBNr{yI=y#}{u4g@k$^xtY3TJLfj1Wah`+h2;8jsF zCw8Tma5MQOqjO$I!T?XB{P%870(?gNA^2rR!5Mah1!|`wNOf_|lL*}2HzzKuf0wD% zI~5(gyvzT*hc?CWm9!!4KwSSQNk{+JmbdUw>6NU_W9Rts(EUO|uhNAW;ckrEd`MHM z2eedR=NkykXOgjgWn2QS|F3>?Zsl8h-$G^BnjEAz3Vo+c2_D&*~%wQ?v}oFi+mADxh2jMIm2+?Stm+wNP~ zPbP{+UYikyryjw92aHC~qgtIeDK&oo@BfJ#1cu+p{FLEI|N9XFf*j(Dl(>f1ud{4V zuepWCp{?9Ao(MezG;3+5??iZ4~ADUUVGh+=|3#FmU$(d(xG# z7C{a{@aUwZ#H7&MJ(AdiW)MPN*1cXRz>7)*@sL;B`G|Y$5Trs}CPHxCpa`0nAqcOl z>CkHe2z1g+w*UX3|5HQoq5p*>6~Z70hfEs_Yi{Ok@95~+yY6N~QKZ4X^AY}|%j_mV zGH=5T9EvnaeZDSy#0W4@S6)K3D|SAj*~$^+(Q&Lh?%QWt`e#23v z$Y)hQ-(HEC5Wqn~LSEh8LdOp^@X5#=WEOJvu^AJDf9M+;#=X7y0oQ~GQl*npRmBLE zpyOs`T9~Z0bkSxLqIV7{#V55%0~>0 zz^PTAAXcVy!RF}RCtZ;Scm+6olyr1H@e!l>`TO^nYPK~oFf!&Zo%S5K>>M1xqD4rS zeE4*bqV$Q8V+2hdeud7TJ9fI<6sE)Z0e?Hd#R0xVfykYTP^Ak^OT+gPBGqQX1MC=G$s*IbV33~XlSSyO;YgGp=8Zc zVPz$Xx3~B3#DuiGJQ5BPtQ2M9fZQY-3NS7EF8rouW-}F9tbe}G!2!aJ+qciE3@O9o z<5C_TJPuo(vHSbxz{upNv0kbHRp9-D196r#(bAgInI{z@hz!MWkMmUu8XCBnnHdCh z^au@x;!{zPTy&l+CDb6@s&I*Xu`gc`>+9>CP8XTiTb!Y_Y7C_{H5Wi1d`cnR-C{7X zurs+zG}wSww70iU0~&O90L@8aVj^%KY=p7Xr}w~52nf7rSl}p}i3GH9_5fxZITe+X zNr`Ziycz4fxnnk9yS`!u2P_2z1<#r(M~2f*FRa~W`zJv238YE~lQr>ssG*?&yoHVj zrib3Xyo`6)_?vGw6nC`QAy`mYh>3w=JU6n30ytM#SXhhG4iuoR0s^#`C79=d~&p{`>zNznd?Baf3_<0ILAL1K0#u?~n#Xj0SJVL!{4=_A$|Hw-N#{S4vW2 z<=59^L0kc(W2XDViFd6{?QiD&OE!(m&5mTLECxs-xhiQeG)ag$Iy&H*G-&h=NDKrR z>!oUv9G?^V7*b)vo}M1m7ojkT;A}xp)4AVDE$*k^Kq9B&Vgl&E$IvlAvrlT zC_>F8Gx)>5*$*F`2t6C}>i&Kpo!yMhc~{EqZ24N87aj-)?IycVO?E3cd0FaK z<{Y1ZgCIOuxuj486VwC2lZ6U6F$$85)8If&ega9YN2?OAg-=K*kBG(rcz?7f#?eaF79@1pq>fyf!j(&YFuYLlFT1AxM!%5^w+jUk8R6aFEpW^??l% zC;&D+Jw2(GdzWeqaR4vKQ{;hkLCLByWdI1V*G zvErd19iW4(P%eu|IXbeI zD^>@DNy*UnpHceAg@lL$0s@Q);D8ir+^`ZE6C(vsz)S-QqoLv95|oKzKpH71fCAo) zjEn@_3=|)a4unh)SgApW2@gnf|7DR*e_#D}FU-%MKf5U?R(+E!oM~DAmZ2y^^$z5w z={8TtyYn@ChLj&3s{nUn-`d(*ey~ZM_O?qaS7$EYIicxc$bcyYa3`{H#Nq&s0A~f# z-ssrahJzg`7kWQL``xU<)4wc73|!m=mU+plyXgMiy_<7jClM9elLf$OznJ zt^cbBki1boafF6XXPR+jl)?kP@bCm6PyT{U&yG{~;Vnhln8Ar10QmX&`NnnHK+ppC zI0$gm0$u@RBjETi$6Q@Gt!A8?kj`zXlH>w_3M6qBqs|y0fz2_?70$?+p?-8tmx@4y zo74i_RO1<(L-vo<6xpz_ut1_70B-QVav(V^4Y1<$G4t`0p9mQco!8gbNAqRaFZZXi z*s}UN=gnJ#0J0G-a01(-fUBwq1~xlvuzjDUCWN6%8>2`X!5|?)Wo2cB5VNymfgc%DeL1SfJP<~0}#0E0KCi&&b^80 zHvo8>0h)pTnNB8#VCU{WUid+~@DoIxwxVE4k8w9Z?uJyRArI|I5H1ejz_Oi3Rh*LH zHXvaO1?W`58jGripOK=F2;cxU5v=M)zQL!eFWadj=1@QZ-PI*}P7M^io12?l58Ec8 zCIkSyhD;sKc_9|gAmBwy-^xf)VnRVf@9gb?&d$yv9HN&$5w1f30A#jMu1UaSr=49r zH90v5L|UEM5E@XowYIv0_vXvK^0}Yj{F}^<=H2w_Glgjwz*Z3o2FRg#egowU za0-C+npCx7!R-eLfT)1?WRZ+obA^}?NJ&fcH-^(FKmw>0D+A4wb)F0fUh#&gm_2dfSKDpaHyJ=>2gL7x5Uco$4-*#`ce&9PKaNZk4LB)K7Xatm0a8Ag zpK3Y}4oC(jfL!0vN`qB)wNY1qa4M5dNPRsAZ}T`0KpH7#W5dAXuztk$#>d5l15g?E z14AQfHy}ofpqWmfrlX7=U_*I(ehncyb9aL|D9T4Edp!~KkS(aN;?zSw6_C;rMZD72LMztH#e@02Tqk`$a2&O z?-KHvKy*O>2&RwS0B}hdF}L386u#F1vQ+z3FLJtQpa>x97(O~G59A2|#Y-+#i1V3s z|A=X86F@;h{RckN)2jXb{p1`R^*wuLg#8eqVPPh>|0a$$+M36fEX~c00S;AQDzu>g zjC*^WEeF59J_-ue03|U{D%oE>qp$>GUOyhfk3Y z14;!-78W$1Uj8rio<{JP@Wv=IDV zusO#Yz!e-BAMg3R3Yc>*mUmOk*||~?mp{_WRE;t>^w>v`RQVQ z?*=-$WT!QhGzB&R6ABVbAPzKjnjgEA`_wI56;4SLJ9G5%U@Zo_rnRFc#Sg-_!=?N( z3D564XNF#H#tF9;;rP8Wo+$46l@SRRyPpyDFH<)Q6PXv>+OPd zy?fUwD=Pz-KVDg!G29({a$mgM)$LZT@d`Mq`bBoZK*&jtA3xR^-y!LGfK+`rweJcK zZ1O!reHv>xHLZdE{R$vQ%}KVSBsS*>Q#hMB{j7T zc$yGQGsm_*20Ef<_&u%u?m$YKaV!ETs#k9;K*-1W_l{5t-_?bp(5gKbX5 z&oj+@H*ef9LDlZwHtZ-a?)Td>;L!RBS4jk>16yeU3S1}OZ?q}o@R1#|*SbVsgW}HQ z@9!0CUAkos^*l?4m)uH+nUL1@Zi|*t5gS>WscV zhX_Z=Kr{tWCpR~j<}%&+U-O>QSjoabxI{0q9 zshEB*1EmiW(=|c!dPG}=eG%vHntU1Mmh+R=h!>}dJh2YH6IJ%EBS$s^2;%XG*ht=5g+F$$4+of;e9Vs5zs+iG*U-(EKF{X0V znQ8lWhr;WdnGUT0y?z=URlZP*U)Fw|FdHEFHv6#1$A{Z?XI2f@1Pvnt_Tb_#jF8+z zY2L{z)Ulq1rlU3;bKs)_=`*y`^~+RIj)OZxdSwh&ik5KMCmP>cjZZ=8`Qd{e%Eu&} zH^RnrXR`C~@SsrG%yQ=@qSCv)R4Y9XqmL)NUc}YT=5r%;{Fmh}73v?>%cUS%WqwQM zj6^k;s_1KUe2?=wvAB@2w{giRwz1(w@@MiIw$}h`<@){c(x0v5e&vrX;3&>@@{x2* z>xNsW{ilLem6SfUtL{)nX%j+~w((Lkt|AY>o_Jhd&czeHftBB|5~KG}Y9Kb8L4kk$ z`gO0uUL%qe#uKlqn3(Lu2L|CU=nWX{>U0=k^qs3?6|{V_wKOyDVoPJ6QAXDjY$I%q z$mV>}}*K9|He7Ss%21QN~@E>sEZ(KZI z?Dt19t3Dz!a$SnnO6B$IC=GAlzWp6=3o*;2{fTlxw!d)6W(yr*piKacTXiG)>MB1# z_7X%{Q6v{kHR4>dfu8=UtVqYi@v)REVrg&NW+rR)GH>k8HZn+UO^k^N-YmOZIr?q8 zNb4&^?Sr;C`Rc_J)Lv*!48VgkEZ>b z-@3MKiw`#NSh}MwUB9Qp4oUy}(vqr^lOUk;gs}_Ig6!XA^Okst&V!fum@O~9O1uz} zmUdwBG77H7)>akJL?EI;?xXNHmQP33%$J6JVYa$3A?`85WfXuMM{1C!`+G^f9l8BN zg_kIykrBy3m5F#Uvh@~8do3KmeER?d<|NcU{Ois!U7*<*P0PUWjCp*l*&OT}3cd>$ zF4!1yt{K@Xa&^bFFH01?JVKbD_s=Ow(J9%lPaf`5-@0vEyJp##m0;p3^Cr0w_M=OE z5eXYh3`0v?#?40GM1CE5Ek{GoCO@nEcM~05&6~(WOgna*zEhBWKA#4K(M`2IiU=La zw6^zVFN4zd#DL`IjOqF8o?pt&@{Q=|4nsR7DIoA>6)eaUvFTv9=}ZnA`CR9P5I&N;C;9N`)bR!|iQ{9H%}A zwj@ZgBHCkrznHkPZ=D)g@!Ke?JH2N=zTAwhVV^s&)%(53qwF*1&jG;6%~Z*j1;nTI@_E2 z*%%kMk5CRn3<7<+iJ=eNJ!*tNWXvbvP2O3H0N&-6h3;d>z{h+Bi7oHxDUOA8obD?O z(%+Z457Dfoq~yK$n#bE>KrzejB%DfhO%0?V{Ag-x-vCMLB@^ZI5`T;(xeR{*k_jqc zjXy_JlG`1ET~g`g5gxx~PJ+_OLs2Pd^h*HmmT$86W3}Z2@wP-&2M2y5KY+rrfQYllyn3>YxFw_Q zoDhQkxhii1m?jcy5&{Uf9zr4B*w&W1hSw~Q zjgI9odBdbedi{5mZao86CBBFtw1v{R5nB4QSyWem*e5-K13@@7HaFLR^5W}wz;~OEPK` z+z}@a2!n-3x=!by_~`_+ zLAV#+)dfghDnPR+3h}(pFUx0iRhtN){2({UQ~}rQVz~nD`L~G@FQ&fg46bA*rHXs+su22kO72<>XdY z*3JR8Yx4f_@m#oSVcW#S1Z1Qn^+LP=sq&Y{s2N#Vt&TF)ZwJD6v9Xc1Xk>&gbnjLF z4G;-tD?dh|W%W`=gzb}D{Ru?n=IwtL=MjZ0f&}ytR3*2enms}8D!A*8|3daIcxWhX z?))5(Sz`W7K)=51c?%hj>3URu^0SS z)y8(`?mxa92P5JZsNyesnb}&O}?R#kkY^aWS7p(w)&$8nUM_;#U2JNj^P3>%# z46Xfe&l}tvWY6}P+lOcZLZskt`?>*~-GA-}nfL&GX8YT?Y?tgklL+o4_wKGqZOXH=SX>_oisGT}hhw~U78%qla1z$u!mHa$!JO~-jsl0~xS1}Tx9;&bvrXJ;6G%=ry6MH*c z;kEE}PM%&KTT{Q#X7qdc{CL~Z#`!{hKAn372IHpc|qM3Dt~`U`~3Nhkm|3=Q}BaGHfh0gFdG^)kTc{Gku5NQH4PT1 zBqtpy7H!PmM!Sxdjt)BI$zvgJqZn%$u@>N!{B>m9>lyDwuj_E~|JS9nQ==RTEY2Nb zcG%>Phy+%YRS*MF62*@l!MYlJknT zR|>+od-B92o!}a1?5L_)&YsTFx%1=+4>n%x)7{L$JDGz`L^zVp9M~DvJfVKt*fHX{ zq&=w(3n%&SwK}}&(wm=EQ<7~eQ~3GhcyA`YMH#I!{aHRc{WE7MsOn(?xN|wW&8E@X zUVx3%$avISb!L;%StYJJ?=d{Oe}BzQMTKuWW7mI*9zPPzDGs@6d^`v-1SMZG1P`F{ zB7x%n%m=K%JgDKTH_QE&pZ`rqNB7(_sLWjiw8pM*HAZ&!VBE6#1o)tP&u?4?=QKB> ztiLQKB*YAK;Zho!e2n@`RH4U-6Ss|w{((3teoDRkxI=0ECXO%PJRHcDg#U+ z!J-az)ZY~B>8h@-{(L^j;xW^$Bw{asY;r>}sf%8jNB5kL&X_j)A@3^bFBh1t6^)nS zwn3TLdw8#kSx<6uGT+}KOG`@-H8jXdkn#BTtGsy-VHFt_RnybM3jG$$H;eEZA)AX< zR-KRI0snBOz(|$S3tZ)&I|e=(vi7IRu8a@hAG1u=RGddHwA&OSd^Dg!b{eVOsK50o z92g*X2-i{9_d5F?d$_2%zNY52g#}k)cmejThXCzeap+%)YQ~-pa1 zzeKpyeVR5{Nzp^e|KGZHXgKk*z8qk1g;CR^eh5!U2!Z0%eyK=5s~+2$09@>{RqlvS zStu!Y2?#K9gw&fA>CAh(EJ|euBX2@m#`!104Gxw~0Ya*xqGFmwvN`gmCY?q1!BcgN5sr?GyDl}gd!h8G4V~;P)n33RGpOFsK(vMKW@gRL&%->Tc0ujFg6>({Yirxnw0UDUEAVgv zbcSHBC!>A^Rsy}rvbww$yBR4N1s0c#*H+L2$=r!|OUD+szRfubo8y54^1y`lyPIz8 z;l3vwwaf^#1I7Rx>pEDUaE@T)q63n88h%AqRu*%DHo(VVn0ov5)9JC19X5rrl4{rb zVz<^F=^b~aC-xVBOYNQ`ArW`eJ*){5y*$_-)1aw#PtBZ}g(VQzQAtYYpdQ+P`cc7^ z{$4pp^COr0PeG}~5~qDxL}hzMPwy7~ST*>J?9)`gK9=m6%z-3P<}q6jsCM|-Xl;_} z-5OjEO|B1vZmKoBiMd#*=qoVI@w#)UR-B!ktquB(?x~!FtEWYq_!4*;g7p`n8EA1dMIQr**OG2f4Me~CJBp&l z`U%s32*MoO_>cc4G#P}dWvIH(&(>^<@6{3BFC|r`smxPRQIU}C^z}d+f`ut!IH<_5 zQ!yD>Q(_=xNL22w+9N+^3MOVNQZ%?iku%Rx%L15IgNkO_vV|JS1y}|@K=LiA67bsV5MY+9yxjh;VR}94}yM z6uNcz6u)7yKLfXMC5VQCB*O-BW(2qwUO&(2|m6} zP+IbAm97T_katL!aUdxI8W4fC&YpEz{%$%o^m=Hbt&0sGjo`F)?OJ)B@ONvUfv|%| zEIia3O>2nY?bfImLCpS@w>ixbqQa4` z-jOH4#gMSqsKRR-DX)QBiOYzT1+8q2X*pWYA)G%Kl=fK`0CPl+C%ARZaWha|*gI*% zdxl&zCt-N{zy#JfsqEKEyb_t!B?P znH#a&f5oa(cU*xb)xPzwn(0ZQ^w`vS=HwrbI~r`wW?XO>m7&05ce~H@Z%jIKtGHMk zsAynqCnnJDV88Xx zUgXq1rg%%_I)aiovo$Y52Om`2)xZKu;VT{}D_r@&)()ne>{WjPeQ{B8px>WW3Aeu> zoO0o}l$6O3grNs|KjF}ugloTP?Bsqpm2oKY&3fk50XBd^B_$=i$ukp0h}DD_LRNjk z6rf}y1L^}oP6>yo%VFpH1y)Lz?5*l*#kiaDS?$)s6o#PBFVb_RBHgE}#^>j%>5hn> z8$1N$iQDVNIyyUtQPaS;PQcclJvX|)s~Z^G1%q9L2Cs?Cljepua;uEE!z^gAFXJ{Y(NI z0sjLhQVAOFJ6r?*@|@i+5K-%~sHEDMe$)f+`c!Xz!zd*j_ZyqwJN~<@+VU?4OBTCd zUMu-+LaveJaDWMkEr5 z(Cv#_=JJz2L%1Y5o*fH>!U2iG?KT6fc0OcnSO<24vOvx9;S@1^stl@b0^%SrMT}E5?$FBTWhsa*NN*0zK~Y`=6d=3 zUY^sKVCeo*Hv6gue`@k$`9D?=#~h5uXrKRPg%ji&45+9_2q)IZxbg2U%Z7N(rL03C z7b%9@7I*H7E&~3nth`1|>Ia;_UE<=)*AA}lg=Z!iNmXYP1!6IdoZ+i+7@3Iu(L-cb zZevi50$hm#NdC1A4aayRwf<=V^1(dw9SGIz-`_u*ebe9-ufo$#=p>aerng($eV2|_ z5vGiV?y$-&irm7%0ZYd(-1q%gqk3UMC+VU3f$z!UO zqAW0L!zRa8f0z9jU5egrn0}H~LaM*zybguy{Zqq^t3F??)`hh9V)xQip4)%3Wb-Gu z#Hx_K$nO2UKY!d#c@{UaGXqI#42^@o)LHr)aQ!+VXHee+=u9xt-h_*;*n5c|A0Gr% zk)cpX$H@#|8IX+mVEGmIV;Q#a5FAt1#e2TFu&_X5H+nTfMU;}wMio%yj}vAN{>u}> z-8aLyN+Zx0JQ5Ny-L0Jyt_1twoSQF6Rv2Fvwh=%nG%+3(899v0zVp;xI)K*3CDkD? zuRehnUnl2INJt&(O6X^Hzi}(C=WNANzkXd>(k19gz|vzcLT^aG>0d*f&(YCeU#yMG zz|JK#GF+aQE?wfEZj##om*>5Er>&Uo)Ggy;_sQwJ9%~Vh#l)}*QJZvcWUz<){P6m! z9QkbMQFqz|?E6H5Xg&cuh-K_9V`g803%PUh7=6tr+*e!;y(+=o{X~iu>2?4zBT76X zb-drt0JG)q!^>Zj!wg$_3RO^@6Td|8mi;3?Mw=b16ZYa;9eK6PgWnqjc@ke0?gVl& zh|76LpI#7lg;&L3N@1F4-UcgzaUnhs9TFL={cc`=zaiq72{Io4!0C)GGdy`A^C7lC zr}T@}FNgeWg&#NR+&^>5@6VzxadlDByBx4cfk<{zZuX}}K7Y=$Y-T~CeBY$7k2%=7 zF{f-t>N76KtwT6U*nU^-g$9Irm?il> z#Dekx?^{~_3lA&cHmQBb7Wg91bwUeyGEd=dsFbw`wfvW8&g%#(pFsInugs4-!5jQ# zY^wC`eIXKlbfmEgrg`xgFLtkJHoN*gww%U;NO16%mLK@%aj|6O%&5dh4%(#K8Xc#rDGQcg0fZQwd7qMIGooW(Hrat89z4ohk z`*hEBwLR5Rv*iIG3-o*j;np(8$%G)e4}#Y%q;!4JY_LOYBG!zOZj(23FZgade*Cz5 z;?XNVEQm(ymc9;g6-#pI=I&r6E%nIY2OJrfC=jMd8<6yTi!i)OQ8kr^fm-0t{a@o? z>sV-Q_-<9l`LR<`a(AwHi*lR_NU1v-OGQan&0oE1OnY+;G1iG)9<*~YvJcsHEYJk4 zApCNd;oBAa=LsF6$a@;>DmTYoRVO+ey$|JAgwe8PASHJutBtrep>H&fN#Fz+6xmh5 z9%sWH(PV-2zM0URxPZB5xP=#t1tggN+H=5^zL#vhm_G+@;6Fm^>O+{lK4T{m${BDC zzA+lOTVQr2bOylwQ)hQ1#zKp+9iS$BzE`bx;}5XPsjovq{>JqTO+bcs*#y^ss(-(J z)PbXmV))vR8#Yak6-fYnzz9NEL%!lS;zS9A>{urKgs@|Jg*K60=1=LPDt=0)vo@OL zafJ$jktWSQNHd1+hLUIi=rMY&dw<6E)TD3S?QP_xksFmE4Z#@bsUF2& zhrQx3e3is-W4{&4)clNpqst10{{nwC*Q|~< zb**^jT+{wU@s#hj8eokEum1CmYn95=vs=2^1dVXrL3@QY?o)z3%Z>{(1DvqsI`)5+ zG?^8~hnm5g;GP4OQRxl~UnY&kA5@^?@IsKv%dWpT{7qs*ef<+;$YR$C=GCRy|I))t#9JAGYUsg2$AxE!yfJki-dHCSjN0V^n$NKl^OO0k#*fl&_4%0h^*X zA)?t{=ec&Yfa!H31s#KEkH0Wd4HxzpyG)jXbJV9jiT*BFz)+>CVioN66~il7#$aLq zI=B4a-(M_JCMZq{%)-kqX;Z(;GB}zlJp=;d!uVD&L%&Et#(&`@f^U%5Rdiyx%LN(o zdwea}Rr+&A{<-!D9!MTNj!&LE5pe#Zmg+8*`PPxpR&BDsT4q>MbTaB7v=E6f&a@SR zTs442C|HW!Vq)FZ9}oqH=7L_3rjm=T@#j-pFSp)h7yka{P|gRLR5$^NHJrRE{iH^p zo%c_qEDs0mAT3}SJyup$QYWcj)+5xM&3Lr-Ab$s=NGugmOc8R{2P=&%h(b9AcQ<+x zT-t$5y}atZ=F}9{BgVDBSl=AWgrueWvrU~Z)|-iN4E#{7fYlMzxz#Y|3j9riw%vzY zVnv&03gLpJq(|)rr&5D11VKcpxH(ponCNe=1zxma^)%*lOG)U6~1pbX2n zno*i|NkTn<6LFE|6VRM{$vkz}w_Un6X?c2w$;yuwJ3(SYB_YARofEB}OU1&8UDhJq zhXiauT}2Y7U0H%@g?KU8( z_iTmk<%xV0C4K#;KrdHkp3jfhF(}fNnM9FL?6sKQIZeA^LnWHN>{sh=NuD|O>F=3C z!jc{{cR{d~7;diQ(v|*1n#*8_{rW?gc(91CStD`Q`rlw%Tid~#iKVaJ5%~_knTtQ< z)}wOKV#Dmtq(-=dww&#lB4fs?3uW^ z2|f5x`Y(c=gp7^1xA#ZB2oES0sa77qWD%!j6{7f!rexc?*t7CQqN%KVU+gV%7|>4* zAL265co=&!K{7J1rL-D$Z9A1;z15m06+AtQ&yGBDi=l#KX@+JuhMpS$3;)?;nVAj! z0wwC|>NE~*-XZPDcr1{<3cz9xA5Qdsco+&|4|*_DC_8qNxd5vYS5dM{uYOHt6Sa9z zv!Q+ZV=sN{S+oqZ&h<+c+#X zenLkK=+7?OFZ+r07{22fYYEfp8>h zO3r4^0fw0YL3pA$&Pa=`NZHx>h5D5RmE>?<9_lVBIb^>~n3u3*AlM(Hug=|<7lrvE zeS_K!>su0WB2ctAE_e z&ORmb+TPc@;WUNRKfer`E!S(&CMw|+(x}?WlbI0<#lq)Z5we`W(z`x$jgTPDc!E?H zqxBBg!yKM#+rwWDRL<}Amo!0P;}>z*-H(ei7(b))*lVMey@ZncIsn({8Adc^b&SqF z-v`83{3fSO-B|RvHTAa2WP;B%Ko?*%T7`%rYDfePy z^>fC5{rdHBDi<0D|M+&`lqlZi?pg~WiM{4>h;zi;$S=c6`40&&HyT!D(Nuz~hgm1L zw-MiC7?g1>0-uqy|M~fTusqH1dzUnS+>MY*#KBIQ#%>v|klS!pBUfY&xWF!y;5P;} z-PW=Lig)>9w*eYmGipLDru_h@2*P{Z^9?3QbGJR&r*pM%3eHt+tuQ{V>gFv$_%((o z%}_RJ&)icA;i9(P#TK7{8sTcUo%g(S>3NM|Bx;$`2Z8n)IBwqo%(^G^4T`%c*s)C) z6@!2`5IHZ&$^$8PF4+&17T#>|s=B^TuhjKIQ$L_cW)Ovc3~~qw|^`Cu8i-9Q||;AEUSBY z%rS#XO-(I#Vi%x7h4O~fWIG8Lg034I)sQFP&B)StUIAJ(THNW0!41K)sO~z%pcGdj z!L_3&6wKgG%n!hus)U>6J8+^DH@C+`M~eP%4m{)%sE@NA<#gFNegC8ocf=f^Gi&ym zbw^LF=DP?!^aB|C%qeFyKN2N8K{-=62%>0X!A1nAB4^C852993%pI_fiWnECj! zZ7dI_+s1-0Zpp4V{=HDbT{{0Ke?~w=#bB6fy0~>Ok}tTxd2j}2?}B{ z4{y@<2|lBLrT!!7+X2>iW>Ny-<>KVDb=dS*0>vT*N7 zM~HmdRuFX-?Xr`5=~&pstsn@H zq>-?CXe+G`u$4~RsB;OMoL{-YMJfkTO3~lw?lrp?ynGX0q{J(yb`GQ8x$efsEs#&X z{`{4QGpu5JY58mG30jh|tC zyf3Hx2kkbh=fNwoCCN<2I~m^}ibB(H?W9ypV&Vl``4^bL;rca4uqWh;b4j$QEsNi; z>7%K4$3X@NnAhLcAF2aKW3Q4XyYeLhKs{hf*2}Pu^!_p--Ui=_K@A?g)!mEwM-UCU zhcCP;SI8KF)$D~a$1il1IB;Eu?N#7DaoFQo>=*m-(mKT5K@SlZdOGzi;(PvNCB}V- zNqt5}i0^h}6Esueb2D_ohz0r22k>7894}tI`p>J&vtaasqi8mv9o>C*5ycx7IhFS1 ze-6Db*6r|J2tQkIi>^BK4!(Lj>xbq!on%=^-3AY-9E2%9f0o;yPsc`j`Ai~RoA>bf z7i&RQP$ds137Ta|?*554RyesP)Fn9uFo_hmdcRhXWybT%aomFT@-}8N|*?*gB&P&If@E z!o9QJW_~`t5XlU-z`W9RkufpH3qSkYCS=qK*L+~z?Z)zwo#K*I7mKb3(l2P)uBwW81!(E& zSA0C8@Ev(Hpm~&3uPIM@s>=T+mmk z;4An9b96Fn*$Ya=BW*{-s2$-rVhgFKIXGq#0^o1@XLWJYq?+qZm{W$4??@@%S7cAe z5EKAB^z`Y|Pe?^DwG~c=<+6s_%}5Q;uM|E!k4m=j&6{eRnGgcFx%gb1odsORP6nw* z0?e6pXP$SDD1PKUBO$%i@1k=-%>beq58MQk%%8Ct3FwUZ$-QmcO~7qhL<(1%X<1b3 z<-i2))b7NLL5LlevO{B_p$TV~<+0E56l@3ISHI<$qvqx}O4Z3o(t2*=J2b;+;1owi zIvPP0_DDu$IzN2+bPsx?3R-!qHXX+l2KA2t{`Tt+n#Ay9c24wa^f=IN607d<}f<6ED;bY$eJGdQ)>eIJ{4xz30Z2 z`LXi@*PPa3DAKBL&;Iy?Ph!-tv4M8%_-8viXdWy1PtN~!mGOa>)n9mC=5X@tJaF<1 z)hXrOwhJ+^V_nU2TaS>C59G#prGi#6|9T^!Rv0!O(X$gQFo;*c|OPM^}oE|>(z(m0Lg1)P+A#pM2-YglN1r65W znY5Kc59fmu$Bt2I^z`CsF=63wwqeQjhYwjmp!Z%Cz2sK+W#C2adCGr zVqpXUtm5xGreGzsGs}lj-^t3#BA6M`wctgFE~Xh_%k1?KJnQBriXuPlLV&-_rOTI9 zEiF^3Ii~OncnxJ&lQ1Kvvc6s=S;){=)4+fZl*LiX*0&+R)<&QCOD0Qwe--J-I(hy0 z(zFFu5HnCLHq+e(@KwXm2v_c|{rgpa4igtC>{dGuA3m8iZ;j7DYXAboX2i2YQ*S=@ z_1z}j-C(*oj)-%j_Zl+3;N?MS)b{60l}B-w3Z3Vueal6og-Ev{8qc-U9pDD60rem< zctCLndX%CF3m#%qAOnwA!NxKQ`)+b19<23wgTj;g-C{uy{K z3F!=l)LG6DPCdVsQC2|zw1P)TuU>8cKVFgWhYx8!{V@(ipXH5`5(yZrAdzrza9|eC z9YpE_(`)R^%&sHxBxPqaoH}*tMGU4tP{ZfiJEMyxP@G=k_J5%Bz_{2^;gHdNsfFI% z@~7{Hgb+glC^YqyCEIziG`TrXX;9WiGnHdlcYN`Wo2^ph(1j!5_(@(*U!QCWY8ra^ zvuC%!PzXEgo3>u;dc8ceby%u0dvhH;4aS;~4o6V6_xs!3%+1a9&Y!=AriHAmO)%9= zJ8|E+d2^ln?BFJJ{CqSlNdD1@mBEJ2&CjoaI&!X$dLCrPGWfm1(zCgP{Zvp`NuvfB z6y8(wy?uQ=l9C)4FY+xQzcZn`Tj%E0+R}dZ4`&KqzD$1hOeIC5?9Fd9X6luD3ikK+ ze;OX95*8N5o9WFv#LN4j)f1+??H)dV-`(4FjFE|H7w5l@TD%_8|CV)mOZHJJN_h_5 zkpld9YmJ+_`f(AJeI3 zd&04cJieu+@Ohon#FRZEghfX6Ft7_LO}L*9RBShS23VrQDS!Xf;z%9c`9z9auo4gO z3m3)>NR};Aad%N!lgMnqnACHDD)yfze|6k>Vmpz z&=AfvUJ5Vw2YY*a(ofWyC>I9SY#37pBwv?xWvKcy5ULTAq0YrJv7wQE?HYwd5lZ_u z<+nS~&k-LVzq)L9OH5Qu%nSq{>E{3?yy5ie)5T?FHSO(8V`F14SSG@@%T$9P0Chu` zrQ61v97RQT9kTgN`y9Eg*xW5GCjJTlIm(| zXZkFj=0hetG>~I7RN?nWfB3=u#Kc6M(tS)kVa9`0luCe5r%#nskxLG7sCKfA%AS4B z?+Ae{26R$m#Q+%ufcN>n&sqNh8#{Z`8|#pe5X*l9$X?AwPajo;->C zj|LX}+j7X(&aOX2?O8R8=a`AXi{Dt6V?z3#oE?3K#2#Q zrw;4SonhAox2|cb8Fs`Vt%DwyD>t9h)g{v)Xe3PPp&Aj`fq3Km8r=8L?!9|c!rD$q zU|5E&t*xGcK|tF$erj4<8FX}X1dbjJDl8O5IJRK*7^jQJ*G>P0?<&p}+U;Jta>m2c^A4z@8H4RYUXQth_ zQ2|E${@Cv*rcDqN^v}=OT3M|}N5x$(31$WchVKgtH{d_&_WtC17g3V*^x%&^2GtIB zh(pwjd9~?KMEb>4uAVxQyNTrLMTUe;Y zfx;|A3N&m_Pfu&F(zUbAw_RLZV9C3Qnypa3Xo4}O_ z;-1bKjX`bsW;z9Z*`&`D2IP~mA{)^@*!^wrN}vYjEIfNggYJHLOcmgV4Gl_#ZOWmD zY<6ujwCFRkr_5k>cXv0z?=(F!;!u-;4V-74A%zA3(WMNvVZs~uYcL=9&BslTF+DMG zb8~~+CtPNqb+UI(_SXS@ily;uzmTFLG0Yp%ocIOK4I6-%h$`a83-j`>De+9`{OycCd)ye#~NX zs-c6xwcleIH1O)8rR7cRNpyfQ!g*r!3bb-MCcs0Ff&_&Jko2s zV++h=zftkPj8sSD?9cTfe`WX9a8Q4>0|W-;_cc%BFW8T0VXM&Ui%(0vDln=G#yn1C^w5tiq{`cQ2 zE-+8Lk(>aWpg|HNQZ%nipnx5I5JHL_&8EF61qyS z{ic8?S9RfphGTRzFeW485D=vHjO^}kHMG%b8X1M4Rz~y8Rzl+aoMJ~02RTzfE=h%j z+Z2<|98oDKG0dK7tpr9U-_OmB%=1C}#W0{Gj!^)|KZ10@&!Tsr^N8HgV`@x(ML=DL zIVLi%mLQDiy>v*>pfQz}mKGqKA$IwwEDblvrf&O>Q)GOisOY(w1AeFjG!kX`mh>=- z0Gj$XuQ`J|o*=luwIubGlvFh} zZ3OXoP+CUD^z!ALo|_uvrD0wpB4W?D+{ee%6bdpClEU*2ohE!o+Qg);I?Q}vX1-2N zcZ`s->E@+J#2-U?@uPZh@-eC88o<57?CBFHs=*dVK8mWSkco|p+f=Iiq)1OsuX133 zn*e8? z8EZ=n!)7ExI>$ezxs~4zIfaFVyRa+{6a?d{+S;`w+j*BGkQnRI``rb2JOd#N;S1Ob zJ;c?(8%R{d@d5W5am>ldz4qgKi0Wlc+}oM?Zg-j;6w1Bu@N1yu%&}ch9BC{ql`IT< zi^09a!(=!MiN-{q(qU~t>shm}jFc27`j`eJsi9Di@dF&QiZ$9m|3*5-7`0XT;RBnP zm>7EHYCwK|nwSWN=R2=+MyF0~0vAWRQcEu6WM$Q%O|xv;8@XQ)JB60Q2R)h$L_~0fVUAKh6hV4c zkWN({9dlcIPK$_$EU1Uys|us?u?Fu?Xfd=HS>&MhArlBr^z>8DCbD9nkUF{oHzDVC zPWG?Dg5v}iOK(vt5a2|fTm>*W{L(0mxKGeK;n3ApuX3+N zT9jJKrlz}qivr;oPk#RV__R5?&P-7G8yT0OR}7u=oBX~EGCGwQuEnS@@Of~c-Z#i; z=S0a<3u9fO^IIt5;{3)Lq=&3`sY7$Zn(}QnJo#+Z7?Qb_S%Ae zK)8ynZ`c?@*IrR1S-$gr{A&khF zJ=B1Hnl29WGwUG}Kp4*TS#bt`M~09J3Tp0`yOS1%od+M(1)sTfEQj?T>%7IF!HsZR zdHYCrZL6oLBsNGO^T;7gVbR1~YH+czsS~?Yj&a3gr=|fXCno}Xz!1}l`Pk$n(JC1r zvSJ(G>sUg291ILaL;QaJRaBT6b{$Uglv(s~!}-C4<^UK&ZsKudC8f;1+S%I^YZ;ll z(AwH+^a{%-Ou9m_*0ZVkzpmchL`D}uL3E4ZBVJ=nOu{G^3%*C&VfqiVI!-@8Ji}-j z8@~GQ*N(ovzB8CP1^dA#u-t!qZ76J96bd6uKhQ-LF#i~?37ll4L!BJjzzu>*cNr*( z(XEc%rl>*a2$;Q diff --git a/service.subtitles.pipocas/resources/lib/pipocas.py b/service.subtitles.pipocas/resources/lib/pipocas.py index dee384a64..a739ca10e 100644 --- a/service.subtitles.pipocas/resources/lib/pipocas.py +++ b/service.subtitles.pipocas/resources/lib/pipocas.py @@ -5,25 +5,20 @@ import os -from os.path import join as pjoin +from os.path import join as os_path_join import sys -import time -import unicodedata -import urllib import xbmc import xbmcaddon -import xbmcgui import xbmcvfs import fnmatch +import shutil _addon = xbmcaddon.Addon() _scriptname = _addon.getAddonInfo('name') -_language = _addon.getLocalizedString -_dialog = xbmcgui.Dialog() -debug = _addon.getSetting('DEBUG') -is_android = (xbmc.getCondVisibility('system.platform.linux') and xbmc.getCondVisibility('system.platform.android')) +debug = _addon.getSetting('DEBUG') +is_android = (xbmc.getCondVisibility('system.platform.linux') and xbmc.getCondVisibility('system.platform.android')) SUB_EXTS = ['srt', 'sub', 'txt', 'ass', 'ssa', 'smi', 'vtt', 'xml'] HTTP_USER_AGENT = 'User-Agent=Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729)' @@ -41,77 +36,53 @@ def xbmc_extract(SRC, DEST): for ff in ff_ext: ext = os.path.splitext(ff)[1][1:].lower() if ext in SUB_EXTS: - src_file = pjoin(SRC,ff).replace('\\','/') - dst_file = pjoin(xbmc.translatePath(DEST),ff) + src_file = os_path_join(SRC,ff).replace('\\','/') + dst_file = os_path_join(xbmc.translatePath(DEST),ff) success = xbmcvfs.copy(src_file,dst_file) if not success: - log("Error extracting: '%s' to '%s'" % (src_file,dst_file)) + log(f"Error extracting: '{src_file}' to '{dst_file}'") else: - log("Extracting: '%s' to '%s'" % (src_file,dst_file)) + log(f"Extracting: '{src_file}' to '{dst_file}'") else: log("NO FILES YET...") for dd in dd_ext: - dd_mk = pjoin(DEST,dd).replace('\\','/') + dd_mk = os_path_join(DEST,dd).replace('\\','/') success_mk = xbmcvfs.mkdir(dd_mk) if not success_mk: - log("Error creating directory: '%s'" % dd_mk) + log(f"Error creating directory: '{dd_mk}'") else: - log("Created directory: '%s'" % dd_mk) - now_SRC = pjoin(SRC,dd,'').replace('\\','/') - now_DEST = pjoin(DEST,dd) + log(f"Created directory: '{dd_mk}'") + now_SRC = os_path_join(SRC,dd,'').replace('\\','/') + now_DEST = os_path_join(DEST,dd) success_dd = xbmc_extract(now_SRC,now_DEST) if not success_dd: - log("Error extracting inside dir: '%s' to '%s'" % (now_SRC,now_DEST)) + log(f"Error extracting inside dir: '{now_SRC}' to '{now_DEST}'") else: - log("Extracting (back into the ff loop: '%s' to '%s'" % (now_SRC,now_DEST)) + log(f"Extracting (back into the ff loop: '{now_SRC}' to '{now_DEST}'") + def recursive_glob(treeroot, pattern): - results = [] - for base, dirs, files in os.walk(treeroot): - for extension in pattern: - for filename in fnmatch.filter(files, '*.' + extension): results.append(os.path.join(base, filename)) + results = [os_path_join(base, filename) for base, dirs, files in os.walk(treeroot) + for extension in pattern + for filename in fnmatch.filter(files, f'*.{extension.lower()}')] return results - def get_params(): - param = [] paramstring = sys.argv[2] - if len(paramstring) >= 2: - params = paramstring - cleanedparams = params.replace('?', '') - if params.endswith('/'): - params = params[:-2] # XXX: Should be [:-1] ? - pairsofparams = cleanedparams.split('&') - param = {} - for pair in pairsofparams: - splitparams = {} - splitparams = pair.split('=') - if len(splitparams) == 2: - param[splitparams[0]] = splitparams[1] - return param + params = parse_qs(urlparse(paramstring).query) + return params def bubbleSort(subtitles_list): - for n in range(0, len(subtitles_list)): - for i in range(1, len(subtitles_list)): - temp = subtitles_list[i] - if subtitles_list[i]["sync"] > subtitles_list[i-1]["sync"]: - subtitles_list[i] = subtitles_list[i-1] - subtitles_list[i-1] = temp + subtitles_list.sort(key=lambda s: s['sync'], reverse=True) return subtitles_list - def cleanDirectory(directory): try: if xbmcvfs.exists(directory + "/"): - for root, dirs, files in os.walk(directory): - for f in files: - file = os.path.join(root, f) - xbmcvfs.delete(file) - for d in dirs: - dir = os.path.join(root, d) - xbmcvfs.rmdir(dir) + shutil.rmtree(directory) except: pass - if not xbmcvfs.exists(directory): - xbmcvfs.mkdirs(directory) + finally: + if not xbmcvfs.exists(directory): + xbmcvfs.mkdirs(directory) diff --git a/service.subtitles.pipocas/service.py b/service.subtitles.pipocas/service.py index bfcaa110c..f9311c874 100644 --- a/service.subtitles.pipocas/service.py +++ b/service.subtitles.pipocas/service.py @@ -15,8 +15,6 @@ import re import shutil import sys -import string -import time import urllib import xbmc import xbmcaddon @@ -35,33 +33,33 @@ OS_MACHINE = machine() OS_RELEASE = release() OS_VERSION = version() -OS_DETECT = OS_SYSTEM + '-' + OS_ARCH_BIT + '-' + OS_ARCH_LINK -OS_DETECT += ' | host: [%s][%s][%s]' %(OS_MACHINE, OS_RELEASE, OS_VERSION) +OS_DETECT = OS_SYSTEM + "-" + OS_ARCH_BIT + "-" + OS_ARCH_LINK +OS_DETECT += " | host: [%s][%s][%s]" % (OS_MACHINE, OS_RELEASE, OS_VERSION) -main_url = 'https://pipocas.tv/' -debug_pretext = 'Pipocas' +main_url = "https://pipocas.tv/" +debug_pretext = "Pipocas" -_addon = xbmcaddon.Addon() -_author = _addon.getAddonInfo('author') -_scriptid = _addon.getAddonInfo('id') -_scriptname = _addon.getAddonInfo('name') -_version = _addon.getAddonInfo('version') -_language = _addon.getLocalizedString -_dialog = xbmcgui.Dialog() +_addon = xbmcaddon.Addon() +_author = _addon.getAddonInfo("author") +_scriptid = _addon.getAddonInfo("id") +_scriptname = _addon.getAddonInfo("name") +_version = _addon.getAddonInfo("version") +_language = _addon.getLocalizedString +_dialog = xbmcgui.Dialog() -_cwd = xbmcvfs.translatePath(_addon.getAddonInfo('path')) -_profile = xbmcvfs.translatePath(_addon.getAddonInfo('profile')) -_resource = xbmcvfs.translatePath(pjoin(_cwd, 'resources', 'lib')) -_temp = xbmcvfs.translatePath(pjoin(_profile, 'temp')) +_cwd = xbmcvfs.translatePath(_addon.getAddonInfo("path")) +_profile = xbmcvfs.translatePath(_addon.getAddonInfo("profile")) +_resource = xbmcvfs.translatePath(pjoin(_cwd, "resources", "lib")) +_temp = xbmcvfs.translatePath(pjoin(_profile, "temp")) sys.path.append(_resource) from pipocas import * -_search = _addon.getSetting('SEARCH') -debug = _addon.getSetting('DEBUG') +_search = _addon.getSetting("SEARCH") +debug = _addon.getSetting("DEBUG") # Grabbing login and pass from xbmc settings -username = _addon.getSetting('USERNAME') -password = _addon.getSetting('PASSWORD') +username = _addon.getSetting("USERNAME") +password = _addon.getSetting("PASSWORD") if os.path.isdir(_temp): shutil.rmtree(_temp) @@ -70,9 +68,11 @@ xbmcvfs.mkdir(_temp) -#SEARCH_PAGE_URL = main_url + 'modules.php?name=Downloads&file=jz&d_op=search_next&order=&form_cat=28&page=%(page)s&query=%(query)s' -INTERNAL_LINK_URL = 'plugin://%(scriptid)s/?action=download&id=%(id)s&filename=%(filename)s' -HTTP_USER_AGENT = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13' +# SEARCH_PAGE_URL = main_url + 'modules.php?name=Downloads&file=jz&d_op=search_next&order=&form_cat=28&page=%(page)s&query=%(query)s' +INTERNAL_LINK_URL = ( + "plugin://%(scriptid)s/?action=download&id=%(id)s&filename=%(filename)s" +) +HTTP_USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13" # ==================================================================================================================== # Regular expression patterns @@ -80,35 +80,46 @@ """ """ -token_pattern = "" -subtitle_pattern = "" -name_pattern = "

Release: (.+?)<\/span><\/h3>" -id_pattern = "legendas/download/(.+?)\"" -hits_pattern = "
(.+?)
" -#desc_pattern = "
([\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*)
([A-Za-z0-9]+?)" +token_pattern = '' +subtitle_pattern = ( + '' +) +name_pattern = '

Release:\s+?(.+?)<\/span>\s*<\/h3>' +id_pattern = 'legendas/download/(.+?)"' +hits_pattern = '\s+?
\s+?([0-9]+?)
\s+?
' +# desc_pattern = "
([\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*[\n\r\t].*)
([A-Za-z0-9]+?)' +) +rating_pattern = '

\s+?([0-9])/[0-9]\s+?

' release_pattern = "([^\W]\w{1,}\.{1,1}[^\.|^\ ][\w{1,}\.|\-|\(\d\d\d\d\)|\[\d\d\d\d\]]{3,}[\w{3,}\-|\.{1,1}]\w{2,})" release_pattern1 = "([^\W][\w\ ]{4,}[^\Ws][x264|xvid]{1,}-[\w]{1,})" - -def getallsubs(searchstring, languageshort, languagelong, file_original_path, searchstring_notclean): +def getallsubs( + searchstring, languageshort, languagelong, file_original_path, searchstring_notclean +): subtitles_list = [] # LOGIN FIRST AND THEN SEARCH - url = main_url + 'login' + url = main_url + "login" # GET CSRF TOKEN req_headers = { - 'User-Agent': HTTP_USER_AGENT, - 'Referer': url, - 'Keep-Alive': '300', - 'Connection': 'keep-alive' + "User-Agent": HTTP_USER_AGENT, + "Referer": url, + "Keep-Alive": "300", + "Connection": "keep-alive", } sessionPipocasTv = requests.Session() result = sessionPipocasTv.get(url) if result.status_code != 200: - _dialog.notification(_scriptname, _language(32019).encode('utf8'), xbmcgui.NOTIFICATION_ERROR, 1500) + _dialog.notification( + _scriptname, + _language(32019).encode("utf8"), + xbmcgui.NOTIFICATION_ERROR, + 1500, + ) return [] token = re.search(token_pattern, result.text) @@ -120,115 +131,208 @@ def getallsubs(searchstring, languageshort, languagelong, file_original_path, se "_token": token.group(1), } - loginResult = sessionPipocasTv.post( - url, - data=payload, - headers=req_headers - ) + loginResult = sessionPipocasTv.post(url, data=payload, headers=req_headers) if loginResult.status_code != 200: - _dialog.notification(_scriptname, _language(32019).encode('utf8'), xbmcgui.NOTIFICATION_ERROR, 1500) + _dialog.notification( + _scriptname, + _language(32019).encode("utf8"), + xbmcgui.NOTIFICATION_ERROR, + 1500, + ) return [] page = 1 - if languageshort == "pt": - url = main_url + "legendas?t=rel&l=portugues&page=" + str(page) + "&s=" + searchstring - elif languageshort == "pb": - url = main_url + "legendas?t=rel&l=brasileiro&page=" + str(page) + "&s=" + searchstring - elif languageshort == "es": - url = main_url + "legendas?t=rel&l=espanhol&page=" + str(page) + "&s=" + searchstring - elif languageshort == "en": - url = main_url + "legendas?t=rel&l=ingles&page=" + str(page) + "&s=" + searchstring - else: - url = main_url + "home" - + languages = { + "pt": "portugues", + "pb": "brasileiro", + "es": "espanhol", + "en": "ingles", + } + language_name = languages.get(languageshort, "home") + url = f"{main_url}legendas?t=rel&l={language_name}&page={page}&s={searchstring}" + print("URLURLURL: " + url) content = sessionPipocasTv.get(url) - if 'Cria uma conta' in content.text: - _dialog.notification(_scriptname, _language(32019).encode('utf8'), xbmcgui.NOTIFICATION_ERROR, 1500) - return [] + if "Cria uma conta" in content.text: + _dialog.notification( + _scriptname, + _language(32019).encode("utf8"), + xbmcgui.NOTIFICATION_ERROR, + 1500, + ) + return [] - while re.search(subtitle_pattern, content.text, re.IGNORECASE | re.DOTALL) and page < 2: + while ( + re.search(subtitle_pattern, content.text, re.IGNORECASE | re.DOTALL) + and page < 2 + ): log("Getting '%s' inside while ..." % subtitle_pattern) - for matches in re.finditer(subtitle_pattern, content.text, re.IGNORECASE | re.DOTALL): + for matches in re.finditer( + subtitle_pattern, content.text, re.IGNORECASE | re.DOTALL + ): details = matches.group(1) - content_details = sessionPipocasTv.get(main_url + "legendas/info/" + details) - for namematch in re.finditer(name_pattern, content_details.text, re.IGNORECASE | re.DOTALL): + + content_details = sessionPipocasTv.get( + main_url + "legendas/info/" + details + ) + filename = "" + desc = "" + for namematch in re.finditer( + name_pattern, content_details.text, re.IGNORECASE | re.DOTALL + ): filename = str.strip(namematch.group(1)) desc = filename log("FILENAME match: '%s' ..." % namematch.group(1)) - for idmatch in re.finditer(id_pattern, content_details.text, re.IGNORECASE | re.DOTALL): + if filename == "": + _dialog.notification( + _scriptname, + "Bug on name_pattern regex, contact author", + xbmcgui.NOTIFICATION_ERROR, + 300, + ) + id = "" + for idmatch in re.finditer( + id_pattern, content_details.text, re.IGNORECASE | re.DOTALL + ): id = idmatch.group(1) log("ID match: '%s' ..." % idmatch.group(1)) + if id == "": + _dialog.notification( + _scriptname, + "Bug on id_pattern regex, contact author", + xbmcgui.NOTIFICATION_ERROR, + 300, + ) uploader = "" - for upmatch in re.finditer(uploader_pattern, content_details.text, re.IGNORECASE | re.DOTALL): + for upmatch in re.finditer( + uploader_pattern, content_details.text, re.IGNORECASE | re.DOTALL + ): uploader = upmatch.group(1) if uploader == "": uploader = "Bot-Pipocas" - for hitsmatch in re.finditer(hits_pattern, content_details.text, re.IGNORECASE | re.DOTALL): + hits = "0" + for hitsmatch in re.finditer( + hits_pattern, content_details.text, re.IGNORECASE | re.DOTALL + ): hits = hitsmatch.group(1) - downloads = int(hits) / 100 - if (downloads > 5): - downloads = 5 - filename = re.sub('\n', ' ', filename) - desc = re.sub('\n', ' ', desc) + if hits == "0": + _dialog.notification( + _scriptname, + "Bug on hits_pattern regex, contact author", + xbmcgui.NOTIFICATION_ERROR, + 300, + ) + rating = "" + for ratingmatch in re.finditer( + rating_pattern, content_details.text, re.IGNORECASE | re.DOTALL + ): + rating = ratingmatch.group(1) + if rating == "": + _dialog.notification( + _scriptname, + "Bug on rating_pattern regex, contact author", + xbmcgui.NOTIFICATION_ERROR, + 300, + ) + rating = "0" + + if rating == "0": + rate_downloads = 0 + else: + rate_downloads = int(hits) / 100 + + if rate_downloads > 5: + rate_downloads = 5 + + downloads = round((int(rating) + int(rate_downloads)) / 2) + filename = re.sub("\n", " ", filename) + desc = re.sub("\n", " ", desc) # Remove HTML tags on the commentaries - filename = re.sub(r'<[^<]+?>', '', filename) - desc = re.sub(r'<[^<]+?>|[~]', '', desc) + filename = re.sub(r"<[^<]+?>", "", filename) + desc = re.sub(r"<[^<]+?>|[~]", "", desc) # Find filename on the comentaries to show sync label using filename or dirname (making it global for further usage) global filesearch filesearch = os.path.abspath(file_original_path) filesearch = os.path.split(filesearch) dirsearch = filesearch[0].split(os.sep) - dirsearch_check = str.split(dirsearch[-1], '.') + dirsearch_check = str.split(dirsearch[-1], ".") # PARENT FOLDER TWEAK DEFINED IN THE ADD-ON SETTINGS (AUTO | ALWAYS ON (DEACTIVATED) | OFF) - _parentfolder = _addon.getSetting('PARENT') - if _parentfolder == '0': + _parentfolder = _addon.getSetting("PARENT") + if _parentfolder == "0": if re.search(release_pattern, dirsearch[-1], re.IGNORECASE): - _parentfolder = '1' + _parentfolder = "1" else: - _parentfolder = '2' - if _parentfolder == '1': + _parentfolder = "2" + if _parentfolder == "1": if re.search(dirsearch[-1], desc, re.IGNORECASE): sync = True else: sync = False - if _parentfolder == '2': - if (searchstring_notclean != ""): + if _parentfolder == "2": + if searchstring_notclean != "": sync = False if str.lower(searchstring_notclean) in str.lower(desc): sync = True else: - if (str.lower(dirsearch_check[-1]) == "rar") or (str.lower(dirsearch_check[-1]) == "cd1") or (str.lower(dirsearch_check[-1]) == "cd2"): + if ( + (str.lower(dirsearch_check[-1]) == "rar") + or (str.lower(dirsearch_check[-1]) == "cd1") + or (str.lower(dirsearch_check[-1]) == "cd2") + ): sync = False - if len(dirsearch) > 1 and dirsearch[1] != '': - if re.search(filesearch[1][:len(filesearch[1])-4], desc, re.IGNORECASE) or re.search(dirsearch[-2], desc, re.IGNORECASE): + if len(dirsearch) > 1 and dirsearch[1] != "": + if re.search( + filesearch[1][: len(filesearch[1]) - 4], + desc, + re.IGNORECASE, + ) or re.search(dirsearch[-2], desc, re.IGNORECASE): sync = True else: - if re.search(filesearch[1][:len(filesearch[1])-4], desc, re.IGNORECASE): + if re.search( + filesearch[1][: len(filesearch[1]) - 4], + desc, + re.IGNORECASE, + ): sync = True else: sync = False - if len(dirsearch) > 1 and dirsearch[1] != '': - if re.search(filesearch[1][:len(filesearch[1])-4], desc) or re.search(dirsearch[-1], desc, re.IGNORECASE): + if len(dirsearch) > 1 and dirsearch[1] != "": + if re.search( + filesearch[1][: len(filesearch[1]) - 4], desc + ) or re.search(dirsearch[-1], desc, re.IGNORECASE): sync = True else: - if re.search(filesearch[1][:len(filesearch[1])-4], desc, re.IGNORECASE): + if re.search( + filesearch[1][: len(filesearch[1]) - 4], + desc, + re.IGNORECASE, + ): sync = True filename = filename + " " + "hits: " + hits + " uploader: " + uploader - subtitles_list.append({'rating': str(downloads), 'filename': filename, 'hits': hits, 'desc': desc, - 'sync': sync, 'id': id, 'language_short': languageshort, 'language_name': languagelong}) + subtitles_list.append( + { + "rating": str(downloads), + "filename": filename, + "hits": hits, + "desc": desc, + "sync": sync, + "id": id, + "language_short": languageshort, + "language_name": languagelong, + } + ) page = page + 1 - if languageshort == "pt": - url = main_url + "legendas?t=rel&l=portugues&page=" + str(page) + "&s=" + searchstring - elif languageshort == "pb": - url = main_url + "legendas?t=rel&l=brasileiro&page=" + str(page) + "&s=" + searchstring - elif languageshort == "es": - url = main_url + "legendas?t=rel&l=espanhol&page=" + str(page) + "&s=" + searchstring - elif languageshort == "en": - url = main_url + "legendas?t=rel&l=ingles&page=" + str(page) + "&s=" + searchstring - else: - url = main_url + "home" + + language_codes = { + "pt": "portugues", + "pb": "brasileiro", + "es": "espanhol", + "en": "ingles", + } + language = language_codes.get(languageshort, "home") + url = f"{main_url}legendas?t=rel&l={language}&page={page}&s={searchstring}" + content = sessionPipocasTv.get(url) # Bubble sort, to put syncs on top @@ -237,27 +341,32 @@ def getallsubs(searchstring, languageshort, languagelong, file_original_path, se def append_subtitle(item): - listitem = xbmcgui.ListItem( - label=item['language_name'], - label2=item['filename'], - offscreen=True - ) - listitem.setArt( { "icon": str(int(round(float(item["rating"])))), "thumb" : item["language_short"] } ) - listitem.setProperty("sync", 'true' if item["sync"] else 'false') - listitem.setProperty("hearing_imp", 'true' if item.get("hearing_imp", False) else 'false') + label=item["language_name"], label2=item["filename"], offscreen=True + ) + listitem.setArt( + { + "icon": str(int(round(float(item["rating"])))), + "thumb": item["language_short"], + } + ) + listitem.setProperty("sync", "true" if item["sync"] else "false") + listitem.setProperty( + "hearing_imp", "true" if item.get("hearing_imp", False) else "false" + ) ## below arguments are optional, it can be used to pass any info needed in download function - ## anything after "action=download&" will be sent to addon once user clicks listed subtitle to downlaod + ## anything after "action=download&" will be sent to addon once user clicks listed subtitle to download args = dict(item) - args['scriptid'] = _scriptid + args["scriptid"] = _scriptid url = INTERNAL_LINK_URL % args ## add it to list, this can be done as many times as needed for all subtitles found - xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=listitem, isFolder=False) - -class Main: + xbmcplugin.addDirectoryItem( + handle=int(sys.argv[1]), url=url, listitem=listitem, isFolder=False + ) +class Main: def Search(item): log("Host data '%s'" % OS_DETECT) """Called when searching for subtitles from KODI.""" @@ -265,69 +374,89 @@ def Search(item): # use item["some_property"] that was set earlier # once done, set xbmcgui.ListItem() below and pass it to xbmcplugin.addDirectoryItem() # CHECKING FOR ANYTHING IN THE USERNAME AND PASSWORD, IF NULL IT STOPS THE SCRIPT WITH A WARNING - username = _addon.getSetting('USERNAME') - password = _addon.getSetting('PASSWORD') + username = _addon.getSetting("USERNAME") + password = _addon.getSetting("PASSWORD") if not username or not password: xbmcplugin.endOfDirectory(int(sys.argv[1])) - if username == '' and password != '': - _dialog.notification(_scriptname, _language(32016).encode('utf8'), xbmcgui.NOTIFICATION_ERROR, 300) - if username != '' and password == '': - _dialog.notification(_scriptname, _language(32017).encode('utf8'), xbmcgui.NOTIFICATION_ERROR, 300) - if username == '' and password == '': - _dialog.notification(_scriptname, _language(32018).encode('utf8'), xbmcgui.NOTIFICATION_ERROR, 300) + if username == "" and password != "": + _dialog.notification( + _scriptname, + _language(32016).encode("utf8"), + xbmcgui.NOTIFICATION_ERROR, + 300, + ) + elif username != "" and password == "": + _dialog.notification( + _scriptname, + _language(32017).encode("utf8"), + xbmcgui.NOTIFICATION_ERROR, + 300, + ) + elif username == "" and password == "": + _dialog.notification( + _scriptname, + _language(32018).encode("utf8"), + xbmcgui.NOTIFICATION_ERROR, + 300, + ) # PARENT FOLDER TWEAK DEFINED IN THE ADD-ON SETTINGS (AUTO | ALWAYS ON (DEACTIVATED) | OFF) - file_original_path = item['file_original_path'] - _parentfolder = _addon.getSetting('PARENT') - if _parentfolder == '0': + file_original_path = item["file_original_path"] + _parentfolder = _addon.getSetting("PARENT") + if _parentfolder == "0": filename = os.path.abspath(file_original_path) dirsearch = filename.split(os.sep) - log(u"dirsearch_search string = %s" % dirsearch) + log("dirsearch_search string = %s" % dirsearch) if re.search(release_pattern, dirsearch[-2], re.IGNORECASE): - _parentfolder = '1' + _parentfolder = "1" else: - _parentfolder = '2' - if _parentfolder == '1': + _parentfolder = "2" + if _parentfolder == "1": filename = os.path.abspath(file_original_path) dirsearch = filename.split(os.sep) filename = dirsearch[-2] - log(u"_parentfolder1 = %s" % filename) - if _parentfolder == '2': + log("_parentfolder1 = %s" % filename) + if _parentfolder == "2": filename = os.path.splitext(os.path.basename(file_original_path))[0] - log(u"_parentfolder2 = %s" % filename) + log("_parentfolder2 = %s" % filename) filename = xbmc.getCleanMovieTitle(filename)[0] - searchstring_notclean = os.path.splitext( - os.path.basename(file_original_path))[0] + searchstring_notclean = os.path.splitext(os.path.basename(file_original_path))[ + 0 + ] searchstring = "" - log(u"_searchstring_notclean = %s" % searchstring_notclean) - log(u"_searchstring = %s" % searchstring) + log("_searchstring_notclean = %s" % searchstring_notclean) + log("_searchstring = %s" % searchstring) global israr israr = os.path.abspath(file_original_path) israr = os.path.split(israr) israr = israr[0].split(os.sep) - israr = str.split(israr[-1], '.') + israr = str.split(israr[-1], ".") israr = str.lower(israr[-1]) - title = xbmc.getCleanMovieTitle(item['title'])[0] - tvshow = item['tvshow'] - season = item['season'] - episode = item['episode'] - log(u"Tvshow string = %s" % tvshow) - log(u"Title string = %s" % title) + title = xbmc.getCleanMovieTitle(item["title"])[0] + tvshow = item["tvshow"] + season = item["season"] + episode = item["episode"] + log("Tvshow string = %s" % tvshow) + log("Title string = %s" % title) subtitles_list = [] - if item['mansearch']: - searchstring = item['mansearchstr'] - log(u"Manual Searchstring string = %s" % searchstring) + if item["mansearch"]: + searchstring = item["mansearchstr"] + log("Manual Searchstring string = %s" % searchstring) else: - if tvshow != '': + if tvshow != "": searchstring = "%s S%#02dE%#02d" % (tvshow, int(season), int(episode)) - elif title != '' and tvshow != '': + elif title != "" and tvshow != "": searchstring = title else: - if 'rar' in israr and searchstring is not None: - log(u"RAR Searchstring string = %s" % searchstring) - if 'cd1' in str.lower(title) or 'cd2' in str.lower(title) or 'cd3' in str.lower(title): + if "rar" in israr and searchstring is not None: + log("RAR Searchstring string = %s" % searchstring) + if ( + "cd1" in str.lower(title) + or "cd2" in str.lower(title) + or "cd3" in str.lower(title) + ): dirsearch = os.path.abspath(file_original_path) dirsearch = os.path.split(dirsearch) dirsearch = dirsearch[0].split(os.sep) @@ -335,13 +464,17 @@ def Search(item): searchstring_notclean = dirsearch[-3] searchstring = xbmc.getCleanMovieTitle(dirsearch[-3]) searchstring = searchstring[0] - log(u"RAR MULTI1 CD Searchstring string = %s" % searchstring) + log("RAR MULTI1 CD Searchstring string = %s" % searchstring) else: searchstring = title else: searchstring = title - log(u"RAR NO CD Searchstring string = %s" % searchstring) - elif 'cd1' in str.lower(title) or 'cd2' in str.lower(title) or 'cd3' in str.lower(title): + log("RAR NO CD Searchstring string = %s" % searchstring) + elif ( + "cd1" in str.lower(title) + or "cd2" in str.lower(title) + or "cd3" in str.lower(title) + ): dirsearch = os.path.abspath(file_original_path) dirsearch = os.path.split(dirsearch) dirsearch = dirsearch[0].split(os.sep) @@ -349,77 +482,93 @@ def Search(item): searchstring_notclean = dirsearch[-2] searchstring = xbmc.getCleanMovieTitle(dirsearch[-2]) searchstring = searchstring[0] - log(u"MULTI1 CD Searchstring string = %s" % searchstring) + log("MULTI1 CD Searchstring string = %s" % searchstring) else: - #We are at the root of the drive!!! so there's no dir to lookup only file# + # We are at the root of the drive!!! so there's no dir to lookup only file# title = os.path.split(file_original_path) searchstring = title[-1] else: - if title == '': + if title == "": title = os.path.split(file_original_path) searchstring = title[-1] - log(u"TITLE NULL Searchstring string = %s" % searchstring) + log("TITLE NULL Searchstring string = %s" % searchstring) else: - if _search == '0': - if re.search("(.+?s[0-9][0-9]e[0-9][0-9])", filename, re.IGNORECASE): - searchstring = re.search("(.+?s[0-9][0-9]e[0-9][0-9])", filename, re.IGNORECASE) + if _search == "0": + if re.search( + "(.+?s[0-9][0-9]e[0-9][0-9])", filename, re.IGNORECASE + ): + searchstring = re.search( + "(.+?s[0-9][0-9]e[0-9][0-9])", + filename, + re.IGNORECASE, + ) searchstring = searchstring.group(0) - log(u"FilenameTV Searchstring = %s" % searchstring) + log("FilenameTV Searchstring = %s" % searchstring) else: searchstring = filename - log(u"Filename Searchstring = %s" % searchstring) + log("Filename Searchstring = %s" % searchstring) else: - if re.search("(.+?s[0-9][0-9]e[0-9][0-9])", title, re.IGNORECASE): - searchstring = re.search("(.+?s[0-9][0-9]e[0-9][0-9])", title, re.IGNORECASE) + if re.search( + "(.+?s[0-9][0-9]e[0-9][0-9])", title, re.IGNORECASE + ): + searchstring = re.search( + "(.+?s[0-9][0-9]e[0-9][0-9])", title, re.IGNORECASE + ) searchstring = searchstring.group(0) - log(u"TitleTV Searchstring = %s" % searchstring) + log("TitleTV Searchstring = %s" % searchstring) else: searchstring = title - log(u"Title Searchstring = %s" % searchstring) - - PT_ON = _addon.getSetting('PT') - PTBR_ON = _addon.getSetting('PTBR') - ES_ON = _addon.getSetting('ES') - EN_ON = _addon.getSetting('EN') - - if PT_ON == 'true': - subtitles_list = getallsubs(searchstring, "pt", "Portuguese", file_original_path, searchstring_notclean) - for sub in subtitles_list: - append_subtitle(sub) - if PTBR_ON == 'true': - subtitles_list = getallsubs(searchstring, "pb", "Brazilian", file_original_path, searchstring_notclean) - for sub in subtitles_list: - append_subtitle(sub) - if ES_ON == 'true': - subtitles_list = getallsubs(searchstring, "es", "Spanish", file_original_path, searchstring_notclean) - for sub in subtitles_list: - append_subtitle(sub) - if EN_ON == 'true': - subtitles_list = getallsubs(searchstring, "en", "English", file_original_path, searchstring_notclean) - for sub in subtitles_list: - append_subtitle(sub) - if PT_ON == 'false' and PTBR_ON == 'false' and ES_ON == 'false' and EN_ON == 'false': - _dialog.notification(_scriptname, 'Apenas Português | Português Brasil | English | Spanish', xbmcgui.NOTIFICATION_ERROR, 1500) + log("Title Searchstring = %s" % searchstring) + LANGUAGES = { + "pt": "Portuguese", + "pb": "Brazilian", + "es": "Spanish", + "en": "English", + } + for lang, lang_name in LANGUAGES.items(): + if _addon.getSetting(lang.upper()) == "true": + subtitles_list = getallsubs( + searchstring, + lang, + lang_name, + file_original_path, + searchstring_notclean, + ) + for sub in subtitles_list: + append_subtitle(sub) + + if not any( + _addon.getSetting(lang.upper()) == "true" for lang in LANGUAGES.keys() + ): + _dialog.notification( + _scriptname, + "Apenas Português | Português Brasil | English | Spanish", + xbmcgui.NOTIFICATION_ERROR, + 1500, + ) def Download(id, filename): - - if os.path.isdir(_temp):shutil.rmtree(_temp) + if os.path.isdir(_temp): + shutil.rmtree(_temp) xbmcvfs.mkdirs(_temp) - if not os.path.isdir(_temp):xbmcvfs.mkdir(_temp) - unpacked = 'ldivx-' + str(uuid.uuid4()).replace("-","")[0:6] - xbmcvfs.mkdirs(pjoin(_temp,unpacked,'')) - _newtemp = os.path.join(_temp, xbmc.translatePath(unpacked).replace('\\','/')) + if not os.path.isdir(_temp): + xbmcvfs.mkdir(_temp) + unpacked = "ldivx-" + str(uuid.uuid4()).replace("-", "")[0:6] + xbmcvfs.mkdirs(pjoin(_temp, unpacked, "")) + _newtemp = os.path.join( + _temp, xbmcvfs.translatePath(unpacked).replace("\\", "/") + ) - url = main_url + 'login' - download = main_url + 'legendas/download/' + id + url = main_url + "login" + download = main_url + "legendas/download/" + id # GET CSRF TOKEN req_headers = { - 'User-Agent': HTTP_USER_AGENT, - 'Referer': url, - 'Keep-Alive': '300', - 'Connection': 'keep-alive' + "User-Agent": HTTP_USER_AGENT, + "Referer": url, + "Keep-Alive": "300", + "Connection": "keep-alive", } sessionPipocasTv = requests.Session() result = sessionPipocasTv.get(url) @@ -434,11 +583,7 @@ def Download(id, filename): "_token": token.group(1), } - loginResult = sessionPipocasTv.post( - url, - data=payload, - headers=req_headers - ) + loginResult = sessionPipocasTv.post(url, data=payload, headers=req_headers) if not loginResult.ok: return [] @@ -448,9 +593,14 @@ def Download(id, filename): # If user is not registered or User\Pass is misspelled it will generate an error message and break the script execution! thecontent = content.content - if 'Cria uma conta' in content.text: + if "Cria uma conta" in content.text: xbmcplugin.endOfDirectory(int(sys.argv[1])) - _dialog.notification(_scriptname, _language(32019).encode('utf8'), xbmcgui.NOTIFICATION_ERROR, 1500) + _dialog.notification( + _scriptname, + _language(32019).encode("utf8"), + xbmcgui.NOTIFICATION_ERROR, + 1500, + ) return [] if thecontent is not None: @@ -459,51 +609,63 @@ def Download(id, filename): cleanDirectory(_temp) # Check archive type (rar/zip/else) through the file header (rar=Rar!, zip=PK) - log(u"Checking archive type") - - if thecontent[:4].decode() == 'Rar!': - extension = ".rar" - archive_type = 'rar://' - packed = True - log(u"Discovered RAR Archive") - elif thecontent[:2].decode() == 'PK': - extension = ".zip" - archive_type = 'zip://' - packed = True - log(u"Discovered ZIP Archive") + log("Checking archive type") + + # Define dictionary of archive types and their file headers + archive_types = {"rar": b"Rar!", "zip": b"PK"} + + # Check archive type through the file header + file_header = thecontent[:4] + for ext, header in archive_types.items(): + if file_header.startswith(header): + extension = f".{ext}" + archive_type = f"{ext}://" + packed = True + log(f"Discovered {ext.upper()} Archive") + break else: extension = ".srt" - archive_type = '' + archive_type = "" packed = False - log(u"Discovered a non-archive file") + log("Discovered a non-archive file") local_tmp_file = os.path.join(_temp, random + extension) try: - log(u"Saving subtitles to '%s'" % local_tmp_file) + log("Saving subtitles to '%s'" % local_tmp_file) - with open(local_tmp_file,'wb') as local_file_handle: + with open(local_tmp_file, "wb") as local_file_handle: local_file_handle.write(thecontent) local_file_handle.close() xbmc.sleep(500) - log(u"Saving to %s" % local_tmp_file) + log("Saving to %s" % local_tmp_file) except: - log(u"Failed to save subtitle to %s" % local_tmp_file) + log("Failed to save subtitle to %s" % local_tmp_file) if packed: try: - compressed_file = 'rar://' + quote_plus(local_tmp_file) + '/' + compressed_file = "rar://" + quote_plus(local_tmp_file) + "/" log("Will try to extract...") - xbmc_extract(compressed_file,_newtemp) + xbmc_extract(compressed_file, _newtemp) except: - xbmc.executebuiltin("XBMC.Extract(%s, %s)" % (compressed_file, _newtemp), True) + xbmc.executebuiltin( + "XBMC.Extract(%s, %s)" % (compressed_file, _newtemp), True + ) ## IF EXTRACTION FAILS, WHICH HAPPENS SOMETIMES ... BUG?? ... WE WILL BROWSE THE RAR FILE FOR MANUAL EXTRACTION ## searchsubs = recursive_glob(_newtemp, SUB_EXTS) searchsubscount = len(searchsubs) if searchsubscount == 0: dialog = xbmcgui.Dialog() - subs_file = dialog.browse(1, _language(32024).encode('utf8'), 'files', '', False, True, _temp + '/') + subs_file = dialog.browse( + 1, + _language(32024).encode("utf8"), + "files", + "", + False, + True, + _temp + "/", + ) subtitles_list.append(subs_file) ## ELSE WE WILL GO WITH THE NORMAL PROCEDURE ## else: @@ -522,76 +684,90 @@ def Download(id, filename): subtitles_list.append(subs_file) break else: - # If there are more than one subtitle in the temp dir, launch a browse dialog - # so user can choose. + # If there are more than one subtitle in the temp dir, launch a browse dialog + # so user can choose. dialog = xbmcgui.Dialog() - subs_file = dialog.browse(1, _language(32024).encode('utf8'), 'files', '', False, True, _newtemp + '/') + subs_file = dialog.browse( + 1, + _language(32024).encode("utf8"), + "files", + "", + False, + True, + _newtemp + "/", + ) subtitles_list.append(subs_file) break - else: subtitles_list.append(subs_file) + else: + subtitles_list.append(subs_file) return subtitles_list - def get_params(): param = [] paramstring = sys.argv[2] if len(paramstring) >= 2: params = paramstring - cleanedparams = params.replace('?', '') - if params.endswith('/'): params = params[:-2] # XXX: Should be [:-1] ? - pairsofparams = cleanedparams.split('&') + cleanedparams = params.replace("?", "") + if params.endswith("/"): + params = params[:-2] # XXX: Should be [:-1] ? + pairsofparams = cleanedparams.split("&") param = {} for pair in pairsofparams: splitparams = {} - splitparams = pair.split('=') - if len(splitparams) == 2: param[splitparams[0]] = splitparams[1] + splitparams = pair.split("=") + if len(splitparams) == 2: + param[splitparams[0]] = splitparams[1] return param # Get parameters from KODI and launch actions params = get_params() - if params['action'] == 'search' or params['action'] == 'manualsearch': + if params["action"] == "search" or params["action"] == "manualsearch": item = {} - item['temp'] = False - item['rar'] = False - item['year'] = xbmc.getInfoLabel("VideoPlayer.Year") # Year - item['season'] = str(xbmc.getInfoLabel("VideoPlayer.Season")) # Season - item['episode'] = str(xbmc.getInfoLabel("VideoPlayer.Episode")) # Episode - item['tvshow'] = str(xbmc.getInfoLabel("VideoPlayer.TVshowtitle")) # Show - item['title'] = str(xbmc.getInfoLabel("VideoPlayer.OriginalTitle")) # Try to get original title - item['file_original_path'] = urllib.parse.unquote(xbmc.Player().getPlayingFile()) # Full path of a playing file - item['mansearch'] = False - item['languages'] = [] - - if 'searchstring' in params: - item['mansearch'] = True - item['mansearchstr'] = urllib.parse.unquote(params['searchstring']).decode('utf-8') - - for lang in urllib.parse.unquote(params['languages']).split(','): - item['languages'].append(xbmc.convertLanguage(lang, xbmc.ISO_639_2)) - - if not item['title']: - item['title'] = str(xbmc.getInfoLabel("VideoPlayer.Title")) - - if "s" in item['episode'].lower(): + item["temp"] = False + item["rar"] = False + item["year"] = xbmc.getInfoLabel("VideoPlayer.Year") # Year + item["season"] = str(xbmc.getInfoLabel("VideoPlayer.Season")) # Season + item["episode"] = str(xbmc.getInfoLabel("VideoPlayer.Episode")) # Episode + item["tvshow"] = str(xbmc.getInfoLabel("VideoPlayer.TVshowtitle")) # Show + item["title"] = str( + xbmc.getInfoLabel("VideoPlayer.OriginalTitle") + ) # Try to get original title + item["file_original_path"] = urllib.parse.unquote( + xbmc.Player().getPlayingFile() + ) # Full path of a playing file + item["mansearch"] = False + item["languages"] = [] + + if "searchstring" in params: + item["mansearch"] = True + item["mansearchstr"] = urllib.parse.unquote(params["searchstring"]) + + for lang in urllib.parse.unquote(params["languages"]).split(","): + item["languages"].append(xbmc.convertLanguage(lang, xbmc.ISO_639_2)) + + if not item["title"]: + item["title"] = str(xbmc.getInfoLabel("VideoPlayer.Title")) + + if "s" in item["episode"].lower(): # Check if season is "Special" - item['season'] = "0" - item['episode'] = item['episode'][-1:] + item["season"] = "0" + item["episode"] = item["episode"][-1:] - if "http" in item['file_original_path']: - item['temp'] = True + if "http" in item["file_original_path"]: + item["temp"] = True - elif "rar://" in item['file_original_path']: - item['rar'] = True - item['file_original_path'] = os.path.dirname(item['file_original_path'][6:]) + elif "rar://" in item["file_original_path"]: + item["rar"] = True + item["file_original_path"] = os.path.dirname(item["file_original_path"][6:]) - elif "stack://" in item['file_original_path']: - stackPath = item['file_original_path'].split(" , ") - item['file_original_path'] = stackPath[0][8:] + elif "stack://" in item["file_original_path"]: + stackPath = item["file_original_path"].split(" , ") + item["file_original_path"] = stackPath[0][8:] Search(item) - elif params['action'] == 'download': + elif params["action"] == "download": # we pickup all our arguments sent from def Search() subs = Download(params["id"], params["filename"]) @@ -599,7 +775,9 @@ def get_params(): # are still working out how to handle that in KODI core for sub in subs: listitem = xbmcgui.ListItem(label=sub) - xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=sub, listitem=listitem, isFolder=False) + xbmcplugin.addDirectoryItem( + handle=int(sys.argv[1]), url=sub, listitem=listitem, isFolder=False + ) # Send end of directory to KODI xbmcplugin.endOfDirectory(int(sys.argv[1])) From 28b75132e937b7bd31a011d64b74d348a38f4f5a Mon Sep 17 00:00:00 2001 From: Emil Svensson Date: Sun, 7 May 2023 18:20:20 +0200 Subject: [PATCH 040/145] [script.module.inputstreamhelper] 0.6.0+matrix.1 (#2450) --- script.module.inputstreamhelper/README.md | 5 ++ script.module.inputstreamhelper/addon.xml | 7 +- .../lib/inputstreamhelper/__init__.py | 65 +++++++++++-------- .../lib/inputstreamhelper/api.py | 10 ++- .../lib/inputstreamhelper/config.py | 34 +++++++--- .../lib/inputstreamhelper/kodiutils.py | 35 +++++----- .../lib/inputstreamhelper/utils.py | 24 +++++-- .../lib/inputstreamhelper/widevine/arm.py | 12 +++- .../inputstreamhelper/widevine/widevine.py | 61 +++++++++++++---- .../resource.language.en_gb/strings.po | 12 ++-- .../resources/settings.xml | 2 +- 11 files changed, 186 insertions(+), 81 deletions(-) diff --git a/script.module.inputstreamhelper/README.md b/script.module.inputstreamhelper/README.md index dd0399758..50e9fcadc 100644 --- a/script.module.inputstreamhelper/README.md +++ b/script.module.inputstreamhelper/README.md @@ -91,6 +91,11 @@ Please report any issues or bug reports on the [GitHub Issues](https://github.co This module is licensed under the **The MIT License**. Please see the [LICENSE.txt](LICENSE.txt) file for details. ## Releases +### v0.6.0 (2023-05-03) +- Initial support for AARCH64 Linux (@horstle) +- Initial support for AARCH64 Macs (@mediaminister) +- New option to install a specific version on most platforms (@horstle) + ### v0.5.10 (2022-04-18) - Fix automatic submission of release (@mediaminister) - Update German translation (@tweimer) diff --git a/script.module.inputstreamhelper/addon.xml b/script.module.inputstreamhelper/addon.xml index ddd5b64e2..1e7cb745a 100644 --- a/script.module.inputstreamhelper/addon.xml +++ b/script.module.inputstreamhelper/addon.xml @@ -1,5 +1,5 @@ - + @@ -25,6 +25,11 @@ Jednostavan Kodi modul koji olakšava razvijanje dodataka koji se temelje na InputStream dodatku i reprodukciji DRM zaštićenog sadržaja. Простой модуль для Kodi, который облегчает жизнь разработчикам дополнений, с использованием InputStream дополнений и воспроизведения DRM контента. +v0.6.0 (2023-05-03) +- Initial support for AARCH64 Linux (@horstle) +- Initial support for AARCH64 Macs (@mediaminister) +- New option to install a specific version on most platforms (@horstle) + v0.5.10 (2022-04-18) - Fix automatic submission of release - Update German translation diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/__init__.py b/script.module.inputstreamhelper/lib/inputstreamhelper/__init__.py index 51c893323..e1260fdb2 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/__init__.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/__init__.py @@ -9,10 +9,10 @@ from .kodiutils import (addon_version, browsesingle, delete, exists, get_proxies, get_setting, get_setting_bool, get_setting_float, get_setting_int, jsonrpc, kodi_to_ascii, kodi_version, listdir, localize, log, notification, ok_dialog, progress_dialog, select_dialog, set_setting, set_setting_bool, textviewer, translate_path, yesno_dialog) -from .utils import arch, http_download, parse_version, remove_tree, store, system_os, temp_path, unzip +from .utils import arch, download_path, http_download, parse_version, remove_tree, store, system_os, temp_path, unzip, userspace64 from .widevine.arm import dl_extract_widevine, extract_widevine, install_widevine_arm -from .widevine.widevine import (backup_path, has_widevinecdm, ia_cdm_path, install_cdm_from_backup, latest_available_widevine_from_repo, - latest_widevine_version, load_widevine_config, missing_widevine_libs, widevine_config_path, widevine_eula, widevinecdm_path) +from .widevine.widevine import (backup_path, cdm_from_repo, choose_widevine_from_repo, has_widevinecdm, ia_cdm_path, install_cdm_from_backup, latest_widevine_available_from_repo, + latest_widevine_version, load_widevine_config, missing_widevine_libs, widevines_available_from_repo, widevine_config_path, widevine_eula, widevinecdm_path) from .unicodes import compat_path # NOTE: Work around issue caused by platform still using os.popen() @@ -110,7 +110,7 @@ def _get_lib_version(path): def _has_inputstream(self): """Checks if selected InputStream add-on is installed.""" - data = jsonrpc(method='Addons.GetAddonDetails', params=dict(addonid=self.inputstream_addon)) + data = jsonrpc(method='Addons.GetAddonDetails', params={'addonid': self.inputstream_addon}) if 'error' in data: log(3, '{addon} is not installed.', addon=self.inputstream_addon) return False @@ -120,7 +120,7 @@ def _has_inputstream(self): def _inputstream_enabled(self): """Returns whether selected InputStream add-on is enabled..""" - data = jsonrpc(method='Addons.GetAddonDetails', params=dict(addonid=self.inputstream_addon, properties=['enabled'])) + data = jsonrpc(method='Addons.GetAddonDetails', params={'addonid': self.inputstream_addon, 'properties': ['enabled']}) if data.get('result', {}).get('addon', {}).get('enabled'): log(0, '{addon} {version} is enabled.', addon=self.inputstream_addon, version=self._inputstream_version()) return True @@ -130,24 +130,29 @@ def _inputstream_enabled(self): def _enable_inputstream(self): """Enables selected InputStream add-on.""" - data = jsonrpc(method='Addons.SetAddonEnabled', params=dict(addonid=self.inputstream_addon, enabled=True)) + data = jsonrpc(method='Addons.SetAddonEnabled', params={'addonid': self.inputstream_addon, 'enabled': True}) if 'error' in data: return False return True - @staticmethod - def _supports_widevine(): + def _supports_widevine(self): """Checks if Widevine is supported on the architecture/operating system/Kodi version.""" if arch() not in config.WIDEVINE_SUPPORTED_ARCHS: log(4, 'Unsupported Widevine architecture found: {arch}', arch=arch()) ok_dialog(localize(30004), localize(30007, arch=arch())) # Widevine not available on this architecture return False - if arch() == 'arm64' and system_os() != 'Android': - import struct - if struct.calcsize('P') * 8 == 64: - log(4, 'Unsupported 64-bit userspace found. User needs 32-bit userspace on {arch}', arch=arch()) - ok_dialog(localize(30004), localize(30039)) # Widevine not available on ARM64 + if arch() == 'arm64' and system_os() not in ['Android', 'Darwin'] and userspace64(): + is_version = parse_version(addon_version(self.inputstream_addon)) + try: + compat_version = parse_version(config.MINIMUM_INPUTSTREAM_VERSION_ARM64[self.inputstream_addon]) + except KeyError: + log(4, 'Minimum version of {addon} for 64bit support unknown. Continuing into the unknown...'.format(addon=self.inputstream_addon)) + compat_version = parse_version("0.0.0") + + if is_version < compat_version: + log(4, 'Unsupported 64bit userspace found. Needs 32bit or newer ISA (currently {v}) on {arch}', arch=arch(), v=is_version) + ok_dialog(localize(30004), localize(30068, addon=self.inputstream_addon, version=compat_version)) # Need newer ISA or 32bit userspace return False if system_os() not in config.WIDEVINE_SUPPORTED_OS: @@ -168,12 +173,15 @@ def _supports_widevine(): return True @staticmethod - def _install_widevine_x86(bpath): - """Install Widevine CDM on x86 based architectures.""" - cdm = latest_available_widevine_from_repo() + def _install_widevine_from_repo(bpath, choose_version=False): + """Install Widevine CDM from Google's library CDM repository""" + if choose_version: + cdm = choose_widevine_from_repo() + else: + cdm = latest_widevine_available_from_repo() cdm_version = cdm.get('version') - if not store('download_path'): + if not exists(download_path(cdm.get('url'))): downloaded = http_download(cdm.get('url')) else: downloaded = True @@ -206,7 +214,7 @@ def install_and_finish(self, progress, version): return False @cleanup_decorator - def install_widevine(self): + def install_widevine(self, choose_version=False): """Wrapper function that calls Widevine installer method depending on architecture""" if not self._supports_widevine(): return False @@ -214,9 +222,11 @@ def install_widevine(self): if not widevine_eula(): return False - if 'x86' in arch(): - result = self._install_widevine_x86(backup_path()) + if cdm_from_repo(): + result = self._install_widevine_from_repo(backup_path(), choose_version=choose_version) else: + if choose_version: + log(1, "Choosing a version to install is only implemented if the lib is found in googles repo.") result = install_widevine_arm(backup_path()) if not result: return result @@ -232,7 +242,7 @@ def install_widevine(self): @cleanup_decorator def install_widevine_from(self): """Install Widevine from a given URL or file.""" - if yesno_dialog(None, localize(30066)): # download resource with widevine from url? no means specify local + if yesno_dialog(None, localize(30066)): # download resource with widevine from url? no means specify local result = dl_extract_widevine(get_setting("image_url"), backup_path()) if not result: return result @@ -255,7 +265,6 @@ def install_widevine_from(self): return False - @staticmethod def remove_widevine(): """Removes Widevine CDM""" @@ -303,10 +312,10 @@ def _update_widevine(self): if not wv_config: log(3, 'Widevine config missing. Could not determine current version, forcing update.') current_version = '0' - elif 'x86' in arch(): + elif cdm_from_repo(): component = 'Widevine CDM' current_version = wv_config['version'] - latest_version = latest_available_widevine_from_repo().get('version') + latest_version = latest_widevine_available_from_repo().get('version') else: component = 'Chrome OS' current_version = wv_config['version'] @@ -339,9 +348,9 @@ def _check_widevine(self): ok_dialog(localize(30001), localize(30031)) # An update of Widevine is required return self.install_widevine() - if 'x86' in arch(): # check that widevine arch matches system arch + if cdm_from_repo(): # check that widevine arch matches system arch wv_config = load_widevine_config() - if config.WIDEVINE_ARCH_MAP_X86[arch()] != wv_config['arch']: + if config.WIDEVINE_ARCH_MAP_REPO[arch()] != wv_config['arch']: log(4, 'Widevine/system arch mismatch. Reinstall is required.') ok_dialog(localize(30001), localize(30031)) # An update of Widevine is required return self.install_widevine() @@ -450,7 +459,7 @@ def info_dialog(self): else: wv_updated = 'Never' text += localize(30821, version=self._get_lib_version(widevinecdm_path()), date=wv_updated) + '\n' - if arch() in ('arm', 'arm64'): # Chrome OS version + if arch() == 'arm' or arch() == 'arm64' and system_os() != 'Darwin': # Chrome OS version wv_cfg = load_widevine_config() if wv_cfg: text += localize(30822, name=wv_cfg['hwidmatch'].split()[0].lstrip('^'), version=wv_cfg['version']) + '\n' @@ -481,7 +490,7 @@ def rollback_libwv(self): installed_version = load_widevine_config()['version'] del versions[versions.index(installed_version)] - if 'x86' in arch(): + if cdm_from_repo(): show_versions = versions else: show_versions = [] diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/api.py b/script.module.inputstreamhelper/lib/inputstreamhelper/api.py index 6f20ed475..941f975e1 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/api.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/api.py @@ -11,7 +11,10 @@ def run(params): """Route to API method""" if 2 <= len(params) <= 4: if params[1] == 'widevine_install': - widevine_install() + if len(params) == 3: + widevine_install(choose_version=params[2]) + else: + widevine_install() elif params[1] == 'widevine_remove': widevine_remove() elif params[1] in ('rollback', 'widevine_rollback'): @@ -39,9 +42,10 @@ def check_inputstream(protocol, drm=None): Helper(protocol, drm=drm).check_inputstream() -def widevine_install(): +def widevine_install(choose_version=False): """The API interface to install Widevine CDM""" - Helper('mpd', drm='widevine').install_widevine() + choose_version = choose_version in ("True", "true") + Helper('mpd', drm='widevine').install_widevine(choose_version=choose_version) def widevine_install_from(): diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/config.py b/script.module.inputstreamhelper/lib/inputstreamhelper/config.py index e15ca4d12..fae104c86 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/config.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/config.py @@ -42,9 +42,10 @@ 'arm64' ] -WIDEVINE_ARCH_MAP_X86 = { +WIDEVINE_ARCH_MAP_REPO = { 'x86_64': 'x64', - 'x86': 'ia32' + 'x86': 'ia32', + 'arm64': 'arm64' } WIDEVINE_OS_MAP = { @@ -79,16 +80,17 @@ CHROMEOS_RECOVERY_URL = 'https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.json' -# To keep the Chrome OS ARM hardware ID list up to date, the following resources can be used: +# To keep the Chrome OS ARM(64) hardware ID list up to date, the following resources can be used: # https://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices # https://chromiumdash.appspot.com/serving-builds?deviceCategory=Chrome%20OS -# Last updated: 2022-02-24 +# Last updated: 2023-03-24 CHROMEOS_RECOVERY_ARM_HWIDS = [ 'BOB', 'BURNET', 'COACHZ', 'COZMO', 'DAMU', + 'DOJO-EJPG', 'DRUWL', 'DUMO', 'ELM', @@ -107,18 +109,34 @@ 'KEVIN', 'KODAMA', 'KRANE-ZDKS', - 'LAZOR', - 'LIMOZEEN', 'MAKOMO-UTTX', - 'PAZQUEL-HGNV', 'PICO-EXEM', - 'POMPOM-MZVS', + 'QUACKINGSTICK', 'SCARLET', 'SPHERION', + 'TOMATO-LYVN', 'WILLOW-TFIY', 'WORMDINGLER-JQAO', ] +CHROMEOS_RECOVERY_ARM64_HWIDS = [ + 'KINGOFTOWN-KDDA', + 'LAZOR', + 'LIMOZEEN', + 'MAGNETON-LCKC', + 'PAZQUEL-HGNV', + 'PAZQUEL-OPNA', + 'POMPOM-MZVS', + 'RUSTY-ZNCE', + 'STEELIX-VZSZ', + 'TENTACOOL-ZLJE', + 'TENTACRUEL-VAFH', +] + +MINIMUM_INPUTSTREAM_VERSION_ARM64 = { + 'inputstream.adaptive': '20.3.5', +} + CHROMEOS_BLOCK_SIZE = 512 HLS_MINIMUM_IA_VERSION = '2.0.10' diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/kodiutils.py b/script.module.inputstreamhelper/lib/inputstreamhelper/kodiutils.py index 492a90071..4408e51ac 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/kodiutils.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/kodiutils.py @@ -80,9 +80,9 @@ def translate_path(path): return to_unicode(translatePath(from_unicode(path))) -def get_addon_info(key): +def get_addon_info(key, addon=ADDON): """Return addon information""" - return to_unicode(ADDON.getAddonInfo(key)) + return to_unicode(addon.getAddonInfo(key)) def addon_id(): @@ -95,9 +95,14 @@ def addon_profile(): return translate_path(get_addon_info('profile')) -def addon_version(): +def addon_version(addon_name=None): """Cache and return add-on version""" - return get_addon_info('version') + if not addon_name: + addon = ADDON + else: + addon = xbmcaddon.Addon(addon_name) + + return get_addon_info('version', addon) def browsesingle(type, heading, shares='', mask='', useThumbs=False, treatAsFolder=False, defaultt=None): # pylint: disable=invalid-name,redefined-builtin @@ -132,7 +137,7 @@ def select_dialog(heading='', opt_list=None, autoclose=0, preselect=-1, useDetai from xbmcgui import Dialog if not heading: heading = ADDON.getAddonInfo('name') - return Dialog().select(heading, opt_list, autoclose=autoclose, preselect=preselect, useDetails=useDetails) + return Dialog().select(heading, [str(opt) for opt in opt_list], autoclose=autoclose, preselect=preselect, useDetails=useDetails) def textviewer(heading='', text='', usemono=False): @@ -231,13 +236,13 @@ def set_setting_bool(key, value): def get_global_setting(key): """Get a Kodi setting""" - result = jsonrpc(method='Settings.GetSettingValue', params=dict(setting=key)) + result = jsonrpc(method='Settings.GetSettingValue', params={'setting': key}) return result.get('result', {}).get('value') def get_current_window_id(): """Get current window id""" - result = jsonrpc(method='GUI.GetProperties', params=dict(properties=['currentwindow'])) + result = jsonrpc(method='GUI.GetProperties', params={'properties': ['currentwindow']}) if result.get('error'): return None return result.get('result', {}).get('currentwindow').get('id') @@ -276,13 +281,13 @@ def get_proxies(): proxy_types = ['http', 'socks4', 'socks4a', 'socks5', 'socks5h'] - proxy = dict( - scheme=proxy_types[httpproxytype] if 0 <= httpproxytype < 5 else 'http', - server=get_global_setting('network.httpproxyserver'), - port=get_global_setting('network.httpproxyport'), - username=get_global_setting('network.httpproxyusername'), - password=get_global_setting('network.httpproxypassword'), - ) + proxy = { + 'scheme': proxy_types[httpproxytype] if 0 <= httpproxytype < 5 else 'http', + 'server': get_global_setting('network.httpproxyserver'), + 'port': get_global_setting('network.httpproxyport'), + 'username': get_global_setting('network.httpproxyusername'), + 'password': get_global_setting('network.httpproxypassword'), + } if proxy.get('username') and proxy.get('password') and proxy.get('server') and proxy.get('port'): proxy_address = '{scheme}://{username}:{password}@{server}:{port}'.format(**proxy) @@ -295,7 +300,7 @@ def get_proxies(): else: return None - return dict(http=proxy_address, https=proxy_address) + return {'http': proxy_address, 'https': proxy_address} def log(level=0, message='', **kwargs): diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py b/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py index a1a162672..0ab01a174 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py @@ -7,6 +7,8 @@ from time import time from socket import timeout from ssl import SSLError +import struct + try: # Python 3 from urllib.error import HTTPError, URLError @@ -39,6 +41,13 @@ def update_temp_path(new_temp_path): move(old_temp_path, temp_path()) +def download_path(url): + """Choose download target directory based on url.""" + filename = url.split('/')[-1] + + return os.path.join(temp_path(), filename) + + def _http_request(url, headers=None, time_out=10): """Perform an HTTP request and return request""" log(0, 'Request URL: {url}', url=url) @@ -100,11 +109,11 @@ def http_download(url, message=None, checksum=None, hash_alg='sha1', dl_size=Non if req is None: return None - filename = url.split('/')[-1] + dl_path = download_path(url) + filename = os.path.basename(dl_path) if not message: # display "downloading [filename]" message = localize(30015, filename=filename) # Downloading file - download_path = os.path.join(temp_path(), filename) total_length = int(req.info().get('content-length')) if dl_size and dl_size != total_length: log(2, 'The given file size does not match the request!') @@ -118,7 +127,7 @@ def http_download(url, message=None, checksum=None, hash_alg='sha1', dl_size=Non starttime = time() chunk_size = 32 * 1024 - with open(compat_path(download_path), 'wb') as image: + with open(compat_path(dl_path), 'wb') as image: size = 0 while size < total_length: try: @@ -161,7 +170,7 @@ def http_download(url, message=None, checksum=None, hash_alg='sha1', dl_size=Non log(4, 'Download failed, checksums do not match!') return False - if dl_size and stat_file(download_path).st_size() != dl_size: + if dl_size and stat_file(dl_path).st_size() != dl_size: progress.close() req.close() free_space = sizeof_fmt(diskspace()) @@ -170,7 +179,7 @@ def http_download(url, message=None, checksum=None, hash_alg='sha1', dl_size=Non progress.close() req.close() - store('download_path', download_path) + store('download_path', dl_path) return True @@ -311,6 +320,11 @@ def arch(): return sys_arch +def userspace64(): + """To check if userspace is 64bit or 32bit""" + return struct.calcsize('P') * 8 == 64 + + def hardlink(src, dest): """Hardlink a file when possible, copy when needed""" if exists(dest): diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py index e923c5ad7..714e10905 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py @@ -8,7 +8,7 @@ from .. import config from ..kodiutils import browsesingle, localize, log, ok_dialog, open_file, progress_dialog, yesno_dialog -from ..utils import diskspace, http_download, http_get, parse_version, sizeof_fmt, store, system_os, update_temp_path +from ..utils import diskspace, http_download, http_get, parse_version, sizeof_fmt, store, system_os, update_temp_path, userspace64 from .arm_chromeos import ChromeOSImage @@ -16,11 +16,17 @@ def select_best_chromeos_image(devices): """Finds the newest and smallest of the ChromeOS images given""" log(0, 'Find best ARM image to use from the Chrome OS recovery.json') + if userspace64(): + arm_hwids = config.CHROMEOS_RECOVERY_ARM64_HWIDS + else: + arm_hwids = config.CHROMEOS_RECOVERY_ARM_HWIDS + + arm_hwids = [h for arm_hwid in arm_hwids for h in ['^{} '.format(arm_hwid), '^{}-.*'.format(arm_hwid), '^{}.*'.format(arm_hwid)]] best = None for device in devices: # Select ARM hardware only - for arm_hwid in config.CHROMEOS_RECOVERY_ARM_HWIDS: - if '^{0} '.format(arm_hwid) in device['hwidmatch']: + for arm_hwid in arm_hwids: + if arm_hwid in device['hwidmatch']: hwid = arm_hwid break # We found an ARM device, rejoice ! else: diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/widevine.py b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/widevine.py index 61d6a6481..09f3b379e 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/widevine.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/widevine.py @@ -7,7 +7,7 @@ from time import time from .. import config -from ..kodiutils import addon_profile, exists, get_setting_int, listdir, localize, log, mkdirs, ok_dialog, open_file, set_setting, translate_path, yesno_dialog +from ..kodiutils import addon_profile, exists, get_setting_int, listdir, localize, log, mkdirs, ok_dialog, open_file, select_dialog, set_setting, translate_path, yesno_dialog from ..utils import arch, cmd_exists, hardlink, http_download, http_get, http_head, parse_version, remove_tree, run_cmd, store, system_os from ..unicodes import compat_path, to_unicode @@ -28,11 +28,11 @@ def install_cdm_from_backup(version): def widevine_eula(): """Displays the Widevine EULA and prompts user to accept it.""" - if 'x86' in arch(): - cdm_version = latest_available_widevine_from_repo().get('version') + if cdm_from_repo(): + cdm_version = latest_widevine_available_from_repo().get('version') cdm_os = config.WIDEVINE_OS_MAP[system_os()] - cdm_arch = config.WIDEVINE_ARCH_MAP_X86[arch()] - else: # grab the license from the x86 files + cdm_arch = config.WIDEVINE_ARCH_MAP_REPO[arch()] + else: # Grab the license from the x86 files log(0, 'Acquiring Widevine EULA from x86 files.') cdm_version = latest_widevine_version(eula=True) cdm_os = 'mac' @@ -51,6 +51,13 @@ def widevine_eula(): return yesno_dialog(localize(30026), eula, nolabel=localize(30028), yeslabel=localize(30027)) # Widevine CDM EULA +def cdm_from_repo(): + """Whether the Widevine CDM is available from Google's library CDM repository""" + # Based on https://source.chromium.org/chromium/chromium/src/+/master:third_party/widevine/cdm/widevine.gni + if 'x86' in arch() or arch() == 'arm64' and system_os() == 'Darwin': + return True + return False + def backup_path(): """Return the path to the cdm backups""" path = os.path.join(addon_profile(), 'backup', '') @@ -64,7 +71,7 @@ def widevine_config_path(): iacdm = ia_cdm_path() if iacdm is None: return None - if 'x86' in arch(): + if cdm_from_repo(): return os.path.join(iacdm, config.WIDEVINE_CONFIG_NAME) return os.path.join(iacdm, 'config.json') @@ -155,7 +162,7 @@ def missing_widevine_libs(): def latest_widevine_version(eula=False): """Returns the latest available version of Widevine CDM/Chrome OS.""" - if eula or 'x86' in arch(): + if eula or cdm_from_repo(): url = config.WIDEVINE_VERSIONS_URL versions = http_get(url) return versions.split()[-1] @@ -169,20 +176,48 @@ def latest_widevine_version(eula=False): return '' return arm_device.get('version') - -def latest_available_widevine_from_repo(): - """Returns the latest available Widevine CDM version and url from Google's library CDM repository""" +def widevines_available_from_repo(): + """Returns all available Widevine CDM versions and urls from Google's library CDM repository""" cdm_versions = http_get(config.WIDEVINE_VERSIONS_URL).strip('\n').split('\n') cdm_os = config.WIDEVINE_OS_MAP[system_os()] - cdm_arch = config.WIDEVINE_ARCH_MAP_X86[arch()] + cdm_arch = config.WIDEVINE_ARCH_MAP_REPO[arch()] available_cdms = [] for cdm_version in cdm_versions: cdm_url = config.WIDEVINE_DOWNLOAD_URL.format(version=cdm_version, os=cdm_os, arch=cdm_arch) http_status = http_head(cdm_url) if http_status == 200: - available_cdms.append(dict(version=cdm_version, url=cdm_url)) - return available_cdms[-1] + available_cdms.append({'version': cdm_version, 'url': cdm_url}) + + return available_cdms + +def latest_widevine_available_from_repo(available_cdms=None): + """Returns the latest available Widevine CDM version and url from Google's library CDM repository""" + if not available_cdms: + available_cdms = widevines_available_from_repo() + latest = available_cdms[-1] # That's probably correct, but the following for loop makes sure + for cdm in available_cdms: + if parse_version(cdm['version']) > parse_version(latest['version']): + latest = cdm + + return latest + +def choose_widevine_from_repo(): + """Choose from the widevine versions available in Google's library CDM repository""" + available_cdms = widevines_available_from_repo() + latest = latest_widevine_available_from_repo(available_cdms) + + opts = tuple(cdm['version'] for cdm in available_cdms) + preselect = opts.index(latest['version']) + + version_index = select_dialog(localize(30069), opts, preselect=preselect) + if version_index == -1: + log(1, 'User did not choose a version to install!') + return False + + cdm = available_cdms[version_index] + log(0, 'User chose to install Widevine version {version} from {url}', version=cdm['version'], url=cdm['url']) + return cdm def remove_old_backups(bpath): """Removes old Widevine backups, if number of allowed backups is exceeded""" diff --git a/script.module.inputstreamhelper/resources/language/resource.language.en_gb/strings.po b/script.module.inputstreamhelper/resources/language/resource.language.en_gb/strings.po index 914a9db6f..16b0039dc 100644 --- a/script.module.inputstreamhelper/resources/language/resource.language.en_gb/strings.po +++ b/script.module.inputstreamhelper/resources/language/resource.language.en_gb/strings.po @@ -153,10 +153,6 @@ msgctxt "#30038" msgid "Install Widevine" msgstr "" -msgctxt "#30039" -msgid "[B]Widevine CDM[/B] is currently not available natively on ARM64. Please switch to a 32-bit userspace for [B]Widevine CDM[/B] support." -msgstr "" - msgctxt "#30040" msgid "Update available" msgstr "" @@ -265,6 +261,14 @@ msgctxt "#30067" msgid "Specify the resource Widevine should be extracted from." msgstr "" +msgctxt "#30068" +msgid "On ARM64 with 64bit userspace, a newer version of {addon} is needed to use [B]Widevine CDM[/B] natively. Please either switch to a 32-bit userspace or install {addon} in version {version} or later." +msgstr "" + +msgctxt "#30069" +msgid "Choose which version to install" +msgstr "" + ### INFORMATION DIALOG msgctxt "#30800" diff --git a/script.module.inputstreamhelper/resources/settings.xml b/script.module.inputstreamhelper/resources/settings.xml index d3cbabb06..e5938eee8 100644 --- a/script.module.inputstreamhelper/resources/settings.xml +++ b/script.module.inputstreamhelper/resources/settings.xml @@ -12,7 +12,7 @@ - + From 1a64c6c32189a560689682eb3223ffaad0caf8e0 Mon Sep 17 00:00:00 2001 From: rmrector Date: Tue, 9 May 2023 22:47:21 +0000 Subject: [PATCH 041/145] [script.playrandomvideos] 2.1.1 --- script.playrandomvideos/addon.xml | 7 +++++-- script.playrandomvideos/changelog.txt | 3 +++ script.playrandomvideos/python/lib/playrandom.py | 12 ++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/script.playrandomvideos/addon.xml b/script.playrandomvideos/addon.xml index b0089c8a4..958452083 100644 --- a/script.playrandomvideos/addon.xml +++ b/script.playrandomvideos/addon.xml @@ -1,5 +1,5 @@ - + @@ -19,7 +19,10 @@ Plays random videos from all sorts of lists. This add-on can quickly play random episodes from TV shows, movies from genres/sets/years/tags, and videos from playlists, the filesystem, and just about anything else, other than plugins. - v2.1.0 (2022-02-20) + v2.1.1 (2023-05-09) +- Fix: recently played filter + +v2.1.0 (2022-02-20) - Feature: option to filter out recently played videos - Feature: add more metadata to playlist items diff --git a/script.playrandomvideos/changelog.txt b/script.playrandomvideos/changelog.txt index ecea3efdb..e1f1cc70a 100644 --- a/script.playrandomvideos/changelog.txt +++ b/script.playrandomvideos/changelog.txt @@ -1,3 +1,6 @@ +v2.1.1 (2023-05-09) +- Fix: recently played filter + v2.1.0 (2022-02-20) - Feature: option to filter out recently played videos - Feature: add more metadata to playlist items diff --git a/script.playrandomvideos/python/lib/playrandom.py b/script.playrandomvideos/python/lib/playrandom.py index 321caab8f..eb404ce34 100644 --- a/script.playrandomvideos/python/lib/playrandom.py +++ b/script.playrandomvideos/python/lib/playrandom.py @@ -1,7 +1,8 @@ import xbmcgui +from datetime import timedelta from . import quickjson -from .pykodi import get_main_addon, localize as L +from .pykodi import datetime_now, get_main_addon, localize as L from .player import get_player from .generators import get_generator @@ -52,8 +53,11 @@ def _build_watched_before_filter(content): if content == "movies": months = int(get_main_addon().getSetting('movieplayedmonths')) - lastwatched_filter = {'field': 'lastplayed', 'operator': 'notinthelast', 'value': months*30} - return lastwatched_fiter + # jsonrpc stopped playing nicely when combining 'notinthelast' with the other operators in our filter, so falling back to 'lessthan' + #lastwatched_filter = {'field': 'lastplayed', 'operator': 'notinthelast', 'value': months*30} + watchbeforedate = (datetime_now() - timedelta(days=months*30)).isoformat(' ') + lastwatched_filter = {'field': 'lastplayed', 'operator': 'lessthan', 'value': watchbeforedate} + return lastwatched_filter def _parse_path(pathinfo): content = None @@ -148,7 +152,7 @@ def _parse_path(pathinfo): elif watchmode == WATCHMODE_WATCHED: filters.append(played_filter) elif watchmode == WATCHMODE_WATCHEDBEFORE: - lastwatched_filter = _build_watched_before_fiter(content) + lastwatched_filter = _build_watched_before_filter(content) filters.append(lastwatched_filter) if content == 'tvshows' and get_main_addon().getSetting('exclude_extras') == 'true': From 7332fbf7e63330a8c968689b9819b9ceefeaab6d Mon Sep 17 00:00:00 2001 From: Ian Mclaughlin Date: Mon, 15 May 2023 10:52:23 +0100 Subject: [PATCH 042/145] [service.upnext] 1.1.9+matrix.1 (#2454) --- service.upnext/README.md | 7 ++ service.upnext/addon.xml | 2 +- .../resource.language.sv_se/strings.po | 24 ++--- service.upnext/resources/lib/api.py | 90 +++++++++---------- service.upnext/resources/lib/monitor.py | 8 +- .../resources/lib/playbackmanager.py | 6 +- service.upnext/resources/lib/playitem.py | 6 +- service.upnext/resources/lib/utils.py | 13 +-- 8 files changed, 82 insertions(+), 74 deletions(-) diff --git a/service.upnext/README.md b/service.upnext/README.md index 637dfac60..b31e5cdbe 100644 --- a/service.upnext/README.md +++ b/service.upnext/README.md @@ -24,6 +24,13 @@ For [Addon Integration](https://github.com/im85288/service.upnext/wiki/Integrati ## Releases +### v1.1.9 (2023-05-10) +- Fix handling of non-ASCII filenames for Kodi18 (@MoojMidge) +- Fix failing ci workflow (@MoojMidge) +- Update Swedish translation (@Sopor) +- Explicitly set sonarcloud coverage path (@MoojMidge) +- Fix error when kodi is not playing video any longer (@AnonTester) + ### v1.1.8 (2022-09-13) - Never ask if Still Watching? if playedInARow is 0 (@MoojMidge) - Still Watching? checks number of plays not number+1 (@MoojMidge) diff --git a/service.upnext/addon.xml b/service.upnext/addon.xml index d16616b3c..8b83c55c6 100644 --- a/service.upnext/addon.xml +++ b/service.upnext/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/service.upnext/resources/language/resource.language.sv_se/strings.po b/service.upnext/resources/language/resource.language.sv_se/strings.po index 3237e1c33..790ba701a 100644 --- a/service.upnext/resources/language/resource.language.sv_se/strings.po +++ b/service.upnext/resources/language/resource.language.sv_se/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: service.upnext\n" "Report-Msgid-Bugs-To: https://github.com/im85288/service.upnext\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2018-02-26 13:31+0000\n" +"PO-Revision-Date: 2023-02-19 00:00+0000\n" "Last-Translator: Sopor\n" "Language-Team: Swedish\n" "MIME-Version: 1.0\n" @@ -24,7 +24,7 @@ msgstr "Titta nu" msgctxt "#30008" msgid "Up Next" -msgstr "Strax" +msgstr "Up Next" msgctxt "#30009" msgid "Ends at: $INFO[Window.Property(endtime)]" @@ -52,7 +52,7 @@ msgstr "Stäng" msgctxt "#30035" msgid "Continue watching in [COLOR FFFF4081]$INFO[Window.Property(remaining)][/COLOR] seconds" -msgstr "Fortsätt titta i [COLOR FFFF4081]$INFO[Window.Property(remaining)][/COLOR] sekunder" +msgstr "Fortsätt titta om [COLOR FFFF4081]$INFO[Window.Property(remaining)][/COLOR] sekunder" msgctxt "#30036" msgid "Up next in [COLOR FFFF4081]$INFO[Window.Property(remaining)][/COLOR] seconds" @@ -118,7 +118,7 @@ msgstr "Ställ in visningsläget för aviseringarna" msgctxt "#30505" msgid "Show a \"Stop\" button instead of a \"Close\" button" -msgstr "Visa en \"stoppknapp\" i stället för en \"stängknapp\"" +msgstr "Visa en \"Stoppknapp\" i stället för en \"Stängknapp\"" msgctxt "#30600" msgid "Behaviour" @@ -138,7 +138,7 @@ msgstr "Inkludera redan visade avsnitt" msgctxt "#30607" msgid "Number of episodes before \"Still there?\" query" -msgstr "Antal avsnitt innan frågan \"tittar du fortfarande?\"" +msgstr "Antal avsnitt innan frågan \"Tittar du fortfarande?\"" msgctxt "#30609" msgid "Duration in seconds for notification to be shown" @@ -150,7 +150,7 @@ msgstr "Anpassa den automatiska uppspelningslängden efter avsnittets längd" msgctxt "#30613" msgid "All episodes [COLOR gray]any length[/COLOR]" -msgstr "Alla avsnitt [COLOR gray]any length[/COLOR]" +msgstr "Alla avsnitt [COLOR gray]oavsett längd[/COLOR]" msgctxt "#30615" msgid "Very short episodes [COLOR gray]< 10 mins[/COLOR]" @@ -158,7 +158,7 @@ msgstr "Väldigt korta avsnitt [COLOR gray]< 10 min[/COLOR]" msgctxt "#30617" msgid "Short episodes [COLOR gray]> 10 mins[/COLOR]" -msgstr "Korta avsnitt [COLOR gray]> 10 mins[/COLOR]" +msgstr "Korta avsnitt [COLOR gray]> 10 min[/COLOR]" msgctxt "#30619" msgid "Medium episodes [COLOR gray]> 20 mins[/COLOR]" @@ -166,7 +166,7 @@ msgstr "Medellånga avsnitt [COLOR gray]> 20 min[/COLOR]" msgctxt "#30621" msgid "Long episodes [COLOR gray]> 40 mins[/COLOR]" -msgstr "Långa avsnitt [COLOR gray]> 40 mins[/COLOR]" +msgstr "Långa avsnitt [COLOR gray]> 40 min[/COLOR]" msgctxt "#30623" msgid "Very long episodes [COLOR gray]> 60 mins[/COLOR]" @@ -198,16 +198,16 @@ msgstr "Aktivera DEMO-läge" msgctxt "#30805" msgid "Show an UpNext pop-up…" -msgstr "Visa en popup för UpNext…" +msgstr "Visa en UpNext-popup…" msgctxt "#30807" msgid "Show an UpNextSimple pop-up…" -msgstr "Visa en enkel popup för UpNext…" +msgstr "Visa en enkel UpNext-popup…" msgctxt "#30809" msgid "Show a StillWatching pop-up…" -msgstr "Visa en popup för \"tittar du fortfarande\"…" +msgstr "Visa en popup för \"Tittar du fortfarande\"…" msgctxt "#30811" msgid "Show a StillWatchingSimple pop-up…" -msgstr "Visa en enkel popup för \"tittar du fortfarande\"…" +msgstr "Visa en enkel popup för \"Tittar du fortfarande\"…" diff --git a/service.upnext/resources/lib/api.py b/service.upnext/resources/lib/api.py index 0d185a006..29d28fe0c 100644 --- a/service.upnext/resources/lib/api.py +++ b/service.upnext/resources/lib/api.py @@ -38,7 +38,7 @@ def addon_data_received(self, data, encoding='base64'): @staticmethod def play_kodi_item(episode): - jsonrpc(method='Player.Open', id=0, params=dict(item=dict(episodeid=episode.get('episodeid')))) + jsonrpc(method='Player.Open', id=0, params={'item': {'episodeid': episode.get('episodeid')}}) @staticmethod def _get_playerid(playerid_cache=[None]): # pylint: disable=dangerous-default-value @@ -96,10 +96,10 @@ def queue_next_item(self, episode): jsonrpc( method='Playlist.Add', id=0, - params=dict( - playlistid=Api.get_playlistid(), - item=next_item - ) + params={ + 'playlistid': Api.get_playlistid(), + 'item': next_item + } ) return bool(next_item) @@ -110,10 +110,10 @@ def dequeue_next_item(): jsonrpc( method='Playlist.Remove', id=0, - params=dict( - playlistid=Api.get_playlistid(), - position=1 - ) + params={ + 'playlistid': Api.get_playlistid(), + 'position': 1 + } ) return False @@ -123,21 +123,21 @@ def reset_queue(): jsonrpc( method='Playlist.Remove', id=0, - params=dict( - playlistid=Api.get_playlistid(), - position=0 - ) + params={ + 'playlistid': Api.get_playlistid(), + 'position': 0 + } ) def get_next_in_playlist(self, position): - result = jsonrpc(method='Playlist.GetItems', params=dict( - playlistid=Api.get_playlistid(), + result = jsonrpc(method='Playlist.GetItems', params={ + 'playlistid': Api.get_playlistid(), # limits are zero indexed, position is one indexed - limits=dict(start=position, end=position + 1), - properties=['art', 'dateadded', 'episode', 'file', 'firstaired', 'lastplayed', - 'playcount', 'plot', 'rating', 'resume', 'runtime', 'season', - 'showtitle', 'streamdetails', 'title', 'tvshowid', 'writer'], - )) + 'limits': {'start': position, 'end': position + 1}, + 'properties': ['art', 'dateadded', 'episode', 'file', 'firstaired', 'lastplayed', + 'playcount', 'plot', 'rating', 'resume', 'runtime', 'season', + 'showtitle', 'streamdetails', 'title', 'tvshowid', 'writer'], + }) item = result.get('result', {}).get('items') @@ -166,9 +166,9 @@ def get_next_in_playlist(self, position): def play_addon_item(self): if self.data.get('play_url'): self.log('Playing the next episode directly: %(play_url)s' % self.data, 2) - jsonrpc(method='Player.Open', params=dict(item=dict(file=self.data.get('play_url')))) + jsonrpc(method='Player.Open', params={'item': {'file': self.data.get('play_url')}}) else: - self.log('Sending %(encoding)s data to add-on to play: %(play_info)s' % dict(encoding=self.encoding, **self.data), 2) + self.log('Sending %(encoding)s data to add-on to play: %(play_info)s' % dict(encoding=self.encoding, **self.data), 2) # pylint: disable=use-dict-literal event(message=self.data.get('id'), data=self.data.get('play_info'), sender='upnextprovider', encoding=self.encoding) def handle_addon_lookup_of_next_episode(self): @@ -221,21 +221,21 @@ def get_now_playing(self): # Get details of the playing media self.log('Getting details of now playing media', 2) - result = jsonrpc(method='Player.GetItem', params=dict( - playerid=playerid, - properties=['episode', 'genre', 'playcount', 'plotoutline', 'season', 'showtitle', 'tvshowid'], - )) + result = jsonrpc(method='Player.GetItem', params={ + 'playerid': playerid, + 'properties': ['episode', 'genre', 'playcount', 'plotoutline', 'season', 'showtitle', 'tvshowid'], + }) self.log('Got details of now playing media %s' % result, 2) return result def handle_kodi_lookup_of_episode(self, tvshowid, current_file, include_watched, current_episode_id): - result = jsonrpc(method='VideoLibrary.GetEpisodes', params=dict( - tvshowid=tvshowid, - properties=['art', 'dateadded', 'episode', 'file', 'firstaired', 'lastplayed', - 'playcount', 'plot', 'rating', 'resume', 'runtime', 'season', - 'showtitle', 'streamdetails', 'title', 'tvshowid', 'writer'], - sort=dict(method='episode'), - )) + result = jsonrpc(method='VideoLibrary.GetEpisodes', params={ + 'tvshowid': tvshowid, + 'properties': ['art', 'dateadded', 'episode', 'file', 'firstaired', 'lastplayed', + 'playcount', 'plot', 'rating', 'resume', 'runtime', 'season', + 'showtitle', 'streamdetails', 'title', 'tvshowid', 'writer'], + 'sort': {'method': 'episode'}, + }) if not result.get('result'): return None @@ -247,13 +247,13 @@ def handle_kodi_lookup_of_episode(self, tvshowid, current_file, include_watched, return self.find_next_episode(result, current_file, include_watched, current_episode_id) def handle_kodi_lookup_of_current_episode(self, tvshowid, current_episode_id): - result = jsonrpc(method='VideoLibrary.GetEpisodes', params=dict( - tvshowid=tvshowid, - properties=['art', 'dateadded', 'episode', 'file', 'firstaired', 'lastplayed', - 'playcount', 'plot', 'rating', 'resume', 'runtime', 'season', - 'showtitle', 'streamdetails', 'title', 'tvshowid', 'writer'], - sort=dict(method='episode'), - )) + result = jsonrpc(method='VideoLibrary.GetEpisodes', params={ + 'tvshowid': tvshowid, + 'properties': ['art', 'dateadded', 'episode', 'file', 'firstaired', 'lastplayed', + 'playcount', 'plot', 'rating', 'resume', 'runtime', 'season', + 'showtitle', 'streamdetails', 'title', 'tvshowid', 'writer'], + 'sort': {'method': 'episode'}, + }) if not result.get('result'): return None @@ -275,7 +275,7 @@ def handle_kodi_lookup_of_current_episode(self, tvshowid, current_episode_id): @staticmethod def showtitle_to_id(title): - result = jsonrpc(method='VideoLibrary.GetTVShows', id='libTvShows', params=dict(properties=['title'])) + result = jsonrpc(method='VideoLibrary.GetTVShows', id='libTvShows', params={'properties': ['title']}) for tvshow in result.get('result', {}).get('tvshows', []): if tvshow.get('label') == title: @@ -286,10 +286,10 @@ def showtitle_to_id(title): def get_episode_id(showid, show_season, show_episode): show_season = int(show_season) show_episode = int(show_episode) - result = jsonrpc(method='VideoLibrary.GetEpisodes', params=dict( - properties=['episode', 'season'], - tvshowid=int(showid), - )) + result = jsonrpc(method='VideoLibrary.GetEpisodes', params={ + 'properties': ['episode', 'season'], + 'tvshowid': int(showid), + }) episodeid = 0 for episode in result.get('result', {}).get('episodes', []): diff --git a/service.upnext/resources/lib/monitor.py b/service.upnext/resources/lib/monitor.py index e4daba2bf..38d49d4d8 100644 --- a/service.upnext/resources/lib/monitor.py +++ b/service.upnext/resources/lib/monitor.py @@ -6,7 +6,7 @@ from api import Api from playbackmanager import PlaybackManager from player import UpNextPlayer -from statichelper import from_unicode +from statichelper import to_unicode from utils import decode_json, get_property, get_setting_bool, kodi_version_major, log as ulog @@ -57,7 +57,7 @@ def run(self): # pylint: disable=too-many-branches last_file = self.player.get_last_file() try: - current_file = self.player.getPlayingFile() + current_file = to_unicode(self.player.getPlayingFile()) except RuntimeError: self.log('Up Next tracking stopped, failed player.getPlayingFile()', 2) self.player.disable_tracking() @@ -73,7 +73,7 @@ def run(self): # pylint: disable=too-many-branches self.playback_manager.demo.hide() continue - if last_file and last_file == from_unicode(current_file): + if last_file and last_file == current_file: # Already processed this playback before continue @@ -104,7 +104,7 @@ def run(self): # pylint: disable=too-many-branches # Media hasn't reach notification time yet, waiting a bit longer... continue - self.player.set_last_file(from_unicode(current_file)) + self.player.set_last_file(current_file) self.log('Show notification as episode (of length %d secs) ends in %d secs' % (total_time, notification_time), 2) self.playback_manager.launch_up_next() self.log('Up Next style autoplay succeeded', 2) diff --git a/service.upnext/resources/lib/playbackmanager.py b/service.upnext/resources/lib/playbackmanager.py index ed7352963..922e2a0b5 100644 --- a/service.upnext/resources/lib/playbackmanager.py +++ b/service.upnext/resources/lib/playbackmanager.py @@ -5,7 +5,7 @@ from xbmc import sleep from api import Api from demo import DemoOverlay -from player import Player +from player import UpNextPlayer from playitem import PlayItem from state import State from stillwatching import StillWatching @@ -21,7 +21,7 @@ def __init__(self): self.api = Api() self.play_item = PlayItem() self.state = State() - self.player = Player() + self.player = UpNextPlayer() self.demo = DemoOverlay(12005) def log(self, msg, level=2): @@ -117,7 +117,7 @@ def launch_popup(self, episode, source=None): self.log('playing media episode', 2) # Signal to trakt previous episode watched - event(message='NEXTUPWATCHEDSIGNAL', data=dict(episodeid=self.state.current_episode_id), encoding='base64') + event(message='NEXTUPWATCHEDSIGNAL', data={'episodeid': self.state.current_episode_id}, encoding='base64') if source == 'playlist' or self.state.queued: # Play playlist media if should_play_non_default: diff --git a/service.upnext/resources/lib/playitem.py b/service.upnext/resources/lib/playitem.py index 8383a08ff..0436f4f8e 100644 --- a/service.upnext/resources/lib/playitem.py +++ b/service.upnext/resources/lib/playitem.py @@ -4,7 +4,7 @@ from __future__ import absolute_import, division, unicode_literals from xbmc import PlayList from api import Api -from player import Player +from player import UpNextPlayer from state import State from utils import log as ulog @@ -15,7 +15,7 @@ class PlayItem: def __init__(self): self.__dict__ = self._shared_state self.api = Api() - self.player = Player() + self.player = UpNextPlayer() self.state = State() def log(self, msg, level=2): @@ -58,7 +58,7 @@ def get_next(self): # Next video from Kodi library else: - current_file = self.player.getPlayingFile() + current_file = self.player.get_last_file() # Get the active player result = self.api.get_now_playing() self.handle_now_playing_result(result) diff --git a/service.upnext/resources/lib/utils.py b/service.upnext/resources/lib/utils.py index 71346053d..5f6bfdaef 100644 --- a/service.upnext/resources/lib/utils.py +++ b/service.upnext/resources/lib/utils.py @@ -150,11 +150,11 @@ def event(message, data=None, sender=None, encoding='base64'): if not encoded: return - jsonrpc(method='JSONRPC.NotifyAll', params=dict( - sender='%s.SIGNAL' % sender, - message=message, - data=[encoded], - )) + jsonrpc(method='JSONRPC.NotifyAll', params={ + 'sender': '%s.SIGNAL' % sender, + 'message': message, + 'data': [encoded], + }) def log(msg, name=None, level=1): @@ -191,7 +191,8 @@ def jsonrpc(**kwargs): def get_global_setting(setting): """Get a Kodi setting""" - result = jsonrpc(method='Settings.GetSettingValue', params=dict(setting=setting)) + result = jsonrpc(method='Settings.GetSettingValue', + params={'setting': setting}) return result.get('result', {}).get('value') From 9f63e760fc6169111172404fc6382c0f31a33adc Mon Sep 17 00:00:00 2001 From: taxigps Date: Mon, 15 May 2023 18:11:10 +0800 Subject: [PATCH 043/145] [service.subtitles.shooter] 2.0.1 (#2455) --- service.subtitles.shooter/addon.xml | 5 ++++- service.subtitles.shooter/service.py | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/service.subtitles.shooter/addon.xml b/service.subtitles.shooter/addon.xml index 44f58c585..916404ebe 100644 --- a/service.subtitles.shooter/addon.xml +++ b/service.subtitles.shooter/addon.xml @@ -1,7 +1,7 @@ @@ -30,6 +30,9 @@ resources/media/screenshot_3.jpg +V2.0.1 (2023-05-14) +- fixed: function was removed in Kodi 20 + V2.0.0 (2020-04-18) - Ported to python 3.0 for Kodi 19 diff --git a/service.subtitles.shooter/service.py b/service.subtitles.shooter/service.py index 741d7cee2..6675dc294 100644 --- a/service.subtitles.shooter/service.py +++ b/service.subtitles.shooter/service.py @@ -26,10 +26,10 @@ __version__ = __addon__.getAddonInfo('version') __language__ = __addon__.getLocalizedString -__cwd__ = xbmc.translatePath( __addon__.getAddonInfo('path') ) -__profile__ = xbmc.translatePath( __addon__.getAddonInfo('profile') ) -__resource__ = xbmc.translatePath( os.path.join( __cwd__, 'resources', 'lib' ) ) -__temp__ = xbmc.translatePath( os.path.join( __profile__, 'temp') ) +__cwd__ = xbmcvfs.translatePath( __addon__.getAddonInfo('path') ) +__profile__ = xbmcvfs.translatePath( __addon__.getAddonInfo('profile') ) +__resource__ = xbmcvfs.translatePath( os.path.join( __cwd__, 'resources', 'lib' ) ) +__temp__ = xbmcvfs.translatePath( os.path.join( __profile__, 'temp') ) sys.path.append (__resource__) from langconv import * From bf1b4bfd171a896a9dee95e9d64e9233ace87ff0 Mon Sep 17 00:00:00 2001 From: Kyle Johnson Date: Sat, 20 May 2023 08:51:17 -0400 Subject: [PATCH 044/145] [script.artistslideshow] v3.3.5 (#2456) - fix for AS not accepting images with uppercase extensions - removed Leia to Matrix transition code - updated translation files --- script.artistslideshow/addon.xml | 12 +- script.artistslideshow/changelog.txt | 5 + .../resource.language.de_de/strings.po | 30 +-- .../resource.language.es_es/strings.po | 12 +- .../resource.language.et_ee/strings.po | 162 ++++++------- .../resource.language.fr_fr/strings.po | 18 +- .../resource.language.hr_hr/strings.po | 216 +++++++++--------- .../resource.language.it_it/strings.po | 8 +- .../resource.language.ru_ru/strings.po | 24 +- .../resource.language.sk_sk/strings.po | 8 +- .../resources/lib/artistslideshow.py | 68 +++--- .../resources/lib/fileops.py | 2 +- .../resources/lib/xlogger.py | 2 +- .../resources/plugins/fanarttv.py | 5 +- .../resources/plugins/kodi.py | 2 +- .../resources/plugins/lastfm.py | 23 +- .../resources/plugins/local.py | 19 +- .../resources/plugins/theaudiodb.py | 5 +- 18 files changed, 307 insertions(+), 314 deletions(-) diff --git a/script.artistslideshow/addon.xml b/script.artistslideshow/addon.xml index 203a7d776..00e3f280b 100644 --- a/script.artistslideshow/addon.xml +++ b/script.artistslideshow/addon.xml @@ -1,9 +1,8 @@ - + - @@ -11,9 +10,10 @@ -v.3.3.3 -- trim_cache now deletes information as well as images -- update to new settings format +v.3.3.5 +- fix for AS not accepting images with uppercase extensions +- removed Leia to Matrix transition code +- updated translation files icon.png @@ -36,6 +36,7 @@ v.3.3.3 Bajá imágenes e información adicional sobre el artista Descarga imágenes e información adicional del intérprete que esté sonando Descargar imágenes e información adicional del artista actualmente en reproducción + Lae alla pilte ja lisateavet hetkel mängiva esitaja kohta Noutaa kuvia ja lisätietoja parhaillaan toistettavasta esittäjästä Télécharger des images et des infos additionnelles sur l'artiste écouté Télécharger les images et les informations additionnelles de l'artiste en cours de lecture @@ -67,6 +68,7 @@ v.3.3.3 Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to. Addon para descargar imágenes e información adicional de fanart.tv y theaudiodb.com del intérprete que se está reproduciendo. Las imágenes, junto con imágenes de intérpretes locales, y la información puede ser utilizada por la piel para crear una presentación de diapositivas para el intérprete que se está escuchando. Complemento para descargar imágenes e información adicional de fanart.tv y theaudiodb.com del artista actualmente en reproducción. Las imágenes, junto con las imágenes e información locales de los artistas pueden ser utilizados por la máscara para crear una presentación del artista que estés escuchando. + Lisamoodul, millega saab alla laadida pilte ja lisateavet fanart.tv ja theaudiodb.com saitidelt hetkel mängiva esitaja kohta. Koos meediakogus leiduvate esitajate piltide ja teabega saab rüü neid kasutada kuulatava esitaja slaidiseansi loomiseks. Lisäosa parhaillaan kuunneltavan esittäjän kuvien ja tietojen noutoon mm. Fanart.tv- ja TheAudioDB.com-palveluista. Ulkoasut voivat luoda kuvaesityksiä kuunneltavasta esittäjästä käyttäen näitä tietoja ja esittäjien paikallisia kuvia. Addiciel pour télécharger des images et des informations additionnelles sur fanart.tv et theaudiodb.com de l'artiste en cours d'écoute. Les images, ainsi que les images locales de l'artiste, et les infos peuvent être utilisées par l'habillage pour créer un diaporama pour l'artiste en cours d'écoute. Extension permettant de télécharger des images et des informations supplémentaires depuis fanart.tv et depuis theaudiodb.com de l'artiste en cours d'écoute. Les images téléchargées, les images locales des artistes et les informations peuvent être utilisées par le skin pour créer un diaporama pour l'artiste écouté. diff --git a/script.artistslideshow/changelog.txt b/script.artistslideshow/changelog.txt index a85a19a70..35b3ed39b 100644 --- a/script.artistslideshow/changelog.txt +++ b/script.artistslideshow/changelog.txt @@ -1,3 +1,8 @@ +v.3.3.5 +- fix for AS not accepting images with uppercase extensions +- removed Leia to Matrix transition code +- updated translation files + v.3.3.3 - trim_cache now deletes information as well as images - update to new settings format diff --git a/script.artistslideshow/resources/language/resource.language.de_de/strings.po b/script.artistslideshow/resources/language/resource.language.de_de/strings.po index 2320774b5..165ce11c4 100644 --- a/script.artistslideshow/resources/language/resource.language.de_de/strings.po +++ b/script.artistslideshow/resources/language/resource.language.de_de/strings.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2021-07-18 09:29+0000\n" +"PO-Revision-Date: 2023-02-06 23:15+0000\n" "Last-Translator: Kai Sommerfeld \n" "Language-Team: German \n" "Language: de_de\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.7.1\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -94,7 +94,7 @@ msgstr "Client-API-Key" msgctxt "#32110" msgid "I donate to this service" -msgstr "Ich spende für diesen Service" +msgstr "Ich spende für diesen Dienst" msgctxt "#32111" msgid "Use fallback slideshow" @@ -118,11 +118,11 @@ msgstr "Album-Fanart von Kodi einschließen" msgctxt "#32116" msgid "Limit size of download cache" -msgstr "Größe des Download-Caches begrenzen" +msgstr "Größe des Downloadcaches begrenzen" msgctxt "#32117" msgid "Maximum cache size (in megabytes)" -msgstr "Maximale Cache-Größe (in Megabytes)" +msgstr "Maximale Cachegröße (in Megabytes)" msgctxt "#32118" msgid "Alternate name for local fanart folder" @@ -134,7 +134,7 @@ msgstr "Debug-Protokollierung aktivieren" msgctxt "#32120" msgid "Disable secondary and featured artist images" -msgstr "Sekundäre und vorgestellte Interpertenbilder deaktivieren" +msgstr "Sekundäre und vorgestellte Interpretenbilder deaktivieren" msgctxt "#32121" msgid "Store artist images in" @@ -190,7 +190,7 @@ msgstr "macOS" msgctxt "#32134" msgid "Move images to Kodi music artist folder" -msgstr "Bilder in Kodis Musikinterpreten-Ordner verschieben" +msgstr "Bilder in Kodis Musikinterpretenordner verschieben" msgctxt "#32135" msgid "Get artist bio from Kodi" @@ -210,11 +210,11 @@ msgstr "Schwarzblende beim Interpretenwechsel" msgctxt "#32139" msgid "Main thread sleep time (in seconds)" -msgstr "Wartezeit des Haupt-Threads (in Sekunden)" +msgstr "Wartezeit des Hauptthreads (in Sekunden)" msgctxt "#32140" msgid "Main thread idle sleep time (in seconds)" -msgstr "Leerlauf-Wartezeit des Haupt-Threads (in Sekunden)" +msgstr "Leerlaufwartezeit des Hauptthreads (in Sekunden)" msgctxt "#32141" msgid "Slideshow thread sleep time (in seconds)" @@ -222,7 +222,7 @@ msgstr "Wartezeit des Diashow-Threads (in Sekunden)" msgctxt "#32142" msgid "Show notification during image downloads" -msgstr "Benachrichtigung während Herunterladen von Bildern anzeigen" +msgstr "Benachrichtigung beim Herunterladen von Bildern anzeigen" msgctxt "#32143" msgid "Only show notification if there are images to download" @@ -266,11 +266,11 @@ msgstr "Herunterladen abgeschlossen" # Dialog texts msgctxt "#32300" msgid "This will move and rename your image files and cannot be undone. Are you sure you want to do this?" -msgstr "Dies wird die Bilddateien verschieben und umbenennen und kann nicht rückgängig gemacht werden. Fortfahren?" +msgstr "Dies verschiebt und benennt die Bilddateien um und kann nicht rückgängig gemacht werden. Fortfahren?" msgctxt "#32301" msgid "Unable to retrieve path to Kodi music artist image storage. Please check Settings > Media > Music and ensure the Artist Information Folder is set." -msgstr "Pfad für Kodis Musikinterpreten-Bilderspeicherort kann nicht ermittelt werden. Bitte prüfen, dass unter Einstellungen > Medien > Musik der Ordner für Interpreteninformationen festgelegt ist." +msgstr "Pfad für Kodis Speicherort der Musikinterpretenbilder kann nicht ermittelt werden. Bitte prüfen, dass unter Einstellungen > Medien > Musik der Ordner für Interpreteninformationen festgelegt ist." msgctxt "#32302" msgid "Artist Slideshow is already set to use the Kodi artist information folder. Please set to use either addon_data folder or a custom location and try again." @@ -278,11 +278,11 @@ msgstr "Artist Slideshow ist bereits konfiguriert, Kodis Interpreteninformatione msgctxt "#32303" msgid "Moving and renaming images from custom location..." -msgstr "Verschieben und Umbennenen der Bilder aus benutzerdefiertem Ordner ..." +msgstr "Verschieben und Umbenennen der Bilder aus benutzerdefiertem Ordner ..." msgctxt "#32304" msgid "Moving and renaming images from addon_data folder..." -msgstr "Verschieben und Umbennenen der Bilder aus Ordner „addon_data“ ..." +msgstr "Verschieben und Umbenennen der Bilder aus Ordner „addon_data“ …" msgctxt "#32305" msgid "No artist directories found." diff --git a/script.artistslideshow/resources/language/resource.language.es_es/strings.po b/script.artistslideshow/resources/language/resource.language.es_es/strings.po index daa0c7fd0..8d2fe60f5 100644 --- a/script.artistslideshow/resources/language/resource.language.es_es/strings.po +++ b/script.artistslideshow/resources/language/resource.language.es_es/strings.po @@ -5,17 +5,17 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-03-01 17:13+0000\n" -"Last-Translator: Alfonso Cachero \n" +"PO-Revision-Date: 2023-02-27 11:31+0000\n" +"Last-Translator: José Antonio Alvarado \n" "Language-Team: Spanish (Spain) \n" "Language: es_es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.11\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -142,7 +142,7 @@ msgstr "Almacenar imágenes de intérprete en" msgctxt "#32122" msgid "addon_data folder" -msgstr "addon_data folder" +msgstr "carpeta addon_data" msgctxt "#32123" msgid "Kodi artist information folder" @@ -244,7 +244,7 @@ msgstr "Artist Slideshow" msgctxt "#32201" msgid "Warning" -msgstr "Precaución" +msgstr "Advertencia" msgctxt "#32202" msgid "Error" diff --git a/script.artistslideshow/resources/language/resource.language.et_ee/strings.po b/script.artistslideshow/resources/language/resource.language.et_ee/strings.po index 522766446..fd56f613d 100644 --- a/script.artistslideshow/resources/language/resource.language.et_ee/strings.po +++ b/script.artistslideshow/resources/language/resource.language.et_ee/strings.po @@ -5,25 +5,25 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-03-11 00:15+0000\n" -"Last-Translator: Christian Gade \n" +"PO-Revision-Date: 2023-02-27 11:31+0000\n" +"Last-Translator: rimasx \n" "Language-Team: Estonian \n" "Language: et_ee\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.11.2\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" -msgstr "" +msgstr "Lae alla pilte ja lisateavet hetkel mängiva esitaja kohta" msgctxt "Addon Description" msgid "Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to." -msgstr "" +msgstr "Lisamoodul, millega saab alla laadida pilte ja lisateavet fanart.tv ja theaudiodb.com saitidelt hetkel mängiva esitaja kohta. Koos meediakogus leiduvate esitajate piltide ja teabega saab rüü neid kasutada kuulatava esitaja slaidiseansi loomiseks." # Section Headings msgctxt "#32000" @@ -40,15 +40,15 @@ msgstr "Pildid" msgctxt "#32003" msgid "Album Info" -msgstr "" +msgstr "Albumi info" msgctxt "#32004" msgid "Artist Bio" -msgstr "" +msgstr "Esitaja elulugu" msgctxt "#32005" msgid "Similar Artists" -msgstr "" +msgstr "Sarnased esitajad" msgctxt "#32006" msgid "Advanced" @@ -58,75 +58,75 @@ msgstr "Täpsem" # Settings msgctxt "#32101" msgid "Download images from fanart.tv" -msgstr "" +msgstr "Hangi pilte saidilt fanart.tv" msgctxt "#32102" msgid "Download images from theaudiodb.com" -msgstr "" +msgstr "Hangi pilte saidilt theaudiodb.com" msgctxt "#32103" msgid "Download album info from the audiodb.com" -msgstr "" +msgstr "Hangi albumiteave saidilt audiodb.com" msgctxt "#32104" msgid "Download album info from the last.fm" -msgstr "" +msgstr "Hangi albumiteave saidilt last.fm" msgctxt "#32105" msgid "Download artist bio from theaudiodb.com" -msgstr "" +msgstr "Hangi esitaja elulugu saidilt theaudiodb.com" msgctxt "#32106" msgid "Download artist bio from last.fm" -msgstr "" +msgstr "Hangi esitaja elulugu saidilt last.fm" msgctxt "#32107" msgid "Download similar artists from last.fm" -msgstr "" +msgstr "Hangi sarnaseid esitajaid saidilt last.fm" msgctxt "#32108" msgid "Download all images regardless of resolution" -msgstr "" +msgstr "Laadi alla kõik pildid sõltumata eraldusvõimest" msgctxt "#32109" msgid "Client API key" -msgstr "" +msgstr "Kliendi API võti" msgctxt "#32110" msgid "I donate to this service" -msgstr "" +msgstr "Annetan sellele teenusele" msgctxt "#32111" msgid "Use fallback slideshow" -msgstr "" +msgstr "Kasuta varuslaidiseanssi" msgctxt "#32112" msgid "Use override slideshow" -msgstr "" +msgstr "Kasuta asendusslaidiseanssi" msgctxt "#32113" msgid "Custom location" -msgstr "" +msgstr "Kohandatud asukoht" msgctxt "#32114" msgid "Include Kodi artist fanart" -msgstr "" +msgstr "Kaasa Kodi esitaja fännipldid" msgctxt "#32115" msgid "Include Kodi album fanart" -msgstr "" +msgstr "Kaasa Kodi albumi fännipildid" msgctxt "#32116" msgid "Limit size of download cache" -msgstr "" +msgstr "Piira allalaadimise vahemälu suurust" msgctxt "#32117" msgid "Maximum cache size (in megabytes)" -msgstr "" +msgstr "Maksimaalne vahemälu suurus (megabaitides)" msgctxt "#32118" msgid "Alternate name for local fanart folder" -msgstr "" +msgstr "Kohaliku fännipildi kausta alternatiivne nimi" msgctxt "#32119" msgid "Enable debug logging" @@ -134,117 +134,117 @@ msgstr "Luba silumise logimine" msgctxt "#32120" msgid "Disable secondary and featured artist images" -msgstr "" +msgstr "Keela teisesed ja esiletõstetud esitaja pildid" msgctxt "#32121" msgid "Store artist images in" -msgstr "" +msgstr "Salvesta esitaja pildid asukohta" msgctxt "#32122" msgid "addon_data folder" -msgstr "" +msgstr "addon_data kaust" msgctxt "#32123" msgid "Kodi artist information folder" -msgstr "" +msgstr "Kodi esitaja teabe kaust" msgctxt "#32124" msgid "Priority" -msgstr "" +msgstr "Prioriteet" msgctxt "#32125" msgid "Store artist information in" -msgstr "" +msgstr "Salvesta esitaja teave asukohta" msgctxt "#32126" msgid "Preferred language for artist bio" -msgstr "" +msgstr "Eelistatud keel esitaja eluloo jaoks" msgctxt "#32127" msgid "Use extrafanart folder" -msgstr "" +msgstr "Kasuta extrafanart kausta" msgctxt "#32128" msgid "Platform for image storage" -msgstr "" +msgstr "Piltide salvestamise platvorm" msgctxt "#32129" msgid "Replace illegal path characters in artist name with" -msgstr "" +msgstr "Asenda esitaja nimes olevad keelatud märgid märgiga" msgctxt "#32130" msgid "Replace trailing period in artist name with" -msgstr "" +msgstr "Asenda esitaja nime lõpus olevad punktid märgiga" msgctxt "#32131" msgid "Windows" -msgstr "" +msgstr "Windows" msgctxt "#32132" msgid "Other" -msgstr "" +msgstr "Muu" msgctxt "#32133" msgid "MacOS" -msgstr "" +msgstr "MacOS" msgctxt "#32134" msgid "Move images to Kodi music artist folder" -msgstr "" +msgstr "Liiguta pildid Kodi muusika kataloogi" msgctxt "#32135" msgid "Get artist bio from Kodi" -msgstr "" +msgstr "Hangi esitaja elulugu Kodist" msgctxt "#32136" msgid "Custom location" -msgstr "" +msgstr "Kohandatud asukoht" msgctxt "#32137" msgid "Delay between slide transitions (in seconds)" -msgstr "" +msgstr "Slaidiseansi pildi vahetamise vahemik (sekundites)" msgctxt "#32138" msgid "Fade to black during change in artists" -msgstr "" +msgstr "Esitajate vahetamisel tuhmub mustaks" msgctxt "#32139" msgid "Main thread sleep time (in seconds)" -msgstr "" +msgstr "Pealõnga puhkeaeg (sekundites)" msgctxt "#32140" msgid "Main thread idle sleep time (in seconds)" -msgstr "" +msgstr "Põhilõnga jõudeoleku aeg (sekundites)" msgctxt "#32141" msgid "Slideshow thread sleep time (in seconds)" -msgstr "" +msgstr "Slaidiseansi lõime puhkeaeg (sekundites)" msgctxt "#32142" msgid "Show notification during image downloads" -msgstr "" +msgstr "Kuva märguanne piltide allalaadimise ajal" msgctxt "#32143" msgid "Only show notification if there are images to download" -msgstr "" +msgstr "Kuva märguanne ainult siis, kui pilte allalaadimiseks leidub" msgctxt "#32144" msgid "Use more agressive artist search for streams" -msgstr "" +msgstr "Kasuta meediavoogude jaoks agressiivsemat esineja otsingut" msgctxt "#32145" msgid "Pause slideshow on playback pause" -msgstr "" +msgstr "Peata slaidiseanss taasesituse pausimisel" # empty strings from id 32145 to 32199 # Dialog headings msgctxt "#32200" msgid "Artist Slideshow" -msgstr "" +msgstr "Esitaja slaidiseanss" msgctxt "#32201" msgid "Warning" -msgstr "" +msgstr "Hoiatus" msgctxt "#32202" msgid "Error" @@ -252,87 +252,87 @@ msgstr "Viga" msgctxt "#32203" msgid "Progress" -msgstr "" +msgstr "Edenemine" msgctxt "#32204" msgid "Downloading" -msgstr "" +msgstr "Allalaadimine" msgctxt "#32205" msgid "Download Complete" -msgstr "" +msgstr "Allalaadimine on lõpetatud" # empty strings from id 32206 to 32299 # Dialog texts msgctxt "#32300" msgid "This will move and rename your image files and cannot be undone. Are you sure you want to do this?" -msgstr "" +msgstr "See teisaldab ja nimetab pildifailid ümber ning seda ei saa tagasi võtta. Kas oled kindel, et soovid seda teha?" msgctxt "#32301" msgid "Unable to retrieve path to Kodi music artist image storage. Please check Settings > Media > Music and ensure the Artist Information Folder is set." -msgstr "" +msgstr "Kodi muusika esitajate piltide salvestuskohta ei õnnestunud tuua. Vali Seaded > Meedia > Muusika ja veendu, et esitajateabe jaoks on kaust määratud." msgctxt "#32302" msgid "Artist Slideshow is already set to use the Kodi artist information folder. Please set to use either addon_data folder or a custom location and try again." -msgstr "" +msgstr "Esitaja slaidiseanss on juba seadistatud kasutama Kodi esitaja teabekausta. Määra kas addon_data kaust või kohandatud asukoht ja proovi uuesti." msgctxt "#32303" msgid "Moving and renaming images from custom location..." -msgstr "" +msgstr "Piltide teisaldamine ja ümbernimetamine kohandatud asukohast..." msgctxt "#32304" msgid "Moving and renaming images from addon_data folder..." -msgstr "" +msgstr "Piltide teisaldamine ja ümbernimetamine addon_data kaustast..." msgctxt "#32305" msgid "No artist directories found." -msgstr "" +msgstr "Esitaja katalooge ei leitud." msgctxt "#32306" msgid "Image move complete. You may now change the Artist Slideshow storage location to Kodi artist information folder." -msgstr "" +msgstr "Pildi teisaldamine on lõpetatud. Nüüd võid muuta esitaja slaidiseansi salvestuskoha Kodi esitaja teabekaustaks." msgctxt "#32307" msgid "Downloading new artist images" -msgstr "" +msgstr "Esitajale uute piltide allalaadimine" msgctxt "#32308" msgid "artist images downloaded" -msgstr "" +msgstr "esitaja pildid alla laetud" msgctxt "#32309" msgid "artist image downloaded" -msgstr "" +msgstr "esitaja pilt alla laetud" # empty strings from id 32310 to 32900 # Languages msgctxt "#32901" msgid "Albanian" -msgstr "" +msgstr "Albaania" msgctxt "#32902" msgid "Arabic" -msgstr "" +msgstr "Araabia" msgctxt "#32903" msgid "Belarusian" -msgstr "" +msgstr "Valgevene" msgctxt "#32904" msgid "Bosnian (Latin)" -msgstr "" +msgstr "Bosnia (ladina)" msgctxt "#32905" msgid "Bulgarian" -msgstr "" +msgstr "Bulgaaria" msgctxt "#32906" msgid "Catalan" -msgstr "" +msgstr "Katalaani" msgctxt "#32907" msgid "Chinese" -msgstr "" +msgstr "Hiina" msgctxt "#32908" msgid "Croatian" @@ -356,19 +356,19 @@ msgstr "" msgctxt "#32913" msgid "Estonian" -msgstr "" +msgstr "Eesti" msgctxt "#32914" msgid "Finnish" -msgstr "" +msgstr "Soome" msgctxt "#32915" msgid "French" -msgstr "" +msgstr "Prantsuse" msgctxt "#32916" msgid "German" -msgstr "" +msgstr "Saksa" msgctxt "#32917" msgid "Greek" @@ -426,11 +426,11 @@ msgstr "" # empty string with id 32931 msgctxt "#32932" msgid "Polish" -msgstr "" +msgstr "Poola" msgctxt "#32933" msgid "Portuguese" -msgstr "" +msgstr "Portugali" msgctxt "#32934" msgid "Portuguese (Brazil)" diff --git a/script.artistslideshow/resources/language/resource.language.fr_fr/strings.po b/script.artistslideshow/resources/language/resource.language.fr_fr/strings.po index 275e71cf6..f01cd4584 100644 --- a/script.artistslideshow/resources/language/resource.language.fr_fr/strings.po +++ b/script.artistslideshow/resources/language/resource.language.fr_fr/strings.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-10-26 17:15+0000\n" +"PO-Revision-Date: 2023-01-01 16:15+0000\n" "Last-Translator: skypichat \n" "Language-Team: French (France) \n" "Language: fr_fr\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.14.1\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -52,7 +52,7 @@ msgstr "Artistes similaires" msgctxt "#32006" msgid "Advanced" -msgstr "Avancés" +msgstr "Avancé" # empty strings from id 32007 to 32099 # Settings @@ -110,11 +110,11 @@ msgstr "Emplacement personnalisé" msgctxt "#32114" msgid "Include Kodi artist fanart" -msgstr "Utiliser le diaporama prioritaire" +msgstr "Inclure le fanart de l'artiste de Kodi" msgctxt "#32115" msgid "Include Kodi album fanart" -msgstr "Inclure le fanart de l'album depuis Kodi" +msgstr "Inclure le fanart de l'album de Kodi" msgctxt "#32116" msgid "Limit size of download cache" @@ -130,7 +130,7 @@ msgstr "Nom alternatif pour le dossier local des fanart" msgctxt "#32119" msgid "Enable debug logging" -msgstr "Activer la journalisation de débogage" +msgstr "Activer la journalisation du débogage" msgctxt "#32120" msgid "Disable secondary and featured artist images" @@ -270,7 +270,7 @@ msgstr "Cette opération déplacera et renommera vos fichiers d'images et ne pou msgctxt "#32301" msgid "Unable to retrieve path to Kodi music artist image storage. Please check Settings > Media > Music and ensure the Artist Information Folder is set." -msgstr "Impossible de récupérer le chemin d'accès au stockage des images des artistes musicaux de Kodi. Veuillez vérifier Paramètres > Médiathèque > Musique et assurez-vous que le Dossier d'informations de l'artiste est défini." +msgstr "Impossible de récupérer le chemin d'accès au stockage des images des artistes musicaux de Kodi. Veuillez vérifier : Paramètres > Médiathèque > Musique et assurez-vous que le Dossier d'informations de l'artiste est défini." msgctxt "#32302" msgid "Artist Slideshow is already set to use the Kodi artist information folder. Please set to use either addon_data folder or a custom location and try again." @@ -417,7 +417,7 @@ msgstr "Lituanien" msgctxt "#32929" msgid "Macedonian" -msgstr "Macédoine" +msgstr "Macédonien" msgctxt "#32930" msgid "Norwegian" diff --git a/script.artistslideshow/resources/language/resource.language.hr_hr/strings.po b/script.artistslideshow/resources/language/resource.language.hr_hr/strings.po index 45b51787d..0b55c266a 100644 --- a/script.artistslideshow/resources/language/resource.language.hr_hr/strings.po +++ b/script.artistslideshow/resources/language/resource.language.hr_hr/strings.po @@ -5,17 +5,17 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-03-01 17:13+0000\n" -"Last-Translator: Christian Gade \n" +"PO-Revision-Date: 2023-01-15 13:15+0000\n" +"Last-Translator: gogogogi \n" "Language-Team: Croatian \n" "Language: hr_hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.11\n" +"X-Generator: Weblate 4.15\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -36,15 +36,15 @@ msgstr "Pohrana" msgctxt "#32002" msgid "Images" -msgstr "" +msgstr "Slike" msgctxt "#32003" msgid "Album Info" -msgstr "" +msgstr "Informacije albuma" msgctxt "#32004" msgid "Artist Bio" -msgstr "" +msgstr "Životopis izvođača" msgctxt "#32005" msgid "Similar Artists" @@ -58,51 +58,51 @@ msgstr "Napredno" # Settings msgctxt "#32101" msgid "Download images from fanart.tv" -msgstr "" +msgstr "Preuzmi slike s fanart.tv" msgctxt "#32102" msgid "Download images from theaudiodb.com" -msgstr "" +msgstr "Preuzmi slike s theaudiodb.com" msgctxt "#32103" msgid "Download album info from the audiodb.com" -msgstr "" +msgstr "Preuzmi informacije albuma s audiodb.com" msgctxt "#32104" msgid "Download album info from the last.fm" -msgstr "" +msgstr "Preuzmi informacije albuma s last.fm" msgctxt "#32105" msgid "Download artist bio from theaudiodb.com" -msgstr "" +msgstr "Preuzmi informacije životopisa izvođača s theaudiodb.com" msgctxt "#32106" msgid "Download artist bio from last.fm" -msgstr "" +msgstr "Preuzmi informacije životopisa izvođača s last.fm" msgctxt "#32107" msgid "Download similar artists from last.fm" -msgstr "" +msgstr "Preuzmi srodne izvođače s last.fm" msgctxt "#32108" msgid "Download all images regardless of resolution" -msgstr "" +msgstr "Preuzmi sve slike neovisno o razlučivosti" msgctxt "#32109" msgid "Client API key" -msgstr "" +msgstr "API ključ klijenta" msgctxt "#32110" msgid "I donate to this service" -msgstr "" +msgstr "Donirao sam ovoj usluzi" msgctxt "#32111" msgid "Use fallback slideshow" -msgstr "" +msgstr "Koristi pričuvne slike prezentacije" msgctxt "#32112" msgid "Use override slideshow" -msgstr "" +msgstr "Koristi zaobiđene slike prezentacije" msgctxt "#32113" msgid "Custom location" @@ -110,23 +110,23 @@ msgstr "Prilagođena lokacija" msgctxt "#32114" msgid "Include Kodi artist fanart" -msgstr "" +msgstr "Uključi Kodi slike omota izvođača" msgctxt "#32115" msgid "Include Kodi album fanart" -msgstr "" +msgstr "Uključi Kodi slike omota albuma" msgctxt "#32116" msgid "Limit size of download cache" -msgstr "" +msgstr "Ograničenje veličine predmemorije preuzimanja" msgctxt "#32117" msgid "Maximum cache size (in megabytes)" -msgstr "" +msgstr "Najveća veličina predmemorije (u megabajtima)" msgctxt "#32118" msgid "Alternate name for local fanart folder" -msgstr "" +msgstr "Zamjenski naziv za lokalnu mapu slika omota" msgctxt "#32119" msgid "Enable debug logging" @@ -134,19 +134,19 @@ msgstr "Omogući zapisivanje otklanjanja grešaka" msgctxt "#32120" msgid "Disable secondary and featured artist images" -msgstr "" +msgstr "Onemogući pomoćne i istaknute slike izvođača" msgctxt "#32121" msgid "Store artist images in" -msgstr "" +msgstr "Spremi slike izvođača u" msgctxt "#32122" msgid "addon_data folder" -msgstr "" +msgstr "addon_data mapa" msgctxt "#32123" msgid "Kodi artist information folder" -msgstr "" +msgstr "Kodi mapa informacija izvođača" msgctxt "#32124" msgid "Priority" @@ -154,97 +154,97 @@ msgstr "Prioritet" msgctxt "#32125" msgid "Store artist information in" -msgstr "" +msgstr "Spremi informacije izvođača u" msgctxt "#32126" msgid "Preferred language for artist bio" -msgstr "" +msgstr "Željeni jezik životopisa izvođača" msgctxt "#32127" msgid "Use extrafanart folder" -msgstr "" +msgstr "Koristi mapu dodatnih slika omota" msgctxt "#32128" msgid "Platform for image storage" -msgstr "" +msgstr "Platforma za pohranu slika" msgctxt "#32129" msgid "Replace illegal path characters in artist name with" -msgstr "" +msgstr "Zamijeni nevaljanu putanju znakova u nazivu izvođača s" msgctxt "#32130" msgid "Replace trailing period in artist name with" -msgstr "" +msgstr "Zamijenite točku na kraju nazivu izvođača s" msgctxt "#32131" msgid "Windows" -msgstr "" +msgstr "Windows" msgctxt "#32132" msgid "Other" -msgstr "" +msgstr "Ostali" msgctxt "#32133" msgid "MacOS" -msgstr "" +msgstr "MacOS" msgctxt "#32134" msgid "Move images to Kodi music artist folder" -msgstr "" +msgstr "Premjesti slike u Kodi glazbenu mapu izvođača" msgctxt "#32135" msgid "Get artist bio from Kodi" -msgstr "" +msgstr "Nabavi životopis izvođača s Kodija" msgctxt "#32136" msgid "Custom location" -msgstr "" +msgstr "Prilagođena lokacija" msgctxt "#32137" msgid "Delay between slide transitions (in seconds)" -msgstr "" +msgstr "Odgoda između prijelaza prezentacija (u sekundama)" msgctxt "#32138" msgid "Fade to black during change in artists" -msgstr "" +msgstr "Prijeđi u crno tijekom promjene izvođača" msgctxt "#32139" msgid "Main thread sleep time (in seconds)" -msgstr "" +msgstr "Vrijeme spavanja glavnog niza (u sekundama)" msgctxt "#32140" msgid "Main thread idle sleep time (in seconds)" -msgstr "" +msgstr "Vrijeme mirovanja spavanja glavnog niza (u sekundama)" msgctxt "#32141" msgid "Slideshow thread sleep time (in seconds)" -msgstr "" +msgstr "Vrijeme mirovanja niza prezentacije (u sekundama)" msgctxt "#32142" msgid "Show notification during image downloads" -msgstr "" +msgstr "Prikaži obavijesti tijekom preuzimanja slike" msgctxt "#32143" msgid "Only show notification if there are images to download" -msgstr "" +msgstr "Samo prikaži obavijesti ako ima slika za preuzimanje" msgctxt "#32144" msgid "Use more agressive artist search for streams" -msgstr "" +msgstr "Koristi agresivniju pretragu izvođača za strujanja" msgctxt "#32145" msgid "Pause slideshow on playback pause" -msgstr "" +msgstr "Pauziraj prezentaciju pri pauzi repordukcije" # empty strings from id 32145 to 32199 # Dialog headings msgctxt "#32200" msgid "Artist Slideshow" -msgstr "" +msgstr "Prezentacija izvođača" msgctxt "#32201" msgid "Warning" -msgstr "" +msgstr "Upozorenje" msgctxt "#32202" msgid "Error" @@ -252,235 +252,235 @@ msgstr "Greška" msgctxt "#32203" msgid "Progress" -msgstr "" +msgstr "Napredak" msgctxt "#32204" msgid "Downloading" -msgstr "" +msgstr "Preuzimanje" msgctxt "#32205" msgid "Download Complete" -msgstr "" +msgstr "Preuzimanje završeno" # empty strings from id 32206 to 32299 # Dialog texts msgctxt "#32300" msgid "This will move and rename your image files and cannot be undone. Are you sure you want to do this?" -msgstr "" +msgstr "Ovo će premjestiti i preimenovati vaše datoteke slika, i ovo se ne može poništiti. Sigurno želite ovo učiniti?" msgctxt "#32301" msgid "Unable to retrieve path to Kodi music artist image storage. Please check Settings > Media > Music and ensure the Artist Information Folder is set." -msgstr "" +msgstr "Nemoguće preuzimanje putanje u Kodi glazbenu pohranu slika izvođača. Provjerite Postavke > Mediji > Glazba i pobrinite se da je mapa informacija izvođača postavljena." msgctxt "#32302" msgid "Artist Slideshow is already set to use the Kodi artist information folder. Please set to use either addon_data folder or a custom location and try again." -msgstr "" +msgstr "Prezentacija izvođača je već postavljena da koristi Kodi mapu informacija izvođača. Postavite korištenje ili addon_data mape ili prilagođenu lokaciju i pokušajte ponovno." msgctxt "#32303" msgid "Moving and renaming images from custom location..." -msgstr "" +msgstr "Premještanje i preimenovanje slika iz prilagođene lokacije..." msgctxt "#32304" msgid "Moving and renaming images from addon_data folder..." -msgstr "" +msgstr "Premještanje i preimenovanje slika iz addon_data mape..." msgctxt "#32305" msgid "No artist directories found." -msgstr "" +msgstr "Nema pronađenih direktorija izvođača." msgctxt "#32306" msgid "Image move complete. You may now change the Artist Slideshow storage location to Kodi artist information folder." -msgstr "" +msgstr "Premještanje slika je završeno. Sada možete promijeniti lokaciju pohrane prezentacije izvođača u Kodi mapu informacija izvođača." msgctxt "#32307" msgid "Downloading new artist images" -msgstr "" +msgstr "Preuzimanje novih slika izvođača" msgctxt "#32308" msgid "artist images downloaded" -msgstr "" +msgstr "slike izvođača preuzete" msgctxt "#32309" msgid "artist image downloaded" -msgstr "" +msgstr "slika izvođača preuzeta" # empty strings from id 32310 to 32900 # Languages msgctxt "#32901" msgid "Albanian" -msgstr "" +msgstr "Albanski" msgctxt "#32902" msgid "Arabic" -msgstr "" +msgstr "Arapski" msgctxt "#32903" msgid "Belarusian" -msgstr "" +msgstr "Bjeloruski" msgctxt "#32904" msgid "Bosnian (Latin)" -msgstr "" +msgstr "Bosanski (Latinica)" msgctxt "#32905" msgid "Bulgarian" -msgstr "" +msgstr "Bugarski" msgctxt "#32906" msgid "Catalan" -msgstr "" +msgstr "Katalonski" msgctxt "#32907" msgid "Chinese" -msgstr "" +msgstr "Kineski" msgctxt "#32908" msgid "Croatian" -msgstr "" +msgstr "Hrvatski" msgctxt "#32909" msgid "Czech" -msgstr "" +msgstr "Češki" msgctxt "#32910" msgid "Danish" -msgstr "" +msgstr "Danski" msgctxt "#32911" msgid "Dutch" -msgstr "" +msgstr "Nizozemski" msgctxt "#32912" msgid "English" -msgstr "" +msgstr "Engleski" msgctxt "#32913" msgid "Estonian" -msgstr "" +msgstr "Estonski" msgctxt "#32914" msgid "Finnish" -msgstr "" +msgstr "Finski" msgctxt "#32915" msgid "French" -msgstr "" +msgstr "Francuski" msgctxt "#32916" msgid "German" -msgstr "" +msgstr "Njemački" msgctxt "#32917" msgid "Greek" -msgstr "" +msgstr "Grčki" msgctxt "#32918" msgid "Hebrew" -msgstr "" +msgstr "Hebrejski" msgctxt "#32919" msgid "Hindi" -msgstr "" +msgstr "Hindski" msgctxt "#32920" msgid "Hungarian" -msgstr "" +msgstr "Mađarski" msgctxt "#32921" msgid "Icelandic" -msgstr "" +msgstr "Islandski" msgctxt "#32922" msgid "Indonesian" -msgstr "" +msgstr "Indonezijski" # empty string with id 32923 msgctxt "#32924" msgid "Italian" -msgstr "" +msgstr "Talijanski" msgctxt "#32925" msgid "Japanese" -msgstr "" +msgstr "Japanski" msgctxt "#32926" msgid "Korean" -msgstr "" +msgstr "Korejski" msgctxt "#32927" msgid "Latvian" -msgstr "" +msgstr "Latvijski" msgctxt "#32928" msgid "Lithuanian" -msgstr "" +msgstr "Letonski" msgctxt "#32929" msgid "Macedonian" -msgstr "" +msgstr "Makedonski" msgctxt "#32930" msgid "Norwegian" -msgstr "" +msgstr "Norveški" # empty string with id 32931 msgctxt "#32932" msgid "Polish" -msgstr "" +msgstr "Poljski" msgctxt "#32933" msgid "Portuguese" -msgstr "" +msgstr "Portugalski" msgctxt "#32934" msgid "Portuguese (Brazil)" -msgstr "" +msgstr "Portugalski (Brazil)" msgctxt "#32935" msgid "Romanian" -msgstr "" +msgstr "Rumunjski" msgctxt "#32936" msgid "Russian" -msgstr "" +msgstr "Ruski" msgctxt "#32937" msgid "SerbianLatin" -msgstr "" +msgstr "Srpski latinica" msgctxt "#32938" msgid "Slovak" -msgstr "" +msgstr "Slovački" msgctxt "#32939" msgid "Slovenian" -msgstr "" +msgstr "Slovenski" msgctxt "#32940" msgid "Spanish" -msgstr "" +msgstr "Španjolski" # empty string with id 32941 msgctxt "#32942" msgid "Swedish" -msgstr "" +msgstr "Švedski" msgctxt "#32943" msgid "Thai" -msgstr "" +msgstr "Tajlandski" msgctxt "#32944" msgid "Turkish" -msgstr "" +msgstr "Turski" msgctxt "#32945" msgid "Ukrainian" -msgstr "" +msgstr "Ukrajinski" msgctxt "#32946" msgid "Vietnamese" -msgstr "" +msgstr "Vijetnamski" msgctxt "#32947" msgid "Farsi" -msgstr "" +msgstr "Farsi" diff --git a/script.artistslideshow/resources/language/resource.language.it_it/strings.po b/script.artistslideshow/resources/language/resource.language.it_it/strings.po index d3711106e..0b0546682 100644 --- a/script.artistslideshow/resources/language/resource.language.it_it/strings.po +++ b/script.artistslideshow/resources/language/resource.language.it_it/strings.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-08-23 07:14+0000\n" +"PO-Revision-Date: 2023-05-16 13:16+0000\n" "Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -28,7 +28,7 @@ msgstr "Addon per scaricare immagini ed informazioni aggiuntive da fanart.tv e t # Section Headings msgctxt "#32000" msgid "Slideshow" -msgstr "Slideshow" +msgstr "Presentazione" msgctxt "#32001" msgid "Storage" diff --git a/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po b/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po index a0d5e177e..521ed185a 100644 --- a/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po +++ b/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-11-09 20:21+0000\n" +"PO-Revision-Date: 2023-04-25 18:16+0000\n" "Last-Translator: vgbsd \n" "Language-Team: Russian \n" "Language: ru_ru\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.14.2\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -110,11 +110,11 @@ msgstr "Собственное расположение" msgctxt "#32114" msgid "Include Kodi artist fanart" -msgstr "Включить иллюстрации художников Kodi" +msgstr "Использовать иллюстрации исполнителей из Kodi" msgctxt "#32115" msgid "Include Kodi album fanart" -msgstr "Включить обложки альбомов Kodi" +msgstr "Использовать обложки альбомов из Kodi" msgctxt "#32116" msgid "Limit size of download cache" @@ -170,11 +170,11 @@ msgstr "Платформа хранения изображений" msgctxt "#32129" msgid "Replace illegal path characters in artist name with" -msgstr "Замените недопустимые символы пути в имени исполнителя" +msgstr "Заменить недопустимые символы пути в имени исполнителя на" msgctxt "#32130" msgid "Replace trailing period in artist name with" -msgstr "" +msgstr "Заменить точку в имени исполнителя на" msgctxt "#32131" msgid "Windows" @@ -218,7 +218,7 @@ msgstr "Время ожидания бездействия основного п msgctxt "#32141" msgid "Slideshow thread sleep time (in seconds)" -msgstr "" +msgstr "Время задержки в режиме слайд-шоу (в секундах)" msgctxt "#32142" msgid "Show notification during image downloads" @@ -244,7 +244,7 @@ msgstr "Слайд-шоу исполнителей" msgctxt "#32201" msgid "Warning" -msgstr "" +msgstr "Внимание" msgctxt "#32202" msgid "Error" @@ -252,7 +252,7 @@ msgstr "Ошибка" msgctxt "#32203" msgid "Progress" -msgstr "" +msgstr "Прогресс" msgctxt "#32204" msgid "Downloading" @@ -274,7 +274,7 @@ msgstr "Не удаётся установить путь к каталогу с msgctxt "#32302" msgid "Artist Slideshow is already set to use the Kodi artist information folder. Please set to use either addon_data folder or a custom location and try again." -msgstr "" +msgstr "Artist Slideshow уже настроено на использование папки с информацией об исполнителе в Kodi. Пожалуйста, задайте использование папки addon_data или пользовательского расположения и повторите попытку." msgctxt "#32303" msgid "Moving and renaming images from custom location..." @@ -282,7 +282,7 @@ msgstr "Перемещение и переименование изображе msgctxt "#32304" msgid "Moving and renaming images from addon_data folder..." -msgstr "" +msgstr "Перемещение и переименование изображений из папки addon_data..." msgctxt "#32305" msgid "No artist directories found." diff --git a/script.artistslideshow/resources/language/resource.language.sk_sk/strings.po b/script.artistslideshow/resources/language/resource.language.sk_sk/strings.po index 276096272..f83eed9f1 100644 --- a/script.artistslideshow/resources/language/resource.language.sk_sk/strings.po +++ b/script.artistslideshow/resources/language/resource.language.sk_sk/strings.po @@ -5,9 +5,9 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-04-08 00:13+0000\n" +"PO-Revision-Date: 2023-04-11 08:16+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Slovak \n" "Language: sk_sk\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 4.11.2\n" +"X-Generator: Weblate 4.15.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -52,7 +52,7 @@ msgstr "" msgctxt "#32006" msgid "Advanced" -msgstr "" +msgstr "Pokročilé" # empty strings from id 32007 to 32099 # Settings diff --git a/script.artistslideshow/resources/lib/artistslideshow.py b/script.artistslideshow/resources/lib/artistslideshow.py index c929f3619..1d31d6950 100644 --- a/script.artistslideshow/resources/lib/artistslideshow.py +++ b/script.artistslideshow/resources/lib/artistslideshow.py @@ -25,8 +25,9 @@ import threading import time import json as _json -from kodi_six import xbmc, xbmcgui, xbmcvfs -from kodi_six.utils import py2_encode, py2_decode +import xbmc +import xbmcgui +import xbmcvfs from resources.plugins import * from resources.lib.fileops import * from resources.lib.url import URL @@ -115,7 +116,7 @@ def AddImage(self, path): if not path: LW.log(['Image path was empty, nothing added']) return False - if path.endswith(self.VALIDIMAGETYPES): + if path.lower().endswith(self.VALIDIMAGETYPES): self.IMAGES.append(path) LW.log(['Added to image display group: ' + path]) self.IMAGEADDED = True @@ -293,8 +294,7 @@ def _clean_dir(self, dir_path): LW.log(['unexpected error while getting directory list', e]) return for old_file in old_files: - success, loglines = deleteFile( - os.path.join(dir_path, py2_encode(old_file))) + success, loglines = deleteFile(os.path.join(dir_path, old_file)) LW.log(loglines) def _clean_text(self, text): @@ -438,7 +438,7 @@ def _get_artistbio(self): bio_params['mbid'] = self.MBID bio_params['infodir'] = self.INFODIR bio_params['localartistdir'] = os.path.join( - self.LOCALARTISTPATH, py2_decode(self.NAME)) + self.LOCALARTISTPATH, self.NAME) bio_params['lang'] = self.LANGUAGE bio_params['artist'] = self.NAME bio = '' @@ -464,7 +464,7 @@ def _get_artistalbums(self): album_params = {} album_params['infodir'] = self.INFODIR album_params['localartistdir'] = os.path.join( - self.LOCALARTISTPATH, py2_decode(self.NAME)) + self.LOCALARTISTPATH, self.NAME) album_params['lang'] = self.LANGUAGE album_params['artist'] = self.NAME albums = [] @@ -491,7 +491,7 @@ def _get_artistsimilar(self): similar_params = {} similar_params['infodir'] = self.INFODIR similar_params['localartistdir'] = os.path.join( - self.LOCALARTISTPATH, py2_decode(self.NAME)) + self.LOCALARTISTPATH, self.NAME) similar_params['lang'] = self.LANGUAGE similar_params['artist'] = self.NAME similar_artists = [] @@ -562,8 +562,8 @@ def _get_current_artists_filtered(self, artist_names, mbids): LW.log(['left with', artist_names]) for artist_name, mbid in _zip_longest(artist_names, mbids, fillvalue=''): if artist_name: - artists_info.append((py2_encode(artist_name), self._get_musicbrainz_id( - py2_encode(artist_name), mbid))) + artists_info.append( + (artist_name, self._get_musicbrainz_id(artist_name, mbid))) return artists_info def _get_current_artists_info(self): @@ -961,11 +961,10 @@ def _move_to_kodi_storage(self): for thedir in dirs: if (src == self.LOCALARTISTPATH) and self.USEFANARTFOLDER: image_src = os.path.join( - self.LOCALARTISTPATH, py2_decode(thedir), self.FANARTFOLDER) + self.LOCALARTISTPATH, thedir, self.FANARTFOLDER) else: - image_src = os.path.join(src, py2_decode(thedir)) - image_dest = os.path.join( - kodi_music_artist_path, py2_decode(thedir)) + image_src = os.path.join(src, thedir) + image_dest = os.path.join(kodi_music_artist_path, thedir) LW.log(['moving images from %s to %s' % (image_src, image_dest)]) files = self._get_file_list(image_src) self.FANARTNUMBER = False @@ -1050,7 +1049,7 @@ def _remove_trailing_dot(self, thename): def _set_artwork_from_dir(self, thedir, files): for thefile in files: - self.SLIDESHOW.AddImage(os.path.join(thedir, py2_decode(thefile))) + self.SLIDESHOW.AddImage(os.path.join(thedir, thefile)) def _set_cachedir(self, theartist): self.CACHEDIR = self._set_thedir(theartist, 'ArtistSlideshow') @@ -1122,10 +1121,6 @@ def _set_safe_artist_name(self, theartist): s_name = s_name + self.ILLEGALREPLACE else: s_name = s_name + c - try: - s_name = py2_decode(s_name) - except UnicodeDecodeError: - s_name = '' return s_name def _set_thedir(self, theartist, dirtype): @@ -1158,14 +1153,13 @@ def _trim_cache(self): if (now - self.LASTCACHETRIM > cache_trim_delay): LW.log(['trimming the cache down to %s bytes' % self.MAXCACHESIZE]) - cache_root = py2_encode(os.path.join( - ADDONDATAPATH, 'ArtistSlideshow', '')) + cache_root = os.path.join(ADDONDATAPATH, 'ArtistSlideshow', '') folders, fls = xbmcvfs.listdir(cache_root) LW.log(['cache folders returned:']) LW.log(folders) try: folders.sort(key=lambda x: os.path.getmtime( - os.path.join(cache_root, py2_encode(x))), reverse=True) + os.path.join(cache_root, x)), reverse=True) except Exception as e: LW.log(['unexpected error sorting cache directory', e]) return @@ -1175,19 +1169,17 @@ def _trim_cache(self): if self._playback_stopped_or_changed(wait_time=0.1): break cache_size = cache_size + \ - self._get_folder_size(os.path.join( - cache_root, py2_encode(folder))) + self._get_folder_size(os.path.join(cache_root, folder)) LW.log(['looking at folder %s cache size is now %s' % (folder, cache_size)]) if (cache_size > self.MAXCACHESIZE and not first_folder): - self._trim_one_folder(os.path.join( - cache_root, py2_encode(folder))) + self._trim_one_folder(os.path.join(cache_root, folder)) if self.LOCALINFOSTORAGE and self.LOCALINFOPATH: - self._trim_one_folder(os.path.join(self.LOCALINFOPATH, py2_decode( - folder))) + self._trim_one_folder( + os.path.join(self.LOCALINFOPATH, folder)) else: self._trim_one_folder(os.path.join( - ADDONDATAPATH, 'ArtistInformation', py2_decode(folder))) + ADDONDATAPATH, 'ArtistInformation', folder)) first_folder = False self.LASTCACHETRIM = now @@ -1231,8 +1223,8 @@ def _use_correct_artwork(self): self.ARTISTNUM += 1 self.NAME = artist self.MBID = mbid - self._set_infodir(py2_decode(self.NAME)) - self._set_cachedir(py2_decode(self.NAME)) + self._set_infodir(self.NAME) + self._set_cachedir(self.NAME) if (self.ARTISTNUM == 1): self._get_artistinfo() images = self._get_file_list(self.CACHEDIR, do_filter=True) @@ -1300,10 +1292,8 @@ def _upgrade(self): dirs = [] if dirs: for thedir in dirs: - src = os.path.join( - src_root, py2_decode(thedir), self.IMGDB) - dst = os.path.join( - dst_root, py2_decode(thedir), self.IMGDB) + src = os.path.join(src_root, thedir, self.IMGDB) + dst = os.path.join(dst_root, thedir, self.IMGDB) success, loglines = moveFile(src, dst) LW.log(loglines) src_root = getSettingString('local_artist_path') @@ -1319,10 +1309,10 @@ def _upgrade(self): dirs = [] if dirs: for thedir in dirs: - src = os.path.join(src_root, py2_decode( - thedir), self.FANARTFOLDER, self.IMGDB) - dst = os.path.join(dst_root, py2_decode( - thedir), 'information', self.IMGDB) + src = os.path.join( + src_root, thedir, self.FANARTFOLDER, self.IMGDB) + dst = os.path.join( + dst_root, thedir, 'information', self.IMGDB) success, loglines = moveFile(src, dst) LW.log(loglines) self._update_check_file( diff --git a/script.artistslideshow/resources/lib/fileops.py b/script.artistslideshow/resources/lib/fileops.py index 7c5803ed7..311ea66d7 100644 --- a/script.artistslideshow/resources/lib/fileops.py +++ b/script.artistslideshow/resources/lib/fileops.py @@ -4,7 +4,7 @@ import re import sys try: - from kodi_six import xbmcvfs + import xbmcvfs isXBMC = True except ImportError: isXBMC = False diff --git a/script.artistslideshow/resources/lib/xlogger.py b/script.artistslideshow/resources/lib/xlogger.py index 67aa3d7ba..6e21ced8e 100644 --- a/script.artistslideshow/resources/lib/xlogger.py +++ b/script.artistslideshow/resources/lib/xlogger.py @@ -1,7 +1,7 @@ # v.0.4.14 try: - from kodi_six import xbmc + import xbmc LOGTYPE = 'xbmc' except ImportError: import os diff --git a/script.artistslideshow/resources/plugins/fanarttv.py b/script.artistslideshow/resources/plugins/fanarttv.py index 9b2c31188..2aa7a50b7 100644 --- a/script.artistslideshow/resources/plugins/fanarttv.py +++ b/script.artistslideshow/resources/plugins/fanarttv.py @@ -4,10 +4,9 @@ import os import time import random -from kodi_six import xbmcvfs +import xbmcvfs from resources.lib.url import URL from resources.lib.fileops import readFile, writeFile, deleteFile, checkPath -from kodi_six.utils import py2_encode import json as _json try: from . import fanarttv_info as settings @@ -102,7 +101,7 @@ def _get_data(self, filepath, cachefilepath, url, url_params): self.LOGLINES.extend(uloglines) if success: success, wloglines = writeFile( - py2_encode(_json.dumps(json_data)), filepath) + _json.dumps(json_data), filepath) self.LOGLINES.extend(wloglines) exists, cloglines = checkPath(filepath, False) self.LOGLINES.extend(cloglines) diff --git a/script.artistslideshow/resources/plugins/kodi.py b/script.artistslideshow/resources/plugins/kodi.py index 9f4dfc9ec..2ef28f858 100644 --- a/script.artistslideshow/resources/plugins/kodi.py +++ b/script.artistslideshow/resources/plugins/kodi.py @@ -1,6 +1,6 @@ # v.0.3.0 -from kodi_six import xbmc +import xbmc import json as _json diff --git a/script.artistslideshow/resources/plugins/lastfm.py b/script.artistslideshow/resources/plugins/lastfm.py index 5c361c590..480ccd504 100644 --- a/script.artistslideshow/resources/plugins/lastfm.py +++ b/script.artistslideshow/resources/plugins/lastfm.py @@ -7,8 +7,7 @@ import defusedxml.ElementTree as _xmltree from resources.lib.url import URL from resources.lib.fileops import readFile, writeFile, checkPath -from kodi_six.utils import py2_encode -from kodi_six import xbmcvfs +import xbmcvfs try: from . import lastfm_info as settings except ImportError: @@ -55,8 +54,8 @@ def getAlbumList(self, album_params): list(additionalparams.items())) self.LOGLINES.append('trying to get artist albums from ' + self.URL) try: - xmldata = _xmltree.fromstring(py2_encode( - self._get_data(filepath, cachefilepath, url_params))) + xmldata = _xmltree.fromstring(self._get_data( + filepath, cachefilepath, url_params)) except _xmltree.ParseError: self.LOGLINES.append('error reading XML file') return [], self.LOGLINES @@ -66,7 +65,7 @@ def getAlbumList(self, album_params): if match: match = False else: - name = py2_encode(element.text) + name = element.text match = True elif element.tag == "image": if element.attrib.get('size') == "extralarge": @@ -95,8 +94,8 @@ def getBio(self, bio_params): list(additionalparams.items())) self.LOGLINES.append('trying to get artist bio from ' + self.URL) try: - xmldata = _xmltree.fromstring(py2_encode( - self._get_data(filepath, cachefilepath, url_params))) + xmldata = _xmltree.fromstring( + self._get_data(filepath, cachefilepath, url_params)) except _xmltree.ParseError: self.LOGLINES.append('error reading XML file') return '', self.LOGLINES @@ -122,8 +121,8 @@ def getSimilarArtists(self, sim_params): list(additionalparams.items())) self.LOGLINES.append('trying to get similar artists from ' + self.URL) try: - xmldata = _xmltree.fromstring(py2_encode( - self._get_data(filepath, cachefilepath, url_params))) + xmldata = _xmltree.fromstring( + self._get_data(filepath, cachefilepath, url_params)) except _xmltree.ParseError: self.LOGLINES.append('error reading XML file') return [], self.LOGLINES @@ -133,7 +132,7 @@ def getSimilarArtists(self, sim_params): if match: match = False else: - name = py2_encode(element.text) + name = element.text match = True elif element.tag == "image": if element.attrib.get('size') == "extralarge": @@ -159,7 +158,7 @@ def getMBID(self, mbid_params): rloglines, rawxml = readFile(filepath) self.LOGLINES.extend(rloglines) try: - xmldata = _xmltree.fromstring(py2_encode(rawxml)) + xmldata = _xmltree.fromstring(rawxml) except _xmltree.ParseError: self.LOGLINES.append( 'error reading musicbrainz ID from ' + filepath) @@ -198,7 +197,7 @@ def _get_data(self, filepath, cachefilepath, url_params): self.URL, params=url_params) self.LOGLINES.extend(uloglines) if success: - success, wloglines = writeFile(py2_encode(data), filepath) + success, wloglines = writeFile(data, filepath) self.LOGLINES.extend(wloglines) exists, cloglines = checkPath(filepath, False) self.LOGLINES.extend(cloglines) diff --git a/script.artistslideshow/resources/plugins/local.py b/script.artistslideshow/resources/plugins/local.py index 14e7dc7a9..10a1e5bea 100644 --- a/script.artistslideshow/resources/plugins/local.py +++ b/script.artistslideshow/resources/plugins/local.py @@ -3,7 +3,6 @@ import os import defusedxml.ElementTree as _xmltree from resources.lib.fileops import readFile, checkPath -from kodi_six.utils import py2_encode, py2_decode class objectConfig(object): @@ -21,18 +20,18 @@ def getAlbumList(self, album_params): albums = [] filepath = os.path.join(album_params.get( 'localartistdir', ''), self.ALBUMFILEPATH) - local_path = os.path.join(album_params.get('localartistdir', ''), py2_decode( - album_params.get('artist', '')), 'override') + local_path = os.path.join(album_params.get( + 'localartistdir', ''), album_params.get('artist', ''), 'override') self.loglines.append('checking ' + filepath) rloglines, rawxml = readFile(filepath) self.loglines.extend(rloglines) if rawxml: - xmldata = _xmltree.fromstring(py2_encode(rawxml)) + xmldata = _xmltree.fromstring(rawxml) else: return [], self.loglines for element in xmldata.iter(): if element.tag == "name": - name = py2_encode(element.text) + name = element.text elif element.tag == "image": image_text = element.text if not image_text: @@ -55,7 +54,7 @@ def getBio(self, bio_params): loglines, rawxml = readFile(filepath) self.loglines.extend(loglines) if rawxml: - xmldata = _xmltree.fromstring(py2_encode(rawxml)) + xmldata = _xmltree.fromstring(rawxml) else: return '', self.loglines for element in xmldata.iter(): @@ -85,18 +84,18 @@ def getSimilarArtists(self, sim_params): similar_artists = [] filepath = os.path.join(sim_params.get( 'localartistdir', ''), self.SIMILARFILEPATH) - local_path = os.path.join(sim_params.get('localartistdir', ''), py2_decode( - sim_params.get('artist', '')), 'override') + local_path = os.path.join(sim_params.get('localartistdir', ''), + sim_params.get('artist', ''), 'override') self.loglines.append('checking ' + filepath) rloglines, rawxml = readFile(filepath) self.loglines.extend(rloglines) if rawxml: - xmldata = _xmltree.fromstring(py2_encode(rawxml)) + xmldata = _xmltree.fromstring(rawxml) else: return [], self.loglines for element in xmldata.iter(): if element.tag == "name": - name = py2_encode(element.text) + name = element.text elif element.tag == "image": image_text = element.text if not image_text: diff --git a/script.artistslideshow/resources/plugins/theaudiodb.py b/script.artistslideshow/resources/plugins/theaudiodb.py index a3ae4c2bd..77c68317f 100644 --- a/script.artistslideshow/resources/plugins/theaudiodb.py +++ b/script.artistslideshow/resources/plugins/theaudiodb.py @@ -4,10 +4,9 @@ import os import time import random -from kodi_six import xbmcvfs +import xbmcvfs from resources.lib.url import URL from resources.lib.fileops import readFile, writeFile, deleteFile, checkPath -from kodi_six.utils import py2_encode import json as _json try: from . import theaudiodb_info as settings @@ -225,7 +224,7 @@ def _get_data(self, filepath, cachefilepath, url, url_params): self.LOGLINES.extend(uloglines) if success: success, wloglines = writeFile( - py2_encode(_json.dumps(json_data)), filepath) + _json.dumps(json_data), filepath) self.LOGLINES.extend(wloglines) exists, cloglines = checkPath(filepath, False) self.LOGLINES.extend(cloglines) From 39eca545c077bc1ab913ebe6a15219336f46e0c4 Mon Sep 17 00:00:00 2001 From: Allertj <44700026+Allertj@users.noreply.github.com> Date: Mon, 29 May 2023 15:50:27 +0200 Subject: [PATCH 045/145] [script.sublissimo] 2.0.4 (#2458) --- script.sublissimo/addon.xml | 4 +- .../resource.language.es_es/strings.po | 938 ++++++++++++++++++ .../resource.language.it_it/strings.po | 54 +- 3 files changed, 968 insertions(+), 28 deletions(-) create mode 100644 script.sublissimo/resources/language/resource.language.es_es/strings.po diff --git a/script.sublissimo/addon.xml b/script.sublissimo/addon.xml index 084ad133d..65ce35585 100644 --- a/script.sublissimo/addon.xml +++ b/script.sublissimo/addon.xml @@ -1,5 +1,5 @@ - + @@ -26,6 +26,7 @@ Muokkaa ja ajoita tekstitykset kauko-ohjaimellasi Modifica e sincronizza i sottotitoli con il telecomando 리모컨으로 자막 편집 및 동기화 + Editar y sincronizar subtítulos con el mando a distancia 使用遥控器编辑和同步字幕 Mit diesem Skript lassen sich bestimmte Zeilen bearbeiten, Untertitel verschieben oder strecken und mit anderen Untertiteln synchronisieren. Sie können auch mit einer Videodatei synchronisiert werden.[CR][CR]Um diesen Editor einfach zu verwenden, ihn während der Wiedergabe des Videos und des Untertitels, den bearbeiten werden soll, starten. With this script you can edit specific lines, move or stretch subtitles, and synchronize with other subtitles. You can also synchronize with a videofile.[CR][CR]To easily use this editor, launch it when the video and subtitle you wish to edit are playing. @@ -33,6 +34,7 @@ Tällä lisäosalla voidaan muokata yksittäisiä tekstitysrivejä, siirtää ja venyttää tekstityksiä sekä tahdistaa niitä muiden tekstitysten ja videotiedostojen kanssa.[CR][CR]Editorin käynnistys onnistuu helposti suoraan toistettaessa muokkausta vaativaa videota ja tekstitystä. Con questo script puoi modificare righe specifiche, spostare o allungare i sottotitoli e sincronizzare con altri sottotitoli. Puoi anche sincronizzare con un file video.[CR][CR]Per utilizzare facilmente questo editor, avvialo quando il video e i sottotitoli che desideri modificare sono in riproduzione. 이 스크립트를 사용하면 특정 줄을 편집하고, 자막을 이동하거나 늘리고, 다른 자막과 동기화할 수 있습니다. 비디오 파일과 동기화할 수도 있습니다. + Con este script puedes editar líneas específicas, mover o estirar subtítulos y sincronizarlos con otros subtítulos. También puedes sincronizar con un archivo de vídeo.[CR][CR]Para usar fácilmente este editor, lánzalo cuando se estén reproduciendo el vídeo y el subtítulo que deseas editar. 您可以使用此脚本编辑特定行、移动或拉伸字幕,以及与其他字幕同步。您还可以与视频文件同步。[CR][CR]要轻松使用此编辑器,请在要编辑的字幕与视频播放时启动它。 diff --git a/script.sublissimo/resources/language/resource.language.es_es/strings.po b/script.sublissimo/resources/language/resource.language.es_es/strings.po new file mode 100644 index 000000000..15f57363a --- /dev/null +++ b/script.sublissimo/resources/language/resource.language.es_es/strings.po @@ -0,0 +1,938 @@ +# Kodi Media Center language file +# Addon Name: Sublissimo +# Addon id: script.sublissimo +# Addon Provider: AJVM +msgid "" +msgstr "" +"Project-Id-Version: XBMC Addons\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2023-04-26 20:16+0000\n" +"Last-Translator: José Antonio Alvarado \n" +"Language-Team: Spanish (Spain) \n" +"Language: es_es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.15.2\n" + +msgctxt "Addon Summary" +msgid "Edit and synchronize subtitles with your remote" +msgstr "Editar y sincronizar subtítulos con el mando a distancia" + +msgctxt "Addon Description" +msgid "With this script you can edit specific lines, move or stretch subtitles, and synchronize with other subtitles. You can also synchronize with a videofile.[CR][CR]To easily use this editor, launch it when the video and subtitle you wish to edit are playing." +msgstr "Con este script puedes editar líneas específicas, mover o estirar subtítulos y sincronizarlos con otros subtítulos. También puedes sincronizar con un archivo de vídeo.[CR][CR]Para usar fácilmente este editor, lánzalo cuando se estén reproduciendo el vídeo y el subtítulo que deseas editar." + +msgctxt "#31000" +msgid "Scroll subtitles" +msgstr "Desplazarse por los subtítulos" + +msgctxt "#30001" +msgid "Edit or delete lines" +msgstr "Editar o eliminar líneas" + +msgctxt "#31002" +msgid "Move subtitles" +msgstr "Mover subtítulos" + +msgctxt "#31003" +msgid "Stretch/shrink subtitles" +msgstr "Estirar/reducir subtítulos" + +msgctxt "#31004" +msgid "Synchronize with other subtitle" +msgstr "Sincronizar con otro subtítulo" + +msgctxt "#31005" +msgid "Synchronize with video file" +msgstr "Sincronizar con archivo de vídeo" + +msgctxt "#31006" +msgid "Search in subtitle" +msgstr "Buscar en subtítulo" + +msgctxt "#31007" +msgid "Check integrity" +msgstr "Comprobar integridad" + +msgctxt "#31008" +msgid "Save subtitles" +msgstr "Guardar subtítulos" + +msgctxt "#31009" +msgid "Quit" +msgstr "Abandonar" + +msgctxt "#31010" +msgid "Synchronize by frame rate" +msgstr "Sincronizar por tasa de fotogramas" + +msgctxt "#31011" +msgid "Play video with edited subtitle" +msgstr "Reproducir vídeo con subtítulos editados" + +msgctxt "#31013" +msgid "Advanced options" +msgstr "Opciones avanzadas" + +msgctxt "#31001" +msgid "Sublissimo" +msgstr "Sublissimo" + +msgctxt "#33000" +msgid "" +"Select the subtitle to synchronize with. Then:[CR]- Select a timecode in the " +"beginning to a line as reference[CR]- Select the roughly the same line in " +"your subtitle[CR]- Then do same with two lines near the end of both files." +msgstr "Seleccionar el subtítulo con el que sincronizar. Luego:[CR]- Seleccionar un código de tiempo al principio de una línea como referencia[CR]- Seleccionar aproximadamente la misma línea en su subtítulo[CR]- Luego hacer lo mismo con dos líneas cerca del final de ambos archivos." + +msgctxt "#32001" +msgid "Edit line" +msgstr "Editar línea" + +msgctxt "#32002" +msgid "Delete First Subtitle" +msgstr "Borrar el primer subtítulo" + +msgctxt "#32003" +msgid "Delete Last Subtitle" +msgstr "Borrar el último subtítulo" + +msgctxt "#32004" +msgid "Manually Scroll and Delete" +msgstr "Desplazarse y borrar manualmente" + +msgctxt "#32005" +msgid "Back" +msgstr "Atrás" + +msgctxt "#32006" +msgid "Delete this subtitle?" +msgstr "¿Borrar este subtítulo?" + +msgctxt "#32007" +msgid "Select subtitle to edit" +msgstr "Seleccionar subtítulo a editar" + +msgctxt "#32008" +msgid "Return" +msgstr "Retorno" + +msgctxt "#32009" +msgid "Delete" +msgstr "Eliminar" + +msgctxt "#32010" +msgid "All subtitles" +msgstr "Todos los subtítulos" + +msgctxt "#32011" +msgid "Found:" +msgstr "Encontrado:" + +msgctxt "#32012" +msgid "OK" +msgstr "OK" + +msgctxt "#32013" +msgid "More Info" +msgstr "Más información" + +msgctxt "#32014" +msgid "Error" +msgstr "Error" + +msgctxt "#32015" +msgid "Select subtitle to synchronize with" +msgstr "Seleccionar subtítulo para sincronizar con" + +msgctxt "#32016" +msgid "Please select a .srt or a .sub file" +msgstr "Por favor, seleccionar un archivo .srt o .sub" + +msgctxt "#32017" +msgid "Success" +msgstr "Éxito" + +msgctxt "#32018" +msgid "Current first subtitle" +msgstr "Primer subtítulo actual" + +msgctxt "#32019" +msgid "First subtitle is now:" +msgstr "El primer subtítulo es ahora:" + +msgctxt "#32020" +msgid "Please select a video file." +msgstr "Seleccione un archivo de vídeo." + +msgctxt "#32021" +msgid "Current last subtitle" +msgstr "Último subtítulo actual" + +msgctxt "#32022" +msgid "Last subtitle is now:" +msgstr "El último subtítulo es ahora:" + +msgctxt "#32023" +msgid "Enter search string" +msgstr "Introduzca cadena de búsqueda" + +msgctxt "#32024" +msgid "Yes" +msgstr "Si" + +msgctxt "#32025" +msgid "No" +msgstr "No" + +msgctxt "#32026" +msgid "This editor only works with .srt or .sub files" +msgstr "Este editor sólo funciona con archivos .srt o .sub" + +msgctxt "#32027" +msgid "File not found: " +msgstr "Archivo no encontrado: " + +msgctxt "#32028" +msgid "" +"Write the new timestamp for the end position, seperated by a ':'. For " +"instance: 01:22:23:000" +msgstr "Escriba la nueva marca de tiempo para la posición final, separada por un ':'. Por ejemplo: 01:22:23:000" + +msgctxt "#32029" +msgid "For example: 01:22:23:000" +msgstr "Por ejemplo: 01:22:23:000" + +msgctxt "#32030" +msgid "Report" +msgstr "Informe" + +msgctxt "#32031" +msgid "No problems detected" +msgstr "No se han detectado problemas" + +msgctxt "#32032" +msgid "Line:" +msgstr "Línea:" + +msgctxt "#33032" +msgid "Line " +msgstr "Línea " + +msgctxt "#32033" +msgid "Possible problems: " +msgstr "Posibles problemas: " + +msgctxt "#32034" +msgid "Select subtitle to continue..." +msgstr "Seleccionar subtítulo para continuar..." + +msgctxt "#32035" +msgid "Select subtitle to edit" +msgstr "Seleccionar subtítulo a editar" + +msgctxt "#32036" +msgid "Your subtitle starts at " +msgstr "Tu subtítulo comienza en " + +msgctxt "#32037" +msgid "Your subtitle ends at " +msgstr "Tu subtítulo termina en " + +msgctxt "#32038" +msgid "Save with _edited.srt added" +msgstr "Guardar con _edited.srt añadido" + +msgctxt "#32039" +msgid "Save with current filename" +msgstr "Guardar con el nombre del archivo actual" + +msgctxt "#32040" +msgid "Save with custom filename" +msgstr "Guardar con nombre de archivo personalizado" + +msgctxt "#32041" +msgid "Exit without saving" +msgstr "Salir sin guardar" + +msgctxt "#32042" +msgid "Give new filename: " +msgstr "Dar un nuevo nombre de archivo: " + +msgctxt "#32043" +msgid "Written to: " +msgstr "Escrito a: " + +msgctxt "#32044" +msgid "" +"To use the file, select it in the Kodi player subtitle menu when playing the " +"file" +msgstr "Para usar el archivo, seleccionar en el menú de subtítulos del reproductor Kodi cuando se reproduce el archivo" + +msgctxt "#32045" +msgid "File not written" +msgstr "Fichero no escrito" + +msgctxt "#32046" +msgid "Warning" +msgstr "Advertencia" + +msgctxt "#32047" +msgid "You might have unsaved progress on your file" +msgstr "Es posible que haya progreso sin guardar en su archivo" + +msgctxt "#32048" +msgid "Exit Anyway" +msgstr "Salir de todos modos" + +msgctxt "#32049" +msgid "Save" +msgstr "Guardar" + +msgctxt "#32050" +msgid "Subtitles succesfully synced" +msgstr "Subtítulos sincronizados correctamente" + +msgctxt "#32051" +msgid "Move forwards" +msgstr "Avanzar" + +msgctxt "#32052" +msgid "Move backwards" +msgstr "Retroceder" + +msgctxt "#32053" +msgid "Give new time for first subtitle" +msgstr "Dar nuevo tiempo para el primer subtítulo" + +msgctxt "#32054" +msgid "Move forwards by: HH:MM:SS:MSE" +msgstr "Avanzar a: HH:MM:SS:MS" + +msgctxt "#32055" +msgid "Move forwards by: HH:MM:SS:MSE" +msgstr "Avanzar a: HH:MM:SS:MS" + +msgctxt "#32056" +msgid "" +"Please enter valid timecode: HH:MM:SS:MSE. Hours, minutes, seconds, " +"milliseconds. For instance: 01:23:45:000" +msgstr "Por favor, introduzca un código de tiempo válido: HH:MM:SS:MS. Horas, minutos, segundos, milisegundos. Por ejemplo: 01:23:45:000" + +msgctxt "#32057" +msgid "How to sync two subtitles" +msgstr "Cómo sincronizar dos subtítulos" + +msgctxt "#32058" +msgid "" +"In order to synchronize, you will need a subtitle which matches the video " +"perfectly, but has different subtitles, usually from a different language. " +"In the next slide, first select this subtitle.[CR][CR]Then, you'll be asked " +"to select a timecode in this file, which will be used as reference. Ideally, " +"it is the first spoken line from the video. In the next screen, select the " +"line from your original subtitle which matches the first.[CR]" +"[CR]Subsequently, you'll be asked again to select a line from your reference " +"subtitle and to match this with the same line in your original subtitle. " +"Usually the best choice is the last spoken line from the video. After this " +"your two subtitles will sync![CR][CR]Check 'Scroll subtitles' to view them " +"and 'Save subtitles' to write them to a file." +msgstr "Con el fin de sincronizar, necesitarás un subtítulo que coincida perfectamente con el vídeo, pero que tenga subtítulos diferentes, normalmente de un idioma distinto. En la siguiente diapositiva, hay que seleccionar primero este subtítulo.[CR][CR]A continuación, se te pedirá seleccionar un código de tiempo en este archivo, que se utilizará como referencia. Lo ideal es que sea la primera línea hablada del vídeo. En la siguiente pantalla, hay que seleccionar la línea del subtítulo original que coincida con la primera.[CR][CR]A continuación, se te pedirá de nuevo seleccionar una línea del subtítulo de referencia y hacerla coincidir con la misma línea del subtítulo original. Normalmente, la mejor opción es la última línea hablada del vídeo. Después de esto, tus dos subtítulos ¡se sincronizarán![CR][CR]Marca 'Desplazar subtítulos' para verlos y 'Guardar subtítulos' para grabarlos en un archivo." + +msgctxt "#32059" +msgid "File not found" +msgstr "Archivo no encontrado" + +msgctxt "#32060" +msgid "" +"In the next screen, select the video to synchronize with. Go to the point in " +"the video where the first subtitle starts. When you pause the video, choose " +"'Select as start' in the menu, then do the same with the last subtitle." +msgstr "En la siguiente pantalla, seleccionar el vídeo con el que se desea sincronizar. Ir al punto del vídeo donde empieza el primer subtítulo. Cuando pauses el vídeo, elegir 'Seleccionar como inicio' en el menú, y luego hacer lo mismo con el último subtítulo." + +msgctxt "#32061" +msgid "How to sync with a video file" +msgstr "Cómo sincronizar con un archivo de vídeo" + +msgctxt "#32062" +msgid "" +"In the next screen, open the videofile from the library which belongs to the " +"subtitle you have opened. Skip or fast forward to the point where the " +"subtitle should roughly be placed. Pause.[CR][CR]When you paused the video, " +"a menu will pop up with several options. Select 'View or edit first " +"subtitle'. When your first subtitle is not the first line from the video, " +"select 'Delete' until the first subtitle is also the first line from the " +"video.[CR][CR]Then finetune the position of the video, possibly by using the " +"'Skip forward 1 second' or 'Skip backward 1 second' buttons. If the position " +"is perfect, choose 'Select as start'.[CR]Now fast forward to the end of the " +"video, and repeat the same process.[CR][CR]After this, your file will be " +"synced to the video." +msgstr "En la siguiente pantalla, abre el archivo de vídeo de la biblioteca que pertenece al subtítulo que has abierto. Salta o avanza rápidamente hasta el punto en el que aproximadamente debería colocarse el subtítulo. Pausa.[CR][CR]Cuando hayas pausado el vídeo, aparecerá un menú con varias opciones. Seleccionar 'Ver o editar el primer subtítulo'. Si el primer subtítulo no es la primera línea del vídeo, seleccionar 'Borrar' hasta que el primer subtítulo sea también la primera línea del vídeo.[CR][CR]A continuación, afinar la posición del vídeo, posiblemente utilizando los botones 'Saltar adelante 1 segundo' o 'Saltar atrás 1 segundo'. Si la posición es perfecta, elige 'Seleccionar como inicio'.[CR]Ahora avanza rápido hasta el final del vídeo, y repite el mismo proceso.[CR][CR]Después de esto, tu archivo se sincronizará con el vídeo." + +msgctxt "#32063" +msgid "Select timecode of first subtitle to sync with" +msgstr "Seleccionar el código de tiempo del primer subtítulo con el que sincronizar" + +msgctxt "#32064" +msgid "Time selected" +msgstr "Hora seleccionada" + +msgctxt "#33064" +msgid "Time selected" +msgstr "Hora seleccionada" + +msgctxt "#32065" +msgid "Select timecode of subtitle which is roughly the same" +msgstr "Seleccionar el código de tiempo del subtítulo que es aproximadamente el mismo" + +msgctxt "#32066" +msgid "Select time of last subtitle to sync" +msgstr "Seleccionar la hora del último subtítulo a sincronizar" + +msgctxt "#32067" +msgid "Select time of last subtitle" +msgstr "Seleccionar la hora del último subtítulo" + +msgctxt "#32068" +msgid "New timecode" +msgstr "Nuevo código de tiempo" + +msgctxt "#32069" +msgid "" +"Write the new timestamp for the start position, seperated by a ':'. For " +"instance: 01:22:23:000" +msgstr "Escribir la nueva marca de tiempo para la posición de inicio, separada por ':'. Por ejemplo: 01:22:23:000" + +msgctxt "#32070" +msgid "Subtitles moved forward by: {}" +msgstr "Avanzar subtítulos por: {}" + +msgctxt "#32071" +msgid "Subtitles moved backward by {}" +msgstr "Retroceder subtítulos por {}" + +msgctxt "#32072" +msgid "First subtitle now starts at {}" +msgstr "El primer subtítulo ahora empieza en {}" + +msgctxt "#33072" +msgid "Last subtitle now starts at {}" +msgstr "El último subtítulo ahora empieza en {}" + +msgctxt "#32073" +msgid " Paused at: " +msgstr " Pausado en: " + +msgctxt "#32074" +msgid "Continue playing" +msgstr "Seguir jugando" + +msgctxt "#32075" +msgid "Select as start of first subtitle" +msgstr "Seleccionar como inicio del primer subtítulo" + +msgctxt "#32076" +msgid "Skip backwards 1 second" +msgstr "Saltar hacia atrás 1 segundo" + +msgctxt "#32077" +msgid "Skip forwards 1 second" +msgstr "Saltar hacia delante 1 segundo" + +msgctxt "#32078" +msgid "Exit to Main Menu" +msgstr "Salir al menú principal" + +msgctxt "#32079" +msgid "View or delete first subtitle" +msgstr "Ver o eliminar el primer subtítulo" + +msgctxt "#32080" +msgid "View or delete last subtitle" +msgstr "Ver o eliminar el último subtítulo" + +msgctxt "#32081" +msgid "Select as start of last subtitle" +msgstr "Seleccionar como inicio del último subtítulo" + +msgctxt "#32082" +msgid "Set as first subtitle?" +msgstr "¿Establecer como primer subtítulo?" + +msgctxt "#32083" +msgid "Do you want your subtitle to start at: " +msgstr "Quiere que su subtítulo comience en: " + +msgctxt "#32084" +msgid "Reset start time" +msgstr "Restablecer hora de inicio" + +msgctxt "#32085" +msgid "Selected start: " +msgstr "Inicio seleccionado: " + +msgctxt "#32086" +msgid "Selected times:" +msgstr "Horarios seleccionados:" + +msgctxt "#32087" +msgid "Your first subtitle starts at: " +msgstr "Tu primer subtítulo empieza en: " + +msgctxt "#32088" +msgid "Your last subtitle starts at: " +msgstr "Tu último subtítulo empieza en: " + +msgctxt "#32089" +msgid "Select" +msgstr "Seleccionar" + +msgctxt "#32090" +msgid "Reset times" +msgstr "Restablecer tiempos" + +msgctxt "#33065" +msgid "Time selected" +msgstr "Hora seleccionada" + +msgctxt "#32091" +msgid "Select a line with a timecode" +msgstr "Seleccionar una línea con un código de tiempo" + +msgctxt "#32092" +msgid "" +"Please select a line with a timecode, like:[CR]'01:23:45,679 --> " +"01:23:45,679'" +msgstr "Por favor, seleccionar una línea con un código de tiempo, como:[CR]'01:23:45,679 --> 01:23:45,679'" + +msgctxt "#32093" +msgid "Choose movie" +msgstr "Elegir película" + +msgctxt "#32094" +msgid "Choose TV Show" +msgstr "Elegir serie de TV" + +msgctxt "#32095" +msgid "View entire library" +msgstr "Ver toda la biblioteca" + +msgctxt "#32096" +msgid "Exit to main menu with changes" +msgstr "Salir al menú principal con los cambios" + +msgctxt "#32097" +msgid "Save the shown subtitle" +msgstr "Guardar el subtítulo mostrado" + +msgctxt "#32098" +msgid "Exit to main menu w/o changes" +msgstr "Salir al menú principal sin cambios" + +msgctxt "#32099" +msgid "Exit completely" +msgstr "Salir completamente" + +msgctxt "#32100" +msgid "Reset to another framerate" +msgstr "Restablecer a otra tasa de fotogramas" + +msgctxt "#32101" +msgid "Save and Continue playing" +msgstr "Guardar y seguir la reproducción" + +msgctxt "#32102" +msgid "" +"The subtitle is loaded with the new framerate. Pause to reset to another " +"frame rate or to save." +msgstr "El subtítulo se carga con la nueva tasa de fotogramas. Pausa para restablecer otra tasa de fotogramas o para guardar." + +msgctxt "#32103" +msgid "Please enter a valid number" +msgstr "Por favor, introduzca un número válido" + +msgctxt "#32104" +msgid "Get frame rate from video" +msgstr "Obtener la tasa de fotogramas del vídeo" + +msgctxt "#32105" +msgid "Sync options by frame rate" +msgstr "Opciones de sincronización por tasa de fotogramas" + +msgctxt "#32106" +msgid "Frame rate" +msgstr "Tasa de fotogramas" + +msgctxt "#32107" +msgid "New ending time" +msgstr "Nueva hora de finalización" + +msgctxt "#32108" +msgid "Old starting time: " +msgstr "Antigua hora de inicio: " + +msgctxt "#34108" +msgid "Starting time: " +msgstr "Hora de inicio: " + +msgctxt "#32109" +msgid "Old ending time: " +msgstr "Antigua hora de finalización: " + +msgctxt "#34110" +msgid "New starting time: " +msgstr "Nueva hora de comienzo: " + +msgctxt "#32110" +msgid "New ending time: " +msgstr "Nueva hora de finalización: " + +msgctxt "#32111" +msgid "Save and Exit" +msgstr "Guardar y salir" + +msgctxt "#32112" +msgid "Calculate manually" +msgstr "Calcular manualmente" + +msgctxt "#32113" +msgid "Provide sum or factor" +msgstr "Proveer la suma o el factor" + +msgctxt "#32114" +msgid "Calculate factor or provide factor" +msgstr "Calcular el factor o proveer el factor" + +msgctxt "#32115" +msgid "" +"In the next screen, write a sum with the current framerate divided by the " +"real frame rate. If the current frame rate is 25 and it should be 24, type " +"'25/24'. Or type your own factor, like '1.2'" +msgstr "En la siguiente pantalla, escribe una suma con la tasa de fotogramas actual dividida por la tasa de fotogramas real. Si la tasa de fotogramas actual es 25 y debería ser 24, escribe '25/24'. O escribe tu propio factor, como '1.2'" + +msgctxt "#32116" +msgid "Play with the file you opened before" +msgstr "Reproducir el archivo abierto anteriormente" + +msgctxt "#32117" +msgid "Provide factor" +msgstr "Proveer factor" + +msgctxt "#32118" +msgid "Stretch by providing factor" +msgstr "Estirar por el factor proporcionado" + +msgctxt "#32119" +msgid "Stretch by giving new end time" +msgstr "Estirar por la nueva hora final proporcionada" + +msgctxt "#32120" +msgid "The frame rate of this video is " +msgstr "La tasa de fotogramas de este vídeo es " + +msgctxt "#32121" +msgid "" +"The video is playing with the modified subtitle. Pause to save or to return " +"to the menu." +msgstr "El vídeo se reproduce con el subtítulo modificado. Pausa para guardar o para volver al menú." + +msgctxt "#32122" +msgid "Subtitles loaded" +msgstr "Subtítulos cargados" + +msgctxt "#32123" +msgid "" +"The video is playing with the saved subtitle. The filename of the subtitle " +"is: " +msgstr "El vídeo se reproduce con el subtítulo guardado. El nombre de archivo del subtítulo es: " + +msgctxt "#32124" +msgid "Jump to time of current first subtitle" +msgstr "Saltar a la hora del primer subtítulo actual" + +msgctxt "#32125" +msgid "Jump to time of last subtitle" +msgstr "Saltar a la hora del último subtítulo" + +msgctxt "#32126" +msgid "Choose another" +msgstr "Elegir otro" + +msgctxt "#32127" +msgid "Enter frame rate" +msgstr "Introducir tasa de fotogramas" + +msgctxt "#32128" +msgid "Open other subtitle" +msgstr "Abrir otro subtítulo" + +msgctxt "#32129" +msgid "Why do I see this screen?" +msgstr "¿Por qué veo esta pantalla?" + +msgctxt "#32130" +msgid "You have selected a .sub file" +msgstr "Ha seleccionado un archivo .sub" + +msgctxt "#32131" +msgid "" +"You have selected a .sub file, which uses frame rates to indicate when " +"subtitles should be shown. To edit these subtitles, you have to select a " +"frame rate. You can start a video to see what frame rate it has or just pick " +"a random one if you want to use a sync option." +msgstr "Ha seleccionado un archivo .sub, que utiliza tasas de fotogramas para indicar cuándo deben mostrarse los subtítulos. Para editar estos subtítulos, se tiene que seleccionar una tasa de fotogramas. Puedes iniciar un vídeo para ver qué tasa de fotogramas tiene o simplemente elegir una al azar si quieres usar una opción de sincronización." + +msgctxt "#32132" +msgid "This file might not be a valid subtitle" +msgstr "Este archivo podría no ser un subtítulo válido" + +msgctxt "#32133" +msgid "Load anyway" +msgstr "Cargar de todos modos" + +msgctxt "#32134" +msgid "Choose other" +msgstr "Elegir otro" + +msgctxt "#32135" +msgid "Not a valid .sub file" +msgstr "No es un archivo .sub válido" + +msgctxt "#32136" +msgid "This file does not appear to be a valid .sub file." +msgstr "Este archivo no parece ser un archivo .sub válido." + +msgctxt "#32137" +msgid "All found HTML colorcodes reset to white." +msgstr "Todos los códigos de color HTML encontrados se restablecen a blanco." + +msgctxt "#32138" +msgid "Reset color code to white" +msgstr "Restablecer el código de color a blanco" + +msgctxt "#32139" +msgid "Reset color to a custom color" +msgstr "Restablecer el color a un color personalizado" + +msgctxt "#32140" +msgid "" +"Not a valid code for a color. Use 8 digits in a hexadecimal notation: " +"'FF00FF00'" +msgstr "No es un código válido para un color. Usar 8 dígitos en notación hexadecimal: 'FF00FF00'" + +msgctxt "#32141" +msgid "Provide color coding. Use 8 digits. Leave empty to cancel" +msgstr "Proporcione un código de color. Usar 8 dígitos. Dejar vacío para cancelar" + +msgctxt "#32142" +msgid "All found HTML colorcodes reset to " +msgstr "Todos los códigos de color HTML encontrados se restablecen a " + +msgctxt "#35000" +msgid "Cancel" +msgstr "Cancelar" + +msgctxt "#35001" +msgid "Load subtitle" +msgstr "Cargar subtítulo" + +msgctxt "#35002" +msgid "Manually" +msgstr "Manualmente" + +msgctxt "#35003" +msgid "Do you want to edit this subtitle?" +msgstr "¿Desea editar este subtítulo?" + +msgctxt "#35004" +msgid "Playback will stop, but can be resumed from the menu." +msgstr "La reproducción se detendrá, pero puede reanudarse desde el menú." + +msgctxt "#35005" +msgid "" +"A subtitlefile could not be found. Do you want to select one manually and " +"continue with current video?" +msgstr "No se ha encontrado ningún archivo de subtítulos. ¿Desea seleccionar uno manualmente y continuar con el vídeo actual?" + +msgctxt "#35006" +msgid "Video:" +msgstr "Vídeo:" + +msgctxt "#35007" +msgid "Subtitle:" +msgstr "Subtítulo:" + +msgctxt "#35008" +msgid "Play with " +msgstr "Reproducir con " + +msgctxt "#35009" +msgid "Edit and synchronize subtitles with your remote" +msgstr "Editar y sincronizar subtítulos con el mando a distancia" + +msgctxt "#35010" +msgid "" +"With this script you can edit specific lines, move or stretch subtitles, and " +"synchronize with other subtitles. You can also synchronize with a videofile." +msgstr "Con este script puedes editar líneas específicas, mover o estirar subtítulos, y sincronizar con otros subtítulos. También puede sincronizar con un archivo de vídeo." + +msgctxt "#35011" +msgid "Return to Menu" +msgstr "Volver al menú" + +msgctxt "#35016" +msgid "" +"Somewhere in the process of syncing an error occurred. Most of the time this " +"is caused by:[CR] - A .srt file which uses non-standard timestamps.[CR] - A ." +"srt file which has a digit missing in one of its timestamps.[CR] - A file " +"which is not an actual .srt file[CR][CR]Use Main Menu -> Advanced Options -> " +"Check Integrity to scan for faulty timestamps or use a different .srt file." +msgstr "En algún momento del proceso de sincronización se ha producido un error. La mayoría de las veces esto es causado por:[CR] - Un archivo .srt que usa marcas de tiempo no estándar.[CR] - Un archivo .srt al que le falta un dígito en una de sus marcas de tiempo.[CR] - Un archivo que no es un archivo .srt real[CR][CR]Usar Menú Principal -> Opciones Avanzadas -> Comprobar Integridad para buscar marcas de tiempo defectuosas o usar un archivo .srt diferente." + +msgctxt "#35012" +msgid "The following error has occurred:" +msgstr "Se ha producido el siguiente error:" + +msgctxt "#35013" +msgid "Details of Error" +msgstr "Detalles del error" + +msgctxt "#35017" +msgid "Characterset not detected" +msgstr "Juego de caracteres no detectado" + +msgctxt "#35018" +msgid "" +"The correct characterset of this file could not be detected. The file is now " +"loading with the UTF-8 set and errors are replaced with questionmarks." +msgstr "No se ha podido detectar el juego de caracteres correcto de este archivo. El archivo ahora se está cargando con el conjunto UTF-8 y los errores se sustituyen por signos de interrogación." + +msgctxt "#35019" +msgid "Select textline" +msgstr "Seleccionar línea de texto" + +msgctxt "#35020" +msgid "Select time to sync to" +msgstr "Seleccionar la hora de sincronización" + +msgctxt "#35021" +msgid "Shift forwards by microseconds" +msgstr "Avanzar por microsegundos" + +msgctxt "#35022" +msgid "Shift backwards by microseconds" +msgstr "Retroceder por microsegundos" + +msgctxt "#35023" +msgid "Shift forwards by minutes" +msgstr "Avanzar por minutos" + +msgctxt "#35024" +msgid "Shift backwards by minutes" +msgstr "Retroceder por minutos" + +msgctxt "#35025" +msgid "Select which subtitle to delete" +msgstr "Seleccionar qué subtítulo eliminar" + +msgctxt "#35026" +msgid "Minutes" +msgstr "Minutos" + +msgctxt "#35027" +msgid "Microseconds" +msgstr "Microsegundos" + +msgctxt "#35028" +msgid "See contents" +msgstr "Ver contenidos" + +msgctxt "#35029" +msgid "Open anyway" +msgstr "Abrir de todos modos" + +msgctxt "#35030" +msgid "Unlikely to be a subtitle" +msgstr "Es poco probable que sea un subtítulo" + +msgctxt "#35031" +msgid "This file is quite large and unlikely to be a subtitle" +msgstr "Este archivo es bastante grande y es poco probable que sea un subtítulo" + +msgctxt "#35032" +msgid "Could not load subtitle" +msgstr "No se han podido cargar los subtítulos" + +msgctxt "#35033" +msgid "Could not find any subtitles in the file. Is it a valid subtitle?" +msgstr "No se han encontrado subtítulos en el archivo. ¿Es un subtítulo válido?" + +msgctxt "#35034" +msgid "Scanning..." +msgstr "Escaneando..." + +msgctxt "#35035" +msgid "Checking which encoding to use for this file." +msgstr "Comprobar qué codificación usar para este archivo." + +msgctxt "#35036" +msgid "This does not seem to be a valid .sub file." +msgstr "Este no parece ser un archivo .sub válido." + +msgctxt "#35037" +msgid "This does not seem to be a valid .srt file." +msgstr "Este no parece ser un archivo .srt válido." + +msgctxt "#35038" +msgid "Results" +msgstr "Resultados" + +msgctxt "#35039" +msgid "The encoding is: " +msgstr "La codificación es: " + +msgctxt "#35040" +msgid "The following lines were skipped:" +msgstr "Se han omitido las siguientes líneas:" + +msgctxt "#35041" +msgid "Repair manually" +msgstr "Reparar manualmente" + +msgctxt "#35042" +msgid "Jump to Specific subtitle" +msgstr "Saltar a un subtítulo específico" + +msgctxt "#35043" +msgid "View or delete subtitle that is marked as first" +msgstr "Ver o eliminar el subtítulo que está marcado como primero" + +msgctxt "#35044" +msgid "View or delete subtitle that is marked as last" +msgstr "Ver o eliminar el subtítulo que está marcado como último" + +msgctxt "#35045" +msgid "Mark other subtitle as last to sync with" +msgstr "Marcar otro subtítulo como el último para sincronizar con" + +msgctxt "#35046" +msgid "Mark other subtitle as first to sync with" +msgstr "Marcar otro subtítulo como el primero para sincronizar con" + +msgctxt "#35047" +msgid "Change start time" +msgstr "Cambiar la hora de inicio" + +msgctxt "#35048" +msgid "Change end Time" +msgstr "Cambiar la hora de fin" + +msgctxt "#35049" +msgid "Skip backward 100 milliseconds" +msgstr "Retroceder 100 milisegundos" + +msgctxt "#35050" +msgid "Do you want: [CR]{}[CR]To appear at {}?" +msgstr "¿Quieres: [CR]{}[CR]Aparecer en {}?" diff --git a/script.sublissimo/resources/language/resource.language.it_it/strings.po b/script.sublissimo/resources/language/resource.language.it_it/strings.po index c9ac1cc0f..f1921278a 100644 --- a/script.sublissimo/resources/language/resource.language.it_it/strings.po +++ b/script.sublissimo/resources/language/resource.language.it_it/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-08-16 19:29+0000\n" +"PO-Revision-Date: 2023-05-25 18:42+0000\n" "Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13\n" +"X-Generator: Weblate 4.17\n" msgctxt "Addon Summary" msgid "Edit and synchronize subtitles with your remote" @@ -67,7 +67,7 @@ msgstr "Esci" msgctxt "#31010" msgid "Synchronize by frame rate" -msgstr "Sincronizza per framerate" +msgstr "Sincronizza per frequenza fotogrammi" msgctxt "#31011" msgid "Play video with edited subtitle" @@ -106,11 +106,11 @@ msgstr "Scorri ed elimina manualmente" msgctxt "#32005" msgid "Back" -msgstr "indietro" +msgstr "Indietro" msgctxt "#32006" msgid "Delete this subtitle?" -msgstr "Cancello questo sottotitolo?" +msgstr "Eliminare questo sottotitolo?" msgctxt "#32007" msgid "Select subtitle to edit" @@ -146,7 +146,7 @@ msgstr "Errore" msgctxt "#32015" msgid "Select subtitle to synchronize with" -msgstr "Seleziona sottotitoli con cui sincronizzare" +msgstr "Seleziona sottotitolo con cui eseguire la sincronizzazione" msgctxt "#32016" msgid "Please select a .srt or a .sub file" @@ -154,7 +154,7 @@ msgstr "Seleziona un file .srt o .sub" msgctxt "#32017" msgid "Success" -msgstr "Riuscito" +msgstr "Successo" msgctxt "#32018" msgid "Current first subtitle" @@ -182,7 +182,7 @@ msgstr "Inserisci stringa di ricerca" msgctxt "#32024" msgid "Yes" -msgstr "Si" +msgstr "Sì" msgctxt "#32025" msgid "No" @@ -194,7 +194,7 @@ msgstr "Questo editor funziona solo con file .srt o .sub" msgctxt "#32027" msgid "File not found: " -msgstr "File non trovato " +msgstr "File non trovato: " msgctxt "#32028" msgid "" @@ -208,7 +208,7 @@ msgstr "Ad esempio: 01:22:23:000" msgctxt "#32030" msgid "Report" -msgstr "Rapport" +msgstr "Rapporto" msgctxt "#32031" msgid "No problems detected" @@ -423,7 +423,7 @@ msgstr "L'ultimo sottotitolo ora inizia a {}" msgctxt "#32073" msgid " Paused at: " -msgstr " Fermato a: " +msgstr " In pausa a: " msgctxt "#32074" msgid "Continue playing" @@ -459,7 +459,7 @@ msgstr "Seleziona come inizio dell'ultimo sottotitolo" msgctxt "#32082" msgid "Set as first subtitle?" -msgstr "Imposto come primo sottotitolo?" +msgstr "Impostare come primo sottotitolo?" msgctxt "#32083" msgid "Do you want your subtitle to start at: " @@ -513,23 +513,23 @@ msgstr "Scegli film" msgctxt "#32094" msgid "Choose TV Show" -msgstr "Scegli programma TV" +msgstr "Scegli serie TV" msgctxt "#32095" msgid "View entire library" -msgstr "Visualizza l'intera libreria" +msgstr "Visualizza intera libreria" msgctxt "#32096" msgid "Exit to main menu with changes" -msgstr "Esci al menu principale con modifiche" +msgstr "Torna al menu principale con modifiche" msgctxt "#32097" msgid "Save the shown subtitle" -msgstr "Salva il sottotitolo mostrato" +msgstr "Salva il sottotitolo visualizzato" msgctxt "#32098" msgid "Exit to main menu w/o changes" -msgstr "Esci al menu principale senza modifiche" +msgstr "Torna al menu principale senza modifiche" msgctxt "#32099" msgid "Exit completely" @@ -537,7 +537,7 @@ msgstr "Esci completamente" msgctxt "#32100" msgid "Reset to another framerate" -msgstr "Reimposta su un altro framerate" +msgstr "Reimposta su un altra frequenza dei fotogrammi" msgctxt "#32101" msgid "Save and Continue playing" @@ -547,23 +547,23 @@ msgctxt "#32102" msgid "" "The subtitle is loaded with the new framerate. Pause to reset to another " "frame rate or to save." -msgstr "Il sottotitolo viene caricato con il nuovo framerate. Pausa per ripristinare un altro framerate o per salvare." +msgstr "Il sottotitolo viene caricato con la nuova frequenza dei fotogrammi. Pausa per ripristinare un altra frequenza o per salvare." msgctxt "#32103" msgid "Please enter a valid number" -msgstr "Inserire un numero valido" +msgstr "Inserisci un numero valido" msgctxt "#32104" msgid "Get frame rate from video" -msgstr "Ottieni framerate dal video" +msgstr "Ottieni frequenza dei fotogrammi dal video" msgctxt "#32105" msgid "Sync options by frame rate" -msgstr "Sincronizza opzioni in base al framerate" +msgstr "Sincronizza opzioni in base alla frequenza dei fotogrammi" msgctxt "#32106" msgid "Frame rate" -msgstr "Framerate" +msgstr "Frequenza dei fotogrammi" msgctxt "#32107" msgid "New ending time" @@ -630,7 +630,7 @@ msgstr "Allunga dando un nuovo orario di fine" msgctxt "#32120" msgid "The frame rate of this video is " -msgstr "Il framerate di questo video è: " +msgstr "La frequenza dei fotogrammi di questo video è: " msgctxt "#32121" msgid "" @@ -903,7 +903,7 @@ msgstr "Ripara manualmente" msgctxt "#35042" msgid "Jump to Specific subtitle" -msgstr "Vai a sottotitolo specifico" +msgstr "Vai al sottotitolo specifico" msgctxt "#35043" msgid "View or delete subtitle that is marked as first" @@ -915,11 +915,11 @@ msgstr "Visualizza o elimina i sottotitoli contrassegnati come ultimi" msgctxt "#35045" msgid "Mark other subtitle as last to sync with" -msgstr "Contrassegna un altro sottotitolo come ultimo con cui sincronizzare" +msgstr "Contrassegna l'altro sottotitolo come ultimo con cui eseguire la sincronizzazione" msgctxt "#35046" msgid "Mark other subtitle as first to sync with" -msgstr "Contrassegna un altro sottotitolo come primo con cui sincronizzare" +msgstr "Contrassegna l'altro sottotitolo come primo con cui eseguire la sincronizzazione" msgctxt "#35047" msgid "Change start time" From a2c8973f6a133947f6ef50c8daca1c0376ddb0f6 Mon Sep 17 00:00:00 2001 From: emilsvennesson Date: Tue, 30 May 2023 13:57:31 +0000 Subject: [PATCH 046/145] [script.module.inputstreamhelper] 0.6.1+matrix.1 --- script.module.inputstreamhelper/README.md | 4 + script.module.inputstreamhelper/addon.xml | 12 ++- .../lib/inputstreamhelper/config.py | 59 +++--------- .../lib/inputstreamhelper/utils.py | 31 ++++--- .../lib/inputstreamhelper/widevine/arm.py | 29 +++--- .../widevine/arm_chromeos.py | 91 +++++++++++++++++-- .../resource.language.en_gb/strings.po | 12 +++ 7 files changed, 150 insertions(+), 88 deletions(-) diff --git a/script.module.inputstreamhelper/README.md b/script.module.inputstreamhelper/README.md index 50e9fcadc..93c5e8eb6 100644 --- a/script.module.inputstreamhelper/README.md +++ b/script.module.inputstreamhelper/README.md @@ -91,6 +91,10 @@ Please report any issues or bug reports on the [GitHub Issues](https://github.co This module is licensed under the **The MIT License**. Please see the [LICENSE.txt](LICENSE.txt) file for details. ## Releases +### v0.6.1 (2023-05-30) +- Performance improvements on Linux ARM (@horstle) +- This will be the last release for Python 2 i.e. Kodi 18 (Leia) and below. The next release will require Python 3 and Kodi 19 (Matrix) or higher. + ### v0.6.0 (2023-05-03) - Initial support for AARCH64 Linux (@horstle) - Initial support for AARCH64 Macs (@mediaminister) diff --git a/script.module.inputstreamhelper/addon.xml b/script.module.inputstreamhelper/addon.xml index 1e7cb745a..610b2a195 100644 --- a/script.module.inputstreamhelper/addon.xml +++ b/script.module.inputstreamhelper/addon.xml @@ -1,5 +1,5 @@ - + @@ -25,10 +25,14 @@ Jednostavan Kodi modul koji olakšava razvijanje dodataka koji se temelje na InputStream dodatku i reprodukciji DRM zaštićenog sadržaja. Простой модуль для Kodi, который облегчает жизнь разработчикам дополнений, с использованием InputStream дополнений и воспроизведения DRM контента. +v0.6.1 (2023-05-30) +- Performance improvements on Linux ARM +- This will be the last release for Python 2 i.e. Kodi 18 (Leia) and below. The next release will require Python 3 and Kodi 19 (Matrix) or higher. + v0.6.0 (2023-05-03) -- Initial support for AARCH64 Linux (@horstle) -- Initial support for AARCH64 Macs (@mediaminister) -- New option to install a specific version on most platforms (@horstle) +- Initial support for AARCH64 Linux +- Initial support for AARCH64 Macs +- New option to install a specific version on most platforms v0.5.10 (2022-04-18) - Fix automatic submission of release diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/config.py b/script.module.inputstreamhelper/lib/inputstreamhelper/config.py index fae104c86..110e60223 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/config.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/config.py @@ -84,53 +84,22 @@ # https://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices # https://chromiumdash.appspot.com/serving-builds?deviceCategory=Chrome%20OS # Last updated: 2023-03-24 -CHROMEOS_RECOVERY_ARM_HWIDS = [ - 'BOB', - 'BURNET', - 'COACHZ', - 'COZMO', - 'DAMU', - 'DOJO-EJPG', - 'DRUWL', - 'DUMO', - 'ELM', - 'ESCHE', - 'FENNEL', - 'FENNEL14', - 'HANA', - 'HAYATO-YLRO', - 'HOMESTAR-MBLE', - 'JUNIPER-HVPU', - 'KAKADU-WFIQ', - 'KAPPA', - 'KAPPA-EWFK', - 'KATSU', - 'KENZO-IGRW', - 'KEVIN', - 'KODAMA', - 'KRANE-ZDKS', - 'MAKOMO-UTTX', - 'PICO-EXEM', - 'QUACKINGSTICK', - 'SCARLET', - 'SPHERION', - 'TOMATO-LYVN', - 'WILLOW-TFIY', - 'WORMDINGLER-JQAO', +CHROMEOS_RECOVERY_ARM_BNAMES = [ + 'asurada', + 'bob', + 'cherry', + 'elm', + 'hana', + 'jacuzzi', + 'kevin', + 'kukui', + 'scarlet', + 'strongbad', ] -CHROMEOS_RECOVERY_ARM64_HWIDS = [ - 'KINGOFTOWN-KDDA', - 'LAZOR', - 'LIMOZEEN', - 'MAGNETON-LCKC', - 'PAZQUEL-HGNV', - 'PAZQUEL-OPNA', - 'POMPOM-MZVS', - 'RUSTY-ZNCE', - 'STEELIX-VZSZ', - 'TENTACOOL-ZLJE', - 'TENTACRUEL-VAFH', +CHROMEOS_RECOVERY_ARM64_BNAMES = [ + 'corsola', + 'trogdor', ] MINIMUM_INPUTSTREAM_VERSION_ARM64 = { diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py b/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py index 0ab01a174..b4b4452fd 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/utils.py @@ -164,21 +164,26 @@ def http_download(url, message=None, checksum=None, hash_alg='sha1', dl_size=Non progress.update(percent, prog_message) - if checksum and calc_checksum.hexdigest() != checksum: - progress.close() - req.close() - log(4, 'Download failed, checksums do not match!') - return False - - if dl_size and stat_file(dl_path).st_size() != dl_size: - progress.close() - req.close() - free_space = sizeof_fmt(diskspace()) - log(4, 'Download failed, filesize does not match! Filesystem full? Remaining diskspace in temp: {}.'.format(free_space)) - return False - progress.close() req.close() + + checksum_ok = (not checksum or calc_checksum.hexdigest() == checksum) + size_ok = (not dl_size or stat_file(dl_path).st_size() == dl_size) + + if not all((checksum_ok, size_ok)): + free_space = sizeof_fmt(diskspace()) + log(4, 'Something may be wrong with the downloaded file.') + if not checksum_ok: + log(4, 'Provided checksum: {}\nCalculated checksum: {}'.format(checksum, calc_checksum.hexdigest())) + if not size_ok: + free_space = sizeof_fmt(diskspace()) + log(4, 'Expected filesize: {}\nReal filesize: {}\nRemaining diskspace: {}'.format(dl_size, stat_file(dl_path).st_size(), free_space)) + + if yesno_dialog(localize(30003), localize(30070, filename=filename)): # file maybe broken. Continue anyway? + log(4, 'Continuing despite possibly corrupt file!') + else: + return False + store('download_path', dl_path) return True diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py index 714e10905..3cd7bd0e0 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm.py @@ -17,47 +17,44 @@ def select_best_chromeos_image(devices): log(0, 'Find best ARM image to use from the Chrome OS recovery.json') if userspace64(): - arm_hwids = config.CHROMEOS_RECOVERY_ARM64_HWIDS + arm_bnames = config.CHROMEOS_RECOVERY_ARM64_BNAMES else: - arm_hwids = config.CHROMEOS_RECOVERY_ARM_HWIDS + arm_bnames = config.CHROMEOS_RECOVERY_ARM_BNAMES - arm_hwids = [h for arm_hwid in arm_hwids for h in ['^{} '.format(arm_hwid), '^{}-.*'.format(arm_hwid), '^{}.*'.format(arm_hwid)]] best = None for device in devices: # Select ARM hardware only - for arm_hwid in arm_hwids: - if arm_hwid in device['hwidmatch']: - hwid = arm_hwid + for arm_bname in arm_bnames: + if arm_bname == device['file'].split('_')[2]: + device['boardname'] = arm_bname # add this new entry to avoid extracting it from the filename all the time break # We found an ARM device, rejoice ! else: continue # Not ARM, skip this device - device['hwid'] = hwid - # Select the first ARM device if best is None: best = device continue # Go to the next device - # Skip identical hwid - if hwid == best['hwid']: + # Skip identical boardname + if device['boardname'] == best['boardname']: continue # Select the newest version if parse_version(device['version']) > parse_version(best['version']): - log(0, '{device[hwid]} ({device[version]}) is newer than {best[hwid]} ({best[version]})', + log(0, '{device[boardname]} ({device[version]}) is newer than {best[boardname]} ({best[version]})', device=device, best=best) best = device # Select the smallest image (disk space requirement) elif parse_version(device['version']) == parse_version(best['version']): - if int(device['filesize']) + int(device['zipfilesize']) < int(best['filesize']) + int(best['zipfilesize']): - log(0, '{device[hwid]} ({device_size}) is smaller than {best[hwid]} ({best_size})', + if int(device['zipfilesize']) < int(best['zipfilesize']): + log(0, '{device[boardname]} ({device_size}) is smaller than {best[boardname]} ({best_size})', device=device, + device_size=int(device['zipfilesize']), best=best, - device_size=int(device['filesize']) + int(device['zipfilesize']), - best_size=int(best['filesize']) + int(best['zipfilesize'])) + best_size=int(best['zipfilesize'])) best = device return best @@ -96,7 +93,7 @@ def install_widevine_arm(backup_path): localize(30018, diskspace=sizeof_fmt(required_diskspace))) return False - log(2, 'Downloading ChromeOS image for Widevine: {hwid} ({version})'.format(**arm_device)) + log(2, 'Downloading ChromeOS image for Widevine: {boardname} ({version})'.format(**arm_device)) url = arm_device['url'] extracted = dl_extract_widevine(url, backup_path, arm_device) diff --git a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm_chromeos.py b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm_chromeos.py index 120713d39..9a334d102 100644 --- a/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm_chromeos.py +++ b/script.module.inputstreamhelper/lib/inputstreamhelper/widevine/arm_chromeos.py @@ -73,12 +73,67 @@ def chromeos_offset(self): return offset - def find_file(self, filename, path_to_file=("opt", "google", "chrome", "WidevineCdm", "_platform_specific", "cros_arm")): + def _find_file_in_chunk(self, bfname, chunk): """ - Finds a file at a given path, or search upwards if not found. + Checks if the filename is found in the given chunk. + Then makes some plausibility checks, to see if it is in fact a proper dentry. + + returns the dentry if found, else False. + """ + + if bfname in chunk: + i_index_pos = chunk.index(bfname) - 8 # the filename is the last element of the dentry, the elements before are 8 bytes total + file_entry = self.dir_entry(chunk[i_index_pos:i_index_pos + len(bfname) + 8]) # 8 because see above + if file_entry['inode'] < self.sb_dict['s_inodes_count'] and file_entry['name_len'] == len(bfname): + return file_entry + + log(0, 'Found filename, but checks did not pass:') + log(0, 'inode number: {inode} < {count}, name_len: {name_len} == {len_fname}'.format(inode=file_entry['inode'], + count=self.sb_dict['s_inodes_count'], + name_len=file_entry['name_len'], + len_fname=len(bfname))) + return False + + def _find_file_naive(self, fname): + """ + Finds a file by basically searching for the filename as bytes in the bytestream. + Searches through the whole image only once, making it fast, but may be unreliable at times. + Returns a directory entry. + """ + + fname_alt = fname + '#new' # Sometimes the filename has "#new" at the end + bfname = fname.encode('ascii') + bfname_alt = fname_alt.encode('ascii') + chunksize = 4 * 1024**2 + chunk1 = self.read_stream(chunksize) + while True: + chunk2 = self.read_stream(chunksize) + if not chunk2: + raise ChromeOSError('File {fname} not found in the ChromeOS image'.format(fname=fname)) + + chunk = chunk1 + chunk2 + + file_entry = self._find_file_in_chunk(bfname, chunk) + if file_entry: + break + + file_entry = self._find_file_in_chunk(bfname_alt, chunk) + if file_entry: + break + + chunk1 = chunk2 + + return file_entry + + def _find_file_properly(self, filename, path_to_file=("opt", "google", "chrome", "WidevineCdm", "_platform_specific", "cros_arm")): + """ + Finds a file at a given path, or searches upwards if not found. Assumes the path is roughly correct, else it might take long. + It also might take long for ZIP files, since it might have to jump back and forth while traversing down the given path. + + Returns a directory entry. """ root_inode_pos = self._calc_inode_pos(2) root_inode_dict = self._inode_table(root_inode_pos) @@ -107,10 +162,9 @@ def find_file(self, filename, path_to_file=("opt", "google", "chrome", "Widevine def _find_file_in_dir(self, filename, dentries): """ Finds a file in a directory or recursively in its subdirectories. - Returns a directory entry. - Can take long for deep searches. - Returns the first result. + + Returns the first result as a directory entry. """ try: return dentries[filename] @@ -128,6 +182,23 @@ def _find_file_in_dir(self, filename, dentries): return None + def find_file(self, filename, path_to_file=None): + """ + Finds a file. Supplying a path could take longer for ZIP files! + + Returns a directory entry. + """ + + if path_to_file: + return self._find_file_properly(filename, path_to_file) + + try: + return self._find_file_naive(filename) + except ChromeOSError: + if self.progress: + self.progress.update(5, localize(30071)) # Could not find file, doing proper search + return self._find_file_properly(filename) + def _calc_inode_pos(self, inode_num): """Calculate the byte position of an inode from its index""" blk_group_num = (inode_num - 1) // self.sb_dict['s_inodes_per_group'] @@ -223,10 +294,10 @@ def dir_entry(chunk): dir_names = ('inode', 'rec_len', 'name_len', 'file_type', 'name') dir_fmt = ' Date: Wed, 31 May 2023 07:35:03 +0000 Subject: [PATCH 047/145] [weather.ozweather] 2.0.8 --- weather.ozweather/addon.xml | 6 +- weather.ozweather/changelog.txt | 3 + weather.ozweather/resources/ABC.png | Bin 0 -> 73826 bytes .../resources/lib/abc/abc_video.py | 44 ++++++++--- .../resources/lib/bom/bom_forecast.py | 49 ++++++------ .../resources/lib/bom/bom_location.py | 4 +- .../resources/lib/bom/bom_radar.py | 71 +++++++++--------- .../lib/bom/bom_radar_scrape_latest.py | 1 + weather.ozweather/resources/lib/common.py | 7 +- weather.ozweather/resources/lib/forecast.py | 17 +++-- weather.ozweather/resources/lib/locations.py | 3 +- weather.ozweather/resources/lib/ozweather.py | 12 ++- weather.ozweather/resources/lib/store.py | 8 +- weather.ozweather/resources/settings.xml | 17 ----- 14 files changed, 135 insertions(+), 107 deletions(-) create mode 100644 weather.ozweather/resources/ABC.png diff --git a/weather.ozweather/addon.xml b/weather.ozweather/addon.xml index 1a1dfc689..2e65baa31 100644 --- a/weather.ozweather/addon.xml +++ b/weather.ozweather/addon.xml @@ -1,5 +1,5 @@ - + @@ -22,8 +22,8 @@ icon.png fanart.jpg - v2.0.6 - - Update list of radars + v2.0.8 + - Fix for moved ABC weather videos, update list of radars diff --git a/weather.ozweather/changelog.txt b/weather.ozweather/changelog.txt index ce20ddbec..819ea7bc2 100644 --- a/weather.ozweather/changelog.txt +++ b/weather.ozweather/changelog.txt @@ -1,3 +1,6 @@ +2.0.8 +- Fix for moved ABC weather videos, update list of radars + 2.0.6 - Update list of radars diff --git a/weather.ozweather/resources/ABC.png b/weather.ozweather/resources/ABC.png new file mode 100644 index 0000000000000000000000000000000000000000..5753e290a1e24e3c5d73b93e9fc394d4c7d04764 GIT binary patch literal 73826 zcmb5W1yq$=7dA>a(%ncYEsb=iba!{Bg3=9A3P^)UiLwD{q(h{;yF(g5@?RUjbME(l zyg0s{kggn|VA5>XQS z0sI5OMqF7O2Bsn&{l*Lt{5Q3QoVqd$%qs>Mn7~jNm@Dw7z-<^9FAf-(T~ins!88~c zBG=3YH6idnkjxcjrC{!%Ke^wFlEGh)J>`|9kyqhJ;YrBasGd@Rn_=Xo#5H|q_rLoD zlIy(xeXHq}ebB3xo?Dj4YGVOW<`5v}Xd_0R(STO0_AUwEAwM$ZO;1a451 zL3#zYGC5NmnHiat2FFU8MJ@HX#z)?QUDJ+Vhh$!ml?|6zB!4QcH}wZg5q&0()6-v0I>L>ZC6g-lR$$H; zukdb5-0s$|g)rp1ondm&e(96o#x9VGS`NwvzzYH^?WBt%5MMk8$q)EaCPYU8aiwSL^wn^JW@0S z25z+3TySHqr~ujWv{ow;qh9E`f1VHFSdI`y!jyt2)E(wR$YV8XRq7*s`LtnGYHpUi zie1-H!rQ2dh&#F#U`(-Dh(HeM1=)*ARY~dP=ZvA3-34OUt}xK&e`^bs35B&Ae4HyP z-2jmZ5(`kj)ptvh#w5$M%oF9r((2AZq4DZ?ciR0pSu7V54FP&nlXhISco6nBSaVcI zSLnqoXrB{Lp|@d52hfH__TV3sB>F!khWY{ZBo0wRvl;6}<#3MgmrSf5@`R{P99tS4 zz@6ee6q@sP&#fa;@YrKj;0Dx@URG?&??hnrEWS?$kr2_d76g7De04D5$nzkBusAX=v{9qmbaiIUtI3#bFPH~}}wGo0sv&ymXTnLZU&ROW( zxAPgI1Og(QlPWcW5JyffLj_o+;T+8t?MzEGs8!<-n&}+yER;lqWVj$yOsE&PQE)-L z2}2>P_jj zI1jw(rA3sWfMzBfY^G&Yf#^s$>0jHR$)S%UVQ;QZ&5>soJkuH)J~ep@yRCwc@=ZL5 zx*dj55C8IRIt|-miU!69f#2e&!0^Otb4|^_wUvD z98bV9qzw-v&HW@x8`eEzL_@g3E1!sl_ehd9e<&?rM{(Y}3UQQ@R*e0UrYCixF#pti zX(YBH4=^TI^bdDy#pgh%gNdh5OSV-)6I?l;U=u^0JQ%{nfSrHxT9tZyd_WJFUP(}lfWgVrwmXEYR!1S6bKV}p;&^}wkq{-__KerGMUAG-sSJYphiEL zT%lLA_0@QQ9JjD&_^|N3n!iB)$t^lo+-Rc%;N#LNW{HxBvM5fW8QV zFreZ`NV&)(Y$QH9N=QOqL57b)`$#E>`hRP^I8U>sCdF_|9K}to6^hRfS3{Q{vl=mY z9BK?S#iRyvzBK}Th>8u5{z->U)5&GcB>M?mju$RAod1BF;1;n2DNvjGBRRCMK$?LY z3ByYAxPSi9J)@=b>|Y*~0|_T{4ss6U{axpJ7MwUq5cbte*QBm7SQ4Ub6@{69YlYMz ze6s{vxtNl^A1hlqpH6^Q8_5PkyC((;9EU479RDy9V%q69H=zF5MKe+q#n;D>w)(kyg2 z@o5SO3j?;GxC4!DtHTB}fCe?{VHpcVxS00fLGXsrE&o_yv_E(}_z#yqFmO2m@G=-~ zN?`{x30lvZ_k())+E9J~Bz#tcG@JY2fo2EBW)nWjUpe6WWjAG5*Nfkd)%xNISkz^@ z7|1Cw!b9W=Jo~m}g%@Q6fh)mcVhyJ+5kq2rJ{ig`c%<8nK3Io{_$X(L1FN3G0G_4e zGKbWgs`!=2##PT4B_i<(&&27IK(v4zDj;6t*eE!a4~g+VYy=i*7ZnsOC1_*ysBG3Zvqu@Zo1Umrhq_V! zS6TsxKCT%2kLrQ~Mv54+DG?z}Vn+c~W<7_AX!g#56UTh0eSDOW^9Kd;56gRq*fWuQ zL#BP!D7@S_rzztonv!ZQd z@Jy)})S+)Ep+U^CmBb848UXJr&ZBkxf)Yh+eM=Do)f071oc*EUy^YuK!+>CIL*T?i zVP8}-nS#VUV_ZZBmnWR!Yw69LGrcsWpi03$uc&=77B;28A~ZZR44;3xv` z=z=i4&D0*)9+#%So1YNsaKu&^_p)OYT;ALc{~U|4`-wt&Naz8E$FOqf~s! z1W7AlgiHE~Pp%LYk}9<={r@sPfN{W^Bd}F&Z@ZxCjDhz zC|G@{(kt`uLnst@n{fjD(HmMwnbVsOtCuM59O<{3 z69Ma?g^EXdAF;77@-GZPH4rGi1knOfHOZY-l}aGnxjW0^Pt}3B96&`aSC<+{Sd8T4 zGh+X{?m#de(V^c)O+}L`u#$x`y`Ayxfui~YY=p`P01kncs0}=MBih5$Guh7u&7qYI zP-C5iA@v)y+MrL5G?lQJSSet=!n44-m4EYZtv#$L0AQaNk?m=tK=b}X{IjMKkJ|%d zRaDpL(1F-|Vm=iO3JxlrZlhinKf9BPlu0{z-gNMQ08njlq|Y;ngeZ{00_#Yz%S3YPi`jM9!)WtN=l%`n@66mGs zr8>{2#0Fv!E+2%=8HD{F=mfy#5Bz)&Cw>i;I^+N4zbqyJ)0PE50R_`&4;g6Q#R&n% z`VVIXpTXr(Zne$44*M?vv}cn4szt}3hoXiK^f8?HUIsU`A|5!1CjbA511bxehU8B2 zsa}#Xvjl#dW7_G{_W)j*9s`bB%M&a9hxi6s` zl1I7)-4%p_wii@TeuR8buKPo@bFX|BmqWvk0d7KnrW9z&Fw-s7%$GR+>Tv~3z+9ol z(Iw#)05AZG#hn1jkBWI4bw^kIFQYspxcs?8mpmc#@nQebp z(PRDI6wtSZ0r3tlyc>5V3zdr`DgF2$spo!vco6&Iolq`k!p=WX0evoXU4Z^QW3*?w z!lO~^!C0_(EIijP%L45?^2ER$QXAK~&}{feEKi%N)va8>f%wWvj^v=Ip=t=*;L~B# z>gj%bz?Pq(NdCd;zc1iO0Q45Gs8j+G_*VsY--bVE=HmEXS(XS;^MxSwp&162=>dyI zDE9uL{~v$&dsp{B|KvVHEk&!u^T5py#HlyFKN5k~Aw*Gw+5*L1KxzpF)N)SH zD1hWqT)&ZTbdbg*Ai*SfFHb0e-?^@w4kz9c+Pw4CLml*xQRCM8H|zSF!{Vn#5FUWqM5H9Ty`A9XE;K9-eGt&#;Q&shXG z)`B~EC7v-|LXZNRmEeR+_^(D$%LeEmXB;(Bk7SV@~n1-)0u6vnsBd6_+R0=vFKZo8?ewirQ1ej$dMxHulAkB1Y4OE zYIYlz#Qv!a>orHM`t(c&on9!NeN{6rH2Dwh+szpM8eOpuAPUjg1CdaQ;mG5p6Nnc? zNBHCziG$Lc7KHi5&e3_uRKtKYL!WDVh<+qlK9@a1%!eV!vmf94sm34NZlV}|-i)5a z4?=GTH{D!c;mBH_O!HL-F07rVF@tVNKh_HkVaDkjy?I?3R}7=ihO4myl0&6@*-yIR zlt>ypE;F>6rFWboIr6?&8I_3SCQPRHj+Dq-C;Z$#S4$!Bw*iO!w1j;r*~u(#L^SBo z9oQbV%J;SMu7(El*KbI!239H;$=UXQ(vl=^IXlDh zb5uu0Fl-(-RtN}j@J8fhWp;f%etEHAa8`75pmtUyXw3Z4c}bSndR5@F{!wN#q2cIA zsMid>U=k;t(mB^{zSTSXO<&DVFm{N{f_i5h<3diRt4XiPap-BC+pK^-$;?7BXO3 zBYMnrIn%3mv%Zee?B$8uvxUauCTq|Du8pFduCKe0&UktvcJGzG ztDPd!4hnvqEE>IkfcvAR%(N~(#!cW#do+C{louo{i?m^ZaEEpjAzuk%+MRDpo+r1W zPu8q7C>!}Mrq{@Ms!dn8*u$DUe->3vk=@A`|H9ldPY#T!Q7><8l`Gd*8JvxlqEfMH z*7AR2%qF{S9y}t?U|)U?oILn}(d=Q5)RLhe2v~E|Kkv4AKAA;+td(oF%J+PiSE!sT zqQ;lygwwP@wY`?X`naot#Q%*W661;V1BcVe>H_1$8H1<~gupZ}Xqi24$4O!NYQU(@ ztqxsf*J1Kt(Xb|vDl4tq=6C#B6>|5{@}>VJU~c*4Lk;RkToj~02jsb<*|>$evMN-H zUj9f?nNw+h7fZq=$`5UPD#~j*c&Gh;q^|HhL{JY9`wms?##+%E(%tq-$D}`hD=8mk zhrj%DCM3cq7^3o4X|1*@W?WU!fk~pEOBrgJUl8^|wfPhZVsPWq5WTtYO!$lWZ=c9O zw59u(7cMdU7>JHOz^`3iE~?#Zcg7-E`1G=qoiWxU*1m$vdrZ)g5A~q>U^Axj``a|o+<$_13hB7V?i!GrWHlT!lNCF za|8INZa*2UM@C0oZf9>I2-@Vz%OAFqr`>Guz{^%CN)O{^iBTc$d?Os7eG1`|U}B zTVsug#AqUAnt6i z+tHix=P{eLSBS#cw|}m>Pdgfx_-4YoG7t9;ml_%< zTxP~&D7_8B+B;5PHf?S5JBxA#?WlhseOe0E$1~KZ)!z2mS6zt?wlbu*I3Ex%qD^8U zqE5ETYsxwpE8#27gGu3`h|3PL49D3^lsz_Bu^pvzb>?c*V^};{mi3j45qu`o@kPJa zv2Bj^1s)AOGzPDYU6IXHb8UO~rY}(N2 zft)7d;IlHXyM1yaO3CqiCzH%FQx_HR-4=$gd{4|KIty2=74B#uk;MO~l}W_g67G+^ zliq&2`5@zu?i5EfDt;fH?Ah#3c)Wr6R%TnhPi}fv)P(qJiAQyd!tEo&!DfR5vne9} zf|Bj{BY;(KwgPlDw6-=DG^TXY;Ind{qa2VD;Rae2-=Fon7sm6X3$VHQ-_tVgtGt-Xxt zuoq?nm*a72m?T%sWls)eTNYN1drLfKO#8~hM_R#N_p#YWH>Zf7D@y2%@e=x5=frZ>T_?@!dZwcipMr)`dBE&J))1+!Zapf2%%8 z+C6|)iXs*n<7Q$i0G%rqga}M#65u%+A@5F$V*Dz7hq!o`e@+aOyE2nv(8J|~zkhQKbLXnT=e}Pvo-Q%dE*r13>=d8bSd%Ft%V+-^=cB~ZpOedKlWa;D1K*F>!n;>DU0qN(#5P5dvqokLmBCY!MFmdBeL}=Ll3K1@1*+bm?|8pO}(NzQjkdhc=UDCd?lP`LehFjD4>Cy)2qj z^C-*CdAN*}zOUUczy~hiKDi_9C;DtlxU`vzsHSVuC-&r4WHytK&({We5C*LZ82`-? z`J0YI$}X28B7}G^Z!>w;I^j+Kso&gdw+639QuwnJA%UM5{D@92PhT@0?~K^l7t1&> zHK3^_Q6sX@LjzMx&wXC6og^Zz>>jWS$SNTFI}ZEIaGUOD{`f(HqbX6r(C3sQ1e^hA z+ZvgcdNL}4L53thcPDWXu*N2I?}BIHRh;gb?Vg zfSWqcuD?3z8~W!wi`tV2VP({&`x&yM%DAl9avZBd)poKsuGsgDdzMl+PnLxh*5p$h z+dHqbzajB`*;`f@r+sIEj(9WU@^-cPBOcBP@ZBU7(MPer^SbtI*~&;j#YhME-Wy-E z6^TbDk48Itaaf!zuqPmdCn_|`6)P@w!n-S3n3u8S}S76Zek@6^EsB{ ziNk~(nYPs6<5}KShNB?><9Jh<9jotUnjDRg-}u~y)x9cag|k>NH+1ctxc$Qaav|(8 z#zTdu90fHw18MGfxoW75=d(W99+fr)2G{T9!ff(pFEddj4L9A%9r!OdsZzb9~;bDT^tk$6W(0vGTj815pC=b=OQU@S}koC4GA1!B}uG z%}P@sW}7CKz?ipUtSf=&Q#@7bCcR>VQDeR}(XrjfK%$7+?Bh>5^?JjM{Nep;dyH znMG$jYd!3uSgGDNJ1S-rkio6vc`a7{<7o7w=r--1rj$NEIpLXiiYpO1PThNxJ}=L( z6xBs_=(f;zxQrH)+I`rK<1lx2=dk!$87=3d*ghw_`QP5~_*(fWp54fAO-n|?D1E2s zi~jLaY60n@-Q8-;t1Dql4iE`3ExsMLek&jCHrt%(>XpAHCOg9#FAG+-IuEcDe)7X#(S)ijEj?g)g z*7+!k-n~@jyOq}l?!$u(UCYWgHWnVo?HQiYxp%ETUt3_x=jXeA$Y*w0^>;?(G{fE> z7to|GYy;T$Y)u$iBXF2?+utxa4sIq#=1NRYEwk@p&*6+^eqPCT8)BsUY~3Fzu!YRN z!;jCKR@*9yDn@<1-}g^Z9-F`G*wfC>Y^a~Y)w_{sU^&AcnWG^L;N@~SLD2gqf+Q>5 zoNe&leETI~D5Iumc%nn}rJG`Ce)~?|D@Ejv&SGEw14HxOeq7z@39O}(4_s1v5_fuD zAzkzNc--ZwvhZE4iy4vjf@6U){PSARHTG)*xSmJdG~a!lOvpss4qz%dlSvhLfzw%> zWNWdoh!O?p4w>Sr9pNHIkB7+ZJ1$(BU>poaW79hE_*{0|iM}odZ%VOb27#Rz8ljTU zs1YXKkG^i_#^asKr6Dc8TC|^kJwwVpfnU4dZm&6*%7f{@IZxTNT*3HZ_O7%wA0J(R zWUY%r!2i67=3A$dJ=25*77Z*%wHtmpD(2_w1FTjy7F5U3F&_85NlO3Y4TF)CXfAzR z6QRZy0+Tl@gr4K%lFtaj&OccGxo0yBa}lx-cIWxs05%2^v&fKVk3&B5nmK8VHgZAG znKj9r-0(~U%ZXAqlJ*;DgX;3>LtG3YNWUu5-dPwKlbzwZ!?H$)EkLm0Df$1cVDZO4cmV8_=*J-|b7gy(&yO41TL07Dc3(~|`5^N!ING?2_ zrluX_V33aQ%iy{^c`0cdm!Tf(1zOhKh#B38_*}6_1t6MPE|6%wzbyLNi7sC3$FUgW ztYFky9la;Y4jJ?`)VsIM#N?z}9tv+f-eJU|wS!h&U zT|(U4Tut^mN};6fD>H2{^o667G~7C#=5F*c&v;RegJv$pS;p{kz|MYdXtO#)l zNhNI4ubn+&5_wz0;hE6#<|FcN&kw)?l|dZ+x8>n4?`yn~u1xpaX-iFEE^9q>RwRkA z1cWf(8|j+O=)R9#Q8Z{AA>kv_erK*U8UlUiWeRL3=0_R}qiI+mup%A$k0_)kBw+B; z8>WxGhmIy~H+>ulJNHS&T4hx+=qr|!*joL{B61OIwvNk*cq4fW=ybkwD5n;ue0#{< z!#kg%TyHGsI;ZZ@PTCAi4uL0iSOY|GjiK4!nMhD)Kj(@26Y4cQy`QI`89xkfcD;>a z)SGq%(nI2DSmt>z0 z#Z+GHdLCmeMPNKX70hl_LCJco>$GLIf9&*;-g-4=%R7(#;5!)uG?((XPp@A)UG4?F zsOAA08^tY5&t&Tp<{>YO@n;!C)4nx!=2uQG)1z_sJ%h}nFl>hdD}DebgB;cM?~C~% z63Hw>yL~INLxv%lb}w;XvM41oxohb>GVwb>@?==^`mHC9oa8_H%!2fCKILr>pCb{0 zWcxIGj8t-f!Cc5*qyE{bDj?Mnr%21R6Mpta2$*Qfw*Pcn!&y^-BF0-H$M9Z?Ir$L& zBH@t3W=m$?+Ct_Y4n{HmxjJtM0ac4XkCLtzt5C(XwB=^yZwCLZ60!=xtm1>*SmA6( zI?QFR4hrHIJ)!tTQk~@8l(!r(^UW`L*jxrxC8I=K8t@WPs@SyOHOYH;sPH(-O@@6M zj@!BcK|D@kmFw31P8(oE**b9Y;-ZtG<+rgd`9g=dO4l)##5x(Fpad-j5InS zfn&p+`PwA#o>&Kp4BBADh008#XQc!VW^S|GB`nNlj*gk#6=QTiAe> zYBCp*A`0z#7DE&yg14bR+6xWQmJGE!&52S>?g~XCwyNp;dl0>ia7Hi+ai=R@@?bo9 zodDjIn8EY@G$n}W_=WwPu0-Za3Ry|$wO}oc1p=Ug) zGNaz2n>>|qOY=-^qy-=0NYp?*e)I9WI9>WmJjE)uvefFLqlRqHu%)WKXzp|(@Aadi z&(DGC{gQ`*3acT~0}KLNgCVLDfdxjooE@z_2(1X=t}%V<@1*!jbG)` z=rG|goOi$+Q(clr9gK2_HC{Y8hKgx}T}qlzhQ4Q&A$XjsLT)<#SmEd*^=vJA(Hiwu zo{h|(*hxcIb>$2;ehHIa7h|`AsG*|{a1Hor?Yr6x>r$|vxJC)&mL_FZr zvl?hgcdOi$Dx3ZU8_zch8u4*<=MzUg)A8Ck8tI#)b|%JMxF?(EF+aUNG#-n+yWFA5 z_S*SW9%TP@@GG;ri*ZW>eCpe-ei2Fu%S{peR+M_aC{x|p)@~kK{wQQExlR$<|6D?zYCY0*Lh!Q1#zIF zXSID)SA)doruz{z8#^(UB{Q^zwKEGJWXYqnXK2m>K#?e7f|%*|&gIlo5?!nl|B6g% za(18s5F@``6_;W8=d(w{QA1uK8s}uB@{AtFW3@G`N$*vYnlpLN`_zvPmKIOL0}PDx zxGzrhQvj4bzOCcP=+61-T*PKu0EQOWh1jyFPQOGNA^sFVdgIR6I;vfM0x|0$`eI)2 zcz3Y?W4R@#@=*mBS5f*Bx^Y!Ag^TXox1ik=g=c4`$mA+G;jNsl8W{VquyD8B9q^V%ud;PK9X4Ghl2BtU02u)_jK5&1WXBS(^0jiS?uvJ zg5Gx0Mu=sFTi+z5VPky^&RePQ6ibZzv(TWb!MqVVMUVMTo$LlQnG(%oS>xXy62WR> zf7nszKAr)}nVvFv`Of5?t?YMNQ0-X`;q{>OQ_VQpH@8_vI&>^RflC^Bo#+8k(SBmF zg;VB0l%mcH3ZYGIB%lTa!)L86`vl)IQg=IWC6U%JyY+Uu}47H`S zvy$wwV@LEs^(sd2iN)=&A>DXqHVQf%I%{IzIRb}4!3d;emYe{4(N`AIWSqV=k7?zI zQZPXB{}`P3&UzWKVr<5CD9Scoj=opDVCNW>y5d~U>_XNULGqZ`C6esUNjW~WArKt% zt!pb22%ZW16c~pjYOc5I;2`fwxpFgX%h>rmZAON99y< z!LLoIQYJ-h&MXp?TU6nG$C=sItmY~z{jDZmIg1{{1BJhwe|Mna7VWAn)4p=ka=^FV@+G)P!(1aIN9%u19IkitsR-?;}L*US403_q#t)Z7ZFm)UEU~ z;w0SZA-j4`KTZimRl(-%^aP5vmo6+BVfp(=m@-$Q$sD8E_yGzM86Mo1+2hF_F;m|Z ziTyg2D$9l#j;RdXnM8kgiWgZupODHs;##BB3(b8_(DPcwFecOv;So+Ay(+Ae;aEy1 zLsi{=pg5ZL8$J)4DFW0CBCmA_eKLYhCCZg#13?L1q5oTTsvzo3uqCnKDEU#gUE$~h zsDjHzW+al4NZy-0JY+Y0Ng0PEdS|$t`X(|aA}1;H^VjA3(FRYwEO7GSQhm5r2DZ+m zp9LtAwzizp>vU4^Q7L5)%Mi%g6trQ3yq2@W z3%GCAUY=@9Rm9PMH(Kk5{!5c<;~9cl2?0rO3!H&J zeagbVZYGK$7V(#CWwlt=i7Z6$`+ghN7C!eCpNxB`uUs8em}l2G?U~d_qn%}T14{}m zDxhFV>Sgwalln)ut1MEvNK5KStZh$5Hb-Qg9re>>mH@vO$b-s+_MV1+OkVs5#-lOk zfbm~X5-(F=q)l%5qL}XcqL94Ucf+bA&(TOH*5y@F%m--S#`DgeH*zv9Tjufef_W;S zHE?Gkv;yAu=XMTMc*mjJU4@g}&NJimc|)&q0C@S}y=f7x*e9-TfHbi&V(@TR@XK(2 zUSEIh9r-YB+e?V zhEY#a33?1~rjsjDUTIJuFWaxam5q!>vB4=V@+|s& zl9}6wT91*Cuq;$tL{e@vSK|NTWV8n1>Pv7O&6ZW5IIk;_TIPx84snYd0dHZluenEI zo`@Vcpya1C^f57v`~umMC?%9PeS;1vi?whfkP27 zLphmsst@(Mw?HUqzAnaN(&OK!Iu;si6Rp#DW$1k{M_AvZdSbSUUb~fu&VBdRSa)yf zZDaw9Dt+ay;R6n=e*}ce#yQ~)2o;=N=0efJy!_^7XYz<$cWIDG=G)dG8;O|y2wNGS zqkTtU{kCdxssE4xQOa}9Zcyeo$#Ea*Zj;12Z>?v)Oj zPp{4H18q8tk2DXy@hO@7w{M^$;Y-DO7K{UDs-*!}t_DGO@bJK`#q3PIZEgWcf7g9$ z%#|1Zl&~!l$#5pIE5~I&g=_2c$;UL4KZk;8hp3Yf)J1X@4wHssQrTS-L1a@%m-axU^R~>(Fv6A+=9~0AoC!DEX7ST^2!dDXPYc%BsHY2gG3@u&8rx)seI?r(*iv(t91EPV7p3s7}N zN5pmfE``CKiNFc_3&$-M$7hj{G$Y+BL~v+PYXggIS5nY97`rlar3T}x(bSWb+s*x; zvBDsqoa8Vqwz)`=aVvp51;9DQ-3CJjaR-)7;`K?-TjXJU#T)AAHgkXO9bI&zaj|jK zV6z)8WPc1#5|_kLN8~y}N$Dn;`6p~LP65$izic^QE7mZS|HvoxO!PMkhXAAAL46rs z#j1IngqGLwR3sZqZF|y!u9Oehvv0E6D?PGM3B3G`b*s#w(3M^xvyXHDiIWA1`0Tj- zEjiD-Qr<}3v_y)|^R$<>LU##aJQv_FZ3^p@<8Etu3jSjvnn#AyGoeHn)mdI*Q4D&< zO;2N3kGsSr!~>amoL$4N)p&kK$R*?4b|;`^0e$H6YA_m3VhyY$^=TBKfJ z&VTPLeAR>7O(RS)NLRs`HEviWpPz@~){6fu*a~c)E2u_U5)nFGo)=9S5BC&H%VFNF zB*E_72$66dxnztnrRor-Wp3}(EMn_I@L}68-JVjo3 zk{0G4_qu%kAY$WeW#JI$JtU~!iy;DX)rd?AU5Sva{hJxj1KAu~6pw^Wq$;o0@6D1_ zqm;C5d>1gRF5M`DSHQ*-bya)b-`>8~;>d{morSRsKWQ-)uT<4HA3|4JDUjMu#_P$) z^qc>B;Ily)3?j3eBIf5mP!M5p-Rbq1s~lIYv}KZTDMT&^>>t-`BgKYmiv~?mbF@G{2 zqzxkHISEUKFNq0rD9jk+UV^dp_H#Fwv$jPg9NE6jxQrP1j`?%x>5{*NPg(b2{mkCe zOw4(J9+r8+lpU@brLZE*moPvd;B?^&2J2C1w}unkI#^A#sb)1o0OXt1J?@BSQ1q2ff2nOZO)rhfXUEM2Qm{~6?Hm|l0=J49M{)wwV zPGIrCymWUqbr0<;S1XV13=8#~pH?AKq+AWq>aw3su;h~HE&t`!0Sel8Ej%uZxSxJV z&@}7TU&8~A-Ik5@34<1zWaCD#BG#t2K;9fs-FNfy2^Gsyk^JEJ&HZ#k!`F(QgMpSE z<@Tqki2Dk{Mil27J1i@(34&4y{!XF?{QWyv`H9Ly&k ziE_BoKPo#g3^~ajLvDDcRvalBH{1Gs5)adAufhCgB%ZOBySF3{e0b3JRhv*cB!^HyoVOPQL&A>pUxC8N*Gm z%kII8G&d4z8uQC|51q$nTM+)bnV30TjuUj=7E7Jsuati6v#krtZr?`$w^>|41d^q6 zXk{?z$6n%{5L+`n&Zba5!1@7ZtWH0^xG zT+Ga1>gZAn!@bc(R z^dZi0^JwCqF+`DD+x{1ku5Y*NzgJvcZ6-&dxg+_(a2$P}<#jycp^sa~U!i&&F-W0v z!pf+b2f7=AnFM9?IkDG`5aX$2i4xu5?O?40`mo=OHmFeqw5yM3U|fwgz`1Z4OzCeu z;~juSKZRosQkSjoVp4F3p`iZEF@f0EcZ9E39g6UQ64Rymt*QTlNdl&lS~^lVKy+SX zimhzRhIN`Cy4`m*cl&zEE(pZV2O_EBCo56S9cKNKhI7ZGjT*+^P zhip$VzGtlSCR!76YiQ=QNhz~M7{$BA`)QCcqa<&AR8`7B={0$bkuEsQO%fVD!vQ1Y zRQz5o8e6>SF1UH)5%aK(1=5j@q#~a}&0bw;wIM{Ch>$$Y@)J{;2~mnc&=0`aFHYk- zzApmm6(ZQbXiR2GRbcjCdI|5tSI#UN>!HT-1L@#=u_*dDvW(7(bo!nA(*oh*yhzHl zym%SH7$8-r6eP&v_Syw&Kcj-3O_?VW2yO%Ej~s2~BUY>KUpb@4cKxwxS+7C=tbR1H z>kB~u8k>b!Yqy(LN}6{=-FIWRX84zoC|-BruY*+5S>(ala%rc{!P`nX)fCppKqwlL zM%%`eqyp{THxoD=oMp989R%%oF|%MDBs|0PB;1r_(+#Vl(oP_L{OkqJGx7rX7*Yih zGCI;f{+IAzE}#AAhXZ|HT(_s08z|t_m%jvrZRNW|ulBENtku{EDR^mWh(apaLEbG( zCCY1VW^QtSHJBirJ$Ct}l&i_oJ~Z00ah%6VR(Bo83~Gp0FZD&kkC~aU2@a5Zon;yH ziiFT1Ryn*IQr-b?_WTl@M5Jyy9_M^RyqLE%G%i6v3 z0V->cuk)a5{gmc;+S;ZUFUK<72_+cZHdf9)4@vpGSi}W@- zw@M~<1c!}ivqgo=%iVWg1YQs5FknQyWdkUrj=E%`c_!i_}lTRDOp|P z()4%zq{nZ#e7ubkA-Xm?t@+_eijp|LicOGHG!;?dz0JS}j=M<^NE{7oNmrc@Xer)B^VDv&)5gYv8{)GN{*1i2z6c1q!ioigQ(>89l1xBHg zsaqQZ;Y?44%&$1B0EvkhBQRj(MA{J#cpCI>Z(#S~LzeHl*Qrz5kQyOy6x6{+x~ac6 zK*6eUXD{jO1d15>H|TbMwAOepG2zZgv=nBgMG)d7?3Mic+0voBXAX& z&iC3IAdG$6QgV^RFn2@s-`_vl9_tdl-6oIKEd1H5<9!G^N?m3ANe2xdZz~+y@Fjz> zpv|;8fsN*qU?3`1h;#Pw*vd1S{FYk3&uXBOEqHYi7a}`k@w#s*5Y}_!k04duF@Uj0 zI2e22YOl51vXMvzaPhe^(m6U)9LOj>W9T0W5TvTb;bjh6J`q*76EG9*B8@SXVg&P9 zN2*=yBnvtW_zj80$s)2Us+2Kg@0P>&22{{tK!{dvUEO+492HP93g+(E2Dn)fh;OJ~ z@Sc4T=dZ0oMM9x58_SGbNl`X>|Keb*>)zv#TxqQA&zZPZDjpKfYZfUS^(@haVS2hJ z?7D=7>Uv~UUeU7RCKg=|K#?tUlBzs0jLb5KH5&O;t`7_FPTh_vAKBWXU%%`Tvsp*< zUG)jr2|^p_7RXYLRSF%CnydL8^@P}<^=^i?a7~#&!p4poyD<~{(P3C^rfL{y?=&qf zc*BU!YEXLpM4l6Q#ELr`_tgaX@hn+GXB*8@N@d~d=GTOAj@TO<0+Bl8K*iwB4O?)v zdo<{_(iRwljfgg`D}$#LlZVE-9|u?aUf{plX?H)UE1hUtej{Ku9GCn(Qi8Am^d%1A zf}!hlRK!nOW4oMQ&n$EwOe7KW`5A>(1wDt#!0pqfP*pW3f#joDuPIeQXAFepT3PT% z;WZfG!}V)5UtYJbw)>*D3mjfItU$4c9{J3Q8c5>Q_qt_J+@^*3jFm zZPP_Ny7Onw_00H!&LwneG)`wnTIcPRk&wB*NFo^xT7_R;8%`EJ<;OCX{j^uZ8IciH zd|$qj{!BX4$FbrdbI5+cS*UJ_C$kXd($_YD;&YKcxEza&nw{bWxg=`|j;P~RgROvIeUu`6&MY=fS1m@@w5Z*lwL zD+iDwg$*Gh>+n?&2H=;s84taZC)o1+fKtL$zBp>Z)v@c6v~m40hKVu55h3TQ4>c@Q z9L$DRe}Gm}ckCTTX7W4O{Wu=2%jl)Jh16@;bNzdTHch|b2!B(;NxB-G z0g}*(0eKmE3DVBrE6#oq=Qu=*l{SRocG~=J@Kf-@aS3PQq<^f<`&*NkwVK_=mC*Kk zc6XPPRq<*6Dv;~9KA^QwNw7%R9wx-9*a9DR0F3cUNk9akEBHEgc%<@b2uL7JNRlGd#i zGbtd%lj$$MUgNp@a87$kORY5khK269ZHJWHX;`Sc_m zic{Xx&&%TLAg59l4}dpAQ2HQ}ksJ>FtS*di!Rei76~dm#M~-B+Sj$p2Ce0oN2pz5p zVx=vQ)}lgIe|OtEsztlWvI`MF-VH;?p}XckPr-)3#!g_9HtsBnb0mdsC^zA?Rp?#a z+A_I$$r+lP1v{Lyrx~lT_Lq%dV<>AlJBN`2*6`ix4&v<`)Xavf>pt96WcpOadv{9;N+1#54!2_s3I*Bl=?w3Zs!2rc0+UL9(5@qc9h(k=*j;KYKicMgF-6^+5Z{6hB)r(cy92cD)N zh)){ccVd&xtmk^@`zZ(IUjDG101diID1yzLX=8%Wrcn_Z2bEv3)JI-dAANh(n*-VcF4rsC!SQ!HBNm=tS#_Z8W0X1Qpp;#Hm%kXie288jPi5V(p}KC3`JH-bmU%ws{aLU#+K)S=v&zcL!b1oi`jpTTpbxcUZ9&R8Jnz0iGfb;HVdHX2ra;-a|?geec4aGYz@ zb@TN)ZNF}Rcl_;s+{X7y`UcaD^{GmNPsD!tZEINx`|aT4@0dkz5LpPx5N7_}lR=>| z_uUA8u}*$baLU{JOsCSdU&+EMbz(HvQs)O+EqY(+iSe)3dj{qyP zN9ldgu_l{p+tVKoE>y-h)(7)@(Fkom$b`_3%Hh0yawt1ihpzYp`iW+6sHl^tUJ8TV zWQu0rmr6+e8&3EHx?Xi7WSI%qftAR!rKE8~LG`DqtNBQbRAQak^7~sS3HMl)p%2Wf z;bRUje|J}^yeoCtUn~Y2cG=sNWr1Dq!B;yJXLN9`W zolBSq?X%;4+5S4q6R{PY z5pBc!N;@E(5}_a*ZKzrDM2v?0uIsUx6h;IGVMCBKsZeI+F3!GF8pABN%|5c#ZFdg5 zMxZT4DxS+Nb)O(LT%q0Y6RYaj|Zs>egF&qy2}B!R^f0Q z=FikzHrepsq}I^__chv(>1DZ0|M6QW9%gtP&7S9~lG=`^NRkzph(PLwf)oOU6onjs z`PdcpAdp&=B7ulIO8SdxHq0UKp1L9ISI39k6pN7!M6bzQJ-94*ZW>BADv z_rJGp_mGKB1$lNOiWz60(4NrdqAT(rDUT-R<=7(k1gDS#+^83uMniZDTD6xxkOVhL z2TuD!KzU4Pj{^4SH43G;C3(lw!01#kMO~1e#nP?@rWR)w94^V|LnBqRm40}CQ0o$y zJa0f54&{NX+BTFtm5kbVr_36-wcyML&va|b)U|3M07%5fZ|vBN7XN4}uO>rjiZ`zq!d{LR(&_qaWt zmz1^TjH%P=*KNR^dW@eo*U+fP9&<@MvFwp0^|c&Zq8Hhn&pap4GsV3V=o_^91|Za3 zAfx_!6?Xo(V}`O>sGHgQQBER8J(8!$W4r+~nUPSQ0m#lpApC$~5>(hA+i-XhIPre2KLj4oA9j?yRX`m$nKNdNLnCh~4j z+of|F?x&9@BiEP1TSjNcAA{Uaw$yv(GXuQ#u8AkP9cE6B4Iya7Gz6y$-57zAk}=QY zMpvdSj(u$H(ce=?d8%`S>t$kziWXPb@r54G-S@HA5}LA1_P9+ES?s+b@H%R(-@kff zX)Wx&^;ZeuFB*EM)vfJaxA~)9{uKRQn;=nViW?=PXpT#0c+M4?`0W*e1JBMUH3|b! z$p$LCbBVMs=!VebF&s{Nsz!(DhnH&`p_kU2!zU~I4A>Clyq_hBvvF#;9<=*=;lvY# zb;$1=__ARQ{BGFYr+1wAh~b(&A0EMWxmda&;*;g#`aI80kNP2ttru9b0hWlyX8W*# zQbl~-Fbb9|qmHeFJZ2$KTPN-8$y>>6-zW4kJ5hjMFjDL>CU7G%-<_tCKt>KD&m1&VKUjEDkHfFT z<_XKuMIlimp?!Vf<=Klr}#SzvRD4eu3%TEIwP(TDf<>g{aZp7UI2Qr`Ki4jqZ!L-(nU|$mBDmduaV4V0z*DN!k$G_CJIvW-o-a2i0Y#2)uwC zR7TDRFOk2(8bx zsHgW!$%0lh51Pcg9u{%@G)K|SKYPyd&zRfJwmnP^uxWy;q$R_O{WsX9k&Fq;25asf z!cUUFWjEp?GcT+)RF^z|xnE4D?M|nXtQk`g)`m2L6Z)W=cBuC7hpsNvGVl%Vgf{u) zCuN-BZOImMQTV+AOIrOmm@YUWr|av+=u6Vl1BB$T%Iz1u5 z)D63zcQqMtR4gYGd-lXI$uA@<$!evYRW|HH{snWJhhsE}sv~_rmy4ba|KS_nw2;sv z<4JU8r_Q@MSJlS8&-zUaYT67yQGP+R3tu|H9-{Y=0$$LF^=MCLS z^062+FKfE5J(D)Z&oC;lH#tv}^O;FJ@9`J%7pId;5^<0!S@&7KPY^%w-0)2H zuJAEwC!Wu}l(UUJVyFs~$yP0}6x`CK-_ZrQ4BJ{*^RK!E`tOW~mipu8&x!SdkEU;v z?6WUlUcDButhT5l(6oziGu7ON{I>VxKmCdNn@3434Mummo_NRjPilmVeF0Cad^K9j zRzY&ZFWzQXAAYSZ&LN)%LA>{CmVaDsaT7$o7ZMF*a&)eE6hT&3(~NAbvG3v3V%ZT? zxtb0kCz*;=8|mG~u;C zU7E)-wj_W2)NSFT^E~F5?U#TTtMFIRz`c4iYJcB?&!mt*A!K#llZ?;72`u@A!BfUidzi^#v(t8TaD?c^G&0iW!AN9nZp$WD^YH|GWBPsRA-yu?}!BG;FE zql?fJS=|5&BuHvLs)p+q ztgL&5GKv1$w9VCO76NZQB~e|L!h0Ng&?>N{yoK!IB=^(Fr#83!@sp2kGrCT1Z@}>a zBw#asmH{iLkn2-bT&k9(8O9vmw4<-i2R+_eze=swJp`{%SxWq$Z%OG^a3=!eR7~m1 zzaYQKqc0e{GBYXc;IYeh=k+l?CBvlI!}ExgXOB38P;4M*0A>O;#ePMxrSNW3N|oEy z=Vc;T4CATXF6>;5{ZPfYhQlM>A7UiE&%D2_lQnq zdXm1aTV@weJoL0hHRQDxRZ$89oOs*x|OsCfG1r(l}8cdpA#3@u7pVlk|P^OdGCm-u54WQ&| z$u}yf70SY4m%w`U8>~ESzU=1L0>ns#f=9+Yh8;@philQy4f-kCOZ|Rsz*Ap+ zEnO>X%BZ+S5q3+wD2lPo8!cgkmV=LsWOT#zr}qiR^G#w^8zQth9LX}UJWA`&&fv$| zX^xoQz-=eh$Evlzci$`bZpzUZq`4YjBxPzk8V|_Zc7M4FiO>#tRYgY5c1e*KT$Khm z+aRch@VPe2u3l?BUM>VFSvH_ffiy}Lc%4RBN#zA%KMr~9j@qO1Rp?RPX7D}Ke+ zhu-ayk8CD#UWA(Gshn0O`)1T+gaYh7!>ngIZQ%?V@{T>CEZ&zIC=T06`?nb8d^;t& zpx;zlk%Aga2-_cDveLCl8B!1-c6{cBThFr>u`sOk>D0LMLR+QNJP@Q;9G6+Frzf9W zU!mnIGyPbPXSmD25G|=8F}$4z9Gie)6T&0%;1b?n42bT!z1m`{A=UH^AFws&mKA^& zdJD)w_-o^r^VvZzc<-ylBGVtUrSL6J%1H;8Dn^l%3W||_BBXE5&yJZpH~BL?X%Ra& zoyuD4we|G%G)Hsg$fciIL1eP;z6R~XfQQ8IgNdydbW}cI0Ba3sXb7>wdNr|xn<#3^ zoMY5YnouLeF$iu9F{i!XqVi?kVV@7Ol^`si$#utpCfUTeYeN}xIub?ChmGj`E`5ET zZv3c3XqxmBrxRTW?gFmLuSl6|dHkFIsJ`Rh^#jdsn{jv?7p}Lda5I3{71E zq1j@P@@wI)*O|ZJEN~SQb5D?7Oe5E~Db()8|2R;vj2VHvgmA;V{5k=9xe&I&BaGg% zi5u~W2JhzM78O9;>Jbwui%*$Gf7p>od(jTkXmWiNxfW>QCJAp9)3+ibUi9=7C877( zT5%=m<=IuY`-IzEo%2Gw;sNy^0&rb|zA+$WkMfE?u8C09Ue-l$eCaVUG@i)(174db zia8lw?IM88&Vn?ZTqXaRs5hro z)*_BtYQy1BPfF+v#mAg6L#&t206WH34(L~dd4ltUf-?%19AmRz*K{|(=2Sb2v}6W) zAGbK_JzG{Vz^T4B_34s_-Fey6VM*3o^Om)cw-*1^%n}vfa;4D4^YI&yLKbDE!J|qe z{vzx>#MgUxf@9>Qn5(*eDuP|y@CR8V9!v(Lb@+^u&I@9sT>@p0pr{cy#G4l9Q95h{ z1xrRo-_?AC>a%*{dR&$%w8Kt(UojW&!bnVrK1zaqGfO>N9xnI1O)%!x-kRR7GK+L5||1t7og$oN#n`|$4@D8>} z3WF%mR3W@{`p2W$FzVDd6riJ5H8F>k;&EyyrMQH_@~vnA*KZvfjLq<~vmn+CRY;z( zPKwc;`Vo>^wjunVX@vT;>1i>Fdheh67;0`85$-+@@-E|dg5<}|;+`HvK!vBNr-$$y z4l5H2Ll4e@nmFZV?OYZ5VwvAu$Q$kS{8ZXq_UrNmadUOax59*n5yiv>tZ!HzR5j5~ zfdZ{=9munWgG6%E$jD=0K)E)L(|{O43}>9*^I~WMj{Pr7$~SW`8Ss0i+wri_%%XE)^7j%7aHQl5HHe5VU3J5sp}gdR3b zr(S3*UO{+2K?rYN20z16rm3{ld8P!e^CubSxqzaWs2*QdMbtKFAx>Yh`o*B)-c&ph zuwoD#A0t@?s>t+D6u$z$=LT?#inrK&*xoF=^c5*E)DYLFjN-kyTCd5Jce*33sV+M3 zgy&g-FrojW=7}p%~?x$Iq>Zi*O2N-{8x67jkHcLIwxG6RM$Tv$=Df1c5B}XMZKzG z$yc10_nF*{8&{Ir&nEDYZPC&?h67K$zo2X>G`geT>Y>c~2$bimN4)HL{W0{kaqDj` zB=%xQ@vb#kk%Q6OOxPA6{JZ#Q?Sn*UM$7=QZ61aE!hjPbCXtXIH!^-l#8N|-LTi5* zM|NbzpPo=Jo&4n-WBGZoS0LYNRH&1ALiz?g9Jc($sfj7`SdchHLFvx8VMQYGYUcL; zAu|ow1jH%s&DZU6-BaxTq1NO2#Yk?*dym`j+TwtT=-Vf9s0*3-ex5AP1z3xlwyhOG z&DsXbzCfVI4~q6#!55pV+v@46c0Q(7)vS6RZiFr7fHp?^Uas4=1+mFt6u4O=+Dc)? zsAdet<~x2n|6$Vyh3P+`9hEh{mpfGHOv<@^>Er~Fgq$%}kGnsLDysKxz{%=!#-fs7 z=6!9hi()1W^Nm47F}D`qc&wj?c)fefdFZ<635Z*ok5ROmRU6+KhZeN}gT61yvfyd1 zQrRH?P7AZN0PB18j#;EEFZ1|aGhh}U^L4@Ltdf6yE*DY~!)4g$g$@k%(xXpbO zoMSE&wggCu2RoGS8f>I5bmuMqjlUJqLprxe48ub{vlc$L1DC|?KcRIx<7GZ5y#cTT zBP1jq?@w_v;0p#;&7$sug0L^yP4J$uInoi%w8wmuI;rNa@3(7dqk*?!Y6tP^%MwIR zAL!oB=RfbPIMI8CxLnBcb55jY4H`Dr3x^x<6-*k19p2d&{R%yJ6 z#+kI}TvCwpLf}R}b(p;XH14C zsAB5U2%~|XT&6SstM(xE$a(b4Ob8`5RsPenP)zpr2PGs|U&2 zp%N!{_i7ZiD`GSd>SX>JISt(B$gkKh!*6^&vd$RY+gx6Wi=+fjM>inWZ~c{LL38vm za##Gg9xJ$Hbt7LK_n&pJ2se_|XdvF;Rla{!JyoF!Y%)@-ElT9S zzRiV8TM+)_r0ro%5yvLFgm$eze_0s6!Zcdx+Y|Cu5KzLVyGpg`E%UD3SE%?ubA)V z0mv23iR=mO@pk=pxA!{S$nZQM2dL)6n9Lzt{1r!G9Bn>kIn#Wr^9?nG8m_uf4s|^)D!(ke zn67=XZ2IBC-b!INH{yH1gOY-YcIPJ*r79k%3`$LHD$T>dGWcy4UyAH z6NN$bui97_ava&uwPeGewB<^^0oR+O<`{;TnI1WKK~%>@vPsIULDoR8CA!Mc&> zHWx0Rs~ZHK)w)PetphFxn2wAX@6J)z?$qUwp+yV09CQvyUR1one8@$%FCh@$L*c9` z={BU@{2F$3T{Fn97L?t1@$3ooth3Bh)AuU2PR#x0Zr{AyQ()l60V{VF{FHHHa z&N7j0B27Gv^4eX!(6-1?rd-sf2DMVg6G`~e+ih|t!HITdJD*RgcH4nw(C9n29&qc% z)wa;pHALI_iPD3oHKtxp>*EOZ@BmHa-?O(CItbjm@mh?RSe!F5P_o z-6p9u+r#bO1dfJ&JlOOHM7#;~9r>B?y%03j8U(6~!X!2ZyVKcu0X|diN)o)}V?YCA z_`#u$#K5nZo|L%$GAh$l#oGD?l+!eejH<5m!gjpl;5O|YGOVKw3tbU-*Py8f zc__KhSgYSVye?=U(^kN{mbOY3IRsE(?s)NU9a|7GDZ^3iD|$BJYHwBlU$vNNOMxm{ zW+(_+ADkdJ{AK>_2q=-M+;gB2t-N+$l79S+s2WH~OOe2SrXl~*P}ApN#f|_g1f#&# zu)*PmF87I&elewwiZ}mZb)ZWd++5OO7X_bRDKSyh)%aCkRikwX5M5q$9!d66P<)5K zW&l1%4`XUG+_Y~fGe1gIwjo<@(pN5rgPi)0*>~&xJd1%}&llyMbsOK`Wvl1-ltYHI zcrsQ}?9jE|dV=n>)K}P8>B#7aY?)YyKcMDC{vq_kL>ko$E=Zis4PPnai`Vv#JWwRQ zH3IbNNU`5{%mkyTEtOu&M_R(-OrTsd-q+vOgnVrM^QIxI^VKz!jmnUjH%9j>Wo33C z^@X)LF4M;NLSgr@Uo9W|xVWLq(dWJgJFBjIZj4H(m9&uBx%IEuGJ9Ih1pIxzFM`}o zNPgEON<=^7;OEiJAAAqC_j@dGb=)Ci*gf>zM?4t>&_(SNMV8-87`3lk6rE{(r3n<` zdvFbe-l$uO{4a;_m;M~WhftmU{-Dhdn`mXN-L5p8WbiR&zLz4HJt7e+gsidx`oE|( zhR+N7Jj#(v4;s<`ht+ANL~N52Cgi=wZ;_#{C+0TuU#aNbc}){ zl2O2@V<_ksC`ER$%}N1jf;oTXR+RYYwsYrsT1qwa*HXlB{Hl&4z>Bqngz>LFJ`vDA zK%DpXo4bJKq!-qB7%=JQ2%GrFU+;*lpS6D3*66`ZD8G?SRRtM!oE!*CRdpWU=XQa! z@>yCKX@16TZFa%5`?MmaJnfym;QsJ3mfr}-g zXP^Gt<1E3^9FuK8UuVn-7&6@Wjl2k>L zZQ_k3INEZ})gJ2)e`?I+sGl){i#HNvlnZha z81B9fuibHB`E6(i!%b5SA^U(vE`m~b#|OOj7yn{}fQDyKV>&~Kg>;_DZMsP#%?8jt zpeV{)T3RJUn>*xir4?fKV^G5e6xa!n#8@qBb3BvSlRgmH@FJ6Hr#b5Gd|wr#LX=OR zNqoEEVagL>d!7%K)Sz}(X$eKkVCCY1{#XnYz2cYMc{;P{DAImhb-^EDlyAGwc(^@>Ylz%qpo;AJn zKRTYx4xPA;mCN8Qqx6eZM2)yv5TVMZZf+`cTnO!c(J_iRmIyp?JOrfDc-4J`FNbeK9phbJI>X!+rRk%{)s_vM#l&t z``q;kT$>$U^ac3}e`Xq9R%g^QyMW|y@4CpX17{aeTNd3fl!mHnt z76?D1kdpJXoXfO=qhHz4-WR#<1*F?A$7R_Vx}Pb>VPkDCj8v z2?NXu!emYqEI3;YagF7t^8LUuqH9oRrlf8JP*BxXi~!M^pn`$#Yoj4-2j?A<2;?52 zA@H}{%-Sk|9@D1F`fQJB9-R)8%gQUNRvtJjA%rm!y1Wz8nAS9^;}**M;;ThnZe~3~ z&KL{AR|Aqq_{mX7F9xGv1ofut>NK)Pcc>SFMoczeji`T`x8imz?NdL)UhBy z)Uq*VX~CR?f(1uLiB@1(7ieOQ2U_!uCAzd9f0J9kuPEd5C(WswNC~{?;5$3s!KYA7 zpF+B>g72@)f>v8QKFFW`dYdeMKfPGjJ`xz?Ci^Bw9}Q5u76yV4VQ6nFcf$KT!RYo$ zphGRg~*b;F=#cK|K19@DL1jp{P2S69*|Id zCLE18HghB^?*=XQZ@^U`;mCvBv2|0n1FoS6q#J!fJPNnhmx&xU%rj+fJ)Z zf0z;GqqOn&Iv!h$YG$ zHV+88ou2^RME3Ehv|M~!Xx4OHx9vy`_%ib~ja;;3vB?|wL?rRl{;Tk)<#P)7@w7k_ zOmSLP`FlElC!(@stU!hp3#A`~?yl*W_W(nDZm4pqJ+9nlY(1#L;L#3Ju`ZlYrMG72 z>fLy0|Ea?mAz&cXNGG^amuIM|%5hrk8`NhSB*hK7AK!oGOE-{4i4ZtCXzm5w^r~G? z(4;_vHFbXbFUyx{pCVkXZn}^O>#$zR%2llm*ZF&xRIMQw7YU;TzZGr=D|@1f(d-o( z&Cq!VLmO65W`Dp4)or}@v zzac96?_lWa6L{9NX&9h$!-EM;+x>uTu3xuE-j#gI*I50I`2o>8c|khNo~EWBsg#*U z8Mr=XjOh<1G1ZZ1*9SKv6Hs)|oEh$8&eMjbQ5bJ&HJ~D?({oPG6eX}&*8{R8^52Mm zc}O$M1~Gf!PBsKe&!`s;I1l3@bYguN4J-&B`2ShPs!GIpx-h)J3EIvE=qDe)c5ei% zG8u|h9{)oYv&MPBjd>Aqjtr8(MyQ^|{c?KG9-4`jH{7674`D3|46IBlPM4O<^z(ZpJDkjkx{JDWdh;! zhs=Dk3a&jr=Wp@KHW_Abs)Whz!p|uBZnW*Si1Y2EwM1+JEV~yu*Q2ety#fZ1Z+ArA z-eTz@yf6Zxt4f0gR&+nU<~F$c>YC&h+C+&kZ(MzvKy%^@pq8CU=S*CL8@dGqk%wbf zsNsU*=u$2+JXa}_##n9AyqV;#GiD7$Jo34pjajdGs*=XGo8r(nH^gZE-Cw3`+49w} zT5Uve!s9WphqAYd$!AHMaARYyoTpqdk@iC*#lu)9{8Sr}gm4rvu@Fg#y$Db2gQ4@r zl8=(yLE^rXXM3zE{g=)bG*}jy1PQG-KBEDrFQJ9&mg?-Zp9DJ*<;~d`oC_&T05`&b z;ii+@4}c~hK)c3F=t9P)7?ZZRh`D@TV%$B}4Qo25gpCwe0;A?2ii+JqCxj+?Lx7L3 zAVQw4`-?avjc*=#h*y<>I{1u7(Kg>NY__6i{l;h7xdSCu#@#S1&XQbi$X?15!28a2 zj_xq!4T06^e1MJPb@wkXo$ zGjJ)N<}I`t*eqTQ41Y}+en_K-h3L{HJRR?c8I#t zPp1@=Q5LcrjfGKuZeg(7&kj>OP{AX94(WCy!`#?tgg&G+-7j|RO546wbgVm!vw!hH zoQAI)cCB23ZKsq1oUuPJz>6iQ;ILx@AVQ`iWH&1#n(#c=TntX)xb&4z_{86}#m(Xr zuuU;Wn&J*cpr`(WEz(iHkO_>H#n3g>l!BD3n)ecM>T_8btXsK##{w3D1~q*bz-<}& zc?xHrmBA2iQwy{fR)06TRQUEkEW$zqzTgJ2PFe7Am(RFOPd@WB*h9`9r2jmG5Fr-$)$xp@ebA`%#vq8v^J3bfdp&KmgrYKDG zda42BnW66>{?dV~+hG~NicJuE`5V?|9IU^P1W|2(AvZUnHJqeU=fGCP}`WyX3a@9PMh>7LXuR$6uUS-Do6 zlD$8NUj5!>g)qb+6$-t+_WFf@0$CI2YzGDnZVeU~E{C_KNXAGR^T6NrM!c#O2W2og z&!PaAHLIUBEX#T_gvLW+g+5T&0!;T*!~jDeurCiMh`@2H6-1R*F!+!yNM)%)GV5=M zp95m>xe6ZLX_duCZMOp!1XCizBLzkx5)SZ!i#qDPs7gs{FBo|oB?Af@H`p!r#+iUy ztOi(J9n*fzc#2{fYTDA_TpuTvhM%blfRQ(v^CMs8>)!2r!;^_Em#HZ#bL|D4ffm~G zVz_Jk+IS*JDe96%HEa9-a#7e2Ggq=9UN91oMW^wI>T`8h$5C zWYvh_iUctjAg4etO!cSq0*tp)mw)c+BEeZ}HPT ztis~TNm+7~Aej}Hx^s%D?HllXaYM(FAUFr=`I5A1LEHV)b#ngaQ*nTNIlr#&Slf}( z#ip~nz$&|+_;Bj&N6#Zt#5;{U#687LyEaNX;Qk5(2#UU-=O9#>n@-q_ zX|WaPm7cKX4*m*r`Wf9paZ({I6KLwcgZEwPCug`@QqOmlP;SGt%WD#__DNYocqSx; zOKd;s+~?a>Qm2P3CQC9ArHY39K^zmW%ItZ7`QVZcd^$7qavh!cNf-f^B3448GgDs2 zc&2pKTar~*UD_vtx*!vu?!>;3`%q&%ra?Ou;&!*=z7Y5xPHVe;#V)pKuBu|d`+`W@ z^jLO19Z7yb7p^089XZ=^MX76bz?yc(h;L!GT~^TGOjl_Ue5;~0D6;gsyhM?_h z&pO2^7?~}$MPk*oVbWm@kFeM#zW)pnZ(lD zi@x_szX?0^GK*D}6R%435)6|Ar&K*sLp}bunyXcx0KC#$)GHxz*MZGf-bpt>&~4Po zX|oa&X!~EXfqt$*HAokA=Esq-;1>>Cm1E5;k{?rMn{P`PO84xZwB8r#T^aYMKhDhA zZCJB$hH$cU$rNvfN)R850fjn%xaU3mYZnGh=<9c2B3` zk|i@V^RZNt!|5*lz+soIvlI)&|oq7-*_9UO!c55lWyy0N}M=|DQZic z0hsY=1UAGFgC!IUz8t^%8Go)w9VC=Aj10C13)qlo`cW` z*r*P3#YZUOwO{(w|N0C?gSz@8r9a0sN)|N!SY$GD#F7PMfz}ONq zsRNrK^93m1VFWI92ZPVpEC#GBhVqa^msqJuP({7_v1Z4lZ>y&-Oj0f`GMIPS zpZf02h#{V3hc}q2K*1d;p5?OmZFCf8KkO+^dnWI>2ea2Ar9F=;s{f)5h!v)0=rJMj z7z!dG@^qltb(G9o|GOEtrM=$}1ECC<{@j-!=11_*$WLW$$XvU(`xaoPE(@by5$(~H zt`JzZhBDrW&c_^w4NVST-OeI3)icuDuQyvt>;Faydmd2P4$N%;(?1~=@Pg^Ek=+(v z9oE=VKb>zAG=0hJw29+#jIv(F+#-w^e|k0gB8`#(VDq1uCj@X7 zxZV)%Qd;nurSRo%cn0YEV#0ZD^6R44d?lsBiXKV&dW})`-xpOXXZ-1lGv}LMfYU{!s)$&?EA_= zJ$P*SLVrWFOx;OW)??unXxqEC|NCuHz;62iFQ#S&L+8!NIEb}ufpSaqmhge;OX8XN zv|j4gFCd;zCdUYT1#Sr0mxWxn+raF0yAT0gp0(tNJ^+hQy>MyktpUgkc-vEURP;+k zzvZ|{EEo+f81135!c*C+-Ysk8Mv`RV!X|#uKeG$RB90N-ktA~e(ORr$AZk=GyJDYS zo8`)NL}QLBEvmYJ*+4GOees*M6|KH>W_JYXa2e&?9Wuqb8Vgo{w>k4f-M#4y|)gkNu;<_-z>>)(jj#D|r%N>5}UEs@3pOkL@%aRm@@mfXK)G-WhZbQX2#sp2+%`gXmEWiiG zX-yZBaD43cbz`PJD1alc)8pZK8P09HcOx~q$q>&^FwopFR-_K_J)1nm|249Fu+F-> zBym3qQZXtm5ZKbSY1VAn@*$*TffYK-$V-b{K&7u_Vt#;5CsBx2 z%KDhm)L534y}q3Ch(%(Iv$A1?)m?#kEQ?jb?I>0DtmnY9PgarE@2B6ob?~m ztPFgmYg%w4ps416oXQRy-Mh*X`VoI9@!$gw@kIB1BTb-9hdX>S0$B0o-pnqhEaG|n zD-((jF>b(I#aL0G{lZQwmR&I^6$6Ey~wAiS_19V zc8Ur(>YOt`jj7t-uR?_fxa#{@p^~wQ&8*S`1ts{qMo)Zpc4%O0JH-HWd^-Vs1=cp2 znh0K$+#<7%1`~|N#KAVpTlyATX(@f^+9vG06teLNcdBX-f7AIddx6Ht?g?{!ZV3Yu zP#$$y{Hn~CXGGpjRdL%K;$qsnZI6o+vBzG??|2QuKp zi~Z45#)fnu!%P37j?1``M7k#+6m+46GEmY~KPB*aya*fxKy1cn)Szn*I@s6kPZ!tp zWXl$C{drCTTXO-P-G?849NhrP(VG=ovIOo>?UQR~bfBs8fTgP3?l*Vmr}kkA^q+M( z8lq`?t~TLY@sTh_nOjp;Q|ZTS*n4z{nc&z1c`(pgXJK^rbK};GBKdQf{wrG#*hQLC zLCw~PYD_{q|9kh-GoR}{Hp?8ZAbDbJ#7{p}U&4vkjJU77VG9yXk1*dVx0sH()4l52;;`hn0p6iV zz62593hn?#M)y0$Q;SqS#tX8Bt>S-Dv4#BQY_3&G3WPs`XQv0x-V@x%_U_-a7iRLN z0IJWTr8lb@cr1$8oxseKCF%HViP){7qy*HwLq~wg=)hhD2iuX+o>aP0R!%=Sb7Uqa z6XfVphABc@7Lxryw<)VZ<%x-*|F+SXqd)<>Y5VcHC+z3EXVOyC?Fu{1l^^BL;5~V& z*3qY-xYjwi><3_=ISCjY*>FRKT>civh%=jbsQci#U?mGY0Np`2vkSh2;E`gFB#L4` z$ff`)O`0P(2KF5mWKZPT$T*z;SyBOqw=o6(`RpaU_cJBo##p!vwqmQJuyvAE-y*r> zJ8RHn+(%Q(ecAO-TTS853*;yr#VH%50x&{+kVDxy!B4uqNw)qei~Y(GMb(!+sBv6r zi@3w(xk9}wHI@}SX~*Q2^nf^IjE-?hQZOz+CJCcL+HXV&{Q${60U zR2*xp%4^-Pks5zd!@DqSh*i%Ay?lkoAsy>*WzmA~jWJpv2!TnQyrLdcNK-KUjQ}g6 zYq2pQyK%P{7_JK?oN!nSn8@QP}eYRO)fQ*k*PBx|j?qhEn0( z$Hzjzdx_O=2`@E;VHYmm%zgaahCF0BjR7G02+A6#5<04#d=b(&DW$myqq9jT z+Nb->vBj$V8Ktxtp~!?gF!Y#JeG*254H9fX4k{wW7MsP7fB73_4h~Lqh49c_A9@Z)BuVEYU27fBY4zkMXpq^ zi*J>HDq-bIoR`y~K+5j^lHHtf`H)?ahs?``zQ9YmxtRVcQyF}o5B^MOhi@{;rK%;y zA6kxS{};}0F+t zDy}hBEO7e-bWw~nLO6IAcNQa|+?(k+oIYmdinC`26I5|4(-QYQOp~0g=8`0pu^=V{ zlQP}`BWDN7Ntn@ng2GXu-fEK}R-0O+?LQSSEUSP)}SAsQaFhJ-P!`&y-j}rJHAkE$urobCk zirfigsgw)&>+6fT1~qF+i5YBid#?BLV_Ixv8WdS*qV|{9iZ!u7vsv>l#t+cI2Z@N@F;`47YQFTiHw>BT^&)ngCp-5^l{6AUt(Fcm?%Z08Of0FBZvDeDf!wi@i3g z`Lieb<-|JxLGkIjn;&xPzl@H6@v&{Bv;~s8ulVTjRJt8kqv4ZO454H;g8+#H*ecaI zp&xzyFHl>B6L9$?%AdfV{hud5sW7DRU_>1rmSTP?Z$YDt7;x^af^RHnk)8|z)=K?_ z5sN-k)c44an7#7`-(A_BC;wksIZh-GBCt5f_u0ts0_sOZ_g}sS7xyE1r+r0)FoS@X z1Q^05Uy>hpK@w-tq+O_M-z@E8#T1`lHH@(v(k^4r4o^UW7jk7#hq`2QA&2}R-b@M_j-v*m0wa~Icmzf9CD zB`^PqFI~=UfO}&G3J<=3;o*t_3|Vou*laY_9x?Ck6TksC3$9~xu`yMf|R zpz6_s3khtcw`j)5*iKyrk`!CGu?FS4e zxe?#O>XN|Zg}&f`K*+HMu6x zacVq-Bh*tO0X)<8>#UWASO8<;68YVt94$#y9k*o}T9tFza=xv>#`tsQ9f!-f5Qdtvj!v^P!Uq^A+kmzRwSbEqP z1*1~~`LgZKL_p~dw8+k1{-4_g_v?whJt1paG9tPQvt*6*@bb9Uv- zn%PYrt@a`^8>jxo{%UJ5M!||G1kKw;$opr59cqXIL$v6t*=nB;OfO0pKY`6}LIj*g z1?=P+w%tzqhV{XItc8&iQ9rw6h~u59@bXCLU?GQzt#5e@TMBl%>kGW-bdcPDhkW=y zSM}SP>fj!*RRH+~fEc+$C`f6|9aM4B|E&Am1I*sG)mpzX3&3|8;Oh{7r>fi@j%GB- z`NZ`f1Nh5U>C2lQ44NK+zka&!a23#o@t)SmviDo}%V?3pP0-F30d%osc`&#+g`|`o z?E2m9Q1Ao)EeNn-@<7bU39x{t9Hz)w8t3N?dhu~P%}+#m3{SXK=(6=&t+fFa50bK- z!rA@7dM_KM(|X5>$iz`1=gGqf!I z=>`RZ?oyC$0cliP8l+RYx5x(RE|o^QySt=Cq`Q$0>H6*m-*e7&eLwiie(suCGqYw5 znK>#ih}-=baO07HDM_+~ND;b4k^(lxAm#Snr;7sh6Dcx<7TKI2ug~X9VrVh_xx`>> zy5pld5Odychc2)JvCpCVe(x1J$`|Oq%f$cma5#aX8}WT)jlWlHr4)Bs(hK3^r_&Y5 z03M5jS$->51(O(DX(9*z>QY=_L+E~h4I!lxtKXSvBNqp&;c!yyC)um;A-HsVu{fgX zrpM{A^%hKoN2=Ndvoja_mFWO}`+aMtrE+U7AH|=@LpCWE|KHaQs6?-iLj z3fLe2>d!kHY@xSvAynmr>V1uY~aw2k0AKO13O`5K_~(0%t`{$yMrjb+VcyT$qp#1I9j ztyiBrpGBD50Rq}J40$CCJzRPasx2N*$?(g)z?X5-uj!F^7~;JzXl>B^Gpt8^uvW>#3itqL99 zgSylw@yMyHT%cMS7}-Hqq+p4$WQOR&lU}wLQYht_DkgP*@>W+9)NWir?S?ZXixBn| z4S)@-?qp`9lbux^PQH>t8sDsZ^H^#qe`?}w>%baj^C&qJzy-%Es~_#8`<%+aADh#& z0RF5M;AW?vYDf_gB$=O0UuZR;mu)v*Vd{zN|m5eV!K3=So z0{UOLWXWJ)b$~|zuo6>#lVqI#G7#mzUq1(FGmiowEeJ&n{+ZIlWLzf2RxerOL%O`+ zfKmdonrXavZ55mRu52kHrl%**bQzbHK6gS--O&c4Hu8fb^l6KpO1Ja6Dk;?T-ror_ zh({L9f}W^=q*AMR+>6hf_waE`YSsp{vtF-07!3pkHE&=%!~`wX@e^P1AnOBg2D}c! zY`)f;tKl*LR59NEEAWHv>)V?I90FRfjftnN?!3Ebyu$~C%8jaJ(;fh{Q6^Fy1*nf5F^L*r$PL*tWaWRqKG({V zoCG-v5Uv6%4_a6NxiR8c8IxtDrt1dom`u^$+4ba!Xk)u*5kVEUa~r1%w0ZR*08qRs zeE@f80eYRqFNJT&AvrLL8S^v zt`Pe`kuudNSC;L_2C?oE=)^-7{T`AI#@b(8&U1?Y`@~V1+kg57bWx#& z+)tWm5cnI{YjpXCmzM$!3q((!v-+nQa9s*wAJK3BZd|Lvuz=!KDxjxbo!=lW{6RK5 zH9J*I2nW(~GxZ1uXyNqf-(Qx2fcyYb5(QrxGkLxSma${r_4}YIpff_z*=}+itk0;s zsFsU2R=6u}-};vmn*o;|7ioTud(GBJQ!GA25mbs%mcmqBCi}Fjp|72%mVI9oLo?(G zW}7g8Els}Lmpcf`y@2b0m~^=sC64Z02|S59)37v`Mo}gsqWa0oR zBx4fdRNo2U#y`{EOwyORiiFFG5o4q zgg&gS#0P?}Nw+Ej*0Nlc5>mS2bm~Yqeo@MZO1-ay*dw)@nIjVnaw1bfTwi8u-O!Vx#h2*Ar0F1E=K( zf7|K@PMnh#a_aQBX%B#>FhgB)&ctQvD{`pdlJ*NCDd^J(SQXK0*J??05M})WO;~EYp+J2V1bJ$+p7&v%0>c2RE zsqj9X!8omoM|1yrC8z%9V7cMbr7#77Iy%tApVndsA_YXpy+54F)F)WObr?aY%=n_- zB4mi`@<`ct1C~E^CLA4W;~kG1)QV)$OKR+a*NXYNe{l5JRJIeKtGN54ugNdFCus?T zxDt~v%3QoE1WyILek(rt+AQ7(0tZCA{yY$lg{lL(DG)v~0cb9=1FQtVIU;Y7bwwd7 zt%)%diw{q-g4BB9##LV~CQlawzxfEmZ`ouC@e9sHc>mPKqJIK13uRD9o@RpK;O)SzkmA3@FI5SoSKsm)`Nyfm3t(A_Hb&E2njRBBqHEptI!5E;6yR8TG_OY zu5tpR0G0$6Q6yGg$r{B`qrU1)qwpTW7d|$i;5sg|Fnp7N3xII1Irm5Avpnaj$G+E<}7Akdk{7du9480 zN&CTFe+EPm+9{+ZnNTv#h-z06q|(^_MKiHZhH5r<=T(PY1qv zm=tUK`=2G*b(s&{$NWbosFV1|dsvw>P{gXabhtswn+DOosS$H2Ge*%KwuP_U=v3n&2+narOT^ka8n}ZRhFQ zSoXuIs=u$v=}o8-q>1k~$Bt8)6BP~Eni+_$cW;mPf^O)2z(@Wr_wo}~B(Iq?@E=EX z+l@GMWNwc7w~w8Y5*MU3Vy5dG%>vXp=U1c=NUvGr_G?-C#Ri~YZ7BmJJ->v4n2Es~ zH#Fqiy;6D>RzBh))y~v|MP!{{RD~FuN}uW2lh{DME>-Yh+lVL2!TEjtYe}q(SfHsI z`-*IV)Zi9?x)u0)VXy0Jbzt4KQ1azC!1cQ`n5d4l7px%r1L+3D{Bq31XD`gfe{tGg zb+V$PprcGr6F6(v^R?x z_$>mHyG$JRdz*@sRmfD8sNQ|a%vC{+Ovj1Q@my%1J#K%!6C_V%J7FL%MF^XS4^SEX zWR?Fc*Ya;uE~n3GJjIrP)7InEm*(w3sugK0cu`}*utRQh`U;4VATS9V#Jzp=D;5&* zKY47gYB9H<2VbQ6thbbTnk#|m;16I^3$udJ<(~#<;R<5jxM<#cS(|qBL`*?{Mq=6S zisY!bCl{LGJJ|`7e(5NLUJUJbxw~Un<_of1;`gLvY_HO~SKo`HXa&H*59S>MM&& zi$AUCMgyInzz2T}E|l&#%q!}Erd&Y~T+CD(*>mG(;<ECyqrO>=YsHle3;{TH(|CZNSUT1dxh{}42bs29=v;9i(~(_6E5}=dSn*J#M2cnraNBYsLV6#Rxa{=_DMGFi}Mdk z$4do{n-@$>T(#jc@gh82y3J~#^5Ax~AlXuZpw9AHbQJT#N0#v3>?26?jr0Pi0OZvv%dluU z#i!X_+I$ni^p!#&gc?f}dx+t3EfNI|F1@Y>C&aqm)QZ2B11(?)u&c!FU0;zJd)dZI(gd)pP=k)3wrkJ}bXVnS!2@#dE=Cm^?1e^64(M#CcLE4Dl(fEDRZ zq4eg?9%;^4@5d_u2MWVF;I5Pz3ojEC1ow^_4p~DWE|NL;d^p z&{t3(79+55_3-;59$_&QCQ(&H89Kr0o<4uPC+DTM)SLTIUl6!rn)RwYN182V7WH zp@K?#O3&DAlFVsvX4=oFx*#Z8sZ7N_y9!`mOAqM;MSoVCV4d4VJsbLZ=NmgO-iD%u zW+WJ6siv*wl_c)6+VI5U$(MM%Q>Ektrg^f@w7f!`OR)>q-wllE(d2<##fE(8dqY}P z!y($nQ#PGDAD;>PFiqmOHbM!~H{~t_W4>yCt0>60H1Kun8>XsW^tiXIM0*$C?8RFJvX{ztUDJ!;#fTXA_c8awm)fWcDxHREpJW-a#DX6 z>+iqgo!q+x2VIeG!3+HCUbrsvn^~C!K6n!a8@wFg;Oj`(A~^}ucSw4STf6_&-i;nN zx^Ygu(nheLLmgjH@38iK5a0u(6dGZl>vC|4PJ3pEcOYpbSPf@~8{&7ld$&V;f&s34 zsf7FB>Fsmh1?*dou)N-jQvbNa?24P1Duw(FXl2S?#GBuiya%atOKoqcs4kOU7+Sm{ z076WY!5|KQfg(nu=3tD=#4IMa-&4bs2Vw&(pNINu`%w`Zmre#r3OQ(T&hJZjkC6? zY1wOaG0JbCD&=c+8z}Bs16SKBlI1T#{x>W}z$W{lWX|g$N5^+tEO5oYz_c{0C$t&O z{As4Mxbu%(M)o*|r%+>xHAMIg`Kj=Hzr|N?gIQW9<<8_3;3O{fb+yL36V>VGnYuF9 zqrVpaYu+9r@)hT6k;m$=0P~1I^EE)n2h(^D5U_pDLhHJeHdT7n-FCY%$CXSFMqKL| zPELJx-opV|pC}M#-!4ywBfKPl4!W2rAdbjq7^Ji!-4V77Ijr_%3tH#<-~<)b@kSi) zyomm9G|DU{aIp{83GrZvYi}bv9G)T?zjwZjyNT*CvAK>0iOCGGnn(Y2z4EYfF1fz6 z0+LDh6v2}xHKrotV8>-@)!gsl?Nnw0YAWy?_2#Eo?-7YzSvZP%?;{k&M|{cdPepjt zBfVQo2oooV1E~j9(w^KlZ_o|}Si=6|*oxjF<)nMw*f%}$+w46ZG_5yg;v}Jy*RD&F8t+(IhEN_DWirBi4l($}&toz$ffoi=={XM6KCwyh>K3MY4 z^w&xap;96NC}EJr9fJCM1gkJQe;=AFW9C)Rx?;A+4r;YnOD1G_vCIR<#(S?No*z zq*P_$^En%7#QJh$X8NKbl0yd;s|XH(MR)nLp;}IB5E1}d`E(zU26j*azIsLEPe1;b zAS1-P3;V@mn8wqI%r~Ip!k+bX-V01YiKr z$LDD8L-+WW`1mqLl2TZI9`TNUbFb#8iqEn6nIG4@;BOusa+0Bl?XXhrBH7z&QgT z4$0TWOp&LU6WzSs$Ve`3nwUGl6x5a06M_kpRrS>$Nu09~XbAq}&@@vpl&lr_=v9C5 zjfAi$W(qGPh>aPZ4J8pMcOQ$Yd5dt$f1Hj8e5gLPY}K8TOo!*DtvYVPOm0Z(&DL>C zbK@C!min-u`vEBVzr+K12c*5_Ld?aE)<7QR0vFT;=%wluReOR@Cfr*w)auE{7~Hb% z6rt7M6$c!*$PZtmn9V)lfZ33K4ULw;LmvmoC&D!UGskNk=QrH>b~R$0tT*s+MM|yf zFPLp0f@rqjUaN;z4d{Y`KxXP2vM8$e-UE0^Nd+agE1S;4#vnCWcx5h6kd|D+f6NyG zQ1s9Tf;N440Rj-#F@-8p4oK3s;j`Tw9@J4hXpXqvI3m-0!X%!^qFg{2!PH@}a?>Fk zfQtl1%hJBjhno-58>7=;Kkaup79qQ5FO80ZYWaZJR&*5ib-i66uMWDVNRD!QGA0*V zooX_#fOkX(;PeuJ;tvlF=BkZ&H;+6PQ7)GLg&$}d!(rBo@JF>2UyCS47MtRVPxxNAz7dmCk0V@C9ud;9g1RT zf#i)I-q|h;b6h+Qk=a>veU{M>Cb*A5l(ye@vpEs~K&qd9iWciarM;b4=lKBWqVVE; ze*s425W-q;9v!&WJ6T~@aM|dd-OP6|wUq$m5a9bzYdit>*mG;VHwzD-TB2SUh`N=> zP;d3>M#c}r&nG8uD4+z`9kBb95r4zt3T$*JX9oh?S8i;kA$0jA(GM4X-s6py5YJ>Q zVA=@@AZd-rd6VyZa*%MB&|0gsQ(Tu`q?(&Bn?@deEV4}#+K zLToBF%mo{8E4Cpjf>e5{!*(mWCDnIUW^dmYz?6_WgE97a{RCfkGI`u0NAdSpt#0z% z1Ok4tV}3{HP@luc@#q2F-4{<5C42ZvJ*z(>iyC_tM05!g)du-$11O8X>d7)}cAP>%~r#C(g&^{x;xv(%FF`ZEyjum)@VZZv@n_RI2%ikdYWt66x{M~&p z!N6HNzyqHG+1cQ#C9@p&rurKyGmEPvoN2V`I|D8?0c>zfs?eW5`?LulZ6?F83p(Oj zCY?lAZPu8*^Oo}B-KDZuwCttofZqn$$NkWrgfLEz;MXsK+HGAib@_);kO-k(yuHRf z7hU%E%7_dKYW@F?22{NL7sDfuoykjtUF+Y-)=94I=jVhQ1QDgw8^CXL-YoK3UZ1XA-NDBQ6SHF-Yk@{}6y2OwckhJd|J z=2`|i8h3)SonL`I3Q`)*HHXZhM@&=1A?Dlg6-OWEH;R;?7kH(^RiLU#+8+++4T7#m zyn^gN=>ZQ0=be61?6Ok8ly}~_Gtj|=#J*QF@Xy5n9mashw)i-P_o>>f!kF3~bXr|N&^IcScy#SGEwZJ{A&PR)xgF)7Z>HL5ugr&IC zqwmQ@GyCStp#(V`;|zzl`f&IzW|K0ColT-wlI%qi&9+)=j!1yC@2Nf6_g7J z{S}aZ4MxFcoD5>nU8jpF=-P!rXL-{3)F%PU6oCzQ?iN|)?Cr*U_@TRx4j|9* z{@UosLw(3#q|-;cMvdLM+bkcdt=@N*t>(b;NL=J4gHapE4lQp$Crt0ARJ^f74-93h z=UPS6X;W?fm}I`nX8WgtVh7@Ilk43zX@q1y9UgM?kqhgcUklz`OZHqFf9}VeA>jr`Lv?bp>80f=wKNMHoxfIa7#ki z?-y%%a}Pj=d)D29cil$meaOUbu0qK}IP4@t{nr8;0J~GAMc4odPX7~pMI_A8sG?$gX92av(*UDm0 zrl&}g#N=l(m#=o-)Cr^ptFOfBOIObQYz>TtK?aTRLlz)(;Rm**o?+c?i2^^=agFU- z<0Xq!O1&K6=%zHni?2l0tFS9>pAf@k+g3qJ3}VKccPpt?>Akdg*Wxb93Fg9=@DZfA zsMIm_UUlxw2CCgAdCyaW!NsegBH*cb{qLDO>7cxgODMWN;gsDUSY)>XDR(C_;3kiD zVb1~C)Cc_yt=>(Cktfk7s~joJ6KODphI#k)wXtmkq1C7+&+z+oO9Z}}VMm(g%Lm!t zb1uJ9X@`#OrQo{7nBhUyPMju18V6RL#D(rZ^~Dz7z(Zeah90^#>6XZ}v78Df?W#@R zS#){oz6_ZB1=I;&K_MD~8#Tr%92V?&;caK;oEs=|I19`SH2`Ak;3JTJzWe%8jgPo5 zfLRZSHf9~a7TEZaSM`^Cm7W@;C%?Ww>pHB}(@>R2KvS*HonA6G!nA8Dsk7hT*uP=x zTlfM(Hz*GUiXukaESdId5K8@;dz-;M-DM>5i)_ixP6GKls+toK8O zCT?GLoIZr#Deg4fP@b_!2&2T&>gc=?tQwZs&pj}?4paja57Y#&`1YsRnZDYUb;rPa z8;hmf1@pY(3av4=K;|#Go~t^!m=s7{INk#ZeH(NvLKwo(d1d!z_H2e-?NQ3H5Zi%Z zfbGhzdaUo5RX3;;CIY>k*!PRH!0Ir39%N*}H8(`6&S!Z;Q;6bzpjVO1OEPc;DkAk> z(se{~MB9`{u-*~a_Y5zXsRR*^nEYz3ihwd(k2HVtkDA2ODKbE|B4n2Z~G-O!|kHeF1tJOkb3QCI%Cl#gcT|O0{f=L>E;eT;O1swH5lYQ zp`k_&<#izdmaTjad3)v$XrZqyscvLyi0joRZ} zzbWG8X@7O&96=@pi!AndED&TuzKPuhUTVBzDYgI*-mq00j}NKEKvdU6hgZ7|a@U97 z0`C-#Oz2K>G~P-#J{S&H!*Zrtef={-1m^Vw-cUhS+*7!yP`s$J@{pUcu+V>p4dRZhkaK6K{FUYkhPx8K3D%@2aHo+PIO+=O*^JLxK5oksXKq{IQ*GiIQg$AWw+kjk^&DqLnuDkpW4 zr`h4QcP5S()@M_VnayuHd_nJ=u98+MTBK=Z8~OFN^_K;90bM8vlpNy`@H% zl?J9>pfAF7v%8yv$O|g_(b0hhApM`VyitedaK_kh(`EnLtNm}aPPeOdzg?|AS)~IX z?AhAM)~vIR>Usge=GIMz5D4(NsEHBN9-)J)`~5FHq8mc%9X#((Dt$mlX}N#BhT*0+ zLFj8iQk2_4jMtI3p{=0<*33w>UzE@;%=PB4nbd__eb1j!i{U#H zzADa;3z;R{V8)G~0?Yo+5!Jk5*{5o$LJ~RP-oO(eZIh^8Jh9s|b8nYPcAP+hlOVpYg zZ#3_hioorvyGg}k2AO?v(o#=Z9Mn(EcZCbMKhu88-?J38Fsk31jWNdDBT$HlYMf9xON-Vm1xvQoE z^WRZ!ZMg$ODh}cUMY_?4st*sPI)a;pcw*QV?A^O~8abB(1bGwYCa4GSUVwbDy^gbQ zQ6V$#L>G;-a9%?_F7Ban>ty2XOSgCnc3>@3ZvM9zV3FUsrJs(qCWIkyp=Om3;UPao zvZFr`rV`J^C9e}9e@}C_U)mw7AKkkGpI_8iE&HIhrS32amS?lq_?E}b6`ukrT2|un zdNl#JYw5X|XN{44)z|{QwWZo$FGD03gI7IgYm(y~c|C%Ks+~_x$m;4ejXfLx7_kZE zZG@p4VL0!aki@b=)olrKiVib{(rkT@%L#!S9}64yx!I`FYBr>!IwH0);q6AS?$9mN~4)}n$8_md{lZ@>nK0RHUc zH88s7Vd0jDY2S=ZnOG@j{Xa&)=B5p5zalkR4t_+CGHki?BZb9G70=t2Fu)q|J?f)F zS<8jYvp>c@&U7sB314;-7u^=snPi$rqVfT!a9OUZ0CByyt6%16ipcYJJh{Cv+P= z&JsEli+*2DP7-*ax8zg>CM=|2-bf?-`qu<6W;ysfc!sKQ6c>N|rMw^G2UMRxXNya< zBxU{BkGZ5djJv8M>Pxh%zh}v0#rJdF)MDcnWAu?$-l7#fmBAo@Iq#53H1>U~#TIDb z|6Cz2{cke>^C)CD4BUxga3_FD1(hKfQpR=1?f9$l{SPb5*omm=`HGbJ0$CZm85m{i zV+pV=Mk9=BXQ=H{>bdcJr@VF`2BLGKTHh+qYHRPU)=5*zMbFKJCu8c#;>g3K31vbj zt5+mJr>#TMd>Qv1AQe6}J=w{YyD9HK`(25b8p9mHns4^g7xfltoR0(Hb~9b<{%&;@ z@Acz`802RlNf39V;G#$=aCkH2S03m8q-=c}PL8;eVe>$GJ=p-rMwk?C_rR`JT83p5cxlUPytKH@+Y@oEQ**rLSW z!%@TLfid6g2Dss;CL8(oqNZIy5zUGf4MpKWZxqMr42=8DXoPHSS#@!*Aw@Luog2G- zM$IONy8Eid|4?->K$8w?T8vd0v)QBavOuLn@8^lQV8GA8(pIA6d}BIQX5p|PekD*1oSgxw*%-~w zb#2`E&%F08RWt@?)SRAWJ+C}v(NWp?Q1N`{bYi^W-F^={rX>_w#_dj@$uhnp-kA`V z1aHvlB_QY@!-heg9MrI0tO{^$LuP2*b!?$jSlW_xhA2V6^;VS{Hv}^-XEOb>7trPUT!at1^SDe)?v75IjVyR zKBiBDKtVKD*!Ab`psLrgT4fLc3`eeSDb7%9ApdS22O7BTUCN=8RN~b7xViCV7D(+`BbEkx6sNW%ULM<^tPNK!puc{R~wgOBay7q0}Sx z3nLIpCJW`oiLfIHrq(V_LWR{U-p0ee^sthhR5H5eb-c>VH&*=Cav?<@?R z-*hm+7mTln4(ayT{uYS==X;^ntcIgt`^a3Xm2>ZvraJ?! zx$RUeYnRKSQMX8}wh}dKpX`50F@QdR2+MM1wR(k}!==bkuKuUWIY_!_0X;uG+*IIj}fA zR%<5|1bHvr(z8W=bjo9L(>-32u83de(s5Vbm-I{h9^QKc^`5gt z^I*UD&L7px(l(9J8vw62Rq0?m^F&Vd+`3awRFr!qCl1P1YV~egM^6g^F)kQ|;P3If z)-ZsmnTx0{1_)+XJ^rm4j0(|KZv}na;Ms?d+zWUF_b^K?Ftxi#np^R6@?{k6MIS_$ zI7w9Rz0s{B$eYs=VKhcLZutUKq$fB!MY9;-?qp7Mgr^{rPW+Jx#d6S zE9oX95ZF0ry-AWk62eU1B!KO| zEmQgfUI&OOpHGoTEI2Bzzq0g&5jMybj}Ep$rdJ`KDA{dd7myj`{BgWoZ+IlDJzi;E z@1R}%=rCL$dn-kLc_@+h$T0ldY1x5^HTs%@;uEbixG-5=(ItE@3qR@lMs~6X;IO*{ zhtNFA$8Ya~b|wRR`@sKy5Bi`zfDyy6aB#(Y5UVF_8}@`A`Xr?ZH*8%|Ftuxix)))g z%6n5vsZdM&_*Dv%;1`tZ1+=?_u&@vMuL!u7@hh7cOD}q+I(H}o)kcy9*1;3Vx=GfE zZ}GE~8z-qVWLpYno#p{V%rwmppFqnV7@(cs3>BB^8Gcy%&?_oUx37iSP(br(W_W>@z)#s#V5ItI!X4*-i4EJgMH_$%18bVUg>YJ#s3tzAB&-f@(eU)Po zch>ZS4tF&0)hw5j?it)h_)xe0-7}|q!>x^nbtfVECG7~&`_@l3KDP9x6cvLbK!Kzy zH$~8InTO>~WBx#D2c`C=so@a2d?|O}%GtUpvd}HgNP7NLNQ)lkI3XQk6(L}o-9k$( zf*%==4_l^j#d(R&*4-pD)qgBUW8(QdvJXapp5EPd3WBViiWi+jfaLNS23AByXH^9u2;4{2yJKUof-`GwG4#HUsVr&LcuPLKc2=s zLX@k#{mZyvJ=r=N;oD1n+nUFT$rK_rDsJRWp-#Wluk% zR&o4gCX2I_Q6INEFL-l#B&SKZI*p7QA{biS4}{G9o*G1j*hN`4RUw(-0}-eZ=I zUnd+nicR)ZVd1MIN$-55a1uJ4bTkh%TRfJT`lK81x>1cXKW^Slr6HzS>wGx0g~94i z^0Kkqv+aKQ+M|%Qyu6X6_Gwyl6ddMV(;<^2P1oXjMSsdvm6~0~UAoIc8TDBk=z~@o z9UVW&XtT(BUs9uX4Hew~Y}-j#oZlc}^KMAuCA9`!xFu{r($uE(HMp7L#LD^+&B#eF zxF(P`T?RXPa|3H9T3PGGRUO}G2)9>jZ7C3s?|%O~`rEGz*-sjgm#R8ca)Kmm zJHPvFc-St{VzItjEPLyEdcS+VAUD3_lx(h|5kgZ`uVQreZCsm?7~_1sCeeEac2g2I z0vm31Tw|q`6n7VY-!>~sobE`fqK-GYS1E#w#{BUf>Zkog^!CoLgqq+8rCBlM7E{(>bw%U`bdrlv)19Kj2FHMQ&u6540~h{UOG(C-`_gDE7F~L=r24|o1Xj)KRUu;iA_MU z>A1clfDlH)y#BMnrcrM+FH&D&T&HO+XSC_JE`V<)BNvZs^6>dW(-rfraJEdq?7#3* zi6@t4dZQMIa2T{FibSf-V++)~Cos!dcK*C#DLv7^rvk)NNJ}=Q7_ogrrMv}19omBX zB+Ji6Dq}FZhc6IK_^D$u`8YyNRN=a-p)*%K6puvT+S8`n)c-+lI6RZZr@>WqsNBfW zbx)oAI;cP`(SWSKa-CN%oYQomw=zg=)6I0Ipp&>L!NRe#s$frn>sN|8<7tUPCwHev zcQ)fiVgVnDc57*yU(|GEU^aRX3NcW~(X%o^k2sjf8z^8po%U}`3H{R0urHHu z=e>SZA;!&wXZ-wO;#lnAadGaVVjBnQ%pjxQ-Xkmdhcm~WhmJF-vIG>k#Fg9@Q~bKh z_8A@3`0r+;)JBBz>Wi9G&}L|go_`4roOq~Rm&s9_e3p6T!=s08+9TD}=!AzAA@YBF zwdbx}vC!`RSg0?m`BSv83v=Zi$+`D7yl`oWH)>XzTK4Z%6phbx1B#D@$~qQvcHb1> z=S2^0Xp^npJLsLRj2eS2a01&qbLn?@R1;T(W#ZWCkJ8F(KUKaf$Tk!i8mrOxWDOk= zbMc_5JMSF4GQ};OhNgNaX{EbOXA@+*{6e_|!>*6mQTIqG#PbBR0R%V5Eyk>TGe?fb zj1-4Vf%h0iyw!-Qt~{k7BXd5llBFjwzxdYvs$4hpG+n!oRiG{^I&VMy?Nazd9-Z&7 z@N%nna7eyLSn+Yc{3sfNN!7t@(4BPze9JhkrE{I4VRzoUWFzEvF~x38wdL%oGzBe) zeqeT3lzlQk#j$Svra9y{^+%EM`FYnRxA^U-s*DX$>?`00aGrd#`WSIC(xp?A*=QQ- zuy}la-1aWurzVYRX6uPyjg{kY`Q$eatc!W&#_zj3D@Tvx`)#zUjqDfUb+f9j7L#KCDse>~U1)VRS^Lm4Mx6@tb2(yKExy9sf zw?&C!^9YoDjfz7i?@8<3sXk(i)R~V|E7E?g)>kt_{JVYoNS8`kBEsePW~fNq#ay%G z_0P`($s|8^?KcO6tlwt;2#V_)QrdMZDQtS5@%8yCI>OhA<-A3c^;gqP>!GpdU^SiP z$ta1+rUj|I&WMidDhQ{XexVtT^+#}Q^%9=7;dvUkQ3>$2V8$f~mcyEAF%y{Od1 zAMb~4b2ZZsX#UPQ+)%cSkN$B0ykn+1Gf8mS37RoYs~l~5Re>2=`+c~bi+Dp6ueECS zkAzrS&$C=Cx2^5CbqU#36#HLD$*5zN>fh6M-E(Fg29VXRf~C<4&I#)7$JDCP(? z?v+zq5A?Odx?DA}dH?*x!FDHstHJ4y04cIQ*dj2e06Z~CM;~f10^NlOjUl_OA}-&S zhH*2Xkv!~!{gWmpymQxrJxlNPLVVds;@Hgc?1KF+)zszn(3$$iyA?GC5^+hMCmFR% z{UoNIYVKRe3lc$V>qAuyujf36eZQ(1X0*6@DiVT^^3-*0S`aK*u~8Ab>CRK~aIn$@ zI|ck!Gz-4^_dB%qiiMobexjs3GGw8mWBRX%h|!qmTcS|N^e~&ey6qGVN|RFZo#kw! zYPcH#q#Z-=ZPe(O$$wjty~(zL-hSUT1Xl}H`r#k#LEW_NUC)5)KQA^-=t?PFh_!0p zhdyzi!l+o$W*f~@b8_9#UHn?yaBQ;T8F11b+q4`*s-R;8Oh=Jf#rx-AtFpMUjWEuy zOYk1Cpw?d`_#Tl2d~|?efHzjWK)uWdKuf8p+gqd}9SJe?+`V5hhYmw;ZHgXAywO&X z_5WIqpZZNEpPRWCWzk2`Da_*L2PQX5wSj_cl+g8}%B1^@tmDNu)}JG5tjcB2Qzh&% zCchpH$*P*qx$CBx%$*rDm>a3RT;rfiRhex%1$V2c$4B!%V@=elrr@f64^a7`rKmDdhA2Ugx`7Xi+X2&mahm$6y5e%Qm^2L&ppp7$Q+JpFs9X1 zf4dOpZ<>$2V%5m$Dy$K|`?Ok1*Q4J}5bpJPch|fJ9kGIz*5esbH@GnvqB5IxsvT1d zKyx8Y3mW1gEG)-_FU&sU(V-{TjY!0WW;4`nbj^k@j{}6ju8lkc!AZ zJSoCSVhDWHl~Y?VyC#}sa(olHlu*ddd)35f$$xmGls3e>bfdJmw=A4>67l?@$*7Qt z*GN?B{$H-H2qCw90Z;QKsWu^(%}_7T)gJpA*A|kz)$%{*vZ@>4&ph|_ui>jGw^AE1 z#S=yI-Syz(&;e6we)o~u!ck+EP0Jyp-qnp4OlzA&y=y>hhQA_PFd=*^+D2{T{^b@y z`+nJtP?;|8VcD>!+>uZ>Zyua)=5zGP%P(a@d9x?)llVJxCe@sb=*nx;Rc1Ik?os^> zMh{Kb#KzoEV$%vxqDj!zt`JF{n~;4;txW0?Dqa6%smpKduICiH+)H1t$NJ;hwyooZ zRC;Z9l0$)~+sAoQ>>XE_ki{!Rt6E5lnJ)KUIyby8(wrt&;fa!9i=)%?JiD}wWnM@XxJ{s|e*V-MKm6}_)h=#ANPJd_B{`CYPn98!`ZzN(g=}`fBvHnqNF_&~3Xj2V;wabL< zFDCUG0%pK`hjlB16E(+GWDJ4IFuBbfZ|MY@TYp!GQQs)@LreYHq%FSP%Fp4L{{vn5 z#))jq`6IS&Cf~^VNNN)|85^C^g}PmaHQ@KB;~Dg361Yey7JiZc&HotCeQyla_nxN2dqIkIBTd|{=%7x3i5l=zwbTq6Tofp9;TuUm{w$=YPX~vedeL4J z!8VH!@8AX}d8N~ZGW14&`SU)-2Q0m(bDBz}FbYC}A(@61TgG#y)(ujARHh!y zZq2<9kg}v;gbM*Oe*6(iN*tJsz0`!yR2u`M>F$=_4DpI9WjmbEbOs>cdr{N=TZ)wv zmtB>Vk@NU-CY;gpzN=isPL$f0;POJwjL^*B-NrRJ2xd82BFG5I??4L^p#=J84Kh+h zu|)(O%23=y9)W{etf8(-@KK+(l+mgvIy+Yj18RUmdwfH4i8d6Uv$sc2+=Y`q{0pm3eh{Iv=bO z*NO+N2D{DjwJ%XB)@KxA5%MG{F?3|Y*f;gG>bv&b0gN^=>Id2Z0I4Wg)uvFbf!X1H zgP|*dwY$x@+*IE)o1W36zPQ*u5X!i|RErU2+Eu)yE!t2sYH&< z^MNM_s_#W}VDnTO;OLC586Uw9HEs63D+AE!ar&^Exn3k0A(A$38dh$xRw7S9sj$xi=|WS@kq+-oMhQ3c}>Mdgv)cDK#kRS}Ql7Ah(}p@=18#P1{M zDVyJD&qCo&@u?p=m zt%Bwwr8834lUvESklXrwwF-qm6=yB5c5@xZ%_JfQmV}*pc^Gnm02CPOBtftQ! z^@X^xazMV!)Mh_iMZ;2+Bq$_bT)i<&iSf^QP%ZL)i>4FwjPt_&yW1ey(Y^!F$xUv) zIka;ixE`;uM<#%A?~_u9Y&eRZ0^oLw`h!bF!L!92Jo;0wtVcoLV2!c#K$r>7EpcA( z2e1@>LV7v81w^=y6imD33BmKJya`}RB~myrcY2}X3ST}hdk3&sa)Ybav*P)y`!j}o zTpdjPNYWAaQkgvd0eLG3h#~p#!B(4*xfcsdvk&2N1?c|sI!yV@xIXFuuOs;|l-_X{ z(clU-hu)Z_0Dl%&2eMb&TVycC=k`Fb-8SmOBw+`w=H}_m)5CPitx@oKF*e= zvqi4)e>A%aWk4%%^L)FMhkp*TB&sT-IbQ4OYvriK^*3FOcdQjYqDbGhL}aD@8d3#_ z5>NNPh13Qx6RE$JuO1ln|5B)m6II_>ESer%J4XsGbQPPGAMqQkeRE_Dr zcx*nErXFB>EHtZ18U0;$jTqVWIwV0HOuHjp;ypsQYCKZeeic7HK(3DBNk7LUK6py(QJQSY4=Ta+5qJi1(HAc^7{t%4n>o;x9m%u;ahL}XInt; zVo!{98=7_r~RHrh5{=`koMO_xuI;(YD% zV)FY%h}2im`@u*Pu0Q+SS@u}4z7m_)7^kH?@L8ovLy=6bZu;)#CH$QvKY6|OnZX@b zZ#fvrz|J=9$PJDFDMe(00IO|DRsW`G&D_%Hrgi>aW7n3&Auy=x%=8Q3E|OX~XIu8p zUIJ3`hC?!)5JgMGvp|YpiJU9dc3rH>3i@ESZ?VCPqQ5LzGIS~;p6K7`i0%?P%}+iC zy$ngJBSpk}CrLT6sNgBrs@yt~Yp=-xQ6zoMFUdcIgO=NkCwuvNhB5IohN|$@(RWi< z@Mo1GoCtwoZ4Z{E;(oQZu@`0n?{QqE9@KT zPO@;2WR6&E%?qUl3t0plPlzabo%wVEV^`bs_%wAua9-Oe^QV{_3QFHeVq=uyu}C^)0XYfR9mS{cTmf2O#f*(cS!6y`P{}A>Tt|>Ef-ImniC>nyUNrS%+sz6iX}QHINV}E2RD{>yykPSUmI0MO?soVYg{53 zObS#Zix1ok#cbXk<=O|Za|+uE{COs)Jgx%R_E*A=YE^1vma$&+g46hpkYXs zgcd`ODX(6k)jeAqf)*3!&ie*4eg_9!*@Y4lI(zw(7O}^N)$GPwpfHV9WcGS}k<^TZ zD%o6LmIYsHZB=)pNV-cds9}6M`ee``xOM00sBE*Qj#($*UhcvG0iNhA(X{k98z=oI zok?U)-hY<|vL&4KLzoq^UOXK)9HDsI4;Bz0HAeSzMO4}9cX?gYV>xJ z^*LN>&V0lhFDzlY85d{OWw8ZU1^w>zHmjnR&~I0Pg4W3u^Opc7C3g?E2dfYQp!t5O zxA1drG5kk>TaVpV%1Eo6Tn#>b?1l2Fg#$~)Z6$+IBq#YmKBD}rcjzFq*kJ6s&Mqo; zhG_&d{l(dd^0oA2c24ozp;f%yLF5TglRwCr6fpeZ<3vFUU58?s)s@PYzLw0fUPANx zg+9nr2YVU$=P4$NQU!Z+l7Exe-4I!4qj%*UkG(iw?rgjWKbr*hCQbjN&GI8w)_;hd z;R{6UkJuw&PLa{g{>b#Qgp+sd(VF*R9Qf^%zj!ud@ly7AI|oA}vL)zJ=jQk`uP`dF z5U;IUSRe9B?ksxq9*4aX%N|6xq8o}7;|6Q8*qk3(VByb}KbA9``cdzR@pSjnkUo>( z2Mn!W8I#yK|4!%PgP_V%Xa)1h%{Y6pmrHSqQw^Fg@`5Zy^aUP)MWyT-P4HH81p-Q1 zIYal_#6%Lc@&34&fqd~V9#6VCaAN9(PPOS%h7UJ>U%hEE{WXW{JR}QKP4$~Yg^39D z+y2RvB)}}AA$ctXGiVp(iTJ;IWtouem;a*gM-_KOhzWCx;?#7ZjBEPD`gfw4y*v7< zmSNZrGV4h~!9vK+gX#jZkH=5LOB7c{-JI9UtM5AjX(Y$$Si9ea$ImSB7TD4{UnlhG zhvw}(uE@% zbl5SCNmW8_dt)96qe%s|E1ojfl)os8`o4&LesPOI$Zq4}gW{Qidxp~^MGPg|5{hSu zC**p|7ol@Yniu(;$K-Y6a03O_-%Dq0U@--pTs(?^YG0sbq9*u+RDLyE0#~^S8B3ut ziE08LpgR{9SD(xn+tc5_D_dS0QynNG)U#ME?d;UfKWc*w?AXxIy(^; z%U#l}?Eij7)>J^IwJpwN^Mjq-DD2PjjMsE72K^T+Q=vEkpkVQ)*j2%!9vcUMcEt50 zQQ)CC?3=EXaSlvn?9BP+8ZSQI39eGQgOz-e4 zO;(Hf8iQMG-faKP*LovkG;tCq9p5Amm4DYLU}Bl)>kO5fV0J7c+nx6ZoLTD-`_oh`-koj2mt}`?k>P88t&E_+UPrNn;!j;1 zN|&D{b^vj+V*|kVYaSn5T9Om{&$F;-4#C=Jc23`BH(N`!n)fD8q|o4pUKFE)>HzMJ z1$ZQElR8N&t&K)_-cYCZR3z7g{Zd??6A7f}nN48)<&JwKag5aAPii{R9-s_2UZy9P zHjIf?g4V_Fuk4p|Gi}@7m`e17gbuo&llu`Oe0~n+#J>nhyaAJ-qf64D;>f-A$@bOx zw;714(VP-WkIH(0!3|7aF}lK9y>e*UQzfetwHSbR6AN&Iy}c3B(RA+SoFn9$R0iT*Ttqc&&Kb7yj%n$j)ZDIKEQz1gGWW0^3EV zMOY#^41h9(HmR{S4VHFX+Qms$XrV8pNOGL<$Ly>(*T^B2lSy4^Mm z8Mv?sTu%RUP{Vu6s$WK-GbgFb^T;vsDVXZ|%Y3h!?TDRktY~f#`f}Eo?dI-zm%3Ks zL|j<)RR$JzbAy-3f;nz(3&EOD($YETUup(|l!z9XbP9{s*uBrWsBHQfC7v9M2e&&j zhI=0kKWGa+0Hl)F;y-f8pUqTZ4wa{%E&7Cj!EJPUGJC@XA;R43crkU+DR;OD_L;Lu z1WeEI+q+^R*b5V`hSdyPQl2} zNAlLJr*>te!-rh-nuvT-L%+hp$yP?qgy&Htok;4l!3A{b4{V!%tP41GNyu$aC1?l@ii`T|I2d}bt(Kp4j z-A_IPjj)8k-$&)h$s$W-JF1y0)J*$EfN!12BWkikZrl58PGtP(l{AaP1KjI5K zRFyj!NbRSGa|WM9CsH&s*0GjNiis`G@#MAec7c$5GqGzAFjHd0b$3{fI6Qah$sp!7 zcGf4m1*Wp}XCbfN@NVeKm9Y!_L2mx06E6I=Cc@90S$r8HoTdrdTi#hf)>VoXfQm4? z=y_9v8Q&v6?vGsSbH|5{j##cs5$dDbdGa&}V}NJctl0zw^iZjG&D@f`q==Qp5^tA@ zslk?zFk4c*wWUV@XE@eBx|$FvBd)s^?~0$Z(k}G-5e6<;){?*2pg$~*e?3@9%0!;Kpr3<~>AU*|l=W|H5?qoMK ze@G3p{`H2xs-Zz^)rYx-^(vu|h%PTf>gnF_%%reLuL^$Nnv1f6WiLvfz+AKC!)2X< zfir*q=s0m?=Y7%$m1U>SGvYwOcz9%P|`bQ@0*+C?IGFhL11amX6tJ|rz*J)1@1QwL@)=o|m!)}U zLgYo5#K}gHXgVHvkGP?@(2XP$wLr5d&=uM&U6_St^YzslG#f2Hyc?bb3j9+2TaT(c zH74mmw=1@4>lW8q-nV)e+-rkHjddmdS{>`$>aU&7{#^e-j;o6OXxjVVUX&rUS%#`_*U2D~mH`9j z*uQMDDwj<6DOi(S+-76El0b54l)|!Kh<$Z!-3ORYb0^VX-k`Vm`)#|mk-04*hh?Lb zi>b@W$=+W4C&4e@L|V3u?@wm3bJ~vZN$A&zr!AnXq+e}jxDNfrn3Dt|gx!-2_fJlX z*F!od(+B4i5nj4$tfGRK#8khekprt?sJ%ao(@{|;f2%+Z|1s}|(t4jiRqV!&O7FzJ zI`_!?l{y%yiErOpG{?#P_KEn~*FDz#59H_;s6v->n+fDCoau%S*f&ooKN(cvxP_%C z7CvbI_47>QW(@y!g2o`vG5rMzoOb*pO2J-MUNeP!6tQK0mW6aQIfa9jxS@LiL)%}T zoe*u7`<#hr>R@QPy>?ZEhbupv4}czn77Kh|A zC1zqD^jaFQ$K_`SKg*TN;_{uo&j6O>B4?A%M<(s{w!C2S~{K`fR)YX9S_&J}~(n77Gdff70|kv)w62TueMkHYq;qpdR3Ym@y)EG{s+S;vKN^X6 zg^fJeTJ?}KFT}S*9V`SuZO|3a29*YFQ1)XEZ*69g)62ZZji4*Khh~IYcnFV(aLZv> z$%89N-Qt@Y+Qq9fzXAp)U-f(?e*btIuB=}pb{(*$dhX(`K3v(-gX{sqWeK{=;v|#mLH$K+e_ufzP{Ux#hbZBemCc%?*WNr zcD0MEUp287z?Qjhy#%{7(x3o!cjcD2;}o{*_`nX`DC-Q}fYxlT&rK-r;-lKlD((KR zHK6p;>J$qb79U?^3RA!02)r|JzB*9axX1T_P1+p^bw8|+Ma$2qN(#tU^o0%*6Ol#a zcymG`nKLF2rc*KAH@l~@bZ!B;EY;xxnQXU;EB-bBlx`0|fN%A?cSIj@+A9gl-0{7>XigC|^w z`0^#3E+@SCgKr@#R)%1Q2eXzNZ^7NQAQi?j@ywL%&jTsq-f`47$Yy?@oN|UCK2~eu z+pv}#QR*GW+XbW@5H?2q(G5JTu>iW|fH#g~mGBH#$`hp?s5uk#A!>uWNA^29Hg!50 z>TsQ$5Q3b|DY;=n(VA>em!18O)$4q$&JYnQH(Gt%Wp|@cQ>+ndgC-`^Nl~j}tf4^O zP3|_aFLYm)_u9Enk$YiYUBqA5Ig*d zp|fdx1W!qZQz5mrvw64Jgl3p&qx+V`!~#$)j=S1qov3p^Da z$+#6QEWn#_JXfyY6NIC%>8PyhSNdgXwA)Lp`lX(5M_FSX`69M|=AAc@>uKbR)1^`D zVhs)YKi%KaKMge7b)KN!zoi>!78^cH4R)!-DTWiju+2^_u{S-qQUC5c=(HAgy{;x( zSTh~F=rli&F?_`56S|+~{ku`};zC_RLuwD*8kq(AA`e=xuVn{hfX!f+`?^Rvd6GyH zm385nj4ychb>z6l5Ppq@4C@7I;zA&{7bq8bSDSN?bY4kWYwD&sL&4CI`@W&dr_9SQ z4%~6U#y6BW&rVc*ki*jMyP&9MWvWeKyX5Rce4JVu#m~`fI@_OZ17DX%vN+BCd1|jC zF9J3L$yL#~?6A-mr`|Mt?a$6h{zA-_@5SPhEO;P`dPac2qlD4%GQeUY==o?E_xc0oX+K|%B(Y}iXBwDSQFi}1*44IE zsfFPPcGnz7-?})_X~xVUpX@`CIA%8H)z3QoRyE7Z2aDSL4$KwLN)#uC(ruDghvn}} z`0#1KY;PxxR1=dpv`W1Y6#6`F;qv+I(^sG`82nc>KuR+CHmyv*tCpc#63B?exG?c( zO(1^;>km33j~_1Gslwr-_UJeaCZU-}&j&DqHFHTqLgHave}v_R{G(ruogpgV4ZXvi zG56Ghak`f>^doH2pD;KWW&WcP3drHPEG~~g?6~21Tt3k*E5pp&dc96;{`fO1dbiTaKz*`#yD!$o0krsRZwC9P}(5ektly zpg9r6{JXGFKn9*h)=YUvI3KN6Uoo>3*b$mEa`305=!Q5O)u;B04t`qq&0ZC#J=%Vb zUXmdU*$nulX!-f#=TEPpfY!$s-47Z%jtGsXsQM`nYkE6t6zF+8Pkv_H{!T%C94Vt^ zY@Cse3A+9GCg^T|)su{XyD>Cgzs@`WelRf<*g@?yluy;&hKk*VLH{unFa_iB94+P%5i z>}XEMY01|}YS1vrL5U^zuM&~a$-?B>1&4xD1Pc9I5!*&w`W@Mad3G~FNF&fd4N)$P zH$n@buoEEwixV=RiGO9dY>zcFIqFDwU0*ZPj|(aMFqOq+OE(6Ogp&=#Jnua6V{5qZ z5RSd~@v9qs^o1(bzJ84$N@H(5^bVa`+Kr_C$@`>L*Wha$plY)Err1Hq+~BcDuaa`u z!)Jr@upHzUI^_EhAiwNJUY#_CB#F8IzCVd~n=EFu>LIU#$076P1NU0-oTjM}xP*Ej zZe-Z1sLPgGql_jtQ^p*=k9PsGGv%(SQ#%Ps@`5%VLLEwDA))xiAe@bs#W{Cm=^MBy z(XnJFo;b;95V;?He(8&f>o3toFyc>mZv(RLkt{r|@ogb1c7yG{M~_ierpug%z2bnt0v z92UJ@9FScJtvbVWmr!kNFF628JyPpj@VTt38+p*T)IYB(GDhxeP~|4bqW^yOVCy2G z>(l!5hK8{MSQ9=w^gBCxE5%t_(-h)?)8Z#3`)ST6^}9_Cn3>2Bf3eSGcYT5pE}RIy z7Fq4AzZAfh+p=fJxWvxcx!A`vHl4zqei8%JE7n?K*P2(gop#8e`Yw!f17DnLYTe7= z{Xtb7@%n@*9(fGw*TVCaEidFQ$uU8HQ09T~QxF5?}b9sQJW;KgIA=`)l(Qil{QaRKD);hA8kOCGR28s z{=pRWG>QwtfctY7o))YAiG-7^9?j6teZo(f-v0r2*>KsO`$6;2$hnDJ^Ki5yy57K{ zUkn@#Zokj|i(-04-R=4QyqL;O9ej$O^mzgI-yebxmUcC;$S_$TavO;&SyyGFH3i$K zjUG7DH0r!Q0536IZ64qQWdT%mdq7F50mg{9vYWaK=}WVWLvXJzJ;b|VNpL~qjC0&QBp9FUv{MXKaCmP zeLy2G>ebbpJ@>QAne^^w(H$7$QbRvL-FUv*mFc}B7fgQeB+^G_yU!~C8T-<192-US z@krd5r2@6p{B`!YYrzzJBei%j?80aIK{knqx9?-7W;~R&3wUW)Ge&nvGbEZ{_fSr> z>xp$qfj-`wX9DLd$qo&dM_a$_7;~Aisb{n{_E|kF4rc2}uwRutV9@TnA}4$B1Axn* ztzY6TvQd&)pB3+vFqG-OFX}AY9$U)y5$MTeM%s(?^b&m83pZ)4HI{?#_DNHG1YcG^ z-7LMn1yd?FxIl?VRU~bbHm`Iwq3#Qxu{@0BS`YutmDZ4&Zh6h-*HO-yh0|g6k%squ zv-8=Vc!`UQFFP?I&9Yl25n*P|JATFu%Wm%~QyT)QsS8(KT5=n|3l2Rbp#{fnBe9nP z;_=SjyLXy0ls@&i%(==s8q>W>spaIrD81xaVxcj9abEhYsn`0ec#YW8B`-J&7BzjF z2V2M~mYW#PtX90GcVrk63M|>{BXi4tS~C*n2Gcpl@1=sl!3wK-UozO7J<%#@@^aZS z8b#&<{5- zIO~@Fei}~*NFb#XM2CCN`0hU2ZdIsJ6zEJ!4Bhano7tXunERBXf~_n^x$v9-NTxk0757{7qd;N^*`<-><-`})Ykh0aK1 zV&E0O`Lnn?PLb9IHt!57ZRz-V5gjhIa)-sNBy2A1$#~}mIRpiJC=KJ$X@E7m=Xqm1 zfY{$>V^42sInj7o=%*MozG>{!mm(w7cus?qHx+fVm1;WgeZE)mO9)dX^-TEts$8&a z#YR1t3ccEo9Ji}kdutXH8FUKEoE(>3rqzlN>sd$kth7+Y8URHnWA z{dgJ<^*!pjD*MQOU>bIIf42WQSi)(ny(--V3Y=YRhowaqgN_M} zC%A2JDw}5BNckWScnLFBNt}4@uR8(`1&%xc!3A;{BI+O^+Iojap8J9Al#pqp&I+h&@UY2*Fo z$>nRKW`j$4Q;M69tZ%0l0d58BnE)BIa9pQ;Mmvr7c{^8DuYPwXv=qlS9kt6rfhLCY zvdYwfX}^rbaaz9#SaEGqmjxxqu*%e#(`-8N^Bx9bBg+)W&?}3A4J&7LheRbM&7eOc zt^av?LRfuZD>&$Y5FD>?SEc3`7|8;J%P;CKK|-S3w)q=00+K`cBhm;s>Rq`;suW!* zZWfSYG3j1E5uOkB2p)OxahS{SD`Gs1G*+{Ei#B;M>#|XI#y+1O&oYeA(ma&e%kkLv z%{A3EqK%vR<$?aT+&TT-ro7)lcXLg>(`hCEmoMfX18E`YbdGr3-595hZ}iVAQl%;H ztuCzu<%>KN$%4jG*J1I#$v@$@iL!fa6b1g3@KY+&KNg@dCoweY+tlYW{Kvs=`_{NV zmtOXxl`ryHzJ--rQ+2q99s1R5`kdDXbm#^)sgj1a>TnN+mK`g-C2@%{WOtwRe>FJz zyybpUNOAQ#UNkyp7Xq)W92pxfgXn+>7*z_5Xzqm-Q{{Jkx{r_ud}E*BdVLS`+LKYCc%raRQr&F@0D| zc?74C9+3o`Ql9FrqmtawaS%Q7y@BC74S0f$m^Um_yao@+k=G^6gOGym# z$BvIz9px{{mxx-3?axc*-k_D^-?}wW&{(ZPea12~*Q6l-BFprC;e+`5ADyPY(W~54 zsVqGvW7X_Hv#b;$=6P)I<>mO28IG0Mq` zPOEDe$8&w1!R3?dC_|3lV+FLk7OMH&+Cmc7GU`3!jE9p>$?5Eyi{IPcX73{4cT8iZ zJik3Zlezfm-`ME$L_P4mfzm^*^wXz1UyHq+n&>v~RQIG{?EyEvJ$+$QAVXaC1OWeS zEHXTBqN`yii{tPozX*JT@{6_Z5U4gU`f*9tU)~WWQ-nAGYFrR)f#HBCA0RXS-s zAskG3VFltNv%_=-Y9#g-ZW51&$W`Y z&m5f0PyzK+cM9#8avDOS6b{37rJc=}y;=Ei!|_w`;34IG^#||dbvliTQ^lvoGD_&E zqJ{@VA5+}a)G;{DA>b&C>n}yCuRKO3zk%7IOp>P8;iygLjmj4W)LXXrk#x64r|hTl z(;gHs4&5FAy`rBTp@K!o)=x!)U>vb4)eje+u;siIDrs`d*1!B(gX?EhErE9;RIeRg zZ~BMEYhkal*7`AJgc&BYTL#A! zRKnpG?UGSeL&xHeeRf$5M9Xb5synA+#1{v)h zi>U~_uOd-dgC`5*dk~Z4=)m|^)iuI3rq3gs-yQt^R6N#Bs6#ZW;r&P;ZzDx8-$FL~ zPfiyy84xd47?3@R8aKg*ANUZuyS&qETd^x9C3bFEmq71_lYJi`B34#uPeL%gCz z;kc;F*1l;an*lE`5^8#vN1(j0tD(woyD``+7sTFlKklwie%TdGopb_@1|Gxt{<}a6 z8~IDDT3QX^-Zw0Q*Si<>843kgMTP*)*_#MoJ>LGA@oW(Pw-|lu7w%MiIIP~i*VF5~ zY!q3!|B-va!(V_ec~snXd+<|La&yXi4pJ%0f{x$YR^R1!1YDv~<4XO5Zr8%vJ3ve{ zP0i$RZElS#e?f@1j~zb=9DP+!si4o(^=qva39YVWete4~rOuLJ=#FCWIv=$;{7CpI zv_>~0ZAo5yLOk=>+a_4H90%(*Rzep}OMZi6}NvW2}Lo$(#9+3a2HjU}f#t&@H0at6R~z^1&ZRsu&u%<89iZm)C2uy+&?7*#)o^VFDu7c%(l;m2@mM2v5cZ^zX3 zJ7N8UKEjXd7nEG%1zP=-wZk+WuOEAzHAkUNEQ0yCpEsuzQsQBT*tZtQCeMu)M?U-d zY-g%eMrlg_)e;6(55+-N!v%7$(GST%802pFxZeLZYNQzzAGaNSHRb8GvbG5=@NPMP zYxz9#uxGW_$+O2pnzctm6ndg5HTUYDyw0?Mhi!1(5i8u;TBkHy#^&oFL_CP7F?yO) zTxS_y?D6fjs1H3kU#H}t!-44z0<{^!=>FB?nvWC=F`*Uz#E#E`*L~*u{flk4A5OhM z)n;-2c+dbAA~JXWeSC3alV$nX%!q4x29c6mPHK%~0NNR9_N(71ARnPX*58=PJ*0f#g{m2Ccs zO(pHVsWd4hkfnc2ysDH4&z*Os1GqWg|tu_vst@HkJ-=w%O;Tkww zP;H?xCn}b{;}XfP{kjdN)P=e+;SA2tbUg@_ys3W5z1zPQFU zUhB(xR8S6Kt)oj*V^y9UfWblQ;9r4>~xx ziWK02y;TLm?uVv3*eHYqH~dxbh}Q2uyW!CS%GIXND4f975 zZ{V_aBrEB)Q|^P8TKmmucRz#C$L+MGX5rude&1*BAPn?KFy7!Hlx5w!^Y1_R`bPHL z3q{soJ%d%5nJKb3p`$f7^RuKxbS9&hl|`iD9wrf{3NN;lx~%)@_xsNqywkiFl5oKP z-4e#XW06)0Xc`}8WMm-wP?Dk#xU_m!T>M?yuyb#jLdi;RkwcfH@v%bf;?E_YN0R%m!!JHnAk8?eylwSI&d97c6=* zHS`_J*dGR$JyaOK_QEYUy; zRvqz*c=+-uLj3U-9Eb@RKJBaJK9}w!tp?X+k>?e*5%+a@z;~Y>$x+__oT2%AE7Sz} z&NeOc+gd#_asO(!iAk-;aVniCZ@TB8LafAF!)daC%*W_lsK=qLwRFfaC_OP%+emMB zbee4;zW3;)GOcl~J|fJ*8N|95IPLL(w@4KHBPvpaim$H@k~dSEsF%EnT^&h&i{Wb` z?@(>cmQYi{^WXh1#{>6;oxHV!lleo0BQjOF3-SJ{VHTs}vD%lW z1^|jHd@NL~L)5o4 zD*k!=OGpxNq(yua3x0CGik@{Plss)zUMQzYhAW_SD(|0$#BHAF_-)SPWbY>6ZH%+ zpy_xFH~Ur2^Dv>lDhB=yJOzA9GB#2v0!z|qJOth(JEN7cM**@ByrF#1h3dwg132^TixBq)ve01_(_C; zhbi~k^G!2d?@0B6bp@di??mWg1A-nF^imdwa?`PFD$$ z9|nw6?a#a<3`RZTVxnQLdAQaD`ra*Dvo8~VTZl_F&|k7_TpzzpC# zA$PEpe?(>ag>j|a1X2YUqysS0A=&}bCljqFq>BJU}$Q*7x+ZWN76u<`btQ^NC!v<;@G5U z^v}Ebs0&krBvNrY&3%?LM?;ZymV$ZvIp%qaKKMDQo;94f@5HsKeQasGhQIa>W z*hSrVw4&P#Q*vc(P8oQjDF)hq7?7Jttgvn?*|qVxK+aIilxUW9h75ImAL!8ynFGR; z50BCI0^Xg`iirh6oYcSkI(QRO#XT%~IzOX&@vO!jdN$i&qN}>Mg)mWwpnMEqFbP2(L#wQ;tGW?)@^JoEP6I@LCCkiaqxGBSRtoUC7c~8?9kQeYn94L(;u|;z%LMp zN(#qgCRG^1n--XF0X|XM3R3dlA-T@REkJDH8|-g|No2Qy!iJs!Le8JN8TJmR=?)mf zhb_ByXa-cKJg3KuVC2`ok^Oih;!0CjObwh0#s2{_cxhi$RvP&{{OaFKVG1l7e!@dk z23Gbl=u)ljaa6x>y5r{yq5~L52gbB~3|Tt8C_e=q1*H4&){qfp@UXrSQ}f{RiHuxF zXR969SNPX~roP}mo2B1igtzm>{w8ZLFa;(Nh!5V$tB%JYy2RZ+qE((+W^U%=iNtDFaDx|Jo?sG{i1I8Ma5LL zq>$pBkYiy|JKJ)1k#+fbg&0Ty(ks|}z+?&Y#aBR5&BO7)8WhO9^+(qf z2=sYgQlU(<(ZiPPkprG_y$iYA>VO1z5rP;UJM^{xNv_-93k0E?l4J9|f$nRAEp@}r zYfx!WMt&KfFyAKQ4!Oxdve&em{YdAKR7YP=<)L&qc zyeXW_4*{O#T`u4aUn&R+@htJUGawVJVxOq5gM2)PZU=?*O+(g}lwH;<(3XA-Iszya zF~cvgzG+@^aZar&4hNob~0jB6z z1@`ZPtZMVTR(2u;;q#4hXzO3IG^U@Cu>^Ge1S+vJ=|;AXGz{S&byfFT1;{KA07PXv zz<2?imbt^wIIe&Tfy*Q%Ozb60DkMr<0N(kO{o~|+)0Vd!Iy#3zf&)F-H)vio{O_nk z0>#@c{~a^qiV29*I1(SlKyfI^rG?}mU-(IY(Qq5Un6ip?a}a-_0Jc&N&CsvS^F%!r z3L{@#s{L&-2x%o?u5z$8o7T)sZq(8mqJjct8vAc_qQIsFjIec@&v>>INWeRMPFUzC z_)3&6{{_01lxt<^X`=Bgt1|_`ll(+xq@2+{U&8{TB-S6MRW1{DKOwipNdvE`M?6vVXG5Fa~XoG>~zn z*BvEHoTkd!c+qx|PXt4S;PyY+s-*Yu2Eg67!~nYd@iB?^gBIYjQ${%8>wo81^ny)- zz``_LFr|O(kgirxi(!Jt&d`}O}w)o%0>HO8P6@Em|##9uIdPZSM!J*)N~ zZz%mb2V_MJV$Mk5-$ZRShL8x5CBs+ZtGfCB4H&Y#e+Nqk;Vh`00JcE%SDz9w1R`P7 z4)~&TrxQj9*yKIrGzv7Ml7b@jI$#nR%K(azAtqA)8uWc(Y_@Veov?Q$KO&N`-Yl|@rxR$dhr?#>>|a4MIXAs z?d~-9?cX?)Czt}D@G(dgphHm_WEeAG7&H}zJOVD1v1*OV|NDf^c~7U2YYBZL7F{}ru( zfiQhAuj=mRO#BN7@3YaCb|W2_xJRl?L2qyc#4HLyge|3rBZWNwZ&qvb42NFtf`RYr z+u;t;+G_@G#6MslnG`2^vpg9GVu-dhdPo#U#P!cmf+j46Ih0%SN)pl%p%QqDGHCTI z0*Hb+>dK!SDkvL*iQcz_w|N2zg3&`9t9D}mAtuR-G7U!0kH(L5#+kcIZ3bk|e{{rV z=qVH;HPH2VmYZb|EX~71Nb%Mx|4;F{&IyIIKP>eNBM763>jMIV0BfP4Q?Zh!H=xr@ z{;Apo&q$E-zeYEXM6;1OU>8urk`4e)#y)3T_*cUKFG_z{gCAK!t<@;*zoH7O$G7o= z$vg3QbCAKdlz0`f3XecgU*BJVH>x7U7vOY|IaVOTg7hx7!`fWl)46_PsFNY-|NA{#eu2Z{`6hPeQVC+-EM@Ao_)dK}amg?GW; zK|6o)p$t~T{zuDVH$a*5uNs0B6K^vliy);O6c-8kp9nL2=Km10^#-_qDaT*@=d9LW z!U) zYEaDzTmFl`{>O1p0Z8B%_1@z%B!2(rzJpwuvni-M$UpFJ)Kdb37#JALPLFk*OpTq) zgiKzWfqyV~xp@Tcar55eeWbztK#2FD5HCLmH@6Tscg6j*tpDu?b}vn>%-#Oqf6(rD S>lXL{hQec2nPMp;|NjNvTGycf literal 0 HcmV?d00001 diff --git a/weather.ozweather/resources/lib/abc/abc_video.py b/weather.ozweather/resources/lib/abc/abc_video.py index 3a02a7c7c..3bfa17d6e 100644 --- a/weather.ozweather/resources/lib/abc/abc_video.py +++ b/weather.ozweather/resources/lib/abc/abc_video.py @@ -12,17 +12,33 @@ from resources.lib.common import * -def get_abc_weather_video_link(quality): +def scrape_and_play_abc_weather_video(): + """ + On-demand scrape the current ABC video URL and then play it back, with appropriate metadata/art etc. + """ + url = get_abc_weather_video_link() + # Construct an offscreen list item with metadata... + item = xbmcgui.ListItem(path=url) + item.setProperty('mimetype', 'video/mpeg') + item.setInfo('Video', { 'title' : 'ABC Weather In 90 Seconds'}) + item.setArt({'thumb': f'{CWD}/resources/ABC.png'}) + # ...and then play it, fullscreen + xbmc.Player().play(url, item, False) + pass - # Seems like the best/trw option has been removed, so just map these to 1000k - if quality == "Best" or quality == "trw": - quality = "1000k" + +# See bottom of this file for notes on matching the video links (& Store.py for the regex) +def get_abc_weather_video_link(): try: r = requests.get(Store.ABC_URL) - video = re.findall(Store.ABC_WEATHER_VIDEO_PATTERN, r.text) + videos = re.findall(Store.ABC_WEATHER_VIDEO_PATTERN, r.text) + + # for video in videos: + # log(video) + try: - url = f'{Store.ABC_STUB}{video[0][0]}/WIN{video[0][1]}_{quality}.mp4' + url = f'{Store.ABC_STUB}/{videos[1][0]}/{videos[1][1]}/{videos[1][2]}/{videos[1][3]}.mp4' return url except Exception as inst: log("Couldn't get ABC video URL from scraped page: " + str(inst)) @@ -36,14 +52,21 @@ def get_abc_weather_video_link(quality): # UNIT TESTING if __name__ == "__main__": log("\nTesting scraping of ABC Weather Video - here's the 'Best' link:\n") - log(get_abc_weather_video_link("Best") + "\n") + log(get_abc_weather_video_link()) -# ABC VIDEO URL NOTES +# > 2023_05 - CURRENT ABC VIDEO URL NOTES +# view the source on: https://www.abc.net.au/news/weather +# search for 'mp4' +# Regex in Store.py used to match the URL format +# Multiple matches will be found - first is a definition/download link (.mpg) +# 2nd is the highest quality stream (720p) - the one we want. +# https://mediacore-live-production.akamaized.net/video/01/im/Z/0m.mp4 + +# < 2023_05 - LEGACY INFO # note date and quality level variables... -# view source on https://www.abc.net.au/news/newschannel/weather-in-90-seconds/ and find mp4 to see this list, +# view source on https://www.abc.net.au/news/newschannel/weather-in-90-seconds/ and find mp4 to see this list, # the end of the URL can change regularly - # {'url': 'https://abcmedia.akamaized.net/news/news24/wins/201403/WINs_Weather1_0703_1000k.mp4', 'contentType': 'video/mp4', 'codec': 'AVC', 'bitrate': '928', 'width': '1024', 'height': '576', 'filesize': '11657344'} # {'url': 'https://abcmedia.akamaized.net/news/news24/wins/201403/WINs_Weather1_0703_256k.mp4', 'contentType': 'video/mp4', 'codec': 'AVC', 'bitrate': '170', 'width': '320', 'height': '180', 'filesize': '2472086'} # {'url': 'https://abcmedia.akamaized.net/news/news24/wins/201403/WINs_Weather1_0703_512k.mp4', 'contentType': 'video/mp4', 'codec': 'AVC', 'bitrate': '400', 'width': '512', 'height': '288', 'filesize': '5328218'} @@ -51,4 +74,3 @@ def get_abc_weather_video_link(quality): # Other URLs - should match any of these # https://abcmedia.akamaized.net/news/news24/wins/201409/WINm_Update1_0909_VSB03WF2_512k.mp4& # https://abcmedia.akamaized.net/news/news24/wins/201409/WINs_Weather2_0209_trw.mp4 - diff --git a/weather.ozweather/resources/lib/bom/bom_forecast.py b/weather.ozweather/resources/lib/bom/bom_forecast.py index 27fa99cae..5039d1590 100644 --- a/weather.ozweather/resources/lib/bom/bom_forecast.py +++ b/weather.ozweather/resources/lib/bom/bom_forecast.py @@ -18,8 +18,9 @@ """ -# This is a hack fix for a wicked long standing Python bug... +# This is a hack fix for a wicked long-standing Python bug... # See: https://forum.kodi.tv/showthread.php?tid=112916 +# noinspection PyMethodOverriding,PyShadowingBuiltins,SpellCheckingInspection class ProxyDatetime(datetime.datetime): @staticmethod def strptime(date_string, format): @@ -30,6 +31,7 @@ def strptime(date_string, format): datetime.datetime = ProxyDatetime +# noinspection PyShadowingNames def set_key(weather_data, index, key, value): """ Set a key - for old and new weather label support @@ -50,6 +52,7 @@ def set_key(weather_data, index, key, value): weather_data['Daily.' + str(index + 1) + '.' + key] = value.strip() +# noinspection PyShadowingNames def set_keys(weather_data, index, keys, value): """ Set a group of keys at once - for old and new weather label support @@ -91,6 +94,7 @@ def utc_str_to_local_str(utc_str: str, utc_format: str = '%Y-%m-%dT%H:%M:%SZ', l return local_time.strftime(local_format).lstrip('0').lower() +# noinspection PyBroadException,PyShadowingNames def bom_forecast(geohash): """ Return are information, current observations, warnings, and forecast for the given geohash @@ -102,8 +106,6 @@ def bom_forecast(geohash): # Gather the weather data into a dict from which we will later set all the Kodi labels weather_data = {} - - # The areahash is the geohash minus the last character areahash = geohash[:-1] @@ -116,18 +118,18 @@ def bom_forecast(geohash): bom_api_current_observations_url = f'{bom_api_url_areahash}/observations' bom_api_forecast_seven_days_url = f'{bom_api_url_areahash}/forecasts/daily' # FUTURE? - these API end points exist, but are not yet used by OzWeather - bom_api_forecast_three_hourly_url = f'{bom_api_url_areahash}/forecasts/3-hourly' - bom_api_forecast_rain = f'{bom_api_url_areahash}/forecast/rain' + # bom_api_forecast_three_hourly_url = f'{bom_api_url_areahash}/forecasts/3-hourly' + # bom_api_forecast_rain = f'{bom_api_url_areahash}/forecast/rain' # Holders for the BOM JSON API results... area_information = None - current_observations = None + # current_observations = None warnings = None - forecast_seven_days = None + # forecast_seven_days = None # forecast_three_hourly = None # forecast_rain = None - # Get the AREA INFORMATION, including the location's timezone so we can correctly show the location local times + # Get the AREA INFORMATION, including the location's timezone, so we can correctly show the location local times location_timezone = "" # In case we can't get the localised now time, below... now = datetime.datetime.now() @@ -143,7 +145,7 @@ def bom_forecast(geohash): # For any date comparisons - this is the localised now... now = datetime.datetime.now(location_timezone) - except Exception as inst: + except: log(f'Error retrieving area information from {bom_api_area_information_url}') # Get CURRENT OBSERVATIONS @@ -154,7 +156,7 @@ def bom_forecast(geohash): weather_data['ObservationsStation'] = r.json()["data"]['station']['name'] log(current_observations) - except Exception as inst: + except: log(f'Error retrieving current observations from {bom_api_current_observations_url}') return False @@ -164,10 +166,10 @@ def bom_forecast(geohash): warnings = r.json()["data"] log(warnings) - except Exception as inst: + except: log(f'Error retrieving warnings from {bom_api_warnings_url}') - # Get 7 DAY FORECAST + # Get 7-DAY FORECAST try: r = requests.get(bom_api_forecast_seven_days_url) forecast_seven_days = r.json()["data"] @@ -176,7 +178,7 @@ def bom_forecast(geohash): weather_data['ForecastType'] = r.json()["metadata"]["forecast_type"].title() log(forecast_seven_days) - except Exception as inst: + except: log(f'Error retrieving seven day forecast from {bom_api_forecast_seven_days_url}') return False @@ -203,11 +205,11 @@ def bom_forecast(geohash): # CURRENT OBSERVATIONS - # IMPORTANT - to avoid issues with Kodi malforming weather values due to 'magic' - # (the magic is presumably because Kodi seeks to support both farenheit and celsius, so unofrtunately tends to return 0 - # for any non-numeric value in these labels... + # IMPORTANT - to avoid issues with Kodi mal-forming weather values due to 'magic' + # (the magic is presumably because Kodi seeks to support both Fahrenheit and Celsius, so unfortunately tends to return 0 + # for any non-numeric value in these labels...) # ...So, we set the normal Kodi weather labels as best we can. - # ...But, we also set a version with OzW_ prepended to the label name, which is used in OzWeather Skin files to avoid this. + # ...But, we also set a version with OzW_ prepended to the label name, which is used in OzWeather Skin files, to avoid this. if current_observations: weather_data['Current.Temperature'] = current_observations['temp'] @@ -247,7 +249,7 @@ def bom_forecast(geohash): warnings_text = "" if warnings: for i, warning in enumerate(warnings): - # Warnings body...only major warnings as we don't need every little message about sheep grazing etc.. + # Warnings body...only major warnings as we don't need every little message about sheep grazing etc... if warning['warning_group_type'] == 'major': # Don't really care when it was issue, if it hasn't expired, it's current, so show it.. # warning_issued = utc_str_to_local_str(warning['issue_time'], local_format='%d/%m %I:%M%p', time_zone=location_timezone) @@ -311,6 +313,7 @@ def bom_forecast(geohash): # However, preferentially try and use the short text, to cope with BOM madness like: # "icon_descriptor":"mostly_sunny","short_text":"Mostly cloudy." icon_descriptor = forecast_seven_days[i]['icon_descriptor'] + descriptor_from_short_text = None if forecast_seven_days[i]['short_text']: descriptor_from_short_text = forecast_seven_days[i]['short_text'].lower() descriptor_from_short_text = descriptor_from_short_text.replace(' ', '_').replace('.', '').strip() @@ -393,7 +396,7 @@ def bom_forecast(geohash): # TESTING for skin scrolling - DON'T LEAVE THIS UNCOMMENTED! # for j in range(0, 5): - # extended_text += "add some more random text on the end so it just goes on and on\n" + # extended_text += "add some more random text on the end, so it just goes on and on\n" set_key(weather_data, i, "OutlookLong", extended_text) set_key(weather_data, i, "ConditionLong", extended_text) @@ -415,12 +418,12 @@ def bom_forecast(geohash): geohashes_to_test = ['r1r11df', 'r1f94ew'] for geohash in geohashes_to_test: log(f'Getting weather data from BOM for geohash "{geohash}"') - weather_data = bom_forecast(geohash) + test_data = bom_forecast(geohash) - for key in sorted(weather_data): - if weather_data[key] == "?" or weather_data[key] == "na": + for key in sorted(test_data): + if test_data[key] == "?" or test_data[key] == "na": log("**** MISSING: ") - log(f'{key}: "{weather_data[key]}"') + log(f'{key}: "{test_data[key]}"') """ BOM API diff --git a/weather.ozweather/resources/lib/bom/bom_location.py b/weather.ozweather/resources/lib/bom/bom_location.py index 812b22b9f..9e1e13699 100644 --- a/weather.ozweather/resources/lib/bom/bom_location.py +++ b/weather.ozweather/resources/lib/bom/bom_location.py @@ -6,8 +6,6 @@ if not xbmc.getUserAgent(): sys.path.insert(0, '../../..') -from resources.lib.store import Store -from resources.lib.common import * from resources.lib.bom.bom_radar import * @@ -31,7 +29,7 @@ def get_bom_locations_for(text): return locations, location_geohashes except Exception as inst: - log(f'Exception getting locations from {bom_locations_api} for search term {text}') + log(f'Exception getting locations from {Store.BOM_API_LOCATIONS_URL} for search term {text}') log(str(inst)) raise diff --git a/weather.ozweather/resources/lib/bom/bom_radar.py b/weather.ozweather/resources/lib/bom/bom_radar.py index 41da3e579..f5dfd0789 100644 --- a/weather.ozweather/resources/lib/bom/bom_radar.py +++ b/weather.ozweather/resources/lib/bom/bom_radar.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import datetime import ftplib import glob import os @@ -9,7 +8,6 @@ import urllib.error import urllib.parse import urllib.request -import urllib3 from math import sin, cos, sqrt, atan2, radians import xbmc @@ -21,6 +19,7 @@ from resources.lib.common import * +# noinspection PyPep8Naming def get_distance(point1, point2): """ Given two (lat,long) tuples return the distance between them @@ -71,12 +70,12 @@ def dump_all_radar_backgrounds(all_backgrounds_path=None): time.sleep(0.5) -def download_background(radar_code, file_name, backgrounds_path): +def download_background(radar_code, file_name, path): """ Downloads a radar background given a BOM radar code like IDR023 & an output filename - :param radar_code: BOM radar code e.g. 'IDRO023' + :param radar_code: BOM radar code e.g. 'IDR0023' :param file_name: File name to download, e.g. 'locations.png' (see special cases below) - :param backgrounds_path: Path to save the background images + :param path: Path to save the background images """ # Needed due to bug in python 2.7 urllib, doesn't hurt anything else, so leave it in... @@ -109,7 +108,7 @@ def download_background(radar_code, file_name, backgrounds_path): # log("Using cached background - " + out_file_name) # Download the backgrounds only if we don't have them yet - if not os.path.isfile(backgrounds_path + out_file_name): + if not os.path.isfile(path + out_file_name): log("Downloading missing background image....[%s] as [%s]" % (file_name, out_file_name)) @@ -120,7 +119,7 @@ def download_background(radar_code, file_name, backgrounds_path): try: radar_image = urllib.request.urlopen(url_to_get) - with open(backgrounds_path + "/" + out_file_name, "wb") as fh: + with open(path + "/" + out_file_name, "wb") as fh: fh.write(radar_image.read()) except Exception as e: @@ -130,43 +129,43 @@ def download_background(radar_code, file_name, backgrounds_path): log(f"Using cached {out_file_name}") -def prepare_backgrounds(radar_code, backgrounds_path): +def prepare_backgrounds(radar_code, path): """ Download backgrounds for given radar """ log("Calling prepareBackgrounds on [%s]" % radar_code) - download_background(radar_code, "IDR.legend.0.png", backgrounds_path) - download_background(radar_code, "background.png", backgrounds_path) + download_background(radar_code, "IDR.legend.0.png", path) + download_background(radar_code, "background.png", path) # these images don't exist for the national radar, so don't try and get them if radar_code != "IDR00004": - download_background(radar_code, "locations.png", backgrounds_path) - download_background(radar_code, "range.png", backgrounds_path) - download_background(radar_code, "topography.png", backgrounds_path) - download_background(radar_code, "waterways.png", backgrounds_path) + download_background(radar_code, "locations.png", path) + download_background(radar_code, "range.png", path) + download_background(radar_code, "topography.png", path) + download_background(radar_code, "waterways.png", path) -def build_images(radar_code, backgrounds_path, overlay_loop_path): +def build_images(radar_code, path, loop_path): """ Builds the radar images given a BOM radar code like IDR023 The radar images are stored for maximum two hours, backgrounds forever (user can purge the radar background in the addon settings if need be, will force a re-download on next refresh) :param radar_code: BOM Radar code, e.g. 'IDR023' - :param backgrounds_path: path to store the radar backgrounds - :param overlay_loop_path: path to store the radar loop images + :param path: path to store the radar backgrounds + :param loop_path: path to store the radar loop images """ - # grab the current time as as 12 digit 0 padded string + # grab the current time as 12 digit 0 padded string time_now = format(int(time.time()), '012d') log("build_images(%s)" % radar_code) - log("Overlay loop path: " + overlay_loop_path) - log("Backgrounds path: " + backgrounds_path) + log("Overlay loop path: " + loop_path) + log("Backgrounds path: " + path) log("Deleting any radar overlays older than an hour, that's long enough to see what has passed plus not take too long to loop") - current_files = glob.glob(overlay_loop_path + "/*.png") + current_files = glob.glob(loop_path + "/*.png") for count, file in enumerate(current_files): filetime = os.path.getmtime(file) two_hours_ago = time.time() - (1 * 60 * 60) @@ -175,20 +174,21 @@ def build_images(radar_code, backgrounds_path, overlay_loop_path): log("Deleted aged radar image " + str(os.path.basename(file))) # rename the currently kept radar backgrounds to prevent Kodi caching from displaying stale images - current_files = glob.glob(overlay_loop_path + "/*.png") + current_files = glob.glob(loop_path + "/*.png") for file in current_files: os.rename(file, os.path.dirname(file) + "/" + time_now + "." + os.path.basename(file)[13:]) # create the folder for the backgrounds path if it does not yet exist - if not os.path.exists(backgrounds_path): + if not os.path.exists(path): attempts = 0 success = False while not success and (attempts < 20): + # noinspection PyBroadException try: - os.makedirs(backgrounds_path) + os.makedirs(path) success = True - log("Successfully created " + backgrounds_path) - except Exception: + log("Successfully created " + path) + except: attempts += 1 time.sleep(0.1) if not success: @@ -196,15 +196,16 @@ def build_images(radar_code, backgrounds_path, overlay_loop_path): return # ...and create the folder for the radar loop if it does not yet exist - if not os.path.exists(overlay_loop_path): + if not os.path.exists(loop_path): attempts = 0 success = False while not success and (attempts < 20): + # noinspection PyBroadException try: - os.makedirs(overlay_loop_path) + os.makedirs(loop_path) success = True - log("Successfully created " + overlay_loop_path) - except Exception: + log("Successfully created " + loop_path) + except: attempts += 1 time.sleep(0.1) if not success: @@ -212,7 +213,7 @@ def build_images(radar_code, backgrounds_path, overlay_loop_path): return # If for any reason we're missing any background images, this will go get them... - prepare_backgrounds(radar_code, backgrounds_path) + prepare_backgrounds(radar_code, path) # Ok so we should have the backgrounds...now it is time get the current radar loop # first we retrieve a list of the available files via ftp @@ -227,6 +228,7 @@ def build_images(radar_code, backgrounds_path, overlay_loop_path): # Try up to 3 times, with a seconds pause between each, to connect to BOM FTP # (to try and get past very occasional 'too many users' errors) while not ftp and attempts < 3: + # noinspection PyBroadException try: ftp = ftplib.FTP("ftp.bom.gov.au") except: @@ -269,7 +271,7 @@ def build_images(radar_code, backgrounds_path, overlay_loop_path): # which is why we can test here with the current time_now to see if we already have the images) if loop_pic_names: for f in loop_pic_names: - if not os.path.isfile(overlay_loop_path + time_now + "." + f): + if not os.path.isfile(loop_path + time_now + "." + f): # ignore the composite gif... if f[-3:] == "png": image_to_retrieve = Store.BOM_RADAR_FTPSTUB + f @@ -279,7 +281,7 @@ def build_images(radar_code, backgrounds_path, overlay_loop_path): try: radar_image = urllib.request.urlopen(image_to_retrieve) - with open(overlay_loop_path + "/" + output_file, "wb") as fh: + with open(loop_path + "/" + output_file, "wb") as fh: fh.write(radar_image.read()) except Exception as e: @@ -295,10 +297,11 @@ def build_images(radar_code, backgrounds_path, overlay_loop_path): # Run this with a 'clean' argument to first wipe any test files that exist if len(sys.argv) > 1 and sys.argv[1] == "clean": + # noinspection PyBroadException try: log("\n\nCleaning test-outputs folder") shutil.rmtree(os.getcwd() + "/test-outputs/") - except Exception as inst: + except: pass log("\nCurrent files in test-outputs:\n") diff --git a/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py b/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py index 1358b7ded..6ccc22ef7 100644 --- a/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py +++ b/weather.ozweather/resources/lib/bom/bom_radar_scrape_latest.py @@ -2,6 +2,7 @@ import re import requests +# noinspection PyUnresolvedReferences from pprint import pprint from bs4 import BeautifulSoup diff --git a/weather.ozweather/resources/lib/common.py b/weather.ozweather/resources/lib/common.py index f30b65ed0..81c8a2707 100644 --- a/weather.ozweather/resources/lib/common.py +++ b/weather.ozweather/resources/lib/common.py @@ -25,6 +25,7 @@ LANGUAGE = ADDON.getLocalizedString PROFILE = xbmcvfs.translatePath(ADDON.getAddonInfo('profile')) KODI_VERSION = xbmc.getInfoLabel('System.BuildVersion') +# noinspection SpellCheckingInspection USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" HOME_WINDOW = xbmcgui.Window(10000) WEATHER_WINDOW = xbmcgui.Window(12600) @@ -58,9 +59,9 @@ print("\nNo user agent, must be unit testing.\n") def log(message, exception_instance=None, level=None): - print(f'DEBUG: {message}') + print(f'DEBUG {level}: {message}') if exception_instance: - print(f'EXCPT: {traceback.format_exc(exception_instance)}') + print(f'EXCEPTION: {traceback.format_exc(exception_instance)}') else: @@ -150,7 +151,7 @@ def get_setting_as_bool(setting): Helper function to get bool type from settings @param setting: - @return: setting value as boolen + @return: setting value as boolean """ return get_setting(setting).lower() == "true" diff --git a/weather.ozweather/resources/lib/forecast.py b/weather.ozweather/resources/lib/forecast.py index d4ebd65af..33cdbad60 100644 --- a/weather.ozweather/resources/lib/forecast.py +++ b/weather.ozweather/resources/lib/forecast.py @@ -1,9 +1,9 @@ -import xbmcplugin - +# noinspection PyPackages from .abc.abc_video import * +# noinspection PyPackages from .bom.bom_radar import * +# noinspection PyPackages from .bom.bom_forecast import * -from pathlib import Path def clear_properties(): @@ -118,6 +118,7 @@ def clear_properties(): log("********** Oz Weather Couldn't clear all the properties, sorry!!", inst) +# noinspection PyShadowingNames def forecast(geohash, radar_code): """ The main weather data retrieval function @@ -162,19 +163,17 @@ def forecast(geohash, radar_code): time_oldest = utc_str_to_local_str(utc_oldest, "%Y%m%d%H%M") time_newest = utc_str_to_local_str(utc_newest, "%Y%m%d%H%M") - oldest_dt = datetime.datetime.fromtimestamp(os.path.getctime(oldest_file)) - newest_dt = datetime.datetime.fromtimestamp(os.path.getctime(newest_file)) set_property(WEATHER_WINDOW, 'RadarOldest', time_oldest) set_property(WEATHER_WINDOW, 'RadarNewest', time_newest) # Get all the weather & forecast data from the BOM API - weather_data = False + weather_data = None if geohash: log(f'Using the BOM API. Getting weather data for {geohash}') weather_data = bom_forecast(geohash) - # At this point, we should have _something_ - if not, log the issue and we're done... + # At this point, we should have _something_ - if not, log the issue, and we're done... if not weather_data: log("Unable to get weather_data from BOM - internet connection issue or addon not configured?", level=xbmc.LOGINFO) return @@ -186,7 +185,7 @@ def forecast(geohash, radar_code): # Get the ABC 90-second weather video link if extended features is enabled if extended_features: log("Getting the ABC weather video link") - url = get_abc_weather_video_link(ADDON.getSetting("ABCQuality")) + url = get_abc_weather_video_link() if url: set_property(WEATHER_WINDOW, 'Video.1', url) @@ -197,6 +196,7 @@ def forecast(geohash, radar_code): set_property(WEATHER_WINDOW, 'Forecast.Updated', time.strftime("%d/%m/%Y %H:%M")) +# noinspection PyShadowingNames def get_weather(): """ Gets the latest observations, forecast and radar images for the currently chosen location @@ -210,6 +210,7 @@ def get_weather(): # This is/was an attempt to use conditions in skins to basically auto-adapt the MyWeather.xml and all OzWeather # components to the currently-in-use skin. However, no matter what I try I can't get the conditions to work # in the skin files. + # noinspection PyBroadException try: skin_in_use = xbmc.getSkinDir().split('.')[1] set_property(WEATHER_WINDOW, 'SkinInUse', skin_in_use) diff --git a/weather.ozweather/resources/lib/locations.py b/weather.ozweather/resources/lib/locations.py index c84b28a96..1fa471a19 100644 --- a/weather.ozweather/resources/lib/locations.py +++ b/weather.ozweather/resources/lib/locations.py @@ -1,3 +1,4 @@ +# noinspection PyPackages from .common import * @@ -17,7 +18,7 @@ def refresh_locations(): locations = 0 - # If either the main location or the fall back is set, then enable the location + # If either the main location or the fallback is set, then enable the location # This is to cope with the transition period where folks will have the fallbacks set from their legacy settings # But not the new BOM locations if location1 != '': diff --git a/weather.ozweather/resources/lib/ozweather.py b/weather.ozweather/resources/lib/ozweather.py index ac9181226..bdcdda9cc 100644 --- a/weather.ozweather/resources/lib/ozweather.py +++ b/weather.ozweather/resources/lib/ozweather.py @@ -1,9 +1,14 @@ # -*- coding: utf-8 -*- import socket +# noinspection PyPackages from .forecast import * +# noinspection PyPackages from .locations import * +# noinspection PyPackages from .bom.bom_location import * +# noinspection PyPackages +from .abc.abc_video import * def run(args): @@ -22,13 +27,18 @@ def run(args): if args[1].startswith('Location'): find_bom_location() + # RUN MODE - ADDON CALLED FORM Kodi SETTINGS + # the addon is being called from the settings section where the user enters their postcodes + elif args[1].startswith('ABC'): + scrape_and_play_abc_weather_video() + # RUN MODE - GET WEATHER OBSERVATIONS AND FORECAST # script is being called in general use, not from the settings page # sys.argv[1] has the current location number (e.g. '1'), so fetch the weather data else: get_weather() - # If location settings have changed, this kick starts an update + # If location settings have changed, this kick-starts an update refresh_locations() # and close out... diff --git a/weather.ozweather/resources/lib/store.py b/weather.ozweather/resources/lib/store.py index ca906ae7a..166d691c8 100644 --- a/weather.ozweather/resources/lib/store.py +++ b/weather.ozweather/resources/lib/store.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# noinspection SpellCheckingInspection class Store: """ Helper class to provide a centralised store for CONSTANTS and globals @@ -9,9 +10,10 @@ class Store: # CONSTANTS # ABC WEATHER VIDEO - scraping - ABC_URL = "https://www.abc.net.au/news/newschannel/weather-in-90-seconds/" - ABC_WEATHER_VIDEO_PATTERN = "//abcmedia.akamaized.net/news/news24/wins/(.+?)/WIN(.*?)_512k.mp4" - ABC_STUB = "https://abcmedia.akamaized.net/news/news24/wins/" + ABC_URL = "https://www.abc.net.au/news/weather" + ABC_STUB = "https://mediacore-live-production.akamaized.net/video" + # 2023 version - E.g. https://mediacore-live-production.akamaized.net/video/01/im/Z/0m.mp4 + ABC_WEATHER_VIDEO_PATTERN = r"https://mediacore-live-production.akamaized.net/video/(.+?)/(.+?)/(.+?)/(.+?)\.mp" # BOM - JSON API BOM_URL = 'http://www.bom.gov.au' BOM_API_URL = 'https://api.weather.bom.gov.au/v1' diff --git a/weather.ozweather/resources/settings.xml b/weather.ozweather/resources/settings.xml index b47b63030..d7d5aefdc 100644 --- a/weather.ozweather/resources/settings.xml +++ b/weather.ozweather/resources/settings.xml @@ -351,23 +351,6 @@ 0 false - - - 0 - 1000k - - - - - - - - - - false - - - From f320c434150b25eacbda2898832a7533d7b21f87 Mon Sep 17 00:00:00 2001 From: bossanova808 Date: Tue, 6 Jun 2023 01:37:37 +0000 Subject: [PATCH 048/145] [weather.ozweather] 2.0.9 --- weather.ozweather/addon.xml | 6 ++-- weather.ozweather/changelog.txt | 3 ++ weather.ozweather/resources/ABC.png | Bin 73826 -> 0 bytes .../resources/lib/abc/abc_video.py | 28 +++++++++++------- weather.ozweather/resources/lib/store.py | 6 ++-- .../resources/weather-in-90-seconds.png | Bin 0 -> 37939 bytes 6 files changed, 25 insertions(+), 18 deletions(-) delete mode 100644 weather.ozweather/resources/ABC.png create mode 100644 weather.ozweather/resources/weather-in-90-seconds.png diff --git a/weather.ozweather/addon.xml b/weather.ozweather/addon.xml index 2e65baa31..7f5e62ffe 100644 --- a/weather.ozweather/addon.xml +++ b/weather.ozweather/addon.xml @@ -1,5 +1,5 @@ - + @@ -22,8 +22,8 @@ icon.png fanart.jpg - v2.0.8 - - Fix for moved ABC weather videos, update list of radars + 2.0.9 + - Better fix for ABC weather video diff --git a/weather.ozweather/changelog.txt b/weather.ozweather/changelog.txt index 819ea7bc2..19820c417 100644 --- a/weather.ozweather/changelog.txt +++ b/weather.ozweather/changelog.txt @@ -1,3 +1,6 @@ +2.0.9 +- Better fix for ABC weather video + 2.0.8 - Fix for moved ABC weather videos, update list of radars diff --git a/weather.ozweather/resources/ABC.png b/weather.ozweather/resources/ABC.png deleted file mode 100644 index 5753e290a1e24e3c5d73b93e9fc394d4c7d04764..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73826 zcmb5W1yq$=7dA>a(%ncYEsb=iba!{Bg3=9A3P^)UiLwD{q(h{;yF(g5@?RUjbME(l zyg0s{kggn|VA5>XQS z0sI5OMqF7O2Bsn&{l*Lt{5Q3QoVqd$%qs>Mn7~jNm@Dw7z-<^9FAf-(T~ins!88~c zBG=3YH6idnkjxcjrC{!%Ke^wFlEGh)J>`|9kyqhJ;YrBasGd@Rn_=Xo#5H|q_rLoD zlIy(xeXHq}ebB3xo?Dj4YGVOW<`5v}Xd_0R(STO0_AUwEAwM$ZO;1a451 zL3#zYGC5NmnHiat2FFU8MJ@HX#z)?QUDJ+Vhh$!ml?|6zB!4QcH}wZg5q&0()6-v0I>L>ZC6g-lR$$H; zukdb5-0s$|g)rp1ondm&e(96o#x9VGS`NwvzzYH^?WBt%5MMk8$q)EaCPYU8aiwSL^wn^JW@0S z25z+3TySHqr~ujWv{ow;qh9E`f1VHFSdI`y!jyt2)E(wR$YV8XRq7*s`LtnGYHpUi zie1-H!rQ2dh&#F#U`(-Dh(HeM1=)*ARY~dP=ZvA3-34OUt}xK&e`^bs35B&Ae4HyP z-2jmZ5(`kj)ptvh#w5$M%oF9r((2AZq4DZ?ciR0pSu7V54FP&nlXhISco6nBSaVcI zSLnqoXrB{Lp|@d52hfH__TV3sB>F!khWY{ZBo0wRvl;6}<#3MgmrSf5@`R{P99tS4 zz@6ee6q@sP&#fa;@YrKj;0Dx@URG?&??hnrEWS?$kr2_d76g7De04D5$nzkBusAX=v{9qmbaiIUtI3#bFPH~}}wGo0sv&ymXTnLZU&ROW( zxAPgI1Og(QlPWcW5JyffLj_o+;T+8t?MzEGs8!<-n&}+yER;lqWVj$yOsE&PQE)-L z2}2>P_jj zI1jw(rA3sWfMzBfY^G&Yf#^s$>0jHR$)S%UVQ;QZ&5>soJkuH)J~ep@yRCwc@=ZL5 zx*dj55C8IRIt|-miU!69f#2e&!0^Otb4|^_wUvD z98bV9qzw-v&HW@x8`eEzL_@g3E1!sl_ehd9e<&?rM{(Y}3UQQ@R*e0UrYCixF#pti zX(YBH4=^TI^bdDy#pgh%gNdh5OSV-)6I?l;U=u^0JQ%{nfSrHxT9tZyd_WJFUP(}lfWgVrwmXEYR!1S6bKV}p;&^}wkq{-__KerGMUAG-sSJYphiEL zT%lLA_0@QQ9JjD&_^|N3n!iB)$t^lo+-Rc%;N#LNW{HxBvM5fW8QV zFreZ`NV&)(Y$QH9N=QOqL57b)`$#E>`hRP^I8U>sCdF_|9K}to6^hRfS3{Q{vl=mY z9BK?S#iRyvzBK}Th>8u5{z->U)5&GcB>M?mju$RAod1BF;1;n2DNvjGBRRCMK$?LY z3ByYAxPSi9J)@=b>|Y*~0|_T{4ss6U{axpJ7MwUq5cbte*QBm7SQ4Ub6@{69YlYMz ze6s{vxtNl^A1hlqpH6^Q8_5PkyC((;9EU479RDy9V%q69H=zF5MKe+q#n;D>w)(kyg2 z@o5SO3j?;GxC4!DtHTB}fCe?{VHpcVxS00fLGXsrE&o_yv_E(}_z#yqFmO2m@G=-~ zN?`{x30lvZ_k())+E9J~Bz#tcG@JY2fo2EBW)nWjUpe6WWjAG5*Nfkd)%xNISkz^@ z7|1Cw!b9W=Jo~m}g%@Q6fh)mcVhyJ+5kq2rJ{ig`c%<8nK3Io{_$X(L1FN3G0G_4e zGKbWgs`!=2##PT4B_i<(&&27IK(v4zDj;6t*eE!a4~g+VYy=i*7ZnsOC1_*ysBG3Zvqu@Zo1Umrhq_V! zS6TsxKCT%2kLrQ~Mv54+DG?z}Vn+c~W<7_AX!g#56UTh0eSDOW^9Kd;56gRq*fWuQ zL#BP!D7@S_rzztonv!ZQd z@Jy)})S+)Ep+U^CmBb848UXJr&ZBkxf)Yh+eM=Do)f071oc*EUy^YuK!+>CIL*T?i zVP8}-nS#VUV_ZZBmnWR!Yw69LGrcsWpi03$uc&=77B;28A~ZZR44;3xv` z=z=i4&D0*)9+#%So1YNsaKu&^_p)OYT;ALc{~U|4`-wt&Naz8E$FOqf~s! z1W7AlgiHE~Pp%LYk}9<={r@sPfN{W^Bd}F&Z@ZxCjDhz zC|G@{(kt`uLnst@n{fjD(HmMwnbVsOtCuM59O<{3 z69Ma?g^EXdAF;77@-GZPH4rGi1knOfHOZY-l}aGnxjW0^Pt}3B96&`aSC<+{Sd8T4 zGh+X{?m#de(V^c)O+}L`u#$x`y`Ayxfui~YY=p`P01kncs0}=MBih5$Guh7u&7qYI zP-C5iA@v)y+MrL5G?lQJSSet=!n44-m4EYZtv#$L0AQaNk?m=tK=b}X{IjMKkJ|%d zRaDpL(1F-|Vm=iO3JxlrZlhinKf9BPlu0{z-gNMQ08njlq|Y;ngeZ{00_#Yz%S3YPi`jM9!)WtN=l%`n@66mGs zr8>{2#0Fv!E+2%=8HD{F=mfy#5Bz)&Cw>i;I^+N4zbqyJ)0PE50R_`&4;g6Q#R&n% z`VVIXpTXr(Zne$44*M?vv}cn4szt}3hoXiK^f8?HUIsU`A|5!1CjbA511bxehU8B2 zsa}#Xvjl#dW7_G{_W)j*9s`bB%M&a9hxi6s` zl1I7)-4%p_wii@TeuR8buKPo@bFX|BmqWvk0d7KnrW9z&Fw-s7%$GR+>Tv~3z+9ol z(Iw#)05AZG#hn1jkBWI4bw^kIFQYspxcs?8mpmc#@nQebp z(PRDI6wtSZ0r3tlyc>5V3zdr`DgF2$spo!vco6&Iolq`k!p=WX0evoXU4Z^QW3*?w z!lO~^!C0_(EIijP%L45?^2ER$QXAK~&}{feEKi%N)va8>f%wWvj^v=Ip=t=*;L~B# z>gj%bz?Pq(NdCd;zc1iO0Q45Gs8j+G_*VsY--bVE=HmEXS(XS;^MxSwp&162=>dyI zDE9uL{~v$&dsp{B|KvVHEk&!u^T5py#HlyFKN5k~Aw*Gw+5*L1KxzpF)N)SH zD1hWqT)&ZTbdbg*Ai*SfFHb0e-?^@w4kz9c+Pw4CLml*xQRCM8H|zSF!{Vn#5FUWqM5H9Ty`A9XE;K9-eGt&#;Q&shXG z)`B~EC7v-|LXZNRmEeR+_^(D$%LeEmXB;(Bk7SV@~n1-)0u6vnsBd6_+R0=vFKZo8?ewirQ1ej$dMxHulAkB1Y4OE zYIYlz#Qv!a>orHM`t(c&on9!NeN{6rH2Dwh+szpM8eOpuAPUjg1CdaQ;mG5p6Nnc? zNBHCziG$Lc7KHi5&e3_uRKtKYL!WDVh<+qlK9@a1%!eV!vmf94sm34NZlV}|-i)5a z4?=GTH{D!c;mBH_O!HL-F07rVF@tVNKh_HkVaDkjy?I?3R}7=ihO4myl0&6@*-yIR zlt>ypE;F>6rFWboIr6?&8I_3SCQPRHj+Dq-C;Z$#S4$!Bw*iO!w1j;r*~u(#L^SBo z9oQbV%J;SMu7(El*KbI!239H;$=UXQ(vl=^IXlDh zb5uu0Fl-(-RtN}j@J8fhWp;f%etEHAa8`75pmtUyXw3Z4c}bSndR5@F{!wN#q2cIA zsMid>U=k;t(mB^{zSTSXO<&DVFm{N{f_i5h<3diRt4XiPap-BC+pK^-$;?7BXO3 zBYMnrIn%3mv%Zee?B$8uvxUauCTq|Du8pFduCKe0&UktvcJGzG ztDPd!4hnvqEE>IkfcvAR%(N~(#!cW#do+C{louo{i?m^ZaEEpjAzuk%+MRDpo+r1W zPu8q7C>!}Mrq{@Ms!dn8*u$DUe->3vk=@A`|H9ldPY#T!Q7><8l`Gd*8JvxlqEfMH z*7AR2%qF{S9y}t?U|)U?oILn}(d=Q5)RLhe2v~E|Kkv4AKAA;+td(oF%J+PiSE!sT zqQ;lygwwP@wY`?X`naot#Q%*W661;V1BcVe>H_1$8H1<~gupZ}Xqi24$4O!NYQU(@ ztqxsf*J1Kt(Xb|vDl4tq=6C#B6>|5{@}>VJU~c*4Lk;RkToj~02jsb<*|>$evMN-H zUj9f?nNw+h7fZq=$`5UPD#~j*c&Gh;q^|HhL{JY9`wms?##+%E(%tq-$D}`hD=8mk zhrj%DCM3cq7^3o4X|1*@W?WU!fk~pEOBrgJUl8^|wfPhZVsPWq5WTtYO!$lWZ=c9O zw59u(7cMdU7>JHOz^`3iE~?#Zcg7-E`1G=qoiWxU*1m$vdrZ)g5A~q>U^Axj``a|o+<$_13hB7V?i!GrWHlT!lNCF za|8INZa*2UM@C0oZf9>I2-@Vz%OAFqr`>Guz{^%CN)O{^iBTc$d?Os7eG1`|U}B zTVsug#AqUAnt6i z+tHix=P{eLSBS#cw|}m>Pdgfx_-4YoG7t9;ml_%< zTxP~&D7_8B+B;5PHf?S5JBxA#?WlhseOe0E$1~KZ)!z2mS6zt?wlbu*I3Ex%qD^8U zqE5ETYsxwpE8#27gGu3`h|3PL49D3^lsz_Bu^pvzb>?c*V^};{mi3j45qu`o@kPJa zv2Bj^1s)AOGzPDYU6IXHb8UO~rY}(N2 zft)7d;IlHXyM1yaO3CqiCzH%FQx_HR-4=$gd{4|KIty2=74B#uk;MO~l}W_g67G+^ zliq&2`5@zu?i5EfDt;fH?Ah#3c)Wr6R%TnhPi}fv)P(qJiAQyd!tEo&!DfR5vne9} zf|Bj{BY;(KwgPlDw6-=DG^TXY;Ind{qa2VD;Rae2-=Fon7sm6X3$VHQ-_tVgtGt-Xxt zuoq?nm*a72m?T%sWls)eTNYN1drLfKO#8~hM_R#N_p#YWH>Zf7D@y2%@e=x5=frZ>T_?@!dZwcipMr)`dBE&J))1+!Zapf2%%8 z+C6|)iXs*n<7Q$i0G%rqga}M#65u%+A@5F$V*Dz7hq!o`e@+aOyE2nv(8J|~zkhQKbLXnT=e}Pvo-Q%dE*r13>=d8bSd%Ft%V+-^=cB~ZpOedKlWa;D1K*F>!n;>DU0qN(#5P5dvqokLmBCY!MFmdBeL}=Ll3K1@1*+bm?|8pO}(NzQjkdhc=UDCd?lP`LehFjD4>Cy)2qj z^C-*CdAN*}zOUUczy~hiKDi_9C;DtlxU`vzsHSVuC-&r4WHytK&({We5C*LZ82`-? z`J0YI$}X28B7}G^Z!>w;I^j+Kso&gdw+639QuwnJA%UM5{D@92PhT@0?~K^l7t1&> zHK3^_Q6sX@LjzMx&wXC6og^Zz>>jWS$SNTFI}ZEIaGUOD{`f(HqbX6r(C3sQ1e^hA z+ZvgcdNL}4L53thcPDWXu*N2I?}BIHRh;gb?Vg zfSWqcuD?3z8~W!wi`tV2VP({&`x&yM%DAl9avZBd)poKsuGsgDdzMl+PnLxh*5p$h z+dHqbzajB`*;`f@r+sIEj(9WU@^-cPBOcBP@ZBU7(MPer^SbtI*~&;j#YhME-Wy-E z6^TbDk48Itaaf!zuqPmdCn_|`6)P@w!n-S3n3u8S}S76Zek@6^EsB{ ziNk~(nYPs6<5}KShNB?><9Jh<9jotUnjDRg-}u~y)x9cag|k>NH+1ctxc$Qaav|(8 z#zTdu90fHw18MGfxoW75=d(W99+fr)2G{T9!ff(pFEddj4L9A%9r!OdsZzb9~;bDT^tk$6W(0vGTj815pC=b=OQU@S}koC4GA1!B}uG z%}P@sW}7CKz?ipUtSf=&Q#@7bCcR>VQDeR}(XrjfK%$7+?Bh>5^?JjM{Nep;dyH znMG$jYd!3uSgGDNJ1S-rkio6vc`a7{<7o7w=r--1rj$NEIpLXiiYpO1PThNxJ}=L( z6xBs_=(f;zxQrH)+I`rK<1lx2=dk!$87=3d*ghw_`QP5~_*(fWp54fAO-n|?D1E2s zi~jLaY60n@-Q8-;t1Dql4iE`3ExsMLek&jCHrt%(>XpAHCOg9#FAG+-IuEcDe)7X#(S)ijEj?g)g z*7+!k-n~@jyOq}l?!$u(UCYWgHWnVo?HQiYxp%ETUt3_x=jXeA$Y*w0^>;?(G{fE> z7to|GYy;T$Y)u$iBXF2?+utxa4sIq#=1NRYEwk@p&*6+^eqPCT8)BsUY~3Fzu!YRN z!;jCKR@*9yDn@<1-}g^Z9-F`G*wfC>Y^a~Y)w_{sU^&AcnWG^L;N@~SLD2gqf+Q>5 zoNe&leETI~D5Iumc%nn}rJG`Ce)~?|D@Ejv&SGEw14HxOeq7z@39O}(4_s1v5_fuD zAzkzNc--ZwvhZE4iy4vjf@6U){PSARHTG)*xSmJdG~a!lOvpss4qz%dlSvhLfzw%> zWNWdoh!O?p4w>Sr9pNHIkB7+ZJ1$(BU>poaW79hE_*{0|iM}odZ%VOb27#Rz8ljTU zs1YXKkG^i_#^asKr6Dc8TC|^kJwwVpfnU4dZm&6*%7f{@IZxTNT*3HZ_O7%wA0J(R zWUY%r!2i67=3A$dJ=25*77Z*%wHtmpD(2_w1FTjy7F5U3F&_85NlO3Y4TF)CXfAzR z6QRZy0+Tl@gr4K%lFtaj&OccGxo0yBa}lx-cIWxs05%2^v&fKVk3&B5nmK8VHgZAG znKj9r-0(~U%ZXAqlJ*;DgX;3>LtG3YNWUu5-dPwKlbzwZ!?H$)EkLm0Df$1cVDZO4cmV8_=*J-|b7gy(&yO41TL07Dc3(~|`5^N!ING?2_ zrluX_V33aQ%iy{^c`0cdm!Tf(1zOhKh#B38_*}6_1t6MPE|6%wzbyLNi7sC3$FUgW ztYFky9la;Y4jJ?`)VsIM#N?z}9tv+f-eJU|wS!h&U zT|(U4Tut^mN};6fD>H2{^o667G~7C#=5F*c&v;RegJv$pS;p{kz|MYdXtO#)l zNhNI4ubn+&5_wz0;hE6#<|FcN&kw)?l|dZ+x8>n4?`yn~u1xpaX-iFEE^9q>RwRkA z1cWf(8|j+O=)R9#Q8Z{AA>kv_erK*U8UlUiWeRL3=0_R}qiI+mup%A$k0_)kBw+B; z8>WxGhmIy~H+>ulJNHS&T4hx+=qr|!*joL{B61OIwvNk*cq4fW=ybkwD5n;ue0#{< z!#kg%TyHGsI;ZZ@PTCAi4uL0iSOY|GjiK4!nMhD)Kj(@26Y4cQy`QI`89xkfcD;>a z)SGq%(nI2DSmt>z0 z#Z+GHdLCmeMPNKX70hl_LCJco>$GLIf9&*;-g-4=%R7(#;5!)uG?((XPp@A)UG4?F zsOAA08^tY5&t&Tp<{>YO@n;!C)4nx!=2uQG)1z_sJ%h}nFl>hdD}DebgB;cM?~C~% z63Hw>yL~INLxv%lb}w;XvM41oxohb>GVwb>@?==^`mHC9oa8_H%!2fCKILr>pCb{0 zWcxIGj8t-f!Cc5*qyE{bDj?Mnr%21R6Mpta2$*Qfw*Pcn!&y^-BF0-H$M9Z?Ir$L& zBH@t3W=m$?+Ct_Y4n{HmxjJtM0ac4XkCLtzt5C(XwB=^yZwCLZ60!=xtm1>*SmA6( zI?QFR4hrHIJ)!tTQk~@8l(!r(^UW`L*jxrxC8I=K8t@WPs@SyOHOYH;sPH(-O@@6M zj@!BcK|D@kmFw31P8(oE**b9Y;-ZtG<+rgd`9g=dO4l)##5x(Fpad-j5InS zfn&p+`PwA#o>&Kp4BBADh008#XQc!VW^S|GB`nNlj*gk#6=QTiAe> zYBCp*A`0z#7DE&yg14bR+6xWQmJGE!&52S>?g~XCwyNp;dl0>ia7Hi+ai=R@@?bo9 zodDjIn8EY@G$n}W_=WwPu0-Za3Ry|$wO}oc1p=Ug) zGNaz2n>>|qOY=-^qy-=0NYp?*e)I9WI9>WmJjE)uvefFLqlRqHu%)WKXzp|(@Aadi z&(DGC{gQ`*3acT~0}KLNgCVLDfdxjooE@z_2(1X=t}%V<@1*!jbG)` z=rG|goOi$+Q(clr9gK2_HC{Y8hKgx}T}qlzhQ4Q&A$XjsLT)<#SmEd*^=vJA(Hiwu zo{h|(*hxcIb>$2;ehHIa7h|`AsG*|{a1Hor?Yr6x>r$|vxJC)&mL_FZr zvl?hgcdOi$Dx3ZU8_zch8u4*<=MzUg)A8Ck8tI#)b|%JMxF?(EF+aUNG#-n+yWFA5 z_S*SW9%TP@@GG;ri*ZW>eCpe-ei2Fu%S{peR+M_aC{x|p)@~kK{wQQExlR$<|6D?zYCY0*Lh!Q1#zIF zXSID)SA)doruz{z8#^(UB{Q^zwKEGJWXYqnXK2m>K#?e7f|%*|&gIlo5?!nl|B6g% za(18s5F@``6_;W8=d(w{QA1uK8s}uB@{AtFW3@G`N$*vYnlpLN`_zvPmKIOL0}PDx zxGzrhQvj4bzOCcP=+61-T*PKu0EQOWh1jyFPQOGNA^sFVdgIR6I;vfM0x|0$`eI)2 zcz3Y?W4R@#@=*mBS5f*Bx^Y!Ag^TXox1ik=g=c4`$mA+G;jNsl8W{VquyD8B9q^V%ud;PK9X4Ghl2BtU02u)_jK5&1WXBS(^0jiS?uvJ zg5Gx0Mu=sFTi+z5VPky^&RePQ6ibZzv(TWb!MqVVMUVMTo$LlQnG(%oS>xXy62WR> zf7nszKAr)}nVvFv`Of5?t?YMNQ0-X`;q{>OQ_VQpH@8_vI&>^RflC^Bo#+8k(SBmF zg;VB0l%mcH3ZYGIB%lTa!)L86`vl)IQg=IWC6U%JyY+Uu}47H`S zvy$wwV@LEs^(sd2iN)=&A>DXqHVQf%I%{IzIRb}4!3d;emYe{4(N`AIWSqV=k7?zI zQZPXB{}`P3&UzWKVr<5CD9Scoj=opDVCNW>y5d~U>_XNULGqZ`C6esUNjW~WArKt% zt!pb22%ZW16c~pjYOc5I;2`fwxpFgX%h>rmZAON99y< z!LLoIQYJ-h&MXp?TU6nG$C=sItmY~z{jDZmIg1{{1BJhwe|Mna7VWAn)4p=ka=^FV@+G)P!(1aIN9%u19IkitsR-?;}L*US403_q#t)Z7ZFm)UEU~ z;w0SZA-j4`KTZimRl(-%^aP5vmo6+BVfp(=m@-$Q$sD8E_yGzM86Mo1+2hF_F;m|Z ziTyg2D$9l#j;RdXnM8kgiWgZupODHs;##BB3(b8_(DPcwFecOv;So+Ay(+Ae;aEy1 zLsi{=pg5ZL8$J)4DFW0CBCmA_eKLYhCCZg#13?L1q5oTTsvzo3uqCnKDEU#gUE$~h zsDjHzW+al4NZy-0JY+Y0Ng0PEdS|$t`X(|aA}1;H^VjA3(FRYwEO7GSQhm5r2DZ+m zp9LtAwzizp>vU4^Q7L5)%Mi%g6trQ3yq2@W z3%GCAUY=@9Rm9PMH(Kk5{!5c<;~9cl2?0rO3!H&J zeagbVZYGK$7V(#CWwlt=i7Z6$`+ghN7C!eCpNxB`uUs8em}l2G?U~d_qn%}T14{}m zDxhFV>Sgwalln)ut1MEvNK5KStZh$5Hb-Qg9re>>mH@vO$b-s+_MV1+OkVs5#-lOk zfbm~X5-(F=q)l%5qL}XcqL94Ucf+bA&(TOH*5y@F%m--S#`DgeH*zv9Tjufef_W;S zHE?Gkv;yAu=XMTMc*mjJU4@g}&NJimc|)&q0C@S}y=f7x*e9-TfHbi&V(@TR@XK(2 zUSEIh9r-YB+e?V zhEY#a33?1~rjsjDUTIJuFWaxam5q!>vB4=V@+|s& zl9}6wT91*Cuq;$tL{e@vSK|NTWV8n1>Pv7O&6ZW5IIk;_TIPx84snYd0dHZluenEI zo`@Vcpya1C^f57v`~umMC?%9PeS;1vi?whfkP27 zLphmsst@(Mw?HUqzAnaN(&OK!Iu;si6Rp#DW$1k{M_AvZdSbSUUb~fu&VBdRSa)yf zZDaw9Dt+ay;R6n=e*}ce#yQ~)2o;=N=0efJy!_^7XYz<$cWIDG=G)dG8;O|y2wNGS zqkTtU{kCdxssE4xQOa}9Zcyeo$#Ea*Zj;12Z>?v)Oj zPp{4H18q8tk2DXy@hO@7w{M^$;Y-DO7K{UDs-*!}t_DGO@bJK`#q3PIZEgWcf7g9$ z%#|1Zl&~!l$#5pIE5~I&g=_2c$;UL4KZk;8hp3Yf)J1X@4wHssQrTS-L1a@%m-axU^R~>(Fv6A+=9~0AoC!DEX7ST^2!dDXPYc%BsHY2gG3@u&8rx)seI?r(*iv(t91EPV7p3s7}N zN5pmfE``CKiNFc_3&$-M$7hj{G$Y+BL~v+PYXggIS5nY97`rlar3T}x(bSWb+s*x; zvBDsqoa8Vqwz)`=aVvp51;9DQ-3CJjaR-)7;`K?-TjXJU#T)AAHgkXO9bI&zaj|jK zV6z)8WPc1#5|_kLN8~y}N$Dn;`6p~LP65$izic^QE7mZS|HvoxO!PMkhXAAAL46rs z#j1IngqGLwR3sZqZF|y!u9Oehvv0E6D?PGM3B3G`b*s#w(3M^xvyXHDiIWA1`0Tj- zEjiD-Qr<}3v_y)|^R$<>LU##aJQv_FZ3^p@<8Etu3jSjvnn#AyGoeHn)mdI*Q4D&< zO;2N3kGsSr!~>amoL$4N)p&kK$R*?4b|;`^0e$H6YA_m3VhyY$^=TBKfJ z&VTPLeAR>7O(RS)NLRs`HEviWpPz@~){6fu*a~c)E2u_U5)nFGo)=9S5BC&H%VFNF zB*E_72$66dxnztnrRor-Wp3}(EMn_I@L}68-JVjo3 zk{0G4_qu%kAY$WeW#JI$JtU~!iy;DX)rd?AU5Sva{hJxj1KAu~6pw^Wq$;o0@6D1_ zqm;C5d>1gRF5M`DSHQ*-bya)b-`>8~;>d{morSRsKWQ-)uT<4HA3|4JDUjMu#_P$) z^qc>B;Ily)3?j3eBIf5mP!M5p-Rbq1s~lIYv}KZTDMT&^>>t-`BgKYmiv~?mbF@G{2 zqzxkHISEUKFNq0rD9jk+UV^dp_H#Fwv$jPg9NE6jxQrP1j`?%x>5{*NPg(b2{mkCe zOw4(J9+r8+lpU@brLZE*moPvd;B?^&2J2C1w}unkI#^A#sb)1o0OXt1J?@BSQ1q2ff2nOZO)rhfXUEM2Qm{~6?Hm|l0=J49M{)wwV zPGIrCymWUqbr0<;S1XV13=8#~pH?AKq+AWq>aw3su;h~HE&t`!0Sel8Ej%uZxSxJV z&@}7TU&8~A-Ik5@34<1zWaCD#BG#t2K;9fs-FNfy2^Gsyk^JEJ&HZ#k!`F(QgMpSE z<@Tqki2Dk{Mil27J1i@(34&4y{!XF?{QWyv`H9Ly&k ziE_BoKPo#g3^~ajLvDDcRvalBH{1Gs5)adAufhCgB%ZOBySF3{e0b3JRhv*cB!^HyoVOPQL&A>pUxC8N*Gm z%kII8G&d4z8uQC|51q$nTM+)bnV30TjuUj=7E7Jsuati6v#krtZr?`$w^>|41d^q6 zXk{?z$6n%{5L+`n&Zba5!1@7ZtWH0^xG zT+Ga1>gZAn!@bc(R z^dZi0^JwCqF+`DD+x{1ku5Y*NzgJvcZ6-&dxg+_(a2$P}<#jycp^sa~U!i&&F-W0v z!pf+b2f7=AnFM9?IkDG`5aX$2i4xu5?O?40`mo=OHmFeqw5yM3U|fwgz`1Z4OzCeu z;~juSKZRosQkSjoVp4F3p`iZEF@f0EcZ9E39g6UQ64Rymt*QTlNdl&lS~^lVKy+SX zimhzRhIN`Cy4`m*cl&zEE(pZV2O_EBCo56S9cKNKhI7ZGjT*+^P zhip$VzGtlSCR!76YiQ=QNhz~M7{$BA`)QCcqa<&AR8`7B={0$bkuEsQO%fVD!vQ1Y zRQz5o8e6>SF1UH)5%aK(1=5j@q#~a}&0bw;wIM{Ch>$$Y@)J{;2~mnc&=0`aFHYk- zzApmm6(ZQbXiR2GRbcjCdI|5tSI#UN>!HT-1L@#=u_*dDvW(7(bo!nA(*oh*yhzHl zym%SH7$8-r6eP&v_Syw&Kcj-3O_?VW2yO%Ej~s2~BUY>KUpb@4cKxwxS+7C=tbR1H z>kB~u8k>b!Yqy(LN}6{=-FIWRX84zoC|-BruY*+5S>(ala%rc{!P`nX)fCppKqwlL zM%%`eqyp{THxoD=oMp989R%%oF|%MDBs|0PB;1r_(+#Vl(oP_L{OkqJGx7rX7*Yih zGCI;f{+IAzE}#AAhXZ|HT(_s08z|t_m%jvrZRNW|ulBENtku{EDR^mWh(apaLEbG( zCCY1VW^QtSHJBirJ$Ct}l&i_oJ~Z00ah%6VR(Bo83~Gp0FZD&kkC~aU2@a5Zon;yH ziiFT1Ryn*IQr-b?_WTl@M5Jyy9_M^RyqLE%G%i6v3 z0V->cuk)a5{gmc;+S;ZUFUK<72_+cZHdf9)4@vpGSi}W@- zw@M~<1c!}ivqgo=%iVWg1YQs5FknQyWdkUrj=E%`c_!i_}lTRDOp|P z()4%zq{nZ#e7ubkA-Xm?t@+_eijp|LicOGHG!;?dz0JS}j=M<^NE{7oNmrc@Xer)B^VDv&)5gYv8{)GN{*1i2z6c1q!ioigQ(>89l1xBHg zsaqQZ;Y?44%&$1B0EvkhBQRj(MA{J#cpCI>Z(#S~LzeHl*Qrz5kQyOy6x6{+x~ac6 zK*6eUXD{jO1d15>H|TbMwAOepG2zZgv=nBgMG)d7?3Mic+0voBXAX& z&iC3IAdG$6QgV^RFn2@s-`_vl9_tdl-6oIKEd1H5<9!G^N?m3ANe2xdZz~+y@Fjz> zpv|;8fsN*qU?3`1h;#Pw*vd1S{FYk3&uXBOEqHYi7a}`k@w#s*5Y}_!k04duF@Uj0 zI2e22YOl51vXMvzaPhe^(m6U)9LOj>W9T0W5TvTb;bjh6J`q*76EG9*B8@SXVg&P9 zN2*=yBnvtW_zj80$s)2Us+2Kg@0P>&22{{tK!{dvUEO+492HP93g+(E2Dn)fh;OJ~ z@Sc4T=dZ0oMM9x58_SGbNl`X>|Keb*>)zv#TxqQA&zZPZDjpKfYZfUS^(@haVS2hJ z?7D=7>Uv~UUeU7RCKg=|K#?tUlBzs0jLb5KH5&O;t`7_FPTh_vAKBWXU%%`Tvsp*< zUG)jr2|^p_7RXYLRSF%CnydL8^@P}<^=^i?a7~#&!p4poyD<~{(P3C^rfL{y?=&qf zc*BU!YEXLpM4l6Q#ELr`_tgaX@hn+GXB*8@N@d~d=GTOAj@TO<0+Bl8K*iwB4O?)v zdo<{_(iRwljfgg`D}$#LlZVE-9|u?aUf{plX?H)UE1hUtej{Ku9GCn(Qi8Am^d%1A zf}!hlRK!nOW4oMQ&n$EwOe7KW`5A>(1wDt#!0pqfP*pW3f#joDuPIeQXAFepT3PT% z;WZfG!}V)5UtYJbw)>*D3mjfItU$4c9{J3Q8c5>Q_qt_J+@^*3jFm zZPP_Ny7Onw_00H!&LwneG)`wnTIcPRk&wB*NFo^xT7_R;8%`EJ<;OCX{j^uZ8IciH zd|$qj{!BX4$FbrdbI5+cS*UJ_C$kXd($_YD;&YKcxEza&nw{bWxg=`|j;P~RgROvIeUu`6&MY=fS1m@@w5Z*lwL zD+iDwg$*Gh>+n?&2H=;s84taZC)o1+fKtL$zBp>Z)v@c6v~m40hKVu55h3TQ4>c@Q z9L$DRe}Gm}ckCTTX7W4O{Wu=2%jl)Jh16@;bNzdTHch|b2!B(;NxB-G z0g}*(0eKmE3DVBrE6#oq=Qu=*l{SRocG~=J@Kf-@aS3PQq<^f<`&*NkwVK_=mC*Kk zc6XPPRq<*6Dv;~9KA^QwNw7%R9wx-9*a9DR0F3cUNk9akEBHEgc%<@b2uL7JNRlGd#i zGbtd%lj$$MUgNp@a87$kORY5khK269ZHJWHX;`Sc_m zic{Xx&&%TLAg59l4}dpAQ2HQ}ksJ>FtS*di!Rei76~dm#M~-B+Sj$p2Ce0oN2pz5p zVx=vQ)}lgIe|OtEsztlWvI`MF-VH;?p}XckPr-)3#!g_9HtsBnb0mdsC^zA?Rp?#a z+A_I$$r+lP1v{Lyrx~lT_Lq%dV<>AlJBN`2*6`ix4&v<`)Xavf>pt96WcpOadv{9;N+1#54!2_s3I*Bl=?w3Zs!2rc0+UL9(5@qc9h(k=*j;KYKicMgF-6^+5Z{6hB)r(cy92cD)N zh)){ccVd&xtmk^@`zZ(IUjDG101diID1yzLX=8%Wrcn_Z2bEv3)JI-dAANh(n*-VcF4rsC!SQ!HBNm=tS#_Z8W0X1Qpp;#Hm%kXie288jPi5V(p}KC3`JH-bmU%ws{aLU#+K)S=v&zcL!b1oi`jpTTpbxcUZ9&R8Jnz0iGfb;HVdHX2ra;-a|?geec4aGYz@ zb@TN)ZNF}Rcl_;s+{X7y`UcaD^{GmNPsD!tZEINx`|aT4@0dkz5LpPx5N7_}lR=>| z_uUA8u}*$baLU{JOsCSdU&+EMbz(HvQs)O+EqY(+iSe)3dj{qyP zN9ldgu_l{p+tVKoE>y-h)(7)@(Fkom$b`_3%Hh0yawt1ihpzYp`iW+6sHl^tUJ8TV zWQu0rmr6+e8&3EHx?Xi7WSI%qftAR!rKE8~LG`DqtNBQbRAQak^7~sS3HMl)p%2Wf z;bRUje|J}^yeoCtUn~Y2cG=sNWr1Dq!B;yJXLN9`W zolBSq?X%;4+5S4q6R{PY z5pBc!N;@E(5}_a*ZKzrDM2v?0uIsUx6h;IGVMCBKsZeI+F3!GF8pABN%|5c#ZFdg5 zMxZT4DxS+Nb)O(LT%q0Y6RYaj|Zs>egF&qy2}B!R^f0Q z=FikzHrepsq}I^__chv(>1DZ0|M6QW9%gtP&7S9~lG=`^NRkzph(PLwf)oOU6onjs z`PdcpAdp&=B7ulIO8SdxHq0UKp1L9ISI39k6pN7!M6bzQJ-94*ZW>BADv z_rJGp_mGKB1$lNOiWz60(4NrdqAT(rDUT-R<=7(k1gDS#+^83uMniZDTD6xxkOVhL z2TuD!KzU4Pj{^4SH43G;C3(lw!01#kMO~1e#nP?@rWR)w94^V|LnBqRm40}CQ0o$y zJa0f54&{NX+BTFtm5kbVr_36-wcyML&va|b)U|3M07%5fZ|vBN7XN4}uO>rjiZ`zq!d{LR(&_qaWt zmz1^TjH%P=*KNR^dW@eo*U+fP9&<@MvFwp0^|c&Zq8Hhn&pap4GsV3V=o_^91|Za3 zAfx_!6?Xo(V}`O>sGHgQQBER8J(8!$W4r+~nUPSQ0m#lpApC$~5>(hA+i-XhIPre2KLj4oA9j?yRX`m$nKNdNLnCh~4j z+of|F?x&9@BiEP1TSjNcAA{Uaw$yv(GXuQ#u8AkP9cE6B4Iya7Gz6y$-57zAk}=QY zMpvdSj(u$H(ce=?d8%`S>t$kziWXPb@r54G-S@HA5}LA1_P9+ES?s+b@H%R(-@kff zX)Wx&^;ZeuFB*EM)vfJaxA~)9{uKRQn;=nViW?=PXpT#0c+M4?`0W*e1JBMUH3|b! z$p$LCbBVMs=!VebF&s{Nsz!(DhnH&`p_kU2!zU~I4A>Clyq_hBvvF#;9<=*=;lvY# zb;$1=__ARQ{BGFYr+1wAh~b(&A0EMWxmda&;*;g#`aI80kNP2ttru9b0hWlyX8W*# zQbl~-Fbb9|qmHeFJZ2$KTPN-8$y>>6-zW4kJ5hjMFjDL>CU7G%-<_tCKt>KD&m1&VKUjEDkHfFT z<_XKuMIlimp?!Vf<=Klr}#SzvRD4eu3%TEIwP(TDf<>g{aZp7UI2Qr`Ki4jqZ!L-(nU|$mBDmduaV4V0z*DN!k$G_CJIvW-o-a2i0Y#2)uwC zR7TDRFOk2(8bx zsHgW!$%0lh51Pcg9u{%@G)K|SKYPyd&zRfJwmnP^uxWy;q$R_O{WsX9k&Fq;25asf z!cUUFWjEp?GcT+)RF^z|xnE4D?M|nXtQk`g)`m2L6Z)W=cBuC7hpsNvGVl%Vgf{u) zCuN-BZOImMQTV+AOIrOmm@YUWr|av+=u6Vl1BB$T%Iz1u5 z)D63zcQqMtR4gYGd-lXI$uA@<$!evYRW|HH{snWJhhsE}sv~_rmy4ba|KS_nw2;sv z<4JU8r_Q@MSJlS8&-zUaYT67yQGP+R3tu|H9-{Y=0$$LF^=MCLS z^062+FKfE5J(D)Z&oC;lH#tv}^O;FJ@9`J%7pId;5^<0!S@&7KPY^%w-0)2H zuJAEwC!Wu}l(UUJVyFs~$yP0}6x`CK-_ZrQ4BJ{*^RK!E`tOW~mipu8&x!SdkEU;v z?6WUlUcDButhT5l(6oziGu7ON{I>VxKmCdNn@3434Mummo_NRjPilmVeF0Cad^K9j zRzY&ZFWzQXAAYSZ&LN)%LA>{CmVaDsaT7$o7ZMF*a&)eE6hT&3(~NAbvG3v3V%ZT? zxtb0kCz*;=8|mG~u;C zU7E)-wj_W2)NSFT^E~F5?U#TTtMFIRz`c4iYJcB?&!mt*A!K#llZ?;72`u@A!BfUidzi^#v(t8TaD?c^G&0iW!AN9nZp$WD^YH|GWBPsRA-yu?}!BG;FE zql?fJS=|5&BuHvLs)p+q ztgL&5GKv1$w9VCO76NZQB~e|L!h0Ng&?>N{yoK!IB=^(Fr#83!@sp2kGrCT1Z@}>a zBw#asmH{iLkn2-bT&k9(8O9vmw4<-i2R+_eze=swJp`{%SxWq$Z%OG^a3=!eR7~m1 zzaYQKqc0e{GBYXc;IYeh=k+l?CBvlI!}ExgXOB38P;4M*0A>O;#ePMxrSNW3N|oEy z=Vc;T4CATXF6>;5{ZPfYhQlM>A7UiE&%D2_lQnq zdXm1aTV@weJoL0hHRQDxRZ$89oOs*x|OsCfG1r(l}8cdpA#3@u7pVlk|P^OdGCm-u54WQ&| z$u}yf70SY4m%w`U8>~ESzU=1L0>ns#f=9+Yh8;@philQy4f-kCOZ|Rsz*Ap+ zEnO>X%BZ+S5q3+wD2lPo8!cgkmV=LsWOT#zr}qiR^G#w^8zQth9LX}UJWA`&&fv$| zX^xoQz-=eh$Evlzci$`bZpzUZq`4YjBxPzk8V|_Zc7M4FiO>#tRYgY5c1e*KT$Khm z+aRch@VPe2u3l?BUM>VFSvH_ffiy}Lc%4RBN#zA%KMr~9j@qO1Rp?RPX7D}Ke+ zhu-ayk8CD#UWA(Gshn0O`)1T+gaYh7!>ngIZQ%?V@{T>CEZ&zIC=T06`?nb8d^;t& zpx;zlk%Aga2-_cDveLCl8B!1-c6{cBThFr>u`sOk>D0LMLR+QNJP@Q;9G6+Frzf9W zU!mnIGyPbPXSmD25G|=8F}$4z9Gie)6T&0%;1b?n42bT!z1m`{A=UH^AFws&mKA^& zdJD)w_-o^r^VvZzc<-ylBGVtUrSL6J%1H;8Dn^l%3W||_BBXE5&yJZpH~BL?X%Ra& zoyuD4we|G%G)Hsg$fciIL1eP;z6R~XfQQ8IgNdydbW}cI0Ba3sXb7>wdNr|xn<#3^ zoMY5YnouLeF$iu9F{i!XqVi?kVV@7Ol^`si$#utpCfUTeYeN}xIub?ChmGj`E`5ET zZv3c3XqxmBrxRTW?gFmLuSl6|dHkFIsJ`Rh^#jdsn{jv?7p}Lda5I3{71E zq1j@P@@wI)*O|ZJEN~SQb5D?7Oe5E~Db()8|2R;vj2VHvgmA;V{5k=9xe&I&BaGg% zi5u~W2JhzM78O9;>Jbwui%*$Gf7p>od(jTkXmWiNxfW>QCJAp9)3+ibUi9=7C877( zT5%=m<=IuY`-IzEo%2Gw;sNy^0&rb|zA+$WkMfE?u8C09Ue-l$eCaVUG@i)(174db zia8lw?IM88&Vn?ZTqXaRs5hro z)*_BtYQy1BPfF+v#mAg6L#&t206WH34(L~dd4ltUf-?%19AmRz*K{|(=2Sb2v}6W) zAGbK_JzG{Vz^T4B_34s_-Fey6VM*3o^Om)cw-*1^%n}vfa;4D4^YI&yLKbDE!J|qe z{vzx>#MgUxf@9>Qn5(*eDuP|y@CR8V9!v(Lb@+^u&I@9sT>@p0pr{cy#G4l9Q95h{ z1xrRo-_?AC>a%*{dR&$%w8Kt(UojW&!bnVrK1zaqGfO>N9xnI1O)%!x-kRR7GK+L5||1t7og$oN#n`|$4@D8>} z3WF%mR3W@{`p2W$FzVDd6riJ5H8F>k;&EyyrMQH_@~vnA*KZvfjLq<~vmn+CRY;z( zPKwc;`Vo>^wjunVX@vT;>1i>Fdheh67;0`85$-+@@-E|dg5<}|;+`HvK!vBNr-$$y z4l5H2Ll4e@nmFZV?OYZ5VwvAu$Q$kS{8ZXq_UrNmadUOax59*n5yiv>tZ!HzR5j5~ zfdZ{=9munWgG6%E$jD=0K)E)L(|{O43}>9*^I~WMj{Pr7$~SW`8Ss0i+wri_%%XE)^7j%7aHQl5HHe5VU3J5sp}gdR3b zr(S3*UO{+2K?rYN20z16rm3{ld8P!e^CubSxqzaWs2*QdMbtKFAx>Yh`o*B)-c&ph zuwoD#A0t@?s>t+D6u$z$=LT?#inrK&*xoF=^c5*E)DYLFjN-kyTCd5Jce*33sV+M3 zgy&g-FrojW=7}p%~?x$Iq>Zi*O2N-{8x67jkHcLIwxG6RM$Tv$=Df1c5B}XMZKzG z$yc10_nF*{8&{Ir&nEDYZPC&?h67K$zo2X>G`geT>Y>c~2$bimN4)HL{W0{kaqDj` zB=%xQ@vb#kk%Q6OOxPA6{JZ#Q?Sn*UM$7=QZ61aE!hjPbCXtXIH!^-l#8N|-LTi5* zM|NbzpPo=Jo&4n-WBGZoS0LYNRH&1ALiz?g9Jc($sfj7`SdchHLFvx8VMQYGYUcL; zAu|ow1jH%s&DZU6-BaxTq1NO2#Yk?*dym`j+TwtT=-Vf9s0*3-ex5AP1z3xlwyhOG z&DsXbzCfVI4~q6#!55pV+v@46c0Q(7)vS6RZiFr7fHp?^Uas4=1+mFt6u4O=+Dc)? zsAdet<~x2n|6$Vyh3P+`9hEh{mpfGHOv<@^>Er~Fgq$%}kGnsLDysKxz{%=!#-fs7 z=6!9hi()1W^Nm47F}D`qc&wj?c)fefdFZ<635Z*ok5ROmRU6+KhZeN}gT61yvfyd1 zQrRH?P7AZN0PB18j#;EEFZ1|aGhh}U^L4@Ltdf6yE*DY~!)4g$g$@k%(xXpbO zoMSE&wggCu2RoGS8f>I5bmuMqjlUJqLprxe48ub{vlc$L1DC|?KcRIx<7GZ5y#cTT zBP1jq?@w_v;0p#;&7$sug0L^yP4J$uInoi%w8wmuI;rNa@3(7dqk*?!Y6tP^%MwIR zAL!oB=RfbPIMI8CxLnBcb55jY4H`Dr3x^x<6-*k19p2d&{R%yJ6 z#+kI}TvCwpLf}R}b(p;XH14C zsAB5U2%~|XT&6SstM(xE$a(b4Ob8`5RsPenP)zpr2PGs|U&2 zp%N!{_i7ZiD`GSd>SX>JISt(B$gkKh!*6^&vd$RY+gx6Wi=+fjM>inWZ~c{LL38vm za##Gg9xJ$Hbt7LK_n&pJ2se_|XdvF;Rla{!JyoF!Y%)@-ElT9S zzRiV8TM+)_r0ro%5yvLFgm$eze_0s6!Zcdx+Y|Cu5KzLVyGpg`E%UD3SE%?ubA)V z0mv23iR=mO@pk=pxA!{S$nZQM2dL)6n9Lzt{1r!G9Bn>kIn#Wr^9?nG8m_uf4s|^)D!(ke zn67=XZ2IBC-b!INH{yH1gOY-YcIPJ*r79k%3`$LHD$T>dGWcy4UyAH z6NN$bui97_ava&uwPeGewB<^^0oR+O<`{;TnI1WKK~%>@vPsIULDoR8CA!Mc&> zHWx0Rs~ZHK)w)PetphFxn2wAX@6J)z?$qUwp+yV09CQvyUR1one8@$%FCh@$L*c9` z={BU@{2F$3T{Fn97L?t1@$3ooth3Bh)AuU2PR#x0Zr{AyQ()l60V{VF{FHHHa z&N7j0B27Gv^4eX!(6-1?rd-sf2DMVg6G`~e+ih|t!HITdJD*RgcH4nw(C9n29&qc% z)wa;pHALI_iPD3oHKtxp>*EOZ@BmHa-?O(CItbjm@mh?RSe!F5P_o z-6p9u+r#bO1dfJ&JlOOHM7#;~9r>B?y%03j8U(6~!X!2ZyVKcu0X|diN)o)}V?YCA z_`#u$#K5nZo|L%$GAh$l#oGD?l+!eejH<5m!gjpl;5O|YGOVKw3tbU-*Py8f zc__KhSgYSVye?=U(^kN{mbOY3IRsE(?s)NU9a|7GDZ^3iD|$BJYHwBlU$vNNOMxm{ zW+(_+ADkdJ{AK>_2q=-M+;gB2t-N+$l79S+s2WH~OOe2SrXl~*P}ApN#f|_g1f#&# zu)*PmF87I&elewwiZ}mZb)ZWd++5OO7X_bRDKSyh)%aCkRikwX5M5q$9!d66P<)5K zW&l1%4`XUG+_Y~fGe1gIwjo<@(pN5rgPi)0*>~&xJd1%}&llyMbsOK`Wvl1-ltYHI zcrsQ}?9jE|dV=n>)K}P8>B#7aY?)YyKcMDC{vq_kL>ko$E=Zis4PPnai`Vv#JWwRQ zH3IbNNU`5{%mkyTEtOu&M_R(-OrTsd-q+vOgnVrM^QIxI^VKz!jmnUjH%9j>Wo33C z^@X)LF4M;NLSgr@Uo9W|xVWLq(dWJgJFBjIZj4H(m9&uBx%IEuGJ9Ih1pIxzFM`}o zNPgEON<=^7;OEiJAAAqC_j@dGb=)Ci*gf>zM?4t>&_(SNMV8-87`3lk6rE{(r3n<` zdvFbe-l$uO{4a;_m;M~WhftmU{-Dhdn`mXN-L5p8WbiR&zLz4HJt7e+gsidx`oE|( zhR+N7Jj#(v4;s<`ht+ANL~N52Cgi=wZ;_#{C+0TuU#aNbc}){ zl2O2@V<_ksC`ER$%}N1jf;oTXR+RYYwsYrsT1qwa*HXlB{Hl&4z>Bqngz>LFJ`vDA zK%DpXo4bJKq!-qB7%=JQ2%GrFU+;*lpS6D3*66`ZD8G?SRRtM!oE!*CRdpWU=XQa! z@>yCKX@16TZFa%5`?MmaJnfym;QsJ3mfr}-g zXP^Gt<1E3^9FuK8UuVn-7&6@Wjl2k>L zZQ_k3INEZ})gJ2)e`?I+sGl){i#HNvlnZha z81B9fuibHB`E6(i!%b5SA^U(vE`m~b#|OOj7yn{}fQDyKV>&~Kg>;_DZMsP#%?8jt zpeV{)T3RJUn>*xir4?fKV^G5e6xa!n#8@qBb3BvSlRgmH@FJ6Hr#b5Gd|wr#LX=OR zNqoEEVagL>d!7%K)Sz}(X$eKkVCCY1{#XnYz2cYMc{;P{DAImhb-^EDlyAGwc(^@>Ylz%qpo;AJn zKRTYx4xPA;mCN8Qqx6eZM2)yv5TVMZZf+`cTnO!c(J_iRmIyp?JOrfDc-4J`FNbeK9phbJI>X!+rRk%{)s_vM#l&t z``q;kT$>$U^ac3}e`Xq9R%g^QyMW|y@4CpX17{aeTNd3fl!mHnt z76?D1kdpJXoXfO=qhHz4-WR#<1*F?A$7R_Vx}Pb>VPkDCj8v z2?NXu!emYqEI3;YagF7t^8LUuqH9oRrlf8JP*BxXi~!M^pn`$#Yoj4-2j?A<2;?52 zA@H}{%-Sk|9@D1F`fQJB9-R)8%gQUNRvtJjA%rm!y1Wz8nAS9^;}**M;;ThnZe~3~ z&KL{AR|Aqq_{mX7F9xGv1ofut>NK)Pcc>SFMoczeji`T`x8imz?NdL)UhBy z)Uq*VX~CR?f(1uLiB@1(7ieOQ2U_!uCAzd9f0J9kuPEd5C(WswNC~{?;5$3s!KYA7 zpF+B>g72@)f>v8QKFFW`dYdeMKfPGjJ`xz?Ci^Bw9}Q5u76yV4VQ6nFcf$KT!RYo$ zphGRg~*b;F=#cK|K19@DL1jp{P2S69*|Id zCLE18HghB^?*=XQZ@^U`;mCvBv2|0n1FoS6q#J!fJPNnhmx&xU%rj+fJ)Z zf0z;GqqOn&Iv!h$YG$ zHV+88ou2^RME3Ehv|M~!Xx4OHx9vy`_%ib~ja;;3vB?|wL?rRl{;Tk)<#P)7@w7k_ zOmSLP`FlElC!(@stU!hp3#A`~?yl*W_W(nDZm4pqJ+9nlY(1#L;L#3Ju`ZlYrMG72 z>fLy0|Ea?mAz&cXNGG^amuIM|%5hrk8`NhSB*hK7AK!oGOE-{4i4ZtCXzm5w^r~G? z(4;_vHFbXbFUyx{pCVkXZn}^O>#$zR%2llm*ZF&xRIMQw7YU;TzZGr=D|@1f(d-o( z&Cq!VLmO65W`Dp4)or}@v zzac96?_lWa6L{9NX&9h$!-EM;+x>uTu3xuE-j#gI*I50I`2o>8c|khNo~EWBsg#*U z8Mr=XjOh<1G1ZZ1*9SKv6Hs)|oEh$8&eMjbQ5bJ&HJ~D?({oPG6eX}&*8{R8^52Mm zc}O$M1~Gf!PBsKe&!`s;I1l3@bYguN4J-&B`2ShPs!GIpx-h)J3EIvE=qDe)c5ei% zG8u|h9{)oYv&MPBjd>Aqjtr8(MyQ^|{c?KG9-4`jH{7674`D3|46IBlPM4O<^z(ZpJDkjkx{JDWdh;! zhs=Dk3a&jr=Wp@KHW_Abs)Whz!p|uBZnW*Si1Y2EwM1+JEV~yu*Q2ety#fZ1Z+ArA z-eTz@yf6Zxt4f0gR&+nU<~F$c>YC&h+C+&kZ(MzvKy%^@pq8CU=S*CL8@dGqk%wbf zsNsU*=u$2+JXa}_##n9AyqV;#GiD7$Jo34pjajdGs*=XGo8r(nH^gZE-Cw3`+49w} zT5Uve!s9WphqAYd$!AHMaARYyoTpqdk@iC*#lu)9{8Sr}gm4rvu@Fg#y$Db2gQ4@r zl8=(yLE^rXXM3zE{g=)bG*}jy1PQG-KBEDrFQJ9&mg?-Zp9DJ*<;~d`oC_&T05`&b z;ii+@4}c~hK)c3F=t9P)7?ZZRh`D@TV%$B}4Qo25gpCwe0;A?2ii+JqCxj+?Lx7L3 zAVQw4`-?avjc*=#h*y<>I{1u7(Kg>NY__6i{l;h7xdSCu#@#S1&XQbi$X?15!28a2 zj_xq!4T06^e1MJPb@wkXo$ zGjJ)N<}I`t*eqTQ41Y}+en_K-h3L{HJRR?c8I#t zPp1@=Q5LcrjfGKuZeg(7&kj>OP{AX94(WCy!`#?tgg&G+-7j|RO546wbgVm!vw!hH zoQAI)cCB23ZKsq1oUuPJz>6iQ;ILx@AVQ`iWH&1#n(#c=TntX)xb&4z_{86}#m(Xr zuuU;Wn&J*cpr`(WEz(iHkO_>H#n3g>l!BD3n)ecM>T_8btXsK##{w3D1~q*bz-<}& zc?xHrmBA2iQwy{fR)06TRQUEkEW$zqzTgJ2PFe7Am(RFOPd@WB*h9`9r2jmG5Fr-$)$xp@ebA`%#vq8v^J3bfdp&KmgrYKDG zda42BnW66>{?dV~+hG~NicJuE`5V?|9IU^P1W|2(AvZUnHJqeU=fGCP}`WyX3a@9PMh>7LXuR$6uUS-Do6 zlD$8NUj5!>g)qb+6$-t+_WFf@0$CI2YzGDnZVeU~E{C_KNXAGR^T6NrM!c#O2W2og z&!PaAHLIUBEX#T_gvLW+g+5T&0!;T*!~jDeurCiMh`@2H6-1R*F!+!yNM)%)GV5=M zp95m>xe6ZLX_duCZMOp!1XCizBLzkx5)SZ!i#qDPs7gs{FBo|oB?Af@H`p!r#+iUy ztOi(J9n*fzc#2{fYTDA_TpuTvhM%blfRQ(v^CMs8>)!2r!;^_Em#HZ#bL|D4ffm~G zVz_Jk+IS*JDe96%HEa9-a#7e2Ggq=9UN91oMW^wI>T`8h$5C zWYvh_iUctjAg4etO!cSq0*tp)mw)c+BEeZ}HPT ztis~TNm+7~Aej}Hx^s%D?HllXaYM(FAUFr=`I5A1LEHV)b#ngaQ*nTNIlr#&Slf}( z#ip~nz$&|+_;Bj&N6#Zt#5;{U#687LyEaNX;Qk5(2#UU-=O9#>n@-q_ zX|WaPm7cKX4*m*r`Wf9paZ({I6KLwcgZEwPCug`@QqOmlP;SGt%WD#__DNYocqSx; zOKd;s+~?a>Qm2P3CQC9ArHY39K^zmW%ItZ7`QVZcd^$7qavh!cNf-f^B3448GgDs2 zc&2pKTar~*UD_vtx*!vu?!>;3`%q&%ra?Ou;&!*=z7Y5xPHVe;#V)pKuBu|d`+`W@ z^jLO19Z7yb7p^089XZ=^MX76bz?yc(h;L!GT~^TGOjl_Ue5;~0D6;gsyhM?_h z&pO2^7?~}$MPk*oVbWm@kFeM#zW)pnZ(lD zi@x_szX?0^GK*D}6R%435)6|Ar&K*sLp}bunyXcx0KC#$)GHxz*MZGf-bpt>&~4Po zX|oa&X!~EXfqt$*HAokA=Esq-;1>>Cm1E5;k{?rMn{P`PO84xZwB8r#T^aYMKhDhA zZCJB$hH$cU$rNvfN)R850fjn%xaU3mYZnGh=<9c2B3` zk|i@V^RZNt!|5*lz+soIvlI)&|oq7-*_9UO!c55lWyy0N}M=|DQZic z0hsY=1UAGFgC!IUz8t^%8Go)w9VC=Aj10C13)qlo`cW` z*r*P3#YZUOwO{(w|N0C?gSz@8r9a0sN)|N!SY$GD#F7PMfz}ONq zsRNrK^93m1VFWI92ZPVpEC#GBhVqa^msqJuP({7_v1Z4lZ>y&-Oj0f`GMIPS zpZf02h#{V3hc}q2K*1d;p5?OmZFCf8KkO+^dnWI>2ea2Ar9F=;s{f)5h!v)0=rJMj z7z!dG@^qltb(G9o|GOEtrM=$}1ECC<{@j-!=11_*$WLW$$XvU(`xaoPE(@by5$(~H zt`JzZhBDrW&c_^w4NVST-OeI3)icuDuQyvt>;Faydmd2P4$N%;(?1~=@Pg^Ek=+(v z9oE=VKb>zAG=0hJw29+#jIv(F+#-w^e|k0gB8`#(VDq1uCj@X7 zxZV)%Qd;nurSRo%cn0YEV#0ZD^6R44d?lsBiXKV&dW})`-xpOXXZ-1lGv}LMfYU{!s)$&?EA_= zJ$P*SLVrWFOx;OW)??unXxqEC|NCuHz;62iFQ#S&L+8!NIEb}ufpSaqmhge;OX8XN zv|j4gFCd;zCdUYT1#Sr0mxWxn+raF0yAT0gp0(tNJ^+hQy>MyktpUgkc-vEURP;+k zzvZ|{EEo+f81135!c*C+-Ysk8Mv`RV!X|#uKeG$RB90N-ktA~e(ORr$AZk=GyJDYS zo8`)NL}QLBEvmYJ*+4GOees*M6|KH>W_JYXa2e&?9Wuqb8Vgo{w>k4f-M#4y|)gkNu;<_-z>>)(jj#D|r%N>5}UEs@3pOkL@%aRm@@mfXK)G-WhZbQX2#sp2+%`gXmEWiiG zX-yZBaD43cbz`PJD1alc)8pZK8P09HcOx~q$q>&^FwopFR-_K_J)1nm|249Fu+F-> zBym3qQZXtm5ZKbSY1VAn@*$*TffYK-$V-b{K&7u_Vt#;5CsBx2 z%KDhm)L534y}q3Ch(%(Iv$A1?)m?#kEQ?jb?I>0DtmnY9PgarE@2B6ob?~m ztPFgmYg%w4ps416oXQRy-Mh*X`VoI9@!$gw@kIB1BTb-9hdX>S0$B0o-pnqhEaG|n zD-((jF>b(I#aL0G{lZQwmR&I^6$6Ey~wAiS_19V zc8Ur(>YOt`jj7t-uR?_fxa#{@p^~wQ&8*S`1ts{qMo)Zpc4%O0JH-HWd^-Vs1=cp2 znh0K$+#<7%1`~|N#KAVpTlyATX(@f^+9vG06teLNcdBX-f7AIddx6Ht?g?{!ZV3Yu zP#$$y{Hn~CXGGpjRdL%K;$qsnZI6o+vBzG??|2QuKp zi~Z45#)fnu!%P37j?1``M7k#+6m+46GEmY~KPB*aya*fxKy1cn)Szn*I@s6kPZ!tp zWXl$C{drCTTXO-P-G?849NhrP(VG=ovIOo>?UQR~bfBs8fTgP3?l*Vmr}kkA^q+M( z8lq`?t~TLY@sTh_nOjp;Q|ZTS*n4z{nc&z1c`(pgXJK^rbK};GBKdQf{wrG#*hQLC zLCw~PYD_{q|9kh-GoR}{Hp?8ZAbDbJ#7{p}U&4vkjJU77VG9yXk1*dVx0sH()4l52;;`hn0p6iV zz62593hn?#M)y0$Q;SqS#tX8Bt>S-Dv4#BQY_3&G3WPs`XQv0x-V@x%_U_-a7iRLN z0IJWTr8lb@cr1$8oxseKCF%HViP){7qy*HwLq~wg=)hhD2iuX+o>aP0R!%=Sb7Uqa z6XfVphABc@7Lxryw<)VZ<%x-*|F+SXqd)<>Y5VcHC+z3EXVOyC?Fu{1l^^BL;5~V& z*3qY-xYjwi><3_=ISCjY*>FRKT>civh%=jbsQci#U?mGY0Np`2vkSh2;E`gFB#L4` z$ff`)O`0P(2KF5mWKZPT$T*z;SyBOqw=o6(`RpaU_cJBo##p!vwqmQJuyvAE-y*r> zJ8RHn+(%Q(ecAO-TTS853*;yr#VH%50x&{+kVDxy!B4uqNw)qei~Y(GMb(!+sBv6r zi@3w(xk9}wHI@}SX~*Q2^nf^IjE-?hQZOz+CJCcL+HXV&{Q${60U zR2*xp%4^-Pks5zd!@DqSh*i%Ay?lkoAsy>*WzmA~jWJpv2!TnQyrLdcNK-KUjQ}g6 zYq2pQyK%P{7_JK?oN!nSn8@QP}eYRO)fQ*k*PBx|j?qhEn0( z$Hzjzdx_O=2`@E;VHYmm%zgaahCF0BjR7G02+A6#5<04#d=b(&DW$myqq9jT z+Nb->vBj$V8Ktxtp~!?gF!Y#JeG*254H9fX4k{wW7MsP7fB73_4h~Lqh49c_A9@Z)BuVEYU27fBY4zkMXpq^ zi*J>HDq-bIoR`y~K+5j^lHHtf`H)?ahs?``zQ9YmxtRVcQyF}o5B^MOhi@{;rK%;y zA6kxS{};}0F+t zDy}hBEO7e-bWw~nLO6IAcNQa|+?(k+oIYmdinC`26I5|4(-QYQOp~0g=8`0pu^=V{ zlQP}`BWDN7Ntn@ng2GXu-fEK}R-0O+?LQSSEUSP)}SAsQaFhJ-P!`&y-j}rJHAkE$urobCk zirfigsgw)&>+6fT1~qF+i5YBid#?BLV_Ixv8WdS*qV|{9iZ!u7vsv>l#t+cI2Z@N@F;`47YQFTiHw>BT^&)ngCp-5^l{6AUt(Fcm?%Z08Of0FBZvDeDf!wi@i3g z`Lieb<-|JxLGkIjn;&xPzl@H6@v&{Bv;~s8ulVTjRJt8kqv4ZO454H;g8+#H*ecaI zp&xzyFHl>B6L9$?%AdfV{hud5sW7DRU_>1rmSTP?Z$YDt7;x^af^RHnk)8|z)=K?_ z5sN-k)c44an7#7`-(A_BC;wksIZh-GBCt5f_u0ts0_sOZ_g}sS7xyE1r+r0)FoS@X z1Q^05Uy>hpK@w-tq+O_M-z@E8#T1`lHH@(v(k^4r4o^UW7jk7#hq`2QA&2}R-b@M_j-v*m0wa~Icmzf9CD zB`^PqFI~=UfO}&G3J<=3;o*t_3|Vou*laY_9x?Ck6TksC3$9~xu`yMf|R zpz6_s3khtcw`j)5*iKyrk`!CGu?FS4e zxe?#O>XN|Zg}&f`K*+HMu6x zacVq-Bh*tO0X)<8>#UWASO8<;68YVt94$#y9k*o}T9tFza=xv>#`tsQ9f!-f5Qdtvj!v^P!Uq^A+kmzRwSbEqP z1*1~~`LgZKL_p~dw8+k1{-4_g_v?whJt1paG9tPQvt*6*@bb9Uv- zn%PYrt@a`^8>jxo{%UJ5M!||G1kKw;$opr59cqXIL$v6t*=nB;OfO0pKY`6}LIj*g z1?=P+w%tzqhV{XItc8&iQ9rw6h~u59@bXCLU?GQzt#5e@TMBl%>kGW-bdcPDhkW=y zSM}SP>fj!*RRH+~fEc+$C`f6|9aM4B|E&Am1I*sG)mpzX3&3|8;Oh{7r>fi@j%GB- z`NZ`f1Nh5U>C2lQ44NK+zka&!a23#o@t)SmviDo}%V?3pP0-F30d%osc`&#+g`|`o z?E2m9Q1Ao)EeNn-@<7bU39x{t9Hz)w8t3N?dhu~P%}+#m3{SXK=(6=&t+fFa50bK- z!rA@7dM_KM(|X5>$iz`1=gGqf!I z=>`RZ?oyC$0cliP8l+RYx5x(RE|o^QySt=Cq`Q$0>H6*m-*e7&eLwiie(suCGqYw5 znK>#ih}-=baO07HDM_+~ND;b4k^(lxAm#Snr;7sh6Dcx<7TKI2ug~X9VrVh_xx`>> zy5pld5Odychc2)JvCpCVe(x1J$`|Oq%f$cma5#aX8}WT)jlWlHr4)Bs(hK3^r_&Y5 z03M5jS$->51(O(DX(9*z>QY=_L+E~h4I!lxtKXSvBNqp&;c!yyC)um;A-HsVu{fgX zrpM{A^%hKoN2=Ndvoja_mFWO}`+aMtrE+U7AH|=@LpCWE|KHaQs6?-iLj z3fLe2>d!kHY@xSvAynmr>V1uY~aw2k0AKO13O`5K_~(0%t`{$yMrjb+VcyT$qp#1I9j ztyiBrpGBD50Rq}J40$CCJzRPasx2N*$?(g)z?X5-uj!F^7~;JzXl>B^Gpt8^uvW>#3itqL99 zgSylw@yMyHT%cMS7}-Hqq+p4$WQOR&lU}wLQYht_DkgP*@>W+9)NWir?S?ZXixBn| z4S)@-?qp`9lbux^PQH>t8sDsZ^H^#qe`?}w>%baj^C&qJzy-%Es~_#8`<%+aADh#& z0RF5M;AW?vYDf_gB$=O0UuZR;mu)v*Vd{zN|m5eV!K3=So z0{UOLWXWJ)b$~|zuo6>#lVqI#G7#mzUq1(FGmiowEeJ&n{+ZIlWLzf2RxerOL%O`+ zfKmdonrXavZ55mRu52kHrl%**bQzbHK6gS--O&c4Hu8fb^l6KpO1Ja6Dk;?T-ror_ zh({L9f}W^=q*AMR+>6hf_waE`YSsp{vtF-07!3pkHE&=%!~`wX@e^P1AnOBg2D}c! zY`)f;tKl*LR59NEEAWHv>)V?I90FRfjftnN?!3Ebyu$~C%8jaJ(;fh{Q6^Fy1*nf5F^L*r$PL*tWaWRqKG({V zoCG-v5Uv6%4_a6NxiR8c8IxtDrt1dom`u^$+4ba!Xk)u*5kVEUa~r1%w0ZR*08qRs zeE@f80eYRqFNJT&AvrLL8S^v zt`Pe`kuudNSC;L_2C?oE=)^-7{T`AI#@b(8&U1?Y`@~V1+kg57bWx#& z+)tWm5cnI{YjpXCmzM$!3q((!v-+nQa9s*wAJK3BZd|Lvuz=!KDxjxbo!=lW{6RK5 zH9J*I2nW(~GxZ1uXyNqf-(Qx2fcyYb5(QrxGkLxSma${r_4}YIpff_z*=}+itk0;s zsFsU2R=6u}-};vmn*o;|7ioTud(GBJQ!GA25mbs%mcmqBCi}Fjp|72%mVI9oLo?(G zW}7g8Els}Lmpcf`y@2b0m~^=sC64Z02|S59)37v`Mo}gsqWa0oR zBx4fdRNo2U#y`{EOwyORiiFFG5o4q zgg&gS#0P?}Nw+Ej*0Nlc5>mS2bm~Yqeo@MZO1-ay*dw)@nIjVnaw1bfTwi8u-O!Vx#h2*Ar0F1E=K( zf7|K@PMnh#a_aQBX%B#>FhgB)&ctQvD{`pdlJ*NCDd^J(SQXK0*J??05M})WO;~EYp+J2V1bJ$+p7&v%0>c2RE zsqj9X!8omoM|1yrC8z%9V7cMbr7#77Iy%tApVndsA_YXpy+54F)F)WObr?aY%=n_- zB4mi`@<`ct1C~E^CLA4W;~kG1)QV)$OKR+a*NXYNe{l5JRJIeKtGN54ugNdFCus?T zxDt~v%3QoE1WyILek(rt+AQ7(0tZCA{yY$lg{lL(DG)v~0cb9=1FQtVIU;Y7bwwd7 zt%)%diw{q-g4BB9##LV~CQlawzxfEmZ`ouC@e9sHc>mPKqJIK13uRD9o@RpK;O)SzkmA3@FI5SoSKsm)`Nyfm3t(A_Hb&E2njRBBqHEptI!5E;6yR8TG_OY zu5tpR0G0$6Q6yGg$r{B`qrU1)qwpTW7d|$i;5sg|Fnp7N3xII1Irm5Avpnaj$G+E<}7Akdk{7du9480 zN&CTFe+EPm+9{+ZnNTv#h-z06q|(^_MKiHZhH5r<=T(PY1qv zm=tUK`=2G*b(s&{$NWbosFV1|dsvw>P{gXabhtswn+DOosS$H2Ge*%KwuP_U=v3n&2+narOT^ka8n}ZRhFQ zSoXuIs=u$v=}o8-q>1k~$Bt8)6BP~Eni+_$cW;mPf^O)2z(@Wr_wo}~B(Iq?@E=EX z+l@GMWNwc7w~w8Y5*MU3Vy5dG%>vXp=U1c=NUvGr_G?-C#Ri~YZ7BmJJ->v4n2Es~ zH#Fqiy;6D>RzBh))y~v|MP!{{RD~FuN}uW2lh{DME>-Yh+lVL2!TEjtYe}q(SfHsI z`-*IV)Zi9?x)u0)VXy0Jbzt4KQ1azC!1cQ`n5d4l7px%r1L+3D{Bq31XD`gfe{tGg zb+V$PprcGr6F6(v^R?x z_$>mHyG$JRdz*@sRmfD8sNQ|a%vC{+Ovj1Q@my%1J#K%!6C_V%J7FL%MF^XS4^SEX zWR?Fc*Ya;uE~n3GJjIrP)7InEm*(w3sugK0cu`}*utRQh`U;4VATS9V#Jzp=D;5&* zKY47gYB9H<2VbQ6thbbTnk#|m;16I^3$udJ<(~#<;R<5jxM<#cS(|qBL`*?{Mq=6S zisY!bCl{LGJJ|`7e(5NLUJUJbxw~Un<_of1;`gLvY_HO~SKo`HXa&H*59S>MM&& zi$AUCMgyInzz2T}E|l&#%q!}Erd&Y~T+CD(*>mG(;<ECyqrO>=YsHle3;{TH(|CZNSUT1dxh{}42bs29=v;9i(~(_6E5}=dSn*J#M2cnraNBYsLV6#Rxa{=_DMGFi}Mdk z$4do{n-@$>T(#jc@gh82y3J~#^5Ax~AlXuZpw9AHbQJT#N0#v3>?26?jr0Pi0OZvv%dluU z#i!X_+I$ni^p!#&gc?f}dx+t3EfNI|F1@Y>C&aqm)QZ2B11(?)u&c!FU0;zJd)dZI(gd)pP=k)3wrkJ}bXVnS!2@#dE=Cm^?1e^64(M#CcLE4Dl(fEDRZ zq4eg?9%;^4@5d_u2MWVF;I5Pz3ojEC1ow^_4p~DWE|NL;d^p z&{t3(79+55_3-;59$_&QCQ(&H89Kr0o<4uPC+DTM)SLTIUl6!rn)RwYN182V7WH zp@K?#O3&DAlFVsvX4=oFx*#Z8sZ7N_y9!`mOAqM;MSoVCV4d4VJsbLZ=NmgO-iD%u zW+WJ6siv*wl_c)6+VI5U$(MM%Q>Ektrg^f@w7f!`OR)>q-wllE(d2<##fE(8dqY}P z!y($nQ#PGDAD;>PFiqmOHbM!~H{~t_W4>yCt0>60H1Kun8>XsW^tiXIM0*$C?8RFJvX{ztUDJ!;#fTXA_c8awm)fWcDxHREpJW-a#DX6 z>+iqgo!q+x2VIeG!3+HCUbrsvn^~C!K6n!a8@wFg;Oj`(A~^}ucSw4STf6_&-i;nN zx^Ygu(nheLLmgjH@38iK5a0u(6dGZl>vC|4PJ3pEcOYpbSPf@~8{&7ld$&V;f&s34 zsf7FB>Fsmh1?*dou)N-jQvbNa?24P1Duw(FXl2S?#GBuiya%atOKoqcs4kOU7+Sm{ z076WY!5|KQfg(nu=3tD=#4IMa-&4bs2Vw&(pNINu`%w`Zmre#r3OQ(T&hJZjkC6? zY1wOaG0JbCD&=c+8z}Bs16SKBlI1T#{x>W}z$W{lWX|g$N5^+tEO5oYz_c{0C$t&O z{As4Mxbu%(M)o*|r%+>xHAMIg`Kj=Hzr|N?gIQW9<<8_3;3O{fb+yL36V>VGnYuF9 zqrVpaYu+9r@)hT6k;m$=0P~1I^EE)n2h(^D5U_pDLhHJeHdT7n-FCY%$CXSFMqKL| zPELJx-opV|pC}M#-!4ywBfKPl4!W2rAdbjq7^Ji!-4V77Ijr_%3tH#<-~<)b@kSi) zyomm9G|DU{aIp{83GrZvYi}bv9G)T?zjwZjyNT*CvAK>0iOCGGnn(Y2z4EYfF1fz6 z0+LDh6v2}xHKrotV8>-@)!gsl?Nnw0YAWy?_2#Eo?-7YzSvZP%?;{k&M|{cdPepjt zBfVQo2oooV1E~j9(w^KlZ_o|}Si=6|*oxjF<)nMw*f%}$+w46ZG_5yg;v}Jy*RD&F8t+(IhEN_DWirBi4l($}&toz$ffoi=={XM6KCwyh>K3MY4 z^w&xap;96NC}EJr9fJCM1gkJQe;=AFW9C)Rx?;A+4r;YnOD1G_vCIR<#(S?No*z zq*P_$^En%7#QJh$X8NKbl0yd;s|XH(MR)nLp;}IB5E1}d`E(zU26j*azIsLEPe1;b zAS1-P3;V@mn8wqI%r~Ip!k+bX-V01YiKr z$LDD8L-+WW`1mqLl2TZI9`TNUbFb#8iqEn6nIG4@;BOusa+0Bl?XXhrBH7z&QgT z4$0TWOp&LU6WzSs$Ve`3nwUGl6x5a06M_kpRrS>$Nu09~XbAq}&@@vpl&lr_=v9C5 zjfAi$W(qGPh>aPZ4J8pMcOQ$Yd5dt$f1Hj8e5gLPY}K8TOo!*DtvYVPOm0Z(&DL>C zbK@C!min-u`vEBVzr+K12c*5_Ld?aE)<7QR0vFT;=%wluReOR@Cfr*w)auE{7~Hb% z6rt7M6$c!*$PZtmn9V)lfZ33K4ULw;LmvmoC&D!UGskNk=QrH>b~R$0tT*s+MM|yf zFPLp0f@rqjUaN;z4d{Y`KxXP2vM8$e-UE0^Nd+agE1S;4#vnCWcx5h6kd|D+f6NyG zQ1s9Tf;N440Rj-#F@-8p4oK3s;j`Tw9@J4hXpXqvI3m-0!X%!^qFg{2!PH@}a?>Fk zfQtl1%hJBjhno-58>7=;Kkaup79qQ5FO80ZYWaZJR&*5ib-i66uMWDVNRD!QGA0*V zooX_#fOkX(;PeuJ;tvlF=BkZ&H;+6PQ7)GLg&$}d!(rBo@JF>2UyCS47MtRVPxxNAz7dmCk0V@C9ud;9g1RT zf#i)I-q|h;b6h+Qk=a>veU{M>Cb*A5l(ye@vpEs~K&qd9iWciarM;b4=lKBWqVVE; ze*s425W-q;9v!&WJ6T~@aM|dd-OP6|wUq$m5a9bzYdit>*mG;VHwzD-TB2SUh`N=> zP;d3>M#c}r&nG8uD4+z`9kBb95r4zt3T$*JX9oh?S8i;kA$0jA(GM4X-s6py5YJ>Q zVA=@@AZd-rd6VyZa*%MB&|0gsQ(Tu`q?(&Bn?@deEV4}#+K zLToBF%mo{8E4Cpjf>e5{!*(mWCDnIUW^dmYz?6_WgE97a{RCfkGI`u0NAdSpt#0z% z1Ok4tV}3{HP@luc@#q2F-4{<5C42ZvJ*z(>iyC_tM05!g)du-$11O8X>d7)}cAP>%~r#C(g&^{x;xv(%FF`ZEyjum)@VZZv@n_RI2%ikdYWt66x{M~&p z!N6HNzyqHG+1cQ#C9@p&rurKyGmEPvoN2V`I|D8?0c>zfs?eW5`?LulZ6?F83p(Oj zCY?lAZPu8*^Oo}B-KDZuwCttofZqn$$NkWrgfLEz;MXsK+HGAib@_);kO-k(yuHRf z7hU%E%7_dKYW@F?22{NL7sDfuoykjtUF+Y-)=94I=jVhQ1QDgw8^CXL-YoK3UZ1XA-NDBQ6SHF-Yk@{}6y2OwckhJd|J z=2`|i8h3)SonL`I3Q`)*HHXZhM@&=1A?Dlg6-OWEH;R;?7kH(^RiLU#+8+++4T7#m zyn^gN=>ZQ0=be61?6Ok8ly}~_Gtj|=#J*QF@Xy5n9mashw)i-P_o>>f!kF3~bXr|N&^IcScy#SGEwZJ{A&PR)xgF)7Z>HL5ugr&IC zqwmQ@GyCStp#(V`;|zzl`f&IzW|K0ColT-wlI%qi&9+)=j!1yC@2Nf6_g7J z{S}aZ4MxFcoD5>nU8jpF=-P!rXL-{3)F%PU6oCzQ?iN|)?Cr*U_@TRx4j|9* z{@UosLw(3#q|-;cMvdLM+bkcdt=@N*t>(b;NL=J4gHapE4lQp$Crt0ARJ^f74-93h z=UPS6X;W?fm}I`nX8WgtVh7@Ilk43zX@q1y9UgM?kqhgcUklz`OZHqFf9}VeA>jr`Lv?bp>80f=wKNMHoxfIa7#ki z?-y%%a}Pj=d)D29cil$meaOUbu0qK}IP4@t{nr8;0J~GAMc4odPX7~pMI_A8sG?$gX92av(*UDm0 zrl&}g#N=l(m#=o-)Cr^ptFOfBOIObQYz>TtK?aTRLlz)(;Rm**o?+c?i2^^=agFU- z<0Xq!O1&K6=%zHni?2l0tFS9>pAf@k+g3qJ3}VKccPpt?>Akdg*Wxb93Fg9=@DZfA zsMIm_UUlxw2CCgAdCyaW!NsegBH*cb{qLDO>7cxgODMWN;gsDUSY)>XDR(C_;3kiD zVb1~C)Cc_yt=>(Cktfk7s~joJ6KODphI#k)wXtmkq1C7+&+z+oO9Z}}VMm(g%Lm!t zb1uJ9X@`#OrQo{7nBhUyPMju18V6RL#D(rZ^~Dz7z(Zeah90^#>6XZ}v78Df?W#@R zS#){oz6_ZB1=I;&K_MD~8#Tr%92V?&;caK;oEs=|I19`SH2`Ak;3JTJzWe%8jgPo5 zfLRZSHf9~a7TEZaSM`^Cm7W@;C%?Ww>pHB}(@>R2KvS*HonA6G!nA8Dsk7hT*uP=x zTlfM(Hz*GUiXukaESdId5K8@;dz-;M-DM>5i)_ixP6GKls+toK8O zCT?GLoIZr#Deg4fP@b_!2&2T&>gc=?tQwZs&pj}?4paja57Y#&`1YsRnZDYUb;rPa z8;hmf1@pY(3av4=K;|#Go~t^!m=s7{INk#ZeH(NvLKwo(d1d!z_H2e-?NQ3H5Zi%Z zfbGhzdaUo5RX3;;CIY>k*!PRH!0Ir39%N*}H8(`6&S!Z;Q;6bzpjVO1OEPc;DkAk> z(se{~MB9`{u-*~a_Y5zXsRR*^nEYz3ihwd(k2HVtkDA2ODKbE|B4n2Z~G-O!|kHeF1tJOkb3QCI%Cl#gcT|O0{f=L>E;eT;O1swH5lYQ zp`k_&<#izdmaTjad3)v$XrZqyscvLyi0joRZ} zzbWG8X@7O&96=@pi!AndED&TuzKPuhUTVBzDYgI*-mq00j}NKEKvdU6hgZ7|a@U97 z0`C-#Oz2K>G~P-#J{S&H!*Zrtef={-1m^Vw-cUhS+*7!yP`s$J@{pUcu+V>p4dRZhkaK6K{FUYkhPx8K3D%@2aHo+PIO+=O*^JLxK5oksXKq{IQ*GiIQg$AWw+kjk^&DqLnuDkpW4 zr`h4QcP5S()@M_VnayuHd_nJ=u98+MTBK=Z8~OFN^_K;90bM8vlpNy`@H% zl?J9>pfAF7v%8yv$O|g_(b0hhApM`VyitedaK_kh(`EnLtNm}aPPeOdzg?|AS)~IX z?AhAM)~vIR>Usge=GIMz5D4(NsEHBN9-)J)`~5FHq8mc%9X#((Dt$mlX}N#BhT*0+ zLFj8iQk2_4jMtI3p{=0<*33w>UzE@;%=PB4nbd__eb1j!i{U#H zzADa;3z;R{V8)G~0?Yo+5!Jk5*{5o$LJ~RP-oO(eZIh^8Jh9s|b8nYPcAP+hlOVpYg zZ#3_hioorvyGg}k2AO?v(o#=Z9Mn(EcZCbMKhu88-?J38Fsk31jWNdDBT$HlYMf9xON-Vm1xvQoE z^WRZ!ZMg$ODh}cUMY_?4st*sPI)a;pcw*QV?A^O~8abB(1bGwYCa4GSUVwbDy^gbQ zQ6V$#L>G;-a9%?_F7Ban>ty2XOSgCnc3>@3ZvM9zV3FUsrJs(qCWIkyp=Om3;UPao zvZFr`rV`J^C9e}9e@}C_U)mw7AKkkGpI_8iE&HIhrS32amS?lq_?E}b6`ukrT2|un zdNl#JYw5X|XN{44)z|{QwWZo$FGD03gI7IgYm(y~c|C%Ks+~_x$m;4ejXfLx7_kZE zZG@p4VL0!aki@b=)olrKiVib{(rkT@%L#!S9}64yx!I`FYBr>!IwH0);q6AS?$9mN~4)}n$8_md{lZ@>nK0RHUc zH88s7Vd0jDY2S=ZnOG@j{Xa&)=B5p5zalkR4t_+CGHki?BZb9G70=t2Fu)q|J?f)F zS<8jYvp>c@&U7sB314;-7u^=snPi$rqVfT!a9OUZ0CByyt6%16ipcYJJh{Cv+P= z&JsEli+*2DP7-*ax8zg>CM=|2-bf?-`qu<6W;ysfc!sKQ6c>N|rMw^G2UMRxXNya< zBxU{BkGZ5djJv8M>Pxh%zh}v0#rJdF)MDcnWAu?$-l7#fmBAo@Iq#53H1>U~#TIDb z|6Cz2{cke>^C)CD4BUxga3_FD1(hKfQpR=1?f9$l{SPb5*omm=`HGbJ0$CZm85m{i zV+pV=Mk9=BXQ=H{>bdcJr@VF`2BLGKTHh+qYHRPU)=5*zMbFKJCu8c#;>g3K31vbj zt5+mJr>#TMd>Qv1AQe6}J=w{YyD9HK`(25b8p9mHns4^g7xfltoR0(Hb~9b<{%&;@ z@Acz`802RlNf39V;G#$=aCkH2S03m8q-=c}PL8;eVe>$GJ=p-rMwk?C_rR`JT83p5cxlUPytKH@+Y@oEQ**rLSW z!%@TLfid6g2Dss;CL8(oqNZIy5zUGf4MpKWZxqMr42=8DXoPHSS#@!*Aw@Luog2G- zM$IONy8Eid|4?->K$8w?T8vd0v)QBavOuLn@8^lQV8GA8(pIA6d}BIQX5p|PekD*1oSgxw*%-~w zb#2`E&%F08RWt@?)SRAWJ+C}v(NWp?Q1N`{bYi^W-F^={rX>_w#_dj@$uhnp-kA`V z1aHvlB_QY@!-heg9MrI0tO{^$LuP2*b!?$jSlW_xhA2V6^;VS{Hv}^-XEOb>7trPUT!at1^SDe)?v75IjVyR zKBiBDKtVKD*!Ab`psLrgT4fLc3`eeSDb7%9ApdS22O7BTUCN=8RN~b7xViCV7D(+`BbEkx6sNW%ULM<^tPNK!puc{R~wgOBay7q0}Sx z3nLIpCJW`oiLfIHrq(V_LWR{U-p0ee^sthhR5H5eb-c>VH&*=Cav?<@?R z-*hm+7mTln4(ayT{uYS==X;^ntcIgt`^a3Xm2>ZvraJ?! zx$RUeYnRKSQMX8}wh}dKpX`50F@QdR2+MM1wR(k}!==bkuKuUWIY_!_0X;uG+*IIj}fA zR%<5|1bHvr(z8W=bjo9L(>-32u83de(s5Vbm-I{h9^QKc^`5gt z^I*UD&L7px(l(9J8vw62Rq0?m^F&Vd+`3awRFr!qCl1P1YV~egM^6g^F)kQ|;P3If z)-ZsmnTx0{1_)+XJ^rm4j0(|KZv}na;Ms?d+zWUF_b^K?Ftxi#np^R6@?{k6MIS_$ zI7w9Rz0s{B$eYs=VKhcLZutUKq$fB!MY9;-?qp7Mgr^{rPW+Jx#d6S zE9oX95ZF0ry-AWk62eU1B!KO| zEmQgfUI&OOpHGoTEI2Bzzq0g&5jMybj}Ep$rdJ`KDA{dd7myj`{BgWoZ+IlDJzi;E z@1R}%=rCL$dn-kLc_@+h$T0ldY1x5^HTs%@;uEbixG-5=(ItE@3qR@lMs~6X;IO*{ zhtNFA$8Ya~b|wRR`@sKy5Bi`zfDyy6aB#(Y5UVF_8}@`A`Xr?ZH*8%|Ftuxix)))g z%6n5vsZdM&_*Dv%;1`tZ1+=?_u&@vMuL!u7@hh7cOD}q+I(H}o)kcy9*1;3Vx=GfE zZ}GE~8z-qVWLpYno#p{V%rwmppFqnV7@(cs3>BB^8Gcy%&?_oUx37iSP(br(W_W>@z)#s#V5ItI!X4*-i4EJgMH_$%18bVUg>YJ#s3tzAB&-f@(eU)Po zch>ZS4tF&0)hw5j?it)h_)xe0-7}|q!>x^nbtfVECG7~&`_@l3KDP9x6cvLbK!Kzy zH$~8InTO>~WBx#D2c`C=so@a2d?|O}%GtUpvd}HgNP7NLNQ)lkI3XQk6(L}o-9k$( zf*%==4_l^j#d(R&*4-pD)qgBUW8(QdvJXapp5EPd3WBViiWi+jfaLNS23AByXH^9u2;4{2yJKUof-`GwG4#HUsVr&LcuPLKc2=s zLX@k#{mZyvJ=r=N;oD1n+nUFT$rK_rDsJRWp-#Wluk% zR&o4gCX2I_Q6INEFL-l#B&SKZI*p7QA{biS4}{G9o*G1j*hN`4RUw(-0}-eZ=I zUnd+nicR)ZVd1MIN$-55a1uJ4bTkh%TRfJT`lK81x>1cXKW^Slr6HzS>wGx0g~94i z^0Kkqv+aKQ+M|%Qyu6X6_Gwyl6ddMV(;<^2P1oXjMSsdvm6~0~UAoIc8TDBk=z~@o z9UVW&XtT(BUs9uX4Hew~Y}-j#oZlc}^KMAuCA9`!xFu{r($uE(HMp7L#LD^+&B#eF zxF(P`T?RXPa|3H9T3PGGRUO}G2)9>jZ7C3s?|%O~`rEGz*-sjgm#R8ca)Kmm zJHPvFc-St{VzItjEPLyEdcS+VAUD3_lx(h|5kgZ`uVQreZCsm?7~_1sCeeEac2g2I z0vm31Tw|q`6n7VY-!>~sobE`fqK-GYS1E#w#{BUf>Zkog^!CoLgqq+8rCBlM7E{(>bw%U`bdrlv)19Kj2FHMQ&u6540~h{UOG(C-`_gDE7F~L=r24|o1Xj)KRUu;iA_MU z>A1clfDlH)y#BMnrcrM+FH&D&T&HO+XSC_JE`V<)BNvZs^6>dW(-rfraJEdq?7#3* zi6@t4dZQMIa2T{FibSf-V++)~Cos!dcK*C#DLv7^rvk)NNJ}=Q7_ogrrMv}19omBX zB+Ji6Dq}FZhc6IK_^D$u`8YyNRN=a-p)*%K6puvT+S8`n)c-+lI6RZZr@>WqsNBfW zbx)oAI;cP`(SWSKa-CN%oYQomw=zg=)6I0Ipp&>L!NRe#s$frn>sN|8<7tUPCwHev zcQ)fiVgVnDc57*yU(|GEU^aRX3NcW~(X%o^k2sjf8z^8po%U}`3H{R0urHHu z=e>SZA;!&wXZ-wO;#lnAadGaVVjBnQ%pjxQ-Xkmdhcm~WhmJF-vIG>k#Fg9@Q~bKh z_8A@3`0r+;)JBBz>Wi9G&}L|go_`4roOq~Rm&s9_e3p6T!=s08+9TD}=!AzAA@YBF zwdbx}vC!`RSg0?m`BSv83v=Zi$+`D7yl`oWH)>XzTK4Z%6phbx1B#D@$~qQvcHb1> z=S2^0Xp^npJLsLRj2eS2a01&qbLn?@R1;T(W#ZWCkJ8F(KUKaf$Tk!i8mrOxWDOk= zbMc_5JMSF4GQ};OhNgNaX{EbOXA@+*{6e_|!>*6mQTIqG#PbBR0R%V5Eyk>TGe?fb zj1-4Vf%h0iyw!-Qt~{k7BXd5llBFjwzxdYvs$4hpG+n!oRiG{^I&VMy?Nazd9-Z&7 z@N%nna7eyLSn+Yc{3sfNN!7t@(4BPze9JhkrE{I4VRzoUWFzEvF~x38wdL%oGzBe) zeqeT3lzlQk#j$Svra9y{^+%EM`FYnRxA^U-s*DX$>?`00aGrd#`WSIC(xp?A*=QQ- zuy}la-1aWurzVYRX6uPyjg{kY`Q$eatc!W&#_zj3D@Tvx`)#zUjqDfUb+f9j7L#KCDse>~U1)VRS^Lm4Mx6@tb2(yKExy9sf zw?&C!^9YoDjfz7i?@8<3sXk(i)R~V|E7E?g)>kt_{JVYoNS8`kBEsePW~fNq#ay%G z_0P`($s|8^?KcO6tlwt;2#V_)QrdMZDQtS5@%8yCI>OhA<-A3c^;gqP>!GpdU^SiP z$ta1+rUj|I&WMidDhQ{XexVtT^+#}Q^%9=7;dvUkQ3>$2V8$f~mcyEAF%y{Od1 zAMb~4b2ZZsX#UPQ+)%cSkN$B0ykn+1Gf8mS37RoYs~l~5Re>2=`+c~bi+Dp6ueECS zkAzrS&$C=Cx2^5CbqU#36#HLD$*5zN>fh6M-E(Fg29VXRf~C<4&I#)7$JDCP(? z?v+zq5A?Odx?DA}dH?*x!FDHstHJ4y04cIQ*dj2e06Z~CM;~f10^NlOjUl_OA}-&S zhH*2Xkv!~!{gWmpymQxrJxlNPLVVds;@Hgc?1KF+)zszn(3$$iyA?GC5^+hMCmFR% z{UoNIYVKRe3lc$V>qAuyujf36eZQ(1X0*6@DiVT^^3-*0S`aK*u~8Ab>CRK~aIn$@ zI|ck!Gz-4^_dB%qiiMobexjs3GGw8mWBRX%h|!qmTcS|N^e~&ey6qGVN|RFZo#kw! zYPcH#q#Z-=ZPe(O$$wjty~(zL-hSUT1Xl}H`r#k#LEW_NUC)5)KQA^-=t?PFh_!0p zhdyzi!l+o$W*f~@b8_9#UHn?yaBQ;T8F11b+q4`*s-R;8Oh=Jf#rx-AtFpMUjWEuy zOYk1Cpw?d`_#Tl2d~|?efHzjWK)uWdKuf8p+gqd}9SJe?+`V5hhYmw;ZHgXAywO&X z_5WIqpZZNEpPRWCWzk2`Da_*L2PQX5wSj_cl+g8}%B1^@tmDNu)}JG5tjcB2Qzh&% zCchpH$*P*qx$CBx%$*rDm>a3RT;rfiRhex%1$V2c$4B!%V@=elrr@f64^a7`rKmDdhA2Ugx`7Xi+X2&mahm$6y5e%Qm^2L&ppp7$Q+JpFs9X1 zf4dOpZ<>$2V%5m$Dy$K|`?Ok1*Q4J}5bpJPch|fJ9kGIz*5esbH@GnvqB5IxsvT1d zKyx8Y3mW1gEG)-_FU&sU(V-{TjY!0WW;4`nbj^k@j{}6ju8lkc!AZ zJSoCSVhDWHl~Y?VyC#}sa(olHlu*ddd)35f$$xmGls3e>bfdJmw=A4>67l?@$*7Qt z*GN?B{$H-H2qCw90Z;QKsWu^(%}_7T)gJpA*A|kz)$%{*vZ@>4&ph|_ui>jGw^AE1 z#S=yI-Syz(&;e6we)o~u!ck+EP0Jyp-qnp4OlzA&y=y>hhQA_PFd=*^+D2{T{^b@y z`+nJtP?;|8VcD>!+>uZ>Zyua)=5zGP%P(a@d9x?)llVJxCe@sb=*nx;Rc1Ik?os^> zMh{Kb#KzoEV$%vxqDj!zt`JF{n~;4;txW0?Dqa6%smpKduICiH+)H1t$NJ;hwyooZ zRC;Z9l0$)~+sAoQ>>XE_ki{!Rt6E5lnJ)KUIyby8(wrt&;fa!9i=)%?JiD}wWnM@XxJ{s|e*V-MKm6}_)h=#ANPJd_B{`CYPn98!`ZzN(g=}`fBvHnqNF_&~3Xj2V;wabL< zFDCUG0%pK`hjlB16E(+GWDJ4IFuBbfZ|MY@TYp!GQQs)@LreYHq%FSP%Fp4L{{vn5 z#))jq`6IS&Cf~^VNNN)|85^C^g}PmaHQ@KB;~Dg361Yey7JiZc&HotCeQyla_nxN2dqIkIBTd|{=%7x3i5l=zwbTq6Tofp9;TuUm{w$=YPX~vedeL4J z!8VH!@8AX}d8N~ZGW14&`SU)-2Q0m(bDBz}FbYC}A(@61TgG#y)(ujARHh!y zZq2<9kg}v;gbM*Oe*6(iN*tJsz0`!yR2u`M>F$=_4DpI9WjmbEbOs>cdr{N=TZ)wv zmtB>Vk@NU-CY;gpzN=isPL$f0;POJwjL^*B-NrRJ2xd82BFG5I??4L^p#=J84Kh+h zu|)(O%23=y9)W{etf8(-@KK+(l+mgvIy+Yj18RUmdwfH4i8d6Uv$sc2+=Y`q{0pm3eh{Iv=bO z*NO+N2D{DjwJ%XB)@KxA5%MG{F?3|Y*f;gG>bv&b0gN^=>Id2Z0I4Wg)uvFbf!X1H zgP|*dwY$x@+*IE)o1W36zPQ*u5X!i|RErU2+Eu)yE!t2sYH&< z^MNM_s_#W}VDnTO;OLC586Uw9HEs63D+AE!ar&^Exn3k0A(A$38dh$xRw7S9sj$xi=|WS@kq+-oMhQ3c}>Mdgv)cDK#kRS}Ql7Ah(}p@=18#P1{M zDVyJD&qCo&@u?p=m zt%Bwwr8834lUvESklXrwwF-qm6=yB5c5@xZ%_JfQmV}*pc^Gnm02CPOBtftQ! z^@X^xazMV!)Mh_iMZ;2+Bq$_bT)i<&iSf^QP%ZL)i>4FwjPt_&yW1ey(Y^!F$xUv) zIka;ixE`;uM<#%A?~_u9Y&eRZ0^oLw`h!bF!L!92Jo;0wtVcoLV2!c#K$r>7EpcA( z2e1@>LV7v81w^=y6imD33BmKJya`}RB~myrcY2}X3ST}hdk3&sa)Ybav*P)y`!j}o zTpdjPNYWAaQkgvd0eLG3h#~p#!B(4*xfcsdvk&2N1?c|sI!yV@xIXFuuOs;|l-_X{ z(clU-hu)Z_0Dl%&2eMb&TVycC=k`Fb-8SmOBw+`w=H}_m)5CPitx@oKF*e= zvqi4)e>A%aWk4%%^L)FMhkp*TB&sT-IbQ4OYvriK^*3FOcdQjYqDbGhL}aD@8d3#_ z5>NNPh13Qx6RE$JuO1ln|5B)m6II_>ESer%J4XsGbQPPGAMqQkeRE_Dr zcx*nErXFB>EHtZ18U0;$jTqVWIwV0HOuHjp;ypsQYCKZeeic7HK(3DBNk7LUK6py(QJQSY4=Ta+5qJi1(HAc^7{t%4n>o;x9m%u;ahL}XInt; zVo!{98=7_r~RHrh5{=`koMO_xuI;(YD% zV)FY%h}2im`@u*Pu0Q+SS@u}4z7m_)7^kH?@L8ovLy=6bZu;)#CH$QvKY6|OnZX@b zZ#fvrz|J=9$PJDFDMe(00IO|DRsW`G&D_%Hrgi>aW7n3&Auy=x%=8Q3E|OX~XIu8p zUIJ3`hC?!)5JgMGvp|YpiJU9dc3rH>3i@ESZ?VCPqQ5LzGIS~;p6K7`i0%?P%}+iC zy$ngJBSpk}CrLT6sNgBrs@yt~Yp=-xQ6zoMFUdcIgO=NkCwuvNhB5IohN|$@(RWi< z@Mo1GoCtwoZ4Z{E;(oQZu@`0n?{QqE9@KT zPO@;2WR6&E%?qUl3t0plPlzabo%wVEV^`bs_%wAua9-Oe^QV{_3QFHeVq=uyu}C^)0XYfR9mS{cTmf2O#f*(cS!6y`P{}A>Tt|>Ef-ImniC>nyUNrS%+sz6iX}QHINV}E2RD{>yykPSUmI0MO?soVYg{53 zObS#Zix1ok#cbXk<=O|Za|+uE{COs)Jgx%R_E*A=YE^1vma$&+g46hpkYXs zgcd`ODX(6k)jeAqf)*3!&ie*4eg_9!*@Y4lI(zw(7O}^N)$GPwpfHV9WcGS}k<^TZ zD%o6LmIYsHZB=)pNV-cds9}6M`ee``xOM00sBE*Qj#($*UhcvG0iNhA(X{k98z=oI zok?U)-hY<|vL&4KLzoq^UOXK)9HDsI4;Bz0HAeSzMO4}9cX?gYV>xJ z^*LN>&V0lhFDzlY85d{OWw8ZU1^w>zHmjnR&~I0Pg4W3u^Opc7C3g?E2dfYQp!t5O zxA1drG5kk>TaVpV%1Eo6Tn#>b?1l2Fg#$~)Z6$+IBq#YmKBD}rcjzFq*kJ6s&Mqo; zhG_&d{l(dd^0oA2c24ozp;f%yLF5TglRwCr6fpeZ<3vFUU58?s)s@PYzLw0fUPANx zg+9nr2YVU$=P4$NQU!Z+l7Exe-4I!4qj%*UkG(iw?rgjWKbr*hCQbjN&GI8w)_;hd z;R{6UkJuw&PLa{g{>b#Qgp+sd(VF*R9Qf^%zj!ud@ly7AI|oA}vL)zJ=jQk`uP`dF z5U;IUSRe9B?ksxq9*4aX%N|6xq8o}7;|6Q8*qk3(VByb}KbA9``cdzR@pSjnkUo>( z2Mn!W8I#yK|4!%PgP_V%Xa)1h%{Y6pmrHSqQw^Fg@`5Zy^aUP)MWyT-P4HH81p-Q1 zIYal_#6%Lc@&34&fqd~V9#6VCaAN9(PPOS%h7UJ>U%hEE{WXW{JR}QKP4$~Yg^39D z+y2RvB)}}AA$ctXGiVp(iTJ;IWtouem;a*gM-_KOhzWCx;?#7ZjBEPD`gfw4y*v7< zmSNZrGV4h~!9vK+gX#jZkH=5LOB7c{-JI9UtM5AjX(Y$$Si9ea$ImSB7TD4{UnlhG zhvw}(uE@% zbl5SCNmW8_dt)96qe%s|E1ojfl)os8`o4&LesPOI$Zq4}gW{Qidxp~^MGPg|5{hSu zC**p|7ol@Yniu(;$K-Y6a03O_-%Dq0U@--pTs(?^YG0sbq9*u+RDLyE0#~^S8B3ut ziE08LpgR{9SD(xn+tc5_D_dS0QynNG)U#ME?d;UfKWc*w?AXxIy(^; z%U#l}?Eij7)>J^IwJpwN^Mjq-DD2PjjMsE72K^T+Q=vEkpkVQ)*j2%!9vcUMcEt50 zQQ)CC?3=EXaSlvn?9BP+8ZSQI39eGQgOz-e4 zO;(Hf8iQMG-faKP*LovkG;tCq9p5Amm4DYLU}Bl)>kO5fV0J7c+nx6ZoLTD-`_oh`-koj2mt}`?k>P88t&E_+UPrNn;!j;1 zN|&D{b^vj+V*|kVYaSn5T9Om{&$F;-4#C=Jc23`BH(N`!n)fD8q|o4pUKFE)>HzMJ z1$ZQElR8N&t&K)_-cYCZR3z7g{Zd??6A7f}nN48)<&JwKag5aAPii{R9-s_2UZy9P zHjIf?g4V_Fuk4p|Gi}@7m`e17gbuo&llu`Oe0~n+#J>nhyaAJ-qf64D;>f-A$@bOx zw;714(VP-WkIH(0!3|7aF}lK9y>e*UQzfetwHSbR6AN&Iy}c3B(RA+SoFn9$R0iT*Ttqc&&Kb7yj%n$j)ZDIKEQz1gGWW0^3EV zMOY#^41h9(HmR{S4VHFX+Qms$XrV8pNOGL<$Ly>(*T^B2lSy4^Mm z8Mv?sTu%RUP{Vu6s$WK-GbgFb^T;vsDVXZ|%Y3h!?TDRktY~f#`f}Eo?dI-zm%3Ks zL|j<)RR$JzbAy-3f;nz(3&EOD($YETUup(|l!z9XbP9{s*uBrWsBHQfC7v9M2e&&j zhI=0kKWGa+0Hl)F;y-f8pUqTZ4wa{%E&7Cj!EJPUGJC@XA;R43crkU+DR;OD_L;Lu z1WeEI+q+^R*b5V`hSdyPQl2} zNAlLJr*>te!-rh-nuvT-L%+hp$yP?qgy&Htok;4l!3A{b4{V!%tP41GNyu$aC1?l@ii`T|I2d}bt(Kp4j z-A_IPjj)8k-$&)h$s$W-JF1y0)J*$EfN!12BWkikZrl58PGtP(l{AaP1KjI5K zRFyj!NbRSGa|WM9CsH&s*0GjNiis`G@#MAec7c$5GqGzAFjHd0b$3{fI6Qah$sp!7 zcGf4m1*Wp}XCbfN@NVeKm9Y!_L2mx06E6I=Cc@90S$r8HoTdrdTi#hf)>VoXfQm4? z=y_9v8Q&v6?vGsSbH|5{j##cs5$dDbdGa&}V}NJctl0zw^iZjG&D@f`q==Qp5^tA@ zslk?zFk4c*wWUV@XE@eBx|$FvBd)s^?~0$Z(k}G-5e6<;){?*2pg$~*e?3@9%0!;Kpr3<~>AU*|l=W|H5?qoMK ze@G3p{`H2xs-Zz^)rYx-^(vu|h%PTf>gnF_%%reLuL^$Nnv1f6WiLvfz+AKC!)2X< zfir*q=s0m?=Y7%$m1U>SGvYwOcz9%P|`bQ@0*+C?IGFhL11amX6tJ|rz*J)1@1QwL@)=o|m!)}U zLgYo5#K}gHXgVHvkGP?@(2XP$wLr5d&=uM&U6_St^YzslG#f2Hyc?bb3j9+2TaT(c zH74mmw=1@4>lW8q-nV)e+-rkHjddmdS{>`$>aU&7{#^e-j;o6OXxjVVUX&rUS%#`_*U2D~mH`9j z*uQMDDwj<6DOi(S+-76El0b54l)|!Kh<$Z!-3ORYb0^VX-k`Vm`)#|mk-04*hh?Lb zi>b@W$=+W4C&4e@L|V3u?@wm3bJ~vZN$A&zr!AnXq+e}jxDNfrn3Dt|gx!-2_fJlX z*F!od(+B4i5nj4$tfGRK#8khekprt?sJ%ao(@{|;f2%+Z|1s}|(t4jiRqV!&O7FzJ zI`_!?l{y%yiErOpG{?#P_KEn~*FDz#59H_;s6v->n+fDCoau%S*f&ooKN(cvxP_%C z7CvbI_47>QW(@y!g2o`vG5rMzoOb*pO2J-MUNeP!6tQK0mW6aQIfa9jxS@LiL)%}T zoe*u7`<#hr>R@QPy>?ZEhbupv4}czn77Kh|A zC1zqD^jaFQ$K_`SKg*TN;_{uo&j6O>B4?A%M<(s{w!C2S~{K`fR)YX9S_&J}~(n77Gdff70|kv)w62TueMkHYq;qpdR3Ym@y)EG{s+S;vKN^X6 zg^fJeTJ?}KFT}S*9V`SuZO|3a29*YFQ1)XEZ*69g)62ZZji4*Khh~IYcnFV(aLZv> z$%89N-Qt@Y+Qq9fzXAp)U-f(?e*btIuB=}pb{(*$dhX(`K3v(-gX{sqWeK{=;v|#mLH$K+e_ufzP{Ux#hbZBemCc%?*WNr zcD0MEUp287z?Qjhy#%{7(x3o!cjcD2;}o{*_`nX`DC-Q}fYxlT&rK-r;-lKlD((KR zHK6p;>J$qb79U?^3RA!02)r|JzB*9axX1T_P1+p^bw8|+Ma$2qN(#tU^o0%*6Ol#a zcymG`nKLF2rc*KAH@l~@bZ!B;EY;xxnQXU;EB-bBlx`0|fN%A?cSIj@+A9gl-0{7>XigC|^w z`0^#3E+@SCgKr@#R)%1Q2eXzNZ^7NQAQi?j@ywL%&jTsq-f`47$Yy?@oN|UCK2~eu z+pv}#QR*GW+XbW@5H?2q(G5JTu>iW|fH#g~mGBH#$`hp?s5uk#A!>uWNA^29Hg!50 z>TsQ$5Q3b|DY;=n(VA>em!18O)$4q$&JYnQH(Gt%Wp|@cQ>+ndgC-`^Nl~j}tf4^O zP3|_aFLYm)_u9Enk$YiYUBqA5Ig*d zp|fdx1W!qZQz5mrvw64Jgl3p&qx+V`!~#$)j=S1qov3p^Da z$+#6QEWn#_JXfyY6NIC%>8PyhSNdgXwA)Lp`lX(5M_FSX`69M|=AAc@>uKbR)1^`D zVhs)YKi%KaKMge7b)KN!zoi>!78^cH4R)!-DTWiju+2^_u{S-qQUC5c=(HAgy{;x( zSTh~F=rli&F?_`56S|+~{ku`};zC_RLuwD*8kq(AA`e=xuVn{hfX!f+`?^Rvd6GyH zm385nj4ychb>z6l5Ppq@4C@7I;zA&{7bq8bSDSN?bY4kWYwD&sL&4CI`@W&dr_9SQ z4%~6U#y6BW&rVc*ki*jMyP&9MWvWeKyX5Rce4JVu#m~`fI@_OZ17DX%vN+BCd1|jC zF9J3L$yL#~?6A-mr`|Mt?a$6h{zA-_@5SPhEO;P`dPac2qlD4%GQeUY==o?E_xc0oX+K|%B(Y}iXBwDSQFi}1*44IE zsfFPPcGnz7-?})_X~xVUpX@`CIA%8H)z3QoRyE7Z2aDSL4$KwLN)#uC(ruDghvn}} z`0#1KY;PxxR1=dpv`W1Y6#6`F;qv+I(^sG`82nc>KuR+CHmyv*tCpc#63B?exG?c( zO(1^;>km33j~_1Gslwr-_UJeaCZU-}&j&DqHFHTqLgHave}v_R{G(ruogpgV4ZXvi zG56Ghak`f>^doH2pD;KWW&WcP3drHPEG~~g?6~21Tt3k*E5pp&dc96;{`fO1dbiTaKz*`#yD!$o0krsRZwC9P}(5ektly zpg9r6{JXGFKn9*h)=YUvI3KN6Uoo>3*b$mEa`305=!Q5O)u;B04t`qq&0ZC#J=%Vb zUXmdU*$nulX!-f#=TEPpfY!$s-47Z%jtGsXsQM`nYkE6t6zF+8Pkv_H{!T%C94Vt^ zY@Cse3A+9GCg^T|)su{XyD>Cgzs@`WelRf<*g@?yluy;&hKk*VLH{unFa_iB94+P%5i z>}XEMY01|}YS1vrL5U^zuM&~a$-?B>1&4xD1Pc9I5!*&w`W@Mad3G~FNF&fd4N)$P zH$n@buoEEwixV=RiGO9dY>zcFIqFDwU0*ZPj|(aMFqOq+OE(6Ogp&=#Jnua6V{5qZ z5RSd~@v9qs^o1(bzJ84$N@H(5^bVa`+Kr_C$@`>L*Wha$plY)Err1Hq+~BcDuaa`u z!)Jr@upHzUI^_EhAiwNJUY#_CB#F8IzCVd~n=EFu>LIU#$076P1NU0-oTjM}xP*Ej zZe-Z1sLPgGql_jtQ^p*=k9PsGGv%(SQ#%Ps@`5%VLLEwDA))xiAe@bs#W{Cm=^MBy z(XnJFo;b;95V;?He(8&f>o3toFyc>mZv(RLkt{r|@ogb1c7yG{M~_ierpug%z2bnt0v z92UJ@9FScJtvbVWmr!kNFF628JyPpj@VTt38+p*T)IYB(GDhxeP~|4bqW^yOVCy2G z>(l!5hK8{MSQ9=w^gBCxE5%t_(-h)?)8Z#3`)ST6^}9_Cn3>2Bf3eSGcYT5pE}RIy z7Fq4AzZAfh+p=fJxWvxcx!A`vHl4zqei8%JE7n?K*P2(gop#8e`Yw!f17DnLYTe7= z{Xtb7@%n@*9(fGw*TVCaEidFQ$uU8HQ09T~QxF5?}b9sQJW;KgIA=`)l(Qil{QaRKD);hA8kOCGR28s z{=pRWG>QwtfctY7o))YAiG-7^9?j6teZo(f-v0r2*>KsO`$6;2$hnDJ^Ki5yy57K{ zUkn@#Zokj|i(-04-R=4QyqL;O9ej$O^mzgI-yebxmUcC;$S_$TavO;&SyyGFH3i$K zjUG7DH0r!Q0536IZ64qQWdT%mdq7F50mg{9vYWaK=}WVWLvXJzJ;b|VNpL~qjC0&QBp9FUv{MXKaCmP zeLy2G>ebbpJ@>QAne^^w(H$7$QbRvL-FUv*mFc}B7fgQeB+^G_yU!~C8T-<192-US z@krd5r2@6p{B`!YYrzzJBei%j?80aIK{knqx9?-7W;~R&3wUW)Ge&nvGbEZ{_fSr> z>xp$qfj-`wX9DLd$qo&dM_a$_7;~Aisb{n{_E|kF4rc2}uwRutV9@TnA}4$B1Axn* ztzY6TvQd&)pB3+vFqG-OFX}AY9$U)y5$MTeM%s(?^b&m83pZ)4HI{?#_DNHG1YcG^ z-7LMn1yd?FxIl?VRU~bbHm`Iwq3#Qxu{@0BS`YutmDZ4&Zh6h-*HO-yh0|g6k%squ zv-8=Vc!`UQFFP?I&9Yl25n*P|JATFu%Wm%~QyT)QsS8(KT5=n|3l2Rbp#{fnBe9nP z;_=SjyLXy0ls@&i%(==s8q>W>spaIrD81xaVxcj9abEhYsn`0ec#YW8B`-J&7BzjF z2V2M~mYW#PtX90GcVrk63M|>{BXi4tS~C*n2Gcpl@1=sl!3wK-UozO7J<%#@@^aZS z8b#&<{5- zIO~@Fei}~*NFb#XM2CCN`0hU2ZdIsJ6zEJ!4Bhano7tXunERBXf~_n^x$v9-NTxk0757{7qd;N^*`<-><-`})Ykh0aK1 zV&E0O`Lnn?PLb9IHt!57ZRz-V5gjhIa)-sNBy2A1$#~}mIRpiJC=KJ$X@E7m=Xqm1 zfY{$>V^42sInj7o=%*MozG>{!mm(w7cus?qHx+fVm1;WgeZE)mO9)dX^-TEts$8&a z#YR1t3ccEo9Ji}kdutXH8FUKEoE(>3rqzlN>sd$kth7+Y8URHnWA z{dgJ<^*!pjD*MQOU>bIIf42WQSi)(ny(--V3Y=YRhowaqgN_M} zC%A2JDw}5BNckWScnLFBNt}4@uR8(`1&%xc!3A;{BI+O^+Iojap8J9Al#pqp&I+h&@UY2*Fo z$>nRKW`j$4Q;M69tZ%0l0d58BnE)BIa9pQ;Mmvr7c{^8DuYPwXv=qlS9kt6rfhLCY zvdYwfX}^rbaaz9#SaEGqmjxxqu*%e#(`-8N^Bx9bBg+)W&?}3A4J&7LheRbM&7eOc zt^av?LRfuZD>&$Y5FD>?SEc3`7|8;J%P;CKK|-S3w)q=00+K`cBhm;s>Rq`;suW!* zZWfSYG3j1E5uOkB2p)OxahS{SD`Gs1G*+{Ei#B;M>#|XI#y+1O&oYeA(ma&e%kkLv z%{A3EqK%vR<$?aT+&TT-ro7)lcXLg>(`hCEmoMfX18E`YbdGr3-595hZ}iVAQl%;H ztuCzu<%>KN$%4jG*J1I#$v@$@iL!fa6b1g3@KY+&KNg@dCoweY+tlYW{Kvs=`_{NV zmtOXxl`ryHzJ--rQ+2q99s1R5`kdDXbm#^)sgj1a>TnN+mK`g-C2@%{WOtwRe>FJz zyybpUNOAQ#UNkyp7Xq)W92pxfgXn+>7*z_5Xzqm-Q{{Jkx{r_ud}E*BdVLS`+LKYCc%raRQr&F@0D| zc?74C9+3o`Ql9FrqmtawaS%Q7y@BC74S0f$m^Um_yao@+k=G^6gOGym# z$BvIz9px{{mxx-3?axc*-k_D^-?}wW&{(ZPea12~*Q6l-BFprC;e+`5ADyPY(W~54 zsVqGvW7X_Hv#b;$=6P)I<>mO28IG0Mq` zPOEDe$8&w1!R3?dC_|3lV+FLk7OMH&+Cmc7GU`3!jE9p>$?5Eyi{IPcX73{4cT8iZ zJik3Zlezfm-`ME$L_P4mfzm^*^wXz1UyHq+n&>v~RQIG{?EyEvJ$+$QAVXaC1OWeS zEHXTBqN`yii{tPozX*JT@{6_Z5U4gU`f*9tU)~WWQ-nAGYFrR)f#HBCA0RXS-s zAskG3VFltNv%_=-Y9#g-ZW51&$W`Y z&m5f0PyzK+cM9#8avDOS6b{37rJc=}y;=Ei!|_w`;34IG^#||dbvliTQ^lvoGD_&E zqJ{@VA5+}a)G;{DA>b&C>n}yCuRKO3zk%7IOp>P8;iygLjmj4W)LXXrk#x64r|hTl z(;gHs4&5FAy`rBTp@K!o)=x!)U>vb4)eje+u;siIDrs`d*1!B(gX?EhErE9;RIeRg zZ~BMEYhkal*7`AJgc&BYTL#A! zRKnpG?UGSeL&xHeeRf$5M9Xb5synA+#1{v)h zi>U~_uOd-dgC`5*dk~Z4=)m|^)iuI3rq3gs-yQt^R6N#Bs6#ZW;r&P;ZzDx8-$FL~ zPfiyy84xd47?3@R8aKg*ANUZuyS&qETd^x9C3bFEmq71_lYJi`B34#uPeL%gCz z;kc;F*1l;an*lE`5^8#vN1(j0tD(woyD``+7sTFlKklwie%TdGopb_@1|Gxt{<}a6 z8~IDDT3QX^-Zw0Q*Si<>843kgMTP*)*_#MoJ>LGA@oW(Pw-|lu7w%MiIIP~i*VF5~ zY!q3!|B-va!(V_ec~snXd+<|La&yXi4pJ%0f{x$YR^R1!1YDv~<4XO5Zr8%vJ3ve{ zP0i$RZElS#e?f@1j~zb=9DP+!si4o(^=qva39YVWete4~rOuLJ=#FCWIv=$;{7CpI zv_>~0ZAo5yLOk=>+a_4H90%(*Rzep}OMZi6}NvW2}Lo$(#9+3a2HjU}f#t&@H0at6R~z^1&ZRsu&u%<89iZm)C2uy+&?7*#)o^VFDu7c%(l;m2@mM2v5cZ^zX3 zJ7N8UKEjXd7nEG%1zP=-wZk+WuOEAzHAkUNEQ0yCpEsuzQsQBT*tZtQCeMu)M?U-d zY-g%eMrlg_)e;6(55+-N!v%7$(GST%802pFxZeLZYNQzzAGaNSHRb8GvbG5=@NPMP zYxz9#uxGW_$+O2pnzctm6ndg5HTUYDyw0?Mhi!1(5i8u;TBkHy#^&oFL_CP7F?yO) zTxS_y?D6fjs1H3kU#H}t!-44z0<{^!=>FB?nvWC=F`*Uz#E#E`*L~*u{flk4A5OhM z)n;-2c+dbAA~JXWeSC3alV$nX%!q4x29c6mPHK%~0NNR9_N(71ARnPX*58=PJ*0f#g{m2Ccs zO(pHVsWd4hkfnc2ysDH4&z*Os1GqWg|tu_vst@HkJ-=w%O;Tkww zP;H?xCn}b{;}XfP{kjdN)P=e+;SA2tbUg@_ys3W5z1zPQFU zUhB(xR8S6Kt)oj*V^y9UfWblQ;9r4>~xx ziWK02y;TLm?uVv3*eHYqH~dxbh}Q2uyW!CS%GIXND4f975 zZ{V_aBrEB)Q|^P8TKmmucRz#C$L+MGX5rude&1*BAPn?KFy7!Hlx5w!^Y1_R`bPHL z3q{soJ%d%5nJKb3p`$f7^RuKxbS9&hl|`iD9wrf{3NN;lx~%)@_xsNqywkiFl5oKP z-4e#XW06)0Xc`}8WMm-wP?Dk#xU_m!T>M?yuyb#jLdi;RkwcfH@v%bf;?E_YN0R%m!!JHnAk8?eylwSI&d97c6=* zHS`_J*dGR$JyaOK_QEYUy; zRvqz*c=+-uLj3U-9Eb@RKJBaJK9}w!tp?X+k>?e*5%+a@z;~Y>$x+__oT2%AE7Sz} z&NeOc+gd#_asO(!iAk-;aVniCZ@TB8LafAF!)daC%*W_lsK=qLwRFfaC_OP%+emMB zbee4;zW3;)GOcl~J|fJ*8N|95IPLL(w@4KHBPvpaim$H@k~dSEsF%EnT^&h&i{Wb` z?@(>cmQYi{^WXh1#{>6;oxHV!lleo0BQjOF3-SJ{VHTs}vD%lW z1^|jHd@NL~L)5o4 zD*k!=OGpxNq(yua3x0CGik@{Plss)zUMQzYhAW_SD(|0$#BHAF_-)SPWbY>6ZH%+ zpy_xFH~Ur2^Dv>lDhB=yJOzA9GB#2v0!z|qJOth(JEN7cM**@ByrF#1h3dwg132^TixBq)ve01_(_C; zhbi~k^G!2d?@0B6bp@di??mWg1A-nF^imdwa?`PFD$$ z9|nw6?a#a<3`RZTVxnQLdAQaD`ra*Dvo8~VTZl_F&|k7_TpzzpC# zA$PEpe?(>ag>j|a1X2YUqysS0A=&}bCljqFq>BJU}$Q*7x+ZWN76u<`btQ^NC!v<;@G5U z^v}Ebs0&krBvNrY&3%?LM?;ZymV$ZvIp%qaKKMDQo;94f@5HsKeQasGhQIa>W z*hSrVw4&P#Q*vc(P8oQjDF)hq7?7Jttgvn?*|qVxK+aIilxUW9h75ImAL!8ynFGR; z50BCI0^Xg`iirh6oYcSkI(QRO#XT%~IzOX&@vO!jdN$i&qN}>Mg)mWwpnMEqFbP2(L#wQ;tGW?)@^JoEP6I@LCCkiaqxGBSRtoUC7c~8?9kQeYn94L(;u|;z%LMp zN(#qgCRG^1n--XF0X|XM3R3dlA-T@REkJDH8|-g|No2Qy!iJs!Le8JN8TJmR=?)mf zhb_ByXa-cKJg3KuVC2`ok^Oih;!0CjObwh0#s2{_cxhi$RvP&{{OaFKVG1l7e!@dk z23Gbl=u)ljaa6x>y5r{yq5~L52gbB~3|Tt8C_e=q1*H4&){qfp@UXrSQ}f{RiHuxF zXR969SNPX~roP}mo2B1igtzm>{w8ZLFa;(Nh!5V$tB%JYy2RZ+qE((+W^U%=iNtDFaDx|Jo?sG{i1I8Ma5LL zq>$pBkYiy|JKJ)1k#+fbg&0Ty(ks|}z+?&Y#aBR5&BO7)8WhO9^+(qf z2=sYgQlU(<(ZiPPkprG_y$iYA>VO1z5rP;UJM^{xNv_-93k0E?l4J9|f$nRAEp@}r zYfx!WMt&KfFyAKQ4!Oxdve&em{YdAKR7YP=<)L&qc zyeXW_4*{O#T`u4aUn&R+@htJUGawVJVxOq5gM2)PZU=?*O+(g}lwH;<(3XA-Iszya zF~cvgzG+@^aZar&4hNob~0jB6z z1@`ZPtZMVTR(2u;;q#4hXzO3IG^U@Cu>^Ge1S+vJ=|;AXGz{S&byfFT1;{KA07PXv zz<2?imbt^wIIe&Tfy*Q%Ozb60DkMr<0N(kO{o~|+)0Vd!Iy#3zf&)F-H)vio{O_nk z0>#@c{~a^qiV29*I1(SlKyfI^rG?}mU-(IY(Qq5Un6ip?a}a-_0Jc&N&CsvS^F%!r z3L{@#s{L&-2x%o?u5z$8o7T)sZq(8mqJjct8vAc_qQIsFjIec@&v>>INWeRMPFUzC z_)3&6{{_01lxt<^X`=Bgt1|_`ll(+xq@2+{U&8{TB-S6MRW1{DKOwipNdvE`M?6vVXG5Fa~XoG>~zn z*BvEHoTkd!c+qx|PXt4S;PyY+s-*Yu2Eg67!~nYd@iB?^gBIYjQ${%8>wo81^ny)- zz``_LFr|O(kgirxi(!Jt&d`}O}w)o%0>HO8P6@Em|##9uIdPZSM!J*)N~ zZz%mb2V_MJV$Mk5-$ZRShL8x5CBs+ZtGfCB4H&Y#e+Nqk;Vh`00JcE%SDz9w1R`P7 z4)~&TrxQj9*yKIrGzv7Ml7b@jI$#nR%K(azAtqA)8uWc(Y_@Veov?Q$KO&N`-Yl|@rxR$dhr?#>>|a4MIXAs z?d~-9?cX?)Czt}D@G(dgphHm_WEeAG7&H}zJOVD1v1*OV|NDf^c~7U2YYBZL7F{}ru( zfiQhAuj=mRO#BN7@3YaCb|W2_xJRl?L2qyc#4HLyge|3rBZWNwZ&qvb42NFtf`RYr z+u;t;+G_@G#6MslnG`2^vpg9GVu-dhdPo#U#P!cmf+j46Ih0%SN)pl%p%QqDGHCTI z0*Hb+>dK!SDkvL*iQcz_w|N2zg3&`9t9D}mAtuR-G7U!0kH(L5#+kcIZ3bk|e{{rV z=qVH;HPH2VmYZb|EX~71Nb%Mx|4;F{&IyIIKP>eNBM763>jMIV0BfP4Q?Zh!H=xr@ z{;Apo&q$E-zeYEXM6;1OU>8urk`4e)#y)3T_*cUKFG_z{gCAK!t<@;*zoH7O$G7o= z$vg3QbCAKdlz0`f3XecgU*BJVH>x7U7vOY|IaVOTg7hx7!`fWl)46_PsFNY-|NA{#eu2Z{`6hPeQVC+-EM@Ao_)dK}amg?GW; zK|6o)p$t~T{zuDVH$a*5uNs0B6K^vliy);O6c-8kp9nL2=Km10^#-_qDaT*@=d9LW z!U) zYEaDzTmFl`{>O1p0Z8B%_1@z%B!2(rzJpwuvni-M$UpFJ)Kdb37#JALPLFk*OpTq) zgiKzWfqyV~xp@Tcar55eeWbztK#2FD5HCLmH@6Tscg6j*tpDu?b}vn>%-#Oqf6(rD S>lXL{hQec2nPMp;|NjNvTGycf diff --git a/weather.ozweather/resources/lib/abc/abc_video.py b/weather.ozweather/resources/lib/abc/abc_video.py index 3bfa17d6e..3877b70e8 100644 --- a/weather.ozweather/resources/lib/abc/abc_video.py +++ b/weather.ozweather/resources/lib/abc/abc_video.py @@ -3,6 +3,8 @@ import re import sys import xbmc +import json +from bs4 import BeautifulSoup # Small hack to allow for unit testing - see common.py for explanation if not xbmc.getUserAgent(): @@ -21,7 +23,7 @@ def scrape_and_play_abc_weather_video(): item = xbmcgui.ListItem(path=url) item.setProperty('mimetype', 'video/mpeg') item.setInfo('Video', { 'title' : 'ABC Weather In 90 Seconds'}) - item.setArt({'thumb': f'{CWD}/resources/ABC.png'}) + item.setArt({'thumb': f'{CWD}/resources/weather-in-90-seconds.png'}) # ...and then play it, fullscreen xbmc.Player().play(url, item, False) pass @@ -32,20 +34,24 @@ def get_abc_weather_video_link(): try: r = requests.get(Store.ABC_URL) - videos = re.findall(Store.ABC_WEATHER_VIDEO_PATTERN, r.text) - # for video in videos: - # log(video) + bs = BeautifulSoup(r.text, "html.parser") + json_string = bs.find("script", {'type': 'application/json',"id": "__NEXT_DATA__"}) - try: - url = f'{Store.ABC_STUB}/{videos[1][0]}/{videos[1][1]}/{videos[1][2]}/{videos[1][3]}.mp4' - return url - except Exception as inst: - log("Couldn't get ABC video URL from scraped page: " + str(inst)) - return "" + json_object = json.loads(json_string.string) + + # log(json_object) + # Put the json blob into: https://jsonhero.io/j/JU0I9LB4AlLU + # Gives a path to the needed video as: + # $.props.pageProps.channelpage.components.0.component.props.list.3.player.config.sources.1.file + # Rather than grab the URL directly (as place in array might change), grab all the available URLs and get the best quality from it + # See: https://github.com/bossanova808/weather.ozweather/commit/e6158d704fc160808bf66220da711805860d85c7 + data = json_object['props']['pageProps']['channelpage']['components'][0]['component']['props']['list'][3] + urls = [x for x in data['player']['config']['sources'] if x['type'] == 'video/mp4'] + return sorted(urls, key=lambda x: x['bitrate'], reverse=True)[0]['file'] except Exception as inst: - log("********** Couldn't get ABC video page at all: " + str(inst)) + log("Couldn't get ABC video URL from scraped page: " + str(inst)) return "" diff --git a/weather.ozweather/resources/lib/store.py b/weather.ozweather/resources/lib/store.py index 166d691c8..da3e9e3f0 100644 --- a/weather.ozweather/resources/lib/store.py +++ b/weather.ozweather/resources/lib/store.py @@ -10,10 +10,8 @@ class Store: # CONSTANTS # ABC WEATHER VIDEO - scraping - ABC_URL = "https://www.abc.net.au/news/weather" - ABC_STUB = "https://mediacore-live-production.akamaized.net/video" - # 2023 version - E.g. https://mediacore-live-production.akamaized.net/video/01/im/Z/0m.mp4 - ABC_WEATHER_VIDEO_PATTERN = r"https://mediacore-live-production.akamaized.net/video/(.+?)/(.+?)/(.+?)/(.+?)\.mp" + ABC_URL = "https://www.abc.net.au/news/newschannel/news-in-90-seconds" + # BOM - JSON API BOM_URL = 'http://www.bom.gov.au' BOM_API_URL = 'https://api.weather.bom.gov.au/v1' diff --git a/weather.ozweather/resources/weather-in-90-seconds.png b/weather.ozweather/resources/weather-in-90-seconds.png new file mode 100644 index 0000000000000000000000000000000000000000..abcde43c1f200fdb9d4697b5c306fc0e0fe0bbfd GIT binary patch literal 37939 zcmeFZby$?`*Dj2SB4G!qC@S4uDkw^bBAwC_!_Y%xkSZWZNtG3RkZ*~8To6jHKo_Qs|*=FXQ*%q^|#q*<3Lv85+= zG=JjpP~FtS##G#lRaWM*l$!+H0A=oMeAx|UYv&~4Ce8Ziz7p^~@@rn!%YQC$wvlGN zjXdzOw#uW+a%e~M%i=tI+@^ed{Fg<=c})2P_=HRZxGoFu2?+A?3GniXbMuKv2#84V z3tj%_2P-_z(ab_ZP5$0L9|k{3vp#cnwwK`L#b7Wz7(pJiqa`oDxVSiS4*>ygxPsfs z-OkzAjoZ%Y>c8$FZ|-F3Xl3tgg|@ql+|k$s?cyxW3Pb(J98mWEzO9|pKkWn-<8?E( z=jG?&L+147LNn8UUuW;)X#3~kW~RL6w&o~vJ7*`jmjB<^+CM`(qn)0i|BGAy`{n=i z0I;o!%DGgAo*v?IzGCTxW= zwlwFpx3gru{BJW#$f0e~j__a@o#3BQsHjLhuyb-Ywlg(L*!6!s^#8M^{KuI7hoS%XoALk6(En)`(`UwZmgW#Sd0COk z@FF4RAB)2K->=u7*ZxB|`q$+UziE z7Ixj=F;084?D@)cbPqdqv@a~sa1pmz?=xPjWjITx^Tn(&dh$oanJLZ&2mR&G*hdHwiQoSr>k#`u!aB~j{6SS&W8(Nii3Uz`;>k==UX)MY|tB6a;{tECL7Ak4dU znxs*Qy8d3=bA6$|W?i_RPg8*4xiytd;Yy6}9w`}(MjH)}ic3pN@2|-2HD1CF zm7+(dW%tR#Hht>bwlIp(&F`WzJInR>Rl`tb>8%skF(TcZ1fQT5F+ zY0veYxx77V1B2mVw=$LPDv!0f(weoLBcYw|Rb|Njyk6rXBbBr?G=n8fVU63{+mw`) zstID@_phZy&N|aSzML(BCC6h2ySv}#C86-?s>$oyyPRj@qjzSL_cETOaK3AqVr-lx z689R6b{fvv;d#Ahm7Gs2?=YrlF-ml@9p*BT;2}k-owMg z!VBxYSz4UFQ3@>HMOf^o7#+e+@Yeouw@K$`Bz zTjs1_5}ohQ!@|U)uf^Dp)xI#ObWN1R&>CIt)l~^TgDOeC&{+57vQ44t5+rfwzX zm36OoR}0$O*w~;@!_}Up+abHHf*mQ{vrg0P)i880JaJ*+ZR14UQ@-R5%R(Km=u@O& ze;U-q#xNGu^zLF5abugsZR`bD>l}U@mR-H_xL{>v1qxqs&Ta(eU*^Ta5u}2>hR1S_Sjm`XNA7K^= z=g&1Y%%fL&?<6fx;=-J?VS(zMFI%GTRHLVbX*& z@|j>ia~)2>A|`$ou4tyjGi17l-n)vOHItZY*^TMwW^myLHve*-RiVI5@ahDCo(t&c43& zU{$YQVS6)Sd%sopd#X!SQ`M9V%a6lT-+0N$N=WFEp8Zyd7m(8}@87>iwuwl5&PNlJl2S`wj$VxCjp1J%bPx%?hcH|qNmaTo z;wmvq%|f;`I&7FP+EUEE+l!@IQ%z~bL?Y3U+%N6%duF8CGb{0dQ;V46aD@xJ_j1jA zRzqci?Yv@GP{@!-hrZf^N|Ll;w{Wa{pBs%`l;j`-o<&Nf#j$cYNsQ&JJM#Gk9 zQ)WI?j_n9yCnHR~u`ZAU-v%9mCpO5d6 zUhn6&cv19djd%IR&xw_9Cj8w(Es}Cs-Vyd|Eq^E9c{AyG)1?DlN^U_=&gF5BPQTmZu)O&;POW#SIM@9g5zDf6~6m>0RaJ$>$fIJn#McAr2kQtrzX01wQw<{xB_u&s!d5{o_aD zjwI<8(e~>XsdLRb8#PXnu5@g4hBui>NJ`2|ENLm0J4}4%^(D8k>~A*mm%xrnoBUut-cW(63DD1eJ zyM8fEfJ5TIBHT^%m883K_)@g*&PwA7lUi_i_^C;zWSeluuG9r0k(q%ZJ}+pD)v_x3d*4uQMj8Ywm#drS z+_zao%XZVnR$i=@giC@K->%Vyc9MM3URDV0x39``5l;mPRlm?v`<`Xz=;Awl<~H zoMjhgA*7mTULM=nhMZuy$kxZbItUru>p_k3b&{wrNz_iOWpU0ZtNb^HMlGY~#UV;p z;t;$nv*EnDy-O#%lRvs-H2Jm%<|4cGNmkcP`0qgx^vI4Lc1=&%c5}6bcYiQ>cQ9h% zm8XXiyR6!$O1sJ!LyuYBy!A zjGIVeGshJG&g3r&^UM@1xn;@8+;f_apO)zX~ zR%LOoCRCBQ31_*zncS;KN=ixqxQxJU!lYJzz@}qhV7PE*{ZuD}KV<*yWcjY;*`L<@ z&HWm3zFpYI#tC;)n`q#!SV3cbNJ4F_r2-t0;92w$z=`{cT^_ z-QV5V4NvTJsC3Tw%b92*9+2&{%!YWvp&&BxQRqa9S_Uk0VZal8#X*Q#%k^};jiF59 zjwv}gsEk!FyWLiR_*{;&BjlPfT4pKj#he^ToYm8(PsvB+N3KMh5nR})>&4ubpF+l@ z@-{xcQhSJwQOus=ZaD>UE?Yq)-X#XJKRmiS?7OkFH*Awvty!<~Nis7pH8Im%s+A1i;{+|g!(!dn>gnxW#FuvPy=5~}S^N1>?oD2+XgzEg7(p3h@h4bG zndA3`cr^;%}{J!VWA+v6@^11R_TLO&+P0Bu|Cx&O&UDjr$&Mi z@ztK9)&&Q%X;<8K%BPdI5i8JBQJ0tQa^@eVFp>GZ>yglAk!M)F1+LtGUa7dK$QHtf z)fw^d`zaY2R!uFa`|QK7xs|qy5H3J7&Mv5`tX#FT+ESWjJJLLQt0R9hZwRo$jxR^=G?WY4{SYx5YYVl{z6D;OLDh=MM<*%YxavS}eUOAiA(sHlNDbj)R zlf{GQU}Be}{DS>Q!Oe88O;4B0&C62Gt%e&z^lQ39^PPuB4sHd;Sf# z!rgN*<~m3yJ1sN5yD>UCG^8*0X^KS7(#j){+|!TUFm3~sK`ftU?iRASziLq9MIOeC zvi*%Pfu~RZDv4bJ*XSj992ld;Z2g{9is5-2b@$$I@g@Ec06B@o);K{81JcmWCBZ!4 ze8;;T0SZaFE@2HT&%WLK8i#z<1M_Kkm#N8kczcD?K|6!oS8#D&^u*T}``0TeQN_IYn*z)Yg z!-R`WOb~TSi{i@H*Vhp&(d}tQfE~xC&tM6d0JeFi%1|9*My))hgF!QGDXwdK6l3Zh-A?pcU_LsD7VVvBq3Z?#R$ZBnPbHV23!KWWA zY-~7n5!3@L&@jvT?u#xl@s=;^kR{ZePKf|2o*XtyHQ?qBE>rK&H!@mkH_CA38(o|4 zAO3xsYvgK}l$ui`(P+2VD9Wy_BSG8=jAN~^7MC`=<^eNhc+>FcGu=~RhjfuX`=yY) zgODFzfWdq19R*3@R~4c;uCD!*qtmD%hVtia1pFt< zI;TE7JlsvnklZjbO@ipcCBQj*o&c{BC(nuEPTo=f!l2d+iMn*e;03>k?J`m+Pc_-VTavdo5n^8REH1M&C14bI1-+%sm zbs2}1!|RRtQa!7guopg=NSqLAQ6(( zw6uLENyo3;`S`QOd;2{0kU|(U&EbPlvNAC(29Q}leYzTcU;QE*9|`gXlKLB#79q%` zMD`x_DnV^*YGg%n3$Mis?1gAh*G}Jt6%o6$;?{22-BUW5+<{C zGxP*SPyXeTCNkPquvgJlEB9z_WOYpIMKre}9+J7xvbnhlCgNy~D-XXUNO|xDEGQt! zyTnCgV;TDr-`4*6J==Y={fnDS@)9st7^$%HLUhMK;;Ha`BvC8eyJ!7*N6pA+KSR}< zs`1EEmt{Apx~GrWHR`qhVlz^pLU=Ri1Ryw2vFOu_Ej?5*@@j|%zsk%Vf&{a6#Kwf)`ve;|V!m`jOn2T) zV6d|@yv>5UrNWEs$X01U-(~rM0F2Zoci`8GTZ!%9uQdMPZuvzU^FC{C@d?d{;3QHn@rBzBy;_cYB4ktj6UPPvx9B3Bur4Ga>E zFP<~>RE#o#O98aJuJd|xHmp&0y&$Z(w6y=-Yle##-FDadLG`}i);c+9rl8RH?VCJJ zK?8(f%pwkaKA`@vz1H@Er7XU$PZM8~n3(wN7Q|770nD#&!MVA))}m$v*qtDCWR&y| zgIB{yRl2ixIPjgFD};D-g)Ej#h(C1bP}J|DiVoh?p)ve!rf69y^wA{E?R8mr*G~9pr{2SCj{>RluOM$pci7C6gyP*^6 zNr7~S4>E|_W#^=?jn%y(j%Z#a4VEnC&H!@n?e8!B+E_%Gv?;#5zhGoo;cO*tI1h0U z;oZjXR9M5^V1XMO8`17nhTdzvK>F-~()QN)_0J>T1$Og~ld#wOW>SC`D|*V-n9G&L z>$CC(geU<3p-YI~Mz!61l2pg^F)NERN>M}4QLK4ObaSO*@C>0XUa&_0 zVUiTN=ZUI@n4p{uQ^>t!pRL&#BcF0yk|y>K^3cHMTYXT>07(*7qIqJLZKXHQ2Z{;1 zb5vD77c8pWR(=Vnm`FR%Jd%@pb@FeV-ZIR&YUMjahI(d1sT1H2L;%N?Ps;ZU4efw3 zeU+dm11Q*Y=3}5;ixMD^KBgXD%JWaV|7cMVuY~>B--yb{>;Z!GcKPN7CfWOTLuNem zQQr71Uzof`6rEfvWod}#ln=y*Bp9%wNzJNM@<|g&$ih|6IHEk@-kBdz_JAb>E!!ja z36-O}5Lh<$Ya&p?-n2(wft@lr#+)cgun=fiIb67*?tD#64Nx8@fB5aY4Ba~)A3d`& z)!#^va-MmoXILQg=*wxc*B&I&sC4Fi0(y_|hXMzYzm6}zg2)zv_B!-wE4n_ENwQ|W zIB$65b^*qs!JxD-H9*ic!=wgxzM=e(HyF+vv@x5Jot)AUdM2g@g|+i6tU`5(6W@Z* zAkffjBHIY-1NP~)yZEL7^qI%*NgWOekc}_BGP`m8I*(C}elLw3Nbod=PKu&%>Zr!Q zQFygx&|HAF&{_7IOgfgQC;NB+!x3&(2yL9mt6Ei@@^?H+NeK{BPtMl(0|A12rGUX4 z%kZ^2l>d72(nL8`d)EH%(#@(W8JOiQJBDGW*`x=s+sH56KN& zpjf45c5#tgWh>+73ErywW$Mu*cBV2=w+g&-g;8MhzJVlhy>uD9zlh!KimB?~|uN*%28nV;1ssm4rm7)}XyGaEYm)*{cFN5O82Fuj^HZQ%7 zb$4@fYj^!i*)>9+a?5taHVXi3!|<Zjh2osS<3xOfE|6e5QaEJ9xx62$Z~S5y{a`T_iVKJ?pEIZ7R&w$ zi|_aeBWUe?orh zmD&R+dOG3KPdwfeaBuUWgY4#>o}L;RplvzAB&-j~GORz@IpV;ujVuvwFYRbr0 zuR5irr%wa9&00SXlbLziLMWz0h;mo3fpmtmbS&BL9FjSdgnXZYhG`3D+fLm znB7xK*m_#9q3sFcBna##d`5R;e84+M#(;VdP0xP(E9haFRNF;;ZDmd$`8sO0B4-+##E~l95fUX79J=gy2VG6Etd$HD5yO*OAD-iK>!9k(=222$q zos`$+G86&k=jMv~>~LuQU^2MslFvq^S~Gp0u>!=YxCt@HXc`*gt~tO@0L(@;dTk72 zk|ksFzBZ=8QVFyH`HXoKdr4nN=)TFV_`VSN1fV(!EO&vG=`N&}yfxdzN_EC8-6&g;ZIC$-J*t;h-JAd= z0VpXZNVrh38$M?%0MZVh!!IP)`}EM#+Y5y&Zj5qnoPH}_7;S31i@+skW@j^u@tJck z@3Ee$=i^wy%+Jhd|Mja0uuHCf`LF2U+?k>?CIHwWaz#mrouxvifb$AF`D?B>OWV;i z90=HA?hpMf75~72L}{mq?=+<;uElv!vNM8G90ETk?pi<@icb3X$%8V_dr@9qJNVJP z5j8`_M{n2hmxk0`)UfTE@~=3o|T`Uf2E#f zFF!(g*%k!t{aVHU= zda+zjT@Q{A^|E=+>{bPYth)oeKmRbH3Ni+?Bt$ia*FCj|J>MAc8y*VpA)EjP(=(-XQ{PT z%N$5(nX1_yUfSDR+OP2>+bEGq(C(|J=tt1l zU02rd&pYCBAAg=vmExC?sj;VJXAWB$D5y7ZspNoxLV5XndC^5=OB7nF(p>7RtE+>I zE%?5PYjv-(vT}Q}={@o9E{z7S7q_00zz(A5@3#+YGY!3NBeD_J`i=IH++tAW);Ygc zVe}}r=nbTl^~5DFOEVXU^Jw1JeIkkk0%*fziT*ox0 zzEmUM+YkoPfckNNbUSPKj|!K0>zk#0-Q9qXm&WvU-_{4xbsUT52%a7O64W8Pzw=8{ zAHubv@9vsDkJcjfX^RoSub{QspFE&RxzTKbUk56^zf8Bk3;@9H#&f;YBg2(Is_cY+ zFP`p%%mtCSeal&K>`2y zH@)_B{h$xyKjb`G{c$zy@WB_>rOg(F)9r~_*44#F5@5%bxD0@>=L9P|ei^h#HO15( zRo|`dQF7uac^kX$Sy3Dk6S*sZy&s3E^Z8E;5Snqni#ai2P81UsZiHkOEx%hYy*I%l`8~2HjrL`UF-I`wC5OKKI=omc!@$b#1YPEJk^1et^-e&W-b zOcNOl_j|pE5-usot{>`(9SBqN;;*Z=OSIAm88XlU@w zD@z{c1T+xzvCLt6aMTlxUP$ia^HWo#p{A|^GN;z8=TkI938fJB#D}1pQ1Nyk7K1hw zQirVU=phi?quMMWofR8XKK$6Q*^@5Q3((0YNnK3Y$<1vO>QyUhiviokNZbQ-{uIEI zMh@eI#W7|mF#{(Ajcz=aC%7escQiMaE@Z#6s(Z5?Q$w2e-J2%9R`kJ+(rgYz_5I9x z6N_H6XG{kc71N>#HzeU<5K6uHM?nKa>bQ$3!^+nuG%W(@H+T2cIo6;u0?jG~JI6HLlI?+#L%e`4 zB_n-Y#~tWZhxQZ^LLpZcsOZqbvN<;PR3h>Fxr1Xo%^paJObV81qh_PJi+A`E1CLh% z=zkngZ{8u3fQ2GPwXTQw4I>fXE`(wtm>gmnhZjd`j~=>O7^?j4dpqDa>)6}M z@&Ls_>E3!TOFr{<`#@PGqpZ)4g6!5Q94HP74O1;KQ0O*9wN9^jOlLh^0L=r`hVhr` zy7SHwi<-K*JG}tWi9}6B_Ee7G-dJ~FbAYj&Xt9+bD`u)JiiJAu?T`U;jqPN#LDNaM zs;u|^?uMX~f9iS5vQI}1_(>4Ap;u#1k&tw#mdOO@A3|!LeDhMGT_Y3q0fq@rX2q7n z2b577Oip|f@ z*OQ+x0FQ>y0L4v-)20E&LZYIwdz%wtUnnp!(A_l#VL=FI9E?5Pc^Jdh=m0=OKwMl0 zm1_ez9+Ab!e8>9XUWnd7W*h*F0h!D?OE5vq;cw{GsjfC)cWLSG(%tr|0U@u;Hah~u zar(Y?kaQspin&|UZqCimC%gSRp4`#c3YlWWYDn)dXr~eq79Rgb@mU3&Yd#NaNS+wx zd6}Ebv*GKzrseAb_UNsd0kkT+QQpy3^X`C2O)opdCJ;cNgAb}%xz_dI8n9U5)Ky3eg&pmi-H-_4At<7Xz@xO( zR8A5kr+kRhK6Wk9+~>~s)#yoWj=cgEV;S5x%wd#57%IT}$_KuJ&c2V!+tsCEsK}7< z^Hw_MU5P1T*%_lm0(1^kZWf+_Vq*vJ4az#_I!ZKGXFN4~Mv1I6nb3C)mBZ^BV6aIjyX$220UK{#SJlJhiG`{(7RgEej8s zv}13f9 z-K-6?Jp!V7JGz7`&dU7am5b|RKiUu30jbGY=DV}=DoEmgzaMp0t*NX%u2lN4qF&hZmWB>rLdtCRZm>uF|68bL;Dm4FtuA0=GAOj z^TcF%C0`By0r#^w9E#xB{_D=KT438ia+^rV7`y=m^R8^X#u+kyVWcBOJkU2BRk`bH zW6wW7w}#{>XuBw$g3iM7j*ow)>jedRvKL6=8pRqw2T&;Pw%2?rh2`b$z--RhB|S{P zphKL5Et-`tpUgmFlJ+Rt5k>sL$||EufJIO;R8T-*wM&V2JRt)V_))Acw(>jAg`CjX zupr1|pl;u}IYnhJ=>=_w;y{8?c$t-NXOedpEIR{&$TFv)I)Lx**Xp%qlsALwN3T6J z9RR1+ENjiJ{5Fn9W2<9VR1ruBtY*0`+C0agvSeopDpNWr<2$T#v$GB{GcV{DMyj`= zT1?Emk;O&m*4^IS3uN}Vd6tU2>yzDiJbx7dp?%Sc&#bMtnzd?P9))JBa3tSAp{y8J zV-VKpw7ERKDw8c2NUKppUS3{C1mD=V_Z1WrAnbZ^+`4v}Jvj+Zs^1AaiP>Z33a0BG-^J{b z*!L4+Kzm-1tqB{@`L@4@>l3XcmESP-_TGgU7-C9eU+J~vIT{}u``Nf2A_ZK;LK76b zbQQF}d4T;I+>$M=bx)T8GZFWhrQGtra&XH>c1(`~LbyvLjg5_g%X1`DD9J-1F!g{J zG(h|*Uzk2t9PIB8lrm~V+DkyX%Of_?M4O{vw?aA<8=@#}02RRv;m#%Azk+YPo0CHf z3_FOPqr|U%yz5&KPzg=#`G@RNV(p-!pD*voP@eYzlctp1;GlyvQcjk|g9B+yk%u1K=xuj? z5rL%fteQ1jd}xCS;Q!zT6R}?uoV;hLb{9wYP;E>C7kdN2lvk2FHrCcul$F&b-`8{B zskCVO&^#?C7D|E=()#b;J&)+zzpt&O#u!$(E`F%&i1PDJZEmHLTE6A~a2C zkdyhf)p)(0JaF937vu#mm8uG-zQo2FCl0*Nq)zOr# z^K?c~RRpvQD2|SnROg`1mA^J_^!X^~FZA+5Y?_lAIA-8^dz(PYjaifyR? z#|$dWE*@3P(_n~EVux0dM<|nCmz7@)NQ+Yix2F%3TOhO6GEqOevav%KSdVZY>{<>w ziX-|^ZF4>f|0Np)Tm)moz_Yz9jDul>dmC8aspfMZ!OdY8}bC}Dpq zA^T`sI%^F$-%zf!ER?=!uGaaVRLp<|D)n<*2W!BdzI5qK^5$XP z)BK|x8#tT1a*a^V(QiU+kg*w|S$9>!9atRD8SPBBUyyVW@4$LM@1N|p<$gA_d1YQe zh^WUJNBcYaivb0``+Ln7ra1fi`!`@mjDAn_or=rb@19}irjdYnC%N#xhGj!e54rY|` za^qJzaqw1KIR)lqJFr_DLk@%j-phn4JV!sYx(yEMEKcbt>ge8Hi>8C-g;fX*(d)Wy zQ0-CYNR7;tlGEuuOp7l8H4l^|{xgL~VM&LeL$Qsi5|pQ^5XsTrUYGTSL3$CussIR~ z@%VXw4Z!{$w3AMN7d9gc=s8h8G;DlOQ{UCHo zBpRk!G)5HveuOR01mW<#~O9L+TyGR|R@oZ6wyTC1& zFI~z&k&t$M*K;(tS}8ftk^t^EF;VC>960|nj`R2?W1~38&%oSH^W0eydk7k-H<=(2#9+{QHZtZJf<<6Q!b0-Sa+CpmVw>#AnN*juK93KQYXU|ekKKx zH5aERA>fMI4QbcJuGZ7Z>f@$cEefHM0Te+)MLJ_Hs{~FbKyQRxqa95kq3K5QP?6OW z8mnQ@EA-Omy5NWil7~??a(}uWi=Cz)_N*K&3rX@`A4HlvN+S@u4N8~vTF;Yb^>bg% zh3X6@o1-{Etr-D%#L*9umzOwIuZ2Jy=zf4_b9D+W#EAiLZbB_1Qu63Zdq&ev15&** z+F?BftQ+qV_*AD4l;=O>5j2bVU5cN;5Az25{0PRrFSq^6yrX9-rfR;cIyT`&Je4bTVN|7{fE6iel+!b zDkP`~dV|5B)TWW(2S)n{4HA2MKA4g22w5^v4LA`Kb9J)}wkn+IKm?Bk^IVRH((bF* z&c*arI7tC*CeoF1hNKjWP}fhB+WIl&(Bca9&3=1U_SA~X%2Bt85XqDbBRGp-ndF{^ zbDSc&Z^Ch&1vpotE0K5)8vi;+kPjaQ%wIyKOE+Z6O~bv;v(8%}q9fguoJN;>rqZ?m zU?#y>&+;2hK|~WRKvfnN76zylMM;sMN?xJN)X3tsd>gi#pmTUJhRcr9U(*tp6nGQa~pTw>8D< zd+B|_NoZt2w!W%rN5pi|(W6JBUD)41p$X~l(A>t1IB5le{0u);Tv(8_(ELm{iUDma)@%!aKt%#&Q|5K@8T?WHYC`+G~t;!bG+C;TD>E>g=t z*&JFvZws;#^!(wV(CnbL?lG#J&ycKieQLx5IdAWb=z!yXO|3Ays%NfcOId}1H>PqNZF^6&fqgQph92>=V$t|$xz4gBN{x%|KNKoI^y;zK){$7vk&biP_?uY zx(cSeL_(w?C46;OBn0?5P_3g~5C$48at>@djK{xu@;7c%Pm%oXjB1bO*NW0ojQDj7 z?+9`{%34XQ0w@w34`FJo6QX^Nha(N3c*)8@=t0Fp>o3&cz2V@Cf)X;XU8+e4_J9RLlga50+#=owHT zSQ>eOo`a}S+;(f#O$sKAwAD>)Y&+ONkzB5$x7}z z)q7j>NOuNJ`U`U%(0-8<0gR2eH+X6nPlw#|{r!pMPure%+=(m9zB>-TmtnGr50hmK zNCN(aG_KwMOdr_yo5Y$#Cu~H_uaJZ zg4C%_0q!u(Ut&n!gM)SvQh1Op0mVLl<6Mlig#%USIZp!JA57KCNWJp}L~#>6>eFh!uXk?c=+J^&g3RDdu2*_js5O8DuM=>q{LyRWSiD_odKvy0zB#IecE;ID`G zzH77KkImDCKE?Z&Pkwgg%vl4VZS}pCY5rFOI9vpXzY}4y%(Q_H0Te^`Kn?^FEQ{<+ zZ!u^h0a^MOoPWp>X)@~yA)g;D7nhRqA`Xdn3&j+tIau8v1^11aJU;xw9Mbafu*Qk+ zLkN2m1=dtw+XgjMLMxI^M#j-32#J**Yt}RycXa2G-Vj{z3Ck0;i)(O{E(rvc0CRDD z$PBg0w4gkyfGMCD2vm>Nl0L0_7BLrKW6pdpYms;+2x$=wFDZ{6RV05kS6R*ZGIfa- zkSJbp`A!f>yxtj(MJq?95W&1!j-@e^ zQ&0eXlG%0e9CEA(IsSz&0V?-U&(l-}gv~IU5m(4AVyZ-CT^s1=tvDob(;etS&HnCE zf0etQ9$u?v^_&ux%XnekS>5|S1 zb63?w37428W;I1bw7%nhv@|a-5BKiAVn(qK-1z(%rJUvC>loh+400k41*se9OmK4c z1VE@)(v?6yjXB-he372s12RVDhcR0nO^HOL>T06K`=$qQDunoedgCkKzNFm+oqD+P zH;E@z`PylaQ%;Ol^{(GGBwLW-gt%_~*1OafoKSc?cA7%-9CkFU_)K&>9LlA>dXbtn zi>g%iuJOgqABQNsvi>Ob2>i&;l5IgOqfxgyKtTb>EQ>M1 z>;LNgh(kkC=-M`Z50( z8~ptA$b)ZQoWwW#3r;eLwhA%u}39suXqqgZGOe^N_qM=V|29oX)AC66XnTww04$%`Dku5i*)QN z6FX1gP$-_o<67mi8d+xhE;`#k%8hh*Hl?ilDwCFWnu1f^E$v>$zCTE&O7E`hta`zR*vM3dig296SGPMbiH%t3}QOn>O`LJ(Q5z9;Kz#Chu|NYPDZR;N&}$+amBe3r71zdH$^$k$FD!&>MKpn zS^XxT;-p_85uq;s?dYlS458k4!r24zp(@=!F48c!w7$7_#qYWtySe>W2gW#-_GuJW zI&-!8M$yST_Y1PO1$`MGuN$$lHs5>|v`X?jZTO|Q&+xW-YiC8^@UBj)2W8=CxQe{I zxB}NW@k0A}!;tV`^W)dS{!bfNlQCc94Z|{QZ_Cp@VC~8d{t>P$&#%})mg;&epK|1h zzjz6`YvyHfpF4i{m=ddFikXEdI#b6gM<=r@gNbWswe7V@%UAiKjsuqouPT*qo=))b zGarx0a`9o65yZu}UpW5m!wtFdN%;}u#=eTV+IqeeK0kAhAMaAqHg4k|%0yLg(@fF1 zHN8urHo1O2MR+!$nNav}q=d;eGSY+`agBSiZE`Ii%}w^QEqWJujhmH~Dc#G^a+^J- z+q8dS#qa$?$e#pC?mLa1l z`FJ}ntyt5pBNzS{%EjfQ)#u%%C(DvA=up`XM?V(rZt=d%)txVOUGHeY-BzhlP1@bDC6G8Xn}w7Zi6mye~Ad*|LzV-&KO*U;jSy&5Tc$^{^+~ zlN@o82PwkrsgYe1tS4zH6Vp@!=1rTak6#gryQ3U7sU03TASa(9H}OzTQPoFGMua)Z zO*TeL<_TZkGee;a71rj%n8OEs7DrD9%R5R;9`}FH?u~w@LUZH&gV#oi*WcIt?$zg6 z!dx%vWA1BR2wjgC{@dw8L2bLRUg@-3W0zN5RETNe7hW1?{nz$i0%C8}1?0;&7qXqD za&U`T-yY1o%F6!rN%Hmalc$2EPE9dvp9xOk-?NiS`rNX?o_c5@a-=*y#3}FsPlADI zPO9=fw#gGWliN>)-}bn-41L7!77rmyL$mJ26^5DHchX_)Y9%#L5p%Hd2gmHS-Kw1| z8-zTin5CJUe~0OQspwQxqgvNBY*7-NmYBR5rypmL@y1W=d`2GrfeedN)^<`*&~J6o zlyT#$Cy&|32C3VcJ`>2jeqSYRb@uINmq&>cHyb&KHMde+sM<%3}xn>)&ye2#gQm?sWhDn z$AoOhD)?qKPrszj^CZdZUKq)ES}zcE=;*mX_D9cyoJ9;`l;_+G)4L**oWF=jYB19N z+3a_zpPfEs_2AlI$np@G(fpE(=7-?3mr_)^lFCVDlV`5$sccY(>FX-&YAn7y&3xK0 zuv&1H=iBj|7>E4IdS&@fed|z!Vv@GrJmh~2?YgYD84?(D|J14D``wc_LPIUi9G{*u zYIqVSQJ=v*`83U8KaCK5-Fl~NnfySI-Jo?bsx)9be)Z;01$o8GD$&j!vG(kt_CH}dP9;a8s+62A5upqUa%0eu@3VV-I!m7; z?(C-<3ildc&bE-N7SkC8FQr(0bRQgH3nSl@ys{X1{u>v^rN7@oOJ+Uz%-E7qEk!4PP+tT?2gtU+*y2!2ws$|Iujgm0o@GjHP z8;rC#8=ubpA!Szi5BCW{L6NuR8;CZRb7f_p90!>Qr>?O!_TQ2Dr7iPbG3#5DywtdA zqEcFyOSw-@Q_GWbU$bpUCUwKiWR2f6HMQPYv+Jz6Cq#w5Ju7OCRb_W%G=JCU;jb!& zt}QI_zN#=k7;-lgCDKCG)6Z$Bs#T$W{jpw2$8VjswvfMz<5XnDX~VBQ9=s{K!LNHJ z+}s_G*GHwdRq=nme!a-`{%do^u48pITNU>8M?>!oFc?l2K7fM_@77Dm^YguKUzrn6 z&aT+D_jxoZ+`xeg;v!S67D}xtje9Ba@gnv@&8&)w;hv4G?i_^pjh|6WjD$x9+S~me zpB}sHo^I$)ac-zwI98{k!e3r;S6(;$pbln#?Q4`*+TVt$aY59CTbFBV(jIZ8yy`6F3uadl{7QWkXLUzIb{5&OH_7;ws(=?XhFR6hq#^(ycTiZGS38pf*NF2!+$UJuIW_lrI(L8 zJh^EhGM&XK-l6v;i&4v}%t`CPnec~}erLI~t+)wUEbRV$9#T0~%Nfw1E`pC1w5|9j)N&_gfT_%=^}3-(xTaqF7%Oy<5qr`tvL z^;2?R$iE8;D!dlVSePAk_Efm0d}NfS`_O|1y4c(9m{MV@(>6svC90yoUfYqqpM*WD zE}Gt45!qIF^tr~-dHY)~r&46ku8P7@fOV#t^qS`w5<#WtTK!kQAYoz3{vtOiP4kd% z@{{KW^t$`3i;5q#ur^+?IPK)8;x1{lr63-vX-!C&Gx=Q$js4k%emkv`trxhtL;E}y zKZtY=)TZ6`n9bXPzgW}MTjS}^s8ziG?)n!&oh#bMG!?m**PX=iOQgg7LjE7%;i3+idODYy}~$y|J=g4 zMNb~kZWA=~2j-+&zoa=`4hTzsjQt(S)RvGic*Mi~i(8}O0t|TBZvW%^Vzcw>4qxFzoyZ0XVHl}>3C?SDPi#UC&W!t{-`hh`hZI;lVQhZ{Ui_T$h$ksH3fT}P#t z`Zq0!zVBlb+)RhH{qFRA;PfM{J14Z#;g4{dH@}Dv)Mds#THysiTvqa&fJ{)hC@W%0 z?MjGBZpO0Dc4S^lLjdzW1n|>o4<0yf+E@ez=W$J-hbImJBQ)uaR|CHN%rj6{tSTgf zidM`&JHgXX9b8e;T1UAppI_}S!}5u(n%7&O9QOao=b8Dp^QL;q$>9;XpnEeFuobs} zj!$#jBsO5x;@`-}$h$Jk0KaPFA`!xuVl@!~lSlcM1p&(hYCQBr6R=}wBzQnAFXl-1pM z{r==?Lmu8nA_x_s@@6cxU#|x|mhfpQ9)z1@DMOj{EwD8{Y5Xyz&p+HB_A*v{9ieuz zBTe!f9@dZ&6$JAVuX)*rqz_{LarK*l5Gv2{+}fXy;W5!_>cFa?Ya%vk;Ja;;ee~pZ zuo^wM=NKQZo08&ewCy_bbG&8Y%MUWwR-^6ukrdff`28+%T`x8MA-aw}J7EpQxAbE|oj#t0rpSG0p)y&*HVeoJjJw`iDOMz1ih6q&ef{c(`CtvM4wn|Xr&FHQv zJ~&@#;zFfmr_+PI2C#6~wRcH-Ut6nxc=I~w8UiM^&r?>s@`3-^g(my(@x@T=JI!PX&NPh0eNqz^$8bdlj1t?)q#Lj!p18$Z%>aW$*!(V zz)BYv@8po%@g_lqyTu4)t?{WTjjl&I$Q7=nw{Kl5gGwOGpEyq{n9&CleT_Jhzqob& zdkKw*7)U`PTnE&>=F3t<1S{|Uf($n^MD6Z$?Hw|dV07lIemYs%Zj(43)vxO)ZmaShG)G+<5)U{&Hd<`J+s>maDEdV-B+Xz_{Y9U9`=}Z8jp>;g81R zbR#z9`ZK@;v~72h@oXxs2RtyMxow{G#f+o0PAONQDE1_SZjSXeP0ih`0loZqSl%o(@m} zsLt!xZOX@HJZ@)=9-&grHcv?*jRxj#zl)Njj#pH+iMg>kk-o=ik7z@LSz9fRFVYa|gML6z(XWT2dg-k~(!@fAg2NZm2AJr+ij+{#@G$Js=bNWB}$4 zwKe`D0JyB{_2`(-Qe%@&dlN@^{g6PVG6+D|GX?&6b@#hp%;?z0cOBX~z5Lp?$`3y^ z(oniG5%>FR8X&PHC#m^8S{qG5;eiRkZ*Vj(}yYCgE^U?IJ{C?Rd$iWoq zX~Wb8Zp^?}nar03zJCbPPb}^e=_&vjJgdriu42p(hPd}5vWtD}`VlI|#C=!E1a?VO z0uoX|if*$abYv8k(<7uTe0sQI>a$UsC<24S{J@rcv{Jvzb-yiF5Q9TarTBY2+H`JO zX@tkZH}~L(|f`gf1hB+6D4&y`wrDuN>0nH=BQGv&}gt;h}e8JDn3j~s^@~HP=w(>uO;8E zNJHsS*r~~GI}9QhcNkjH`G;1&LWwwK+(=Zm=b#E}kNotmRy*M7ViHH3h%HbcT_^PM zV0jIK5bMda;iu>DLOHo_APWh(JZ{80KJFx-DQoi?f!Id?D3KA7gMo#|k2y!o#^ zg}Jhxf;}GqCHmyM9if=-X|jJvW$KZS3BwPYW8Gs$kZ|p?cZcd$#j2Qau*l< z{am;vcQL?`d_&LMKnpaCzE2h1ET3-?6mPIt@TPXbM#QF&`JxLptk@=Gz6;~6m*bfc z4P3li>mVixbioO7Uya(V^Vr~`teoZ_!vyEo7^D5wQ1lVJ1@i;cl@ z)&pg1uY~D~#g+bjlSS$2D?ZJ>YS4sQ4IIa?+HSUx*=WCle+cDI`WO5EgIcKhMJ3;PTD=-F#yCB8Pb=fuBNK>)S12 z6OA&V--E~!F`~u9#5Hgsnavb5%6#tTbt^*j>pTDD08trvaWy9v6&c`yud4BP`_XarM5Juq0ecXcW0!h5rNLh#==1PfihtUJ95+Wp!s zc6;2TSoPMi+GJy=hqafu#bCuZ&>(?5fW739;^ukb-5-X!NrJx75CbRk2lab+|CqnM7RzqROsFQ%t0cb>wI7 zsy2b@Cswds=PtPbsd7<&7b?R$D}>Zl)_J$~WFXCHddm&L*YZt=W9zt)CB#xy%J+xi zD(uOH`x#yO_nr*J&`3%K1F}5@R&$qD z27K3F^f~d0RfZ;)R*GpP{_uE7=WR7NqZrDH%6^f5Ee}yFALkT|2BqU2D~D}0JHjkH z-1$3Ni^_nR{F=K*A6`G>Fe%Og`==sx{T|O&Xx2VDQ}Fceh`+J?X;#U+5rfC`__Pz|rB~_URL z;phL9H*_K~xeZ&Lv!u}eG}3z@wMwwprx%zTu|Rq6<0*oP^X9Ez+zD(7#in(T$6|`x zjRCM~2hdl`N1OCk*)xC`yXZjQk<PJU7TK( zi!?uWUo2^&_dJQdh#(5Q9vKq>B1&!zeM$3gDYF1Iz6T8JyI#|6DqJdKoOuoy_Poha zJufM9|L@z0UaiR9#Jt|2?|JQ!IU04uiY)%otYO{Ts!o+R^MAO35@Q6p-$?-8f2b|uFFaq|=V$zKs#+fWhdEx=Kc5I* z(f7}uT0bTHyxBVnTurp=!22TJ9utoBF0DRf3+3M@#8$t!{J2ena^1Dkv1WDM66AI1EMV@F`uw|5JR?Ep)`hWFZ;YG3ybJK;chRbuDJOA@*{g+by z@hHR3!+?@g!(LYKpQxBbO_h4<&YhXt(PBbdJ^aqxEGw4=K~8?JW8KV1Xbl|qy!dpA zwvqjEa=b+*Y&1(*O!qCm*x!F0IP1t9_sscNPy#m4734|#Hp`jWb?-|uKP~*xGwz#m zcgZOu-NM{MhtogKr7se% z%N>&2a4k{ZlH0|8m@^J|MA7uHai5C%-i(AeAI8PWUmNa)(!Bf~82PDEKOU}`Uk^eO zEp${% zpJmx5R{LZ{%%a_phuW@3{x2i~N#NX}bmOn)eYt(#eMzc`2EYZ5b z=CF_f7gO$r_nyGbC+lAp@`_lMwr}00LjVk=D)_I&nK#~5ggChG_g!X4B>wpPmOXOj z%i(CfsAo9}CBBu|&p)b8Aw*l#kS{Qi9)^S<-j+wVq(2I%UUckbTMzX__cb>a(A36#G@p2y<`Tzmh+oG7A1RyY7@H zXgz$TR&**N7@*6fc5lSmG!8FodV(GH+=7GrQylUdT!VjRzBREcz>e_k~|dlg`$(VG1pluT<3PD;F0lP!7J zP<=18ZOUC2--~Sl$n6VLdK~U!6U1xE8j8hLk3ghbJa=`!QlpKG5qQfa(6dgXuNo;I zaa)Ae7m?lnVJnpG^zFtZh&Pf`M0PXr6a8D>-?HtW-9EV+%h~r@OMG#K2Nyg_yqSwm zX<7ZswgK5#VZdpqRfsF8lSxwHB-G;zg4bCcCQD=<*v%E4{#ss$MLpqgaB$>h?)ejz z7m8WUFH6*9eo5*BaTC@MCI_D;({ym-J(AVqY2u9IreC9d|G+>!2b-0d8NQB-nsa9d zAWN4q`;pjGGU5S*Pjfjk?$4%g}-mvvdB8?***5qFIHlihO3;yeXlMt za*cNvx{N$)In)*NPnw_BVUD> zWBNez4toNxsG0=}$E@PN<{wA9I2$pf55j>)!tl;GmPl2Jlm5P!qHC>d3Gdg)ADrF+ z^0r++ybEeEf6_gCECaTRD8S0nq9z@s0*Z#HZnCEiHzy_amsAKiCZ;M4xcCQ(S`G#^ z0}=KpHN{_t#Iv9e9&0VUJ`D6oe;3}sL;cXy&O<^dZ8_?L%$8yu&7i>Y$9^atLRN?* zqGxftyNBB!;bcL7Z`=z@j!T(Z;OmOF(1>>&^kt}_DUybNPT?4IdDy1(CXic0UCIFb zyx7Oa!ZTsESL6@x#wZY6Tck6 z|HRq<5)u}W|B0vD_pb~%{r;LjJ7})>y#hf_QiT(zHrAT9V@;L&G@JI1_U?)PV5q3TQ3>1S%31w5QFV{?XD z8~I>>7^-81on=5mEr%tSpwT0)BjrHK3e{iECfoJ1@AVT7oXo$+o$WvSw4;dB-#VxV zT0I&y%Mq~ba9^NEUJPgpUVK0I`x!`-s;q&7J(rC=R|kJRg<6CQdY|ex2CwZ5e@&t4 zbW-nVXiA+w@X&3!UX!^7{I}GPEx1Sl@_!kc%k5wnH8Cd~<2Vm}lVDb&cBPO$xtSvY z&Mgt8@D9Sa;$dHCl3u1Imn<$k7qw{`z#`=i6*^-68&*9_}5* zt(y#(D-%FrKYKM#g2uF0O}HWi?Kv!3a%8bBvem|?k5PS5usm8b4uHO59OkRo9bxy) zkPq`#7Km@J&SZhPsHX#?NnRJs7<6Vs4Wz#Gb9sI-YNx2SBenZVnk}Pa7>o{lDw7lo zipl+E>H)jV#(X z_8;lLNi>t>_v2;sz_4|4o6Bi=+@;J-NIndnbevmzX{{Q?FiTjWxeBU5@aHCE*AMiL zuGNoXuPjV;ySRE=NBgEvTUQ=#dX<>h8Hk9H$3*^r^3c^PY&bJl6Z}rrS!Ns*ZYTU8 zW#>nQu-YK008k^FRALsXw0JV{V@$)^T0_-qGF#3K9+%c>C;ot2YSZ79TbiSZsa6<; zXiaf!`H(g$w14bdm}@Qur%{F~gD~v>Vzb8~uHjByB=t1>j{#q)GF#$QNS95wc;bSM z%XS}=GGRPL0BQ-X3y~T7{-uGRDqXK+Qe~!mu4k1TKv9-{YpIIHp~KutYa5~97ewJD zbE9KI=WZd=udNV8S@#Oz;WC zpkSr&%AeN3Os2-7E1(gtN8&Dkn-&hb z%ozzllrFH%TmzL*i{%E8Dr!s24_PU^ZCtk|AzFe}VR&ecvJ6@x-J-Pjo6D8=V!Pbv zjT3o%>=yYIe@V4x17uF&EY%56o1g<~&-7u#OiB0RL6H#|{j7;`jo_aL@;eSGDU5pT<50Paa3Eas^u)PN zrpj+~s1j-B{ls;Pz0qs?kZ>q9DXd%k;kD6$C~iWO>aRRJfn8#&i$nWML2B_r%ey&h zF97lqR87@U8j{~F`|B44FifRiR_?_`pIz;MGtOWHw?u5b}HE|8OFKadE)A57uxVkbU)Du~eUr;x% zH>EE#en%E%&WiAh`8&CWJ`EMSza=-s^kC0S>sw~YCH9Xc2VILgT9^x|O^I%P8-R@p z7d_^ZmE!w#<&rAxTy;W5LDWswy99k7N%tw~tXwCoLB6=sY_C?h22({}y*kPk;zO+Q z*`9q^3Cr>y5P3WNIws*SOsz45sL%n(|^6^pup|<8C{JIIzCPfKrOQ2 z>vEGvPw+eC?ff{t^Lr+lV-wnPPdldWNJ(<&m(-!ErC3r1eYhDY$g5nTs`i-ta1wZa zE3WO%?K{JVBVbYXALiiod$-*xef4DD1+z(*fx8;_zgdk)&BQQfPHdf;%B@AA2IO8& zZ-m=`bp4oT;(g%Z2UpHPa-MHOBp#nEx#Je4gZxBgLJl4`J-2L&RJgM#JE-jQ55n$| z8v?kQwH%393iK@)OHON`;bIaCCyCv@LD&&{KQ>hqLEb{R`z$08SSBpem~*g*xqDU0 zzi31CbkSDNvP4gdlS)z-HC)arrM?E=lEO}Qq_l0eTz^n#prKh~T=(hPKT~p4_S+I$ zXUZp4MCUe>mr-5kwKLjQW)Gc6~8CAIO0EX79IUEEIdnT z=sN={oY)MDEbnzJmbI*4-1M{l_6;Ay1aE8Plo=yO%JG4<@h<07b*dTQ-)ASK+f7wj zs?cf7<<0c9Qhx1uQ=lA#BA7>3s(%8>F1-m;cL`mP36#|&`59QZF1eo&I|#Sd)btnT z*}P%X3$n*BRjxZx{ISLL+$ln`|18fNW;qUfrdF{)U2$|-@}1*UuP zk(krVR*Yv;=b=yhk!L|qGF%xnbfRdY5SC3`M?j zeB(&KX@_hv&%5Thc(oZ0&Ler-vr9HE1|2&r3r4|c1caX4j}5eu+=Ok|Z1s_5D;if7 z&$r_(iAsN@-W}=(xIemn+(=`UZ8>C8Fzt-93BL+e)7j&=#hI-kom!Bs0aQ~{u6ZyV z$iWQRT>L>Befdw48e8y}Cb>NC#m|jiTDq5f`dyC<7f?CMPZdlCQwCkr zWu2dhCzKfm@Sjetu>)}fpf~bVg^7G3e&f3yyxs+~ce$}bGnUq4VsZm!9q~rvO9ZG$ z>#vCI+8u8D^qE9jUJ1VFXPaY$_hW67i7_A7wmj!K4YkiJ{p#)eUv%?w?eA~bD~Kq1 zr{t5);z^dhp#^$pI;|Edwn}n40O?zht_Vm)gHuKnV#57b#z=M-RLLV>v26D1e1kFI zpTs05eU!U1FJS$>9$Rymcv)zVm&0)sTs<8+s;_T?uPvmu=d*m`Ns=fGtQkWUKtmiJ z^JQP!J-8j#?jNs?kzbad+13H7v@GPkJiYj}*C2|r;*m&PMCUl8#Pv=2;UnJy&hAP- zS&;rg6iE|2YbROqh<~6ubz43RTkeR+N*@7{;A1er(M8NuSbB>KkS=>>5hSlG5%}Fj z^y2B%Lzt(N%gaaK?%fRZGzt){9l)vVS0}75RoY}uBkn!NRa38h5F(Cbid%HNMa!B0ES|1$xo|j!eOU-NIaj#!v`Oqbs{ z;djPQgVUr3>1w5f62Z`>Bm+6t$v!Nj3rF(HZ~4vdORjgQZon44*&E-1TC(`Bj9y%S z#=evDZJU~BNe46W%rzr{N-*_47xaY*(VlniOQXuA>j)j=1i&G`d2cx2&2uVqLr(i8__HSMCIj<%sQ&~fE z?a(Q}jhl7kBAmDn?SwDN+koyuk|;4>jQ#!V6qMHmZ&_-!BUL#vouyMLZiW{SfoCCG zgo5qyaT2>p#N{I&5-3WaZl4go#LUV;VrY2(5LVb7sENz=pUleB7%_v*>MBY|NG4>u z6nJP>`kdn!synP)_{wVD{W2Qd^ZN4~`~0-It&fuqo?Q;bi675F6laI5 zIC$^QH26pS&Qn+Sz~OoQS{Cw+uA6HWBDiAusZ+Q65K3$XYtI^ou`ut2F+uZ1wgCDU zBfqvqNFx0=YKf+yP2kz>MI%EGg*CD9#c6i!4HtQGF-njh>f_ZKQ-97suvH-RqoiwkEuX2HSI zfqG>2>BQDFBj2j@b_-jhNtT*Te*p1)L$+3K3vE%s6e>Aq?_{@ms;Ad5AeOl_NdxXO z0nT*t+SU1`lCJ}=$&9tz7IH?4tJkX!vHyLiAntkZmpF%h40uqO8y>`lBv67>=RTFU zv<$e*b#FYb~w>*5&wU+#tH1dw$1_5d{X$(zs!H6IG-nMN-H+k+~{}r+mSuB%z$qpvCJ4U%AoQAeZBBPM^|VJt0d_{>EF`Yd#}w*RVF}8|x!a^FZw-eM zyM~QTU+>lb^Mt@&0t>u2V?ZbT#S3dbZUD|(y17ekO?r?czrS~)<9$`Ne=m9FgdKai ztv>or*hC_gOye3~x45>*a_gDo>_UI1FsQfgh(k7um6aV?rUQCsCW(GKG!Y)#Kr^wO ztRUz4-347O*Fg6uPxYk3P zPSL~ny#W;#l=gBq}^QcCD>NQ(o+1>bOaVc6;Xb7zt$uozhYVmP|KXD ztpDz(!-EV@OAiHMX|`{B6rL0O*)BpU1RbziL`0bQhdN2!zG-u%S;-ACv^X=zS=erP z%3h6h>uU^mrdXq?R+~lp3aeCmL^KKBf%Rc?))}R}RJO787rTQslL}BbftofKK2w*B zskP9e%-7hNB6IeeYfS84J5J*qII888`IxxdwFlz{bQXzcj~b>jWF#U@-F>*ThOW}q z|G8~^w3W#)63ksAauaE(#Zit`Wj{<9zXmZqayv#5v9Ek0z(==qQP~<|WVUN<`;=v=Op2Y`TuG2sA?_oUDU(S~l1HO}DRa zS8D9KxeSVl)P-3DvI(H8^PIxbZIuUkCz2xj0addY37Kpb4Z1r@s@HIqwaR76(^6GV zbg|~0DL26(rxLngy}v`9<2EoBs0SSy)l<~nfqw2$A82Wx^0iA*77XT3Ln8Yhg0e0ARCA2(gb?+%*X87=bZ0BFP#>&2lH0-DbALg!>GSrs-x_U8-_2sn zsx^U;vhpuP)Mm`LkF+A8!eTOL-Jw!5uCfmD?Z1glEr}Z)D0|yNA_3~)@LVoLb82hr z!lgm$ZSa$48EH_DP7BE3_HXQLgbFXOvJST{-cW6}oV%VeMdHn-V?~JjwcLqgK6rxp z!jK~1?+s%%bV(pluLL7;8aZ3L$?@(zWBU6&2uPFaXDA;%veiYL0 zYA8WN2QAvsIqvl0V`L?*_0TY>+CieHP)myY1h{-DWRyvj{PjoeldXpmOgE1gKnyhI zTag#a*CL&rH-q{R-hs2^8EIs1Og>*(LoIwY@aOBnhCQ1Wj~H5gn}OjM><@b5 ztbcrAwYg~^n04<(EaafpLEES7?oFmVbxW43(!}goyov;)32}B|-ANu>Z=ZmyBEv&k z$zh<_f(ENvnAW^0nEPh1&8LoGaT#~*?q*eCC&F*W50sQOK8KrF=_=F7pFgU21BCIwh^sD^x0BUATX$yz4^blSg# z>!*gQFEfs(fakF`9l~5=d~Y~C9dcu^nA|;19n`2?P0y{shIq-4=8l41$&B9rwB1xF zCKLexsF;MEKH`pJR07-iN^C4}sp0vOj!meT3+XywI0scfMgT*r>!|=4QH##sN%D5! zQ=iYSJYjF2Z1H>fNHcLc!hw*-Dqu*iQRllKh$4zMVc#rq7@haRqwM}E3jm~hc_jEu zI&mP4d%wB(XG~tfhQIscR(q<5uTFw*h}`&{S!oS0R1-fQN1*kuDJaU5jXK7B8x#xo zHYE_jXgVSEow)VS7aD@)5m>I9aG>A;PEhg|jCAgx_~`M8RYLOO-=)^dJDA`YW)*!ejz2oKWuxvOnSJ3D^XdG#n*}k|f@@@=D4x^);hsfOZ zkHQ#tk8V^2C9Z3H9^=L^@ndMB_G`BvDGu)ZS@OKB8r}rbM#Llp)Kpn{_>CsXeCVm} z%`|CtrV;0wGm2ddNYMC@>+TTc{j1d8?emESfDY0O+o?@dOSt}Tz9;1V;0iX#rP-5q z|GGIWaB9fjMqL-IYqU8T0VSIlr=gDP0ky4a1D^0kR?PVqRZDJR`RqGxRBi7=i@90P$b|ba;&GC3h zVfLQs{s)b%_&D#AMY6NS1pH)8-_yg2${!>DTr-_sya_kqg!F#BAvuQ2h!=DGQxg&@ zStc+6rtNoPf7Oo}4;&_p%^9DHfOJ#s94xZr%P-?W^_HYc=QwQAFJVZ+Z2@P(+3uqF zJf3$cNHDlsYfytdtH@#9O!xU1Ippo*|I5oAms=dj^O%&}Q8KCOV z_Qqc_dsc+XJNXk*=Dd=3acEfAi9Jv()qBo;=Rc;tq?X;yR;4Gpg9g8$GJ1dCf|s90 z`iXNdj)&#M@=a&i$ZxOv%d|bS-K_NZ@He>*o4EUs#zrW2x1NZ;ffhF`h~YbV=8@x@ z%IK#V>h47+a2u36Ju8-&ZphI*^_9|d4tzsWk=W83$O>0X2bom-+*s0R;3=IhkTE|qpC z0{iz{*EV$cv$5%#F6!#5(JgOCEN$aJxJ{LQ4o9~*b_pVK=`7f`3eyE&c)B<^bbXxl zU)y~8W(q=KVpWdIkhc}tnl3JqiBeP2FeDlbVeF*9?0 z5gjXR3c_Xg;>uk;=126YNJu;^P^gD~fVzTOMa#lX*5>e$3VqGvM>$P`05Nh-s%Vr< zZZME{a_x|HB~g=?AyKWkb%exskJ)HH-393qNVw|0HB`-;VlGFupbS*~#6hVtsCSQ{ zIZP*i)m#N{n5xo!!x7GvRXi?Rf)SuATT5FO#SJPo9%vS51N-oOJt=QUq!bZeo|~+h z_75Oi?BK9}6+iDaH@^V(w=jwRGsdDWekGhgDQs1@ZVt_aXiOf9XK0G$l8f@jw#x6; zrc=vumBEfZTm>$^-aVLsil)<|^Ac&TuoC zs-ntJI8MW(`$Pl7H(723QV20g)*Jizidlc?6(en|ohBLQO(9=)HXu`!Ienek>|N0J zpKb2Ot`Yb;`%mmisKWp5%nf{Z)vsg9=qIJr7;mT2-iP8)i2U_uP4F#d)KQlGn67DqF_)!-v17iaF5{u5tRyB$dTzU1K z_eIR>#l@p}a`Ox&6qTd1Jl{Fr=F;OPbhzBTH9Mo1sal&_4;0Y!cuZy0Pn$mScH7gm z8XD2vQPwGBVc@@0xE|3~((N~fzBJCYb1pAZ+X*4u9mRWA`t+(5!+fkllQ zAA5d=n@XZm@M4EAmRR1DJkMDEZnPAGU!yH3b+&-`Ej1$HLtDqP5u`)oA+@~uBjOu< z*|WPy2t^5hN6s;BR3j==2}@(c5N}V~&3`cmAP4WB_O#o)J<|Ibt|(dz(c(ngv!DV< zye!MvjsPHQ|2@*4URI_%%^UG3N###gF%FyQ$*99kHDsWLL2@vsl&IImar*l$tQ|_5 z7L)q7IToe`qfK`tQE854=6%`HTTsKB{5!#H8%P`1j>lw=U^XJ*P|T#*wJS9 zK)WQ9zuOG@P*sO69i|0}&Eb7+O>q}xp>-BIJLWW>ns1f}mPE3hCgbTB8|@#Y&OUz- zC#=gEgMbLjK{t*rtOU2DQ`4LChBu=Cf|!$}GNjKU)v|zpWgO??N<{4A*HE%&SelkR z1zBmJIuJPA?2HQW|5D2@%7ukdz{oin%EA?^j!6$fM~ z&yTPTK#~~2e*SVxhKv90wzL*Y)CF-d2kJq3R@3ze3pzgd)100pXV5NR{3tttN}Gby zMZd1%>}CVID)@t^G2AaeHh&T#dyo)H0+xVc#i^?BgblBa)Z>X>P(GC2aEz1li%1O7 z>E}X{8yH-$$|0~YYwcc?N8+87`ur9In_PU%51^>h08c19jjPuI9i^`EVFEx$k4PvK zcs-wBjfuMxPGSgy0yt6%wg(q#lyxaOEjUb)^#8p-`IH-X7u^cw@fPkX#qtj=@`|52 zw=aq57b-K$se<)JfJHGjs|(Lzt#8!Zw(3M)CTloS967vJp2u|@?R1E2HzRhMS{oH?i?a}C+VA>&3Kbf{)a%};)z_1%bmp3VG zFSTGm+`@Z&{$5RU9!1tIBy_h-LUU+MX4vRjzWJF)@~G>E31^BiRp5ZHu_!X%)CB!; zZPd_vR}++Xt9bsRsQqZSiM13YGhv2<@ za1CSHA*P7y2Ap3ejHc_hxNqLSApPZDfQ2sEnHy2BiGfm-@*x#;Fv|?|R2?`C4 z2gC7Pv%YWUd@Q#3(=C{~%W6yDu}36h=@Z&?hA461?)87*mV>9F+D4Bty4tNXkAttj zZyO2aY<|q`77!x%`WF1_s;7=$UWi|sjjeqg0-N#_lml;8 zA4uS`fIr2OLWHF91Y!{oI?WX~h?X3wA9xe>n`^XZe^CWRJHi)i^mMu3_ygU}0wydp z)0tnMlM(q56Hw3qH}#6!;FedpJRG!TncQPd3x)%SD=3Zlu{*y6?X~*&2{?OP!UT{{7@c+%$nW^X(-!c8Jz*y5Z}k)`6S-kGI~EiK%?HrB*qez;bXl!QlU#f z4Crg@aGDw}D|)9U5Ku5fxp<6V&^3>J!D_2Kyk({j+1qwh3Ve)aDZ^v6Epo@3I)J+epm44^SABWb@qPPj?KwAxI1S=`$#nW-%Nb4vgwkP z$mPJKwY^&U7b5Jxo7^9srTf99Hy$#BmSfTd;f_)vtq-=wE7&K7##y`@i>GdwYS@yS zei$rtyfM6;~ATY+72f7D<>qr?AI9`yf3Qd1u58F zC^M6)*)%ZRqE)dAU;tX1tCF*`zX_Y!gY9EIlsIB>D9j4!WVMF&StOxLxUS}FZh@3r zwghjmh!K}&eaYEEEHk5F3>@3>JV@QreS&iRk?QOZ3qwhh5L%eFCVJ7c zy>dHmEcDFm8duXlQ_n$=GFc}SWbKvVzI3N8@RdiqG6V2VLK5&PzY&cQi$B(7|K4b5 z^;gU%HursOcyrvJLC9ab3q8SLF~PCx$Fbp|n5aaVcabu8EkX|2rTi-vR}k)no53?I zphX@2=}4sB8q4hf!H9^5|BsndY*MIyHSwFC()N8e-4you#mb;AdZ;f0c@JfK@S-=O zmn8}3HXJ;liTD4bw%p)T?*c_@fiTai8R>z<;4|A zYq3U5|Gb{D_g|!3+B_Wi&!fZa4__X&QD7>K$Tia2XGhyId6!#gH#N?Nw>xf>2MNxb z#Fn!``hsn~TnkoSFtVQtR?k-oOnLylyK!sGk94*A1!;UF{jG@XKgKbr(-`WJIJyr@*l2Z!R)(`iRC4~2 zzeq=~rr5kV#DAxd+H?fe@+V4?Uh--qZr0%mae@;7Kykt{2oopFZ@hcyyHPE)tItR; zGN&WGqcpE=!m*PD9;X6!ns@JW9B-f`UDCczx+Br$iKe@&vj6@wD7)$3)1*G|zX3_m z95jf+eKr|LcBFwn|8F-tgN~+SaQq*?`w-h;_5U8G-*!Q}_Hp}mgIwt8>gTe~DWM4f DR?iq; literal 0 HcmV?d00001 From 8dc37d34152e68d6e65caf4038ef089edfd8f703 Mon Sep 17 00:00:00 2001 From: L2501 Date: Thu, 6 Jul 2023 00:11:23 +0300 Subject: [PATCH 049/145] [script.module.chardet] 5.1.0 (#2473) --- script.module.chardet/README.md | 6 - script.module.chardet/addon.xml | 4 +- script.module.chardet/lib/LICENSE | 504 --- script.module.chardet/lib/NOTES.rst | 140 - script.module.chardet/lib/README.rst | 65 - script.module.chardet/lib/chardet/__init__.py | 100 +- script.module.chardet/lib/chardet/big5freq.py | 6 +- .../lib/chardet/big5prober.py | 12 +- .../lib/chardet/chardistribution.py | 148 +- .../lib/chardet/charsetgroupprober.py | 45 +- .../lib/chardet/charsetprober.py | 74 +- .../lib/chardet/cli/__init__.py | 1 - .../lib/chardet/cli/chardetect.py | 90 +- .../lib/chardet/codingstatemachine.py | 32 +- .../lib/chardet/codingstatemachinedict.py | 19 + .../lib/chardet/cp949prober.py | 8 +- script.module.chardet/lib/chardet/enums.py | 23 +- .../lib/chardet/escprober.py | 45 +- script.module.chardet/lib/chardet/escsm.py | 385 +- .../lib/chardet/eucjpprober.py | 60 +- .../lib/chardet/euckrfreq.py | 3 +- .../lib/chardet/euckrprober.py | 12 +- .../lib/chardet/euctwfreq.py | 677 ++-- .../lib/chardet/euctwprober.py | 13 +- .../lib/chardet/gb2312freq.py | 3 +- .../lib/chardet/gb2312prober.py | 13 +- .../lib/chardet/hebrewprober.py | 110 +- script.module.chardet/lib/chardet/jisfreq.py | 4 +- .../lib/chardet/johabfreq.py | 2382 +++++++++++++ .../lib/chardet/{compat.py => johabprober.py} | 41 +- script.module.chardet/lib/chardet/jpcntx.py | 219 +- .../lib/chardet/langbulgarianmodel.py | 1061 +++--- .../lib/chardet/langgreekmodel.py | 1061 +++--- .../lib/chardet/langhebrewmodel.py | 533 ++- .../lib/chardet/langhungarianmodel.py | 1061 +++--- .../lib/chardet/langrussianmodel.py | 3173 +++++++++-------- .../lib/chardet/langthaimodel.py | 533 ++- .../lib/chardet/langturkishmodel.py | 533 ++- .../lib/chardet/latin1prober.py | 44 +- .../lib/chardet/macromanprober.py | 162 + .../lib/chardet/mbcharsetprober.py | 62 +- .../lib/chardet/mbcsgroupprober.py | 19 +- script.module.chardet/lib/chardet/mbcssm.py | 813 +++-- .../lib/chardet/metadata/languages.py | 574 +-- .../lib/chardet/resultdict.py | 16 + .../lib/chardet/sbcharsetprober.py | 95 +- .../lib/chardet/sbcsgroupprober.py | 33 +- .../lib/chardet/sjisprober.py | 65 +- .../lib/chardet/universaldetector.py | 236 +- .../lib/chardet/utf1632prober.py | 225 ++ .../lib/chardet/utf8prober.py | 32 +- script.module.chardet/lib/chardet/version.py | 6 +- 52 files changed, 9043 insertions(+), 6538 deletions(-) delete mode 100644 script.module.chardet/README.md delete mode 100644 script.module.chardet/lib/LICENSE delete mode 100644 script.module.chardet/lib/NOTES.rst delete mode 100644 script.module.chardet/lib/README.rst create mode 100644 script.module.chardet/lib/chardet/codingstatemachinedict.py create mode 100644 script.module.chardet/lib/chardet/johabfreq.py rename script.module.chardet/lib/chardet/{compat.py => johabprober.py} (50%) create mode 100644 script.module.chardet/lib/chardet/macromanprober.py create mode 100644 script.module.chardet/lib/chardet/resultdict.py create mode 100644 script.module.chardet/lib/chardet/utf1632prober.py diff --git a/script.module.chardet/README.md b/script.module.chardet/README.md deleted file mode 100644 index ee4d482f5..000000000 --- a/script.module.chardet/README.md +++ /dev/null @@ -1,6 +0,0 @@ -script.module.chardet -===================== - -chardet library module packed for Kodi - -See https://github.com/chardet/chardet diff --git a/script.module.chardet/addon.xml b/script.module.chardet/addon.xml index 56243e20f..972a04e58 100644 --- a/script.module.chardet/addon.xml +++ b/script.module.chardet/addon.xml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@ The Universal Character Encoding Detector LGPL-2.1 all - https://chardet.readthedocs.io/en/latest/ + https://chardet.readthedocs.io/ https://github.com/chardet/chardet resources/icon.png diff --git a/script.module.chardet/lib/LICENSE b/script.module.chardet/lib/LICENSE deleted file mode 100644 index 8add30ad5..000000000 --- a/script.module.chardet/lib/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/script.module.chardet/lib/NOTES.rst b/script.module.chardet/lib/NOTES.rst deleted file mode 100644 index 998db58d4..000000000 --- a/script.module.chardet/lib/NOTES.rst +++ /dev/null @@ -1,140 +0,0 @@ -Class Hierarchy for chardet -=========================== - -Universal Detector ------------------- -Has a list of probers. - -CharSetProber -------------- -Mostly abstract parent class. - -CharSetGroupProber ------------------- -Runs a bunch of related probers at the same time and decides which is best. - -SBCSGroupProber ---------------- -SBCS = Single-ByteCharSet. Runs a bunch of SingleByteCharSetProbers. Always -contains the same SingleByteCharSetProbers. - -SingleByteCharSetProber ------------------------ -A CharSetProber that is used for detecting single-byte encodings by using -a "precedence matrix" (i.e., a character bigram model). - -MBCSGroupProber ---------------- -Runs a bunch of MultiByteCharSetProbers. It also uses a UTF8Prober, which is -essentially a MultiByteCharSetProber that only has a state machine. Always -contains the same MultiByteCharSetProbers. - -MultiByteCharSetProber ----------------------- -A CharSetProber that uses both a character unigram model (or "character -distribution analysis") and an independent state machine for trying to -detect and encoding. - -CodingStateMachine ------------------- -Used for "coding scheme" detection, where we just look for either invalid -byte sequences or sequences that only occur for that particular encoding. - -CharDistributionAnalysis ------------------------- -Used for character unigram distribution encoding detection. Takes a mapping -from characters to a "frequency order" (i.e., what frequency rank that byte has -in the given encoding) and a "typical distribution ratio", which is the number -of occurrences of the 512 most frequently used characters divided by the number -of occurrences of the rest of the characters for a typical document. -The "characters" in this case are 2-byte sequences and they are first converted -to an "order" (name comes from ord() function, I believe). This "order" is used -to index into the frequency order table to determine the frequency rank of that -byte sequence. The reason this extra step is necessary is that the frequency -rank table is language-specific (and not encoding-specific). - - -What's where -============ - - -Bigram files ------------- - -- ``hebrewprober.py`` -- ``jpcntxprober.py`` -- ``langbulgarianmodel.py`` -- ``langcyrillicmodel.py`` -- ``langgreekmodel.py`` -- ``langhebrewmodel.py`` -- ``langhungarianmodel.py`` -- ``langthaimodel.py`` -- ``latin1prober.py`` -- ``sbcharsetprober.py`` -- ``sbcsgroupprober.py`` - - -Coding Scheme files -------------------- - -- ``escprober.py`` -- ``escsm.py`` -- ``utf8prober.py`` -- ``codingstatemachine.py`` -- ``mbcssmprober.py`` - - -Unigram files -------------- - -- ``big5freqprober.py`` -- ``chardistribution.py`` -- ``euckrfreqprober.py`` -- ``euctwfreqprober.py`` -- ``gb2312freqprober.py`` -- ``jisfreqprober.py`` - -Multibyte probers ------------------ - -- ``big5prober.py`` -- ``cp949prober.py`` -- ``eucjpprober.py`` -- ``euckrprober.py`` -- ``euctwprober.py`` -- ``gb2312prober.py`` -- ``mbcharsetprober.py`` -- ``mbcsgroupprober.py`` -- ``sjisprober.py`` - -Misc files ----------- - -- ``__init__.py`` (currently has ``detect`` function in it) -- ``compat.py`` -- ``enums.py`` -- ``universaldetector.py`` -- ``version.py`` - - -Useful links -============ - -This is just a collection of information that I've found useful or thought -might be useful in the future: - -- `BOM by Encoding`_ - -- `A Composite Approach to Language/Encoding Detection`_ - -- `What Every Programmer Absolutely...`_ - -- The actual `source`_ - - -.. _BOM by Encoding: - https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding -.. _A Composite Approach to Language/Encoding Detection: - http://www-archive.mozilla.org/projects/intl/UniversalCharsetDetection.html -.. _What Every Programmer Absolutely...: http://kunststube.net/encoding/ -.. _source: https://dxr.mozilla.org/mozilla/source/intl/chardet/ diff --git a/script.module.chardet/lib/README.rst b/script.module.chardet/lib/README.rst deleted file mode 100644 index b00429165..000000000 --- a/script.module.chardet/lib/README.rst +++ /dev/null @@ -1,65 +0,0 @@ -Chardet: The Universal Character Encoding Detector --------------------------------------------------- - -.. image:: https://img.shields.io/travis/chardet/chardet/stable.svg - :alt: Build status - :target: https://travis-ci.org/chardet/chardet - -.. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg - :target: https://coveralls.io/r/chardet/chardet - -.. image:: https://img.shields.io/pypi/v/chardet.svg - :target: https://warehouse.python.org/project/chardet/ - :alt: Latest version on PyPI - -.. image:: https://img.shields.io/pypi/l/chardet.svg - :alt: License - - -Detects - - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) - - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) - - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) - - EUC-KR, ISO-2022-KR, Johab (Korean) - - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) - - ISO-8859-5, windows-1251 (Bulgarian) - - ISO-8859-1, windows-1252 (Western European languages) - - ISO-8859-7, windows-1253 (Greek) - - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) - - TIS-620 (Thai) - -.. note:: - Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily - disabled until we can retrain the models. - -Requires Python 3.6+. - -Installation ------------- - -Install from `PyPI `_:: - - pip install chardet - -Documentation -------------- - -For users, docs are now available at https://chardet.readthedocs.io/. - -Command-line Tool ------------------ - -chardet comes with a command-line script which reports on the encodings of one -or more files:: - - % chardetect somefile someotherfile - somefile: windows-1252 with confidence 0.5 - someotherfile: ascii with confidence 1.0 - -About ------ - -This is a continuation of Mark Pilgrim's excellent original chardet port from C, and `Ian Cordasco `_'s -`charade `_ Python 3-compatible fork. - -:maintainer: Dan Blanchard diff --git a/script.module.chardet/lib/chardet/__init__.py b/script.module.chardet/lib/chardet/__init__.py index 80ad2546d..fe581623d 100644 --- a/script.module.chardet/lib/chardet/__init__.py +++ b/script.module.chardet/lib/chardet/__init__.py @@ -15,69 +15,101 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from typing import List, Union -from .universaldetector import UniversalDetector +from .charsetgroupprober import CharSetGroupProber +from .charsetprober import CharSetProber from .enums import InputState -from .version import __version__, VERSION - +from .resultdict import ResultDict +from .universaldetector import UniversalDetector +from .version import VERSION, __version__ -__all__ = ['UniversalDetector', 'detect', 'detect_all', '__version__', 'VERSION'] +__all__ = ["UniversalDetector", "detect", "detect_all", "__version__", "VERSION"] -def detect(byte_str): +def detect( + byte_str: Union[bytes, bytearray], should_rename_legacy: bool = False +) -> ResultDict: """ Detect the encoding of the given byte string. :param byte_str: The byte sequence to examine. :type byte_str: ``bytes`` or ``bytearray`` + :param should_rename_legacy: Should we rename legacy encodings + to their more modern equivalents? + :type should_rename_legacy: ``bool`` """ if not isinstance(byte_str, bytearray): if not isinstance(byte_str, bytes): - raise TypeError('Expected object of type bytes or bytearray, got: ' - '{}'.format(type(byte_str))) - else: - byte_str = bytearray(byte_str) - detector = UniversalDetector() + raise TypeError( + f"Expected object of type bytes or bytearray, got: {type(byte_str)}" + ) + byte_str = bytearray(byte_str) + detector = UniversalDetector(should_rename_legacy=should_rename_legacy) detector.feed(byte_str) return detector.close() -def detect_all(byte_str): +def detect_all( + byte_str: Union[bytes, bytearray], + ignore_threshold: bool = False, + should_rename_legacy: bool = False, +) -> List[ResultDict]: """ Detect all the possible encodings of the given byte string. - :param byte_str: The byte sequence to examine. - :type byte_str: ``bytes`` or ``bytearray`` + :param byte_str: The byte sequence to examine. + :type byte_str: ``bytes`` or ``bytearray`` + :param ignore_threshold: Include encodings that are below + ``UniversalDetector.MINIMUM_THRESHOLD`` + in results. + :type ignore_threshold: ``bool`` + :param should_rename_legacy: Should we rename legacy encodings + to their more modern equivalents? + :type should_rename_legacy: ``bool`` """ if not isinstance(byte_str, bytearray): if not isinstance(byte_str, bytes): - raise TypeError('Expected object of type bytes or bytearray, got: ' - '{}'.format(type(byte_str))) - else: - byte_str = bytearray(byte_str) + raise TypeError( + f"Expected object of type bytes or bytearray, got: {type(byte_str)}" + ) + byte_str = bytearray(byte_str) - detector = UniversalDetector() + detector = UniversalDetector(should_rename_legacy=should_rename_legacy) detector.feed(byte_str) detector.close() - if detector._input_state == InputState.HIGH_BYTE: - results = [] - for prober in detector._charset_probers: - if prober.get_confidence() > detector.MINIMUM_THRESHOLD: - charset_name = prober.charset_name - lower_charset_name = prober.charset_name.lower() + if detector.input_state == InputState.HIGH_BYTE: + results: List[ResultDict] = [] + probers: List[CharSetProber] = [] + for prober in detector.charset_probers: + if isinstance(prober, CharSetGroupProber): + probers.extend(p for p in prober.probers) + else: + probers.append(prober) + for prober in probers: + if ignore_threshold or prober.get_confidence() > detector.MINIMUM_THRESHOLD: + charset_name = prober.charset_name or "" + lower_charset_name = charset_name.lower() # Use Windows encoding name instead of ISO-8859 if we saw any # extra Windows-specific bytes - if lower_charset_name.startswith('iso-8859'): - if detector._has_win_bytes: - charset_name = detector.ISO_WIN_MAP.get(lower_charset_name, - charset_name) - results.append({ - 'encoding': charset_name, - 'confidence': prober.get_confidence(), - 'language': prober.language, - }) + if lower_charset_name.startswith("iso-8859") and detector.has_win_bytes: + charset_name = detector.ISO_WIN_MAP.get( + lower_charset_name, charset_name + ) + # Rename legacy encodings with superset encodings if asked + if should_rename_legacy: + charset_name = detector.LEGACY_MAP.get( + charset_name.lower(), charset_name + ) + results.append( + { + "encoding": charset_name, + "confidence": prober.get_confidence(), + "language": prober.language, + } + ) if len(results) > 0: - return sorted(results, key=lambda result: -result['confidence']) + return sorted(results, key=lambda result: -result["confidence"]) return [detector.result] diff --git a/script.module.chardet/lib/chardet/big5freq.py b/script.module.chardet/lib/chardet/big5freq.py index 38f32517a..87d9f972e 100644 --- a/script.module.chardet/lib/chardet/big5freq.py +++ b/script.module.chardet/lib/chardet/big5freq.py @@ -42,9 +42,9 @@ BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 -#Char to FreqOrder table +# Char to FreqOrder table BIG5_TABLE_SIZE = 5376 - +# fmt: off BIG5_CHAR_TO_FREQ_ORDER = ( 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 @@ -383,4 +383,4 @@ 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 ) - +# fmt: on diff --git a/script.module.chardet/lib/chardet/big5prober.py b/script.module.chardet/lib/chardet/big5prober.py index 98f997012..ef09c60e3 100644 --- a/script.module.chardet/lib/chardet/big5prober.py +++ b/script.module.chardet/lib/chardet/big5prober.py @@ -25,23 +25,23 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine from .chardistribution import Big5DistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber from .mbcssm import BIG5_SM_MODEL class Big5Prober(MultiByteCharSetProber): - def __init__(self): - super(Big5Prober, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) self.distribution_analyzer = Big5DistributionAnalysis() self.reset() @property - def charset_name(self): + def charset_name(self) -> str: return "Big5" @property - def language(self): + def language(self) -> str: return "Chinese" diff --git a/script.module.chardet/lib/chardet/chardistribution.py b/script.module.chardet/lib/chardet/chardistribution.py index c0395f4a4..176cb9964 100644 --- a/script.module.chardet/lib/chardet/chardistribution.py +++ b/script.module.chardet/lib/chardet/chardistribution.py @@ -25,40 +25,58 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, - EUCTW_TYPICAL_DISTRIBUTION_RATIO) -from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, - EUCKR_TYPICAL_DISTRIBUTION_RATIO) -from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, - GB2312_TYPICAL_DISTRIBUTION_RATIO) -from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, - BIG5_TYPICAL_DISTRIBUTION_RATIO) -from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, - JIS_TYPICAL_DISTRIBUTION_RATIO) - - -class CharDistributionAnalysis(object): +from typing import Tuple, Union + +from .big5freq import ( + BIG5_CHAR_TO_FREQ_ORDER, + BIG5_TABLE_SIZE, + BIG5_TYPICAL_DISTRIBUTION_RATIO, +) +from .euckrfreq import ( + EUCKR_CHAR_TO_FREQ_ORDER, + EUCKR_TABLE_SIZE, + EUCKR_TYPICAL_DISTRIBUTION_RATIO, +) +from .euctwfreq import ( + EUCTW_CHAR_TO_FREQ_ORDER, + EUCTW_TABLE_SIZE, + EUCTW_TYPICAL_DISTRIBUTION_RATIO, +) +from .gb2312freq import ( + GB2312_CHAR_TO_FREQ_ORDER, + GB2312_TABLE_SIZE, + GB2312_TYPICAL_DISTRIBUTION_RATIO, +) +from .jisfreq import ( + JIS_CHAR_TO_FREQ_ORDER, + JIS_TABLE_SIZE, + JIS_TYPICAL_DISTRIBUTION_RATIO, +) +from .johabfreq import JOHAB_TO_EUCKR_ORDER_TABLE + + +class CharDistributionAnalysis: ENOUGH_DATA_THRESHOLD = 1024 SURE_YES = 0.99 SURE_NO = 0.01 MINIMUM_DATA_THRESHOLD = 3 - def __init__(self): + def __init__(self) -> None: # Mapping table to get frequency order from char order (get from # GetOrder()) - self._char_to_freq_order = None - self._table_size = None # Size of above table + self._char_to_freq_order: Tuple[int, ...] = tuple() + self._table_size = 0 # Size of above table # This is a constant value which varies from language to language, # used in calculating confidence. See # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html # for further detail. - self.typical_distribution_ratio = None - self._done = None - self._total_chars = None - self._freq_chars = None + self.typical_distribution_ratio = 0.0 + self._done = False + self._total_chars = 0 + self._freq_chars = 0 self.reset() - def reset(self): + def reset(self) -> None: """reset analyser, clear any state""" # If this flag is set to True, detection is done and conclusion has # been made @@ -67,7 +85,7 @@ def reset(self): # The number of characters whose frequency order is less than 512 self._freq_chars = 0 - def feed(self, char, char_len): + def feed(self, char: Union[bytes, bytearray], char_len: int) -> None: """feed a character with known length""" if char_len == 2: # we only care about 2-bytes character in our distribution analysis @@ -81,7 +99,7 @@ def feed(self, char, char_len): if 512 > self._char_to_freq_order[order]: self._freq_chars += 1 - def get_confidence(self): + def get_confidence(self) -> float: """return confidence based on existing data""" # if we didn't receive any character in our consideration range, # return negative answer @@ -89,20 +107,21 @@ def get_confidence(self): return self.SURE_NO if self._total_chars != self._freq_chars: - r = (self._freq_chars / ((self._total_chars - self._freq_chars) - * self.typical_distribution_ratio)) + r = self._freq_chars / ( + (self._total_chars - self._freq_chars) * self.typical_distribution_ratio + ) if r < self.SURE_YES: return r # normalize confidence (we don't want to be 100% sure) return self.SURE_YES - def got_enough_data(self): + def got_enough_data(self) -> bool: # It is not necessary to receive all data to draw conclusion. # For charset detection, certain amount of data is enough return self._total_chars > self.ENOUGH_DATA_THRESHOLD - def get_order(self, byte_str): + def get_order(self, _: Union[bytes, bytearray]) -> int: # We do not handle characters based on the original encoding string, # but convert this encoding string to a number, here called order. # This allows multiple encodings of a language to share one frequency @@ -111,13 +130,13 @@ def get_order(self, byte_str): class EUCTWDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCTWDistributionAnalysis, self).__init__() + def __init__(self) -> None: + super().__init__() self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER self._table_size = EUCTW_TABLE_SIZE self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> int: # for euc-TW encoding, we are interested # first byte range: 0xc4 -- 0xfe # second byte range: 0xa1 -- 0xfe @@ -125,18 +144,17 @@ def get_order(self, byte_str): first_char = byte_str[0] if first_char >= 0xC4: return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 - else: - return -1 + return -1 class EUCKRDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCKRDistributionAnalysis, self).__init__() + def __init__(self) -> None: + super().__init__() self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER self._table_size = EUCKR_TABLE_SIZE self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> int: # for euc-KR encoding, we are interested # first byte range: 0xb0 -- 0xfe # second byte range: 0xa1 -- 0xfe @@ -144,18 +162,32 @@ def get_order(self, byte_str): first_char = byte_str[0] if first_char >= 0xB0: return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 - else: - return -1 + return -1 + + +class JOHABDistributionAnalysis(CharDistributionAnalysis): + def __init__(self) -> None: + super().__init__() + self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER + self._table_size = EUCKR_TABLE_SIZE + self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str: Union[bytes, bytearray]) -> int: + first_char = byte_str[0] + if 0x88 <= first_char < 0xD4: + code = first_char * 256 + byte_str[1] + return JOHAB_TO_EUCKR_ORDER_TABLE.get(code, -1) + return -1 class GB2312DistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(GB2312DistributionAnalysis, self).__init__() + def __init__(self) -> None: + super().__init__() self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER self._table_size = GB2312_TABLE_SIZE self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> int: # for GB2312 encoding, we are interested # first byte range: 0xb0 -- 0xfe # second byte range: 0xa1 -- 0xfe @@ -163,18 +195,17 @@ def get_order(self, byte_str): first_char, second_char = byte_str[0], byte_str[1] if (first_char >= 0xB0) and (second_char >= 0xA1): return 94 * (first_char - 0xB0) + second_char - 0xA1 - else: - return -1 + return -1 class Big5DistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(Big5DistributionAnalysis, self).__init__() + def __init__(self) -> None: + super().__init__() self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER self._table_size = BIG5_TABLE_SIZE self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> int: # for big5 encoding, we are interested # first byte range: 0xa4 -- 0xfe # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe @@ -183,28 +214,26 @@ def get_order(self, byte_str): if first_char >= 0xA4: if second_char >= 0xA1: return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 - else: - return 157 * (first_char - 0xA4) + second_char - 0x40 - else: - return -1 + return 157 * (first_char - 0xA4) + second_char - 0x40 + return -1 class SJISDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(SJISDistributionAnalysis, self).__init__() + def __init__(self) -> None: + super().__init__() self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER self._table_size = JIS_TABLE_SIZE self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> int: # for sjis encoding, we are interested # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe # no validation needed here. State machine has done that first_char, second_char = byte_str[0], byte_str[1] - if (first_char >= 0x81) and (first_char <= 0x9F): + if 0x81 <= first_char <= 0x9F: order = 188 * (first_char - 0x81) - elif (first_char >= 0xE0) and (first_char <= 0xEF): + elif 0xE0 <= first_char <= 0xEF: order = 188 * (first_char - 0xE0 + 31) else: return -1 @@ -215,19 +244,18 @@ def get_order(self, byte_str): class EUCJPDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCJPDistributionAnalysis, self).__init__() + def __init__(self) -> None: + super().__init__() self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER self._table_size = JIS_TABLE_SIZE self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> int: # for euc-JP encoding, we are interested # first byte range: 0xa0 -- 0xfe # second byte range: 0xa1 -- 0xfe # no validation needed here. State machine has done that char = byte_str[0] if char >= 0xA0: - return 94 * (char - 0xA1) + byte_str[1] - 0xa1 - else: - return -1 + return 94 * (char - 0xA1) + byte_str[1] - 0xA1 + return -1 diff --git a/script.module.chardet/lib/chardet/charsetgroupprober.py b/script.module.chardet/lib/chardet/charsetgroupprober.py index 5812cef0b..6def56b4a 100644 --- a/script.module.chardet/lib/chardet/charsetgroupprober.py +++ b/script.module.chardet/lib/chardet/charsetgroupprober.py @@ -25,29 +25,30 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .enums import ProbingState +from typing import List, Optional, Union + from .charsetprober import CharSetProber +from .enums import LanguageFilter, ProbingState class CharSetGroupProber(CharSetProber): - def __init__(self, lang_filter=None): - super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) + def __init__(self, lang_filter: LanguageFilter = LanguageFilter.NONE) -> None: + super().__init__(lang_filter=lang_filter) self._active_num = 0 - self.probers = [] - self._best_guess_prober = None + self.probers: List[CharSetProber] = [] + self._best_guess_prober: Optional[CharSetProber] = None - def reset(self): - super(CharSetGroupProber, self).reset() + def reset(self) -> None: + super().reset() self._active_num = 0 for prober in self.probers: - if prober: - prober.reset() - prober.active = True - self._active_num += 1 + prober.reset() + prober.active = True + self._active_num += 1 self._best_guess_prober = None @property - def charset_name(self): + def charset_name(self) -> Optional[str]: if not self._best_guess_prober: self.get_confidence() if not self._best_guess_prober: @@ -55,17 +56,15 @@ def charset_name(self): return self._best_guess_prober.charset_name @property - def language(self): + def language(self) -> Optional[str]: if not self._best_guess_prober: self.get_confidence() if not self._best_guess_prober: return None return self._best_guess_prober.language - def feed(self, byte_str): + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: for prober in self.probers: - if not prober: - continue if not prober.active: continue state = prober.feed(byte_str) @@ -75,7 +74,7 @@ def feed(self, byte_str): self._best_guess_prober = prober self._state = ProbingState.FOUND_IT return self.state - elif state == ProbingState.NOT_ME: + if state == ProbingState.NOT_ME: prober.active = False self._active_num -= 1 if self._active_num <= 0: @@ -83,22 +82,22 @@ def feed(self, byte_str): return self.state return self.state - def get_confidence(self): + def get_confidence(self) -> float: state = self.state if state == ProbingState.FOUND_IT: return 0.99 - elif state == ProbingState.NOT_ME: + if state == ProbingState.NOT_ME: return 0.01 best_conf = 0.0 self._best_guess_prober = None for prober in self.probers: - if not prober: - continue if not prober.active: - self.logger.debug('%s not active', prober.charset_name) + self.logger.debug("%s not active", prober.charset_name) continue conf = prober.get_confidence() - self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) + self.logger.debug( + "%s %s confidence = %s", prober.charset_name, prober.language, conf + ) if best_conf < conf: best_conf = conf self._best_guess_prober = prober diff --git a/script.module.chardet/lib/chardet/charsetprober.py b/script.module.chardet/lib/chardet/charsetprober.py index eac4e5986..a103ca113 100644 --- a/script.module.chardet/lib/chardet/charsetprober.py +++ b/script.module.chardet/lib/chardet/charsetprober.py @@ -28,54 +28,62 @@ import logging import re +from typing import Optional, Union -from .enums import ProbingState +from .enums import LanguageFilter, ProbingState +INTERNATIONAL_WORDS_PATTERN = re.compile( + b"[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?" +) -class CharSetProber(object): + +class CharSetProber: SHORTCUT_THRESHOLD = 0.95 - def __init__(self, lang_filter=None): - self._state = None + def __init__(self, lang_filter: LanguageFilter = LanguageFilter.NONE) -> None: + self._state = ProbingState.DETECTING + self.active = True self.lang_filter = lang_filter self.logger = logging.getLogger(__name__) - def reset(self): + def reset(self) -> None: self._state = ProbingState.DETECTING @property - def charset_name(self): + def charset_name(self) -> Optional[str]: return None - def feed(self, buf): - pass + @property + def language(self) -> Optional[str]: + raise NotImplementedError + + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: + raise NotImplementedError @property - def state(self): + def state(self) -> ProbingState: return self._state - def get_confidence(self): + def get_confidence(self) -> float: return 0.0 @staticmethod - def filter_high_byte_only(buf): - buf = re.sub(b'([\x00-\x7F])+', b' ', buf) + def filter_high_byte_only(buf: Union[bytes, bytearray]) -> bytes: + buf = re.sub(b"([\x00-\x7F])+", b" ", buf) return buf @staticmethod - def filter_international_words(buf): + def filter_international_words(buf: Union[bytes, bytearray]) -> bytearray: """ We define three types of bytes: alphabet: english alphabets [a-zA-Z] international: international characters [\x80-\xFF] marker: everything else [^a-zA-Z\x80-\xFF] - The input buffer can be thought to contain a series of words delimited by markers. This function works to filter all words that contain at least one international character. All contiguous sequences of markers are replaced by a single space ascii character. - This filter applies to all scripts which do not use English characters. """ filtered = bytearray() @@ -83,8 +91,7 @@ def filter_international_words(buf): # This regex expression filters out only words that have at-least one # international character. The word may include one marker character at # the end. - words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', - buf) + words = INTERNATIONAL_WORDS_PATTERN.findall(buf) for word in words: filtered.extend(word[:-1]) @@ -94,20 +101,17 @@ def filter_international_words(buf): # similarly across all languages and may thus have similar # frequencies). last_char = word[-1:] - if not last_char.isalpha() and last_char < b'\x80': - last_char = b' ' + if not last_char.isalpha() and last_char < b"\x80": + last_char = b" " filtered.extend(last_char) return filtered @staticmethod - def filter_with_english_letters(buf): + def remove_xml_tags(buf: Union[bytes, bytearray]) -> bytes: """ Returns a copy of ``buf`` that retains only the sequences of English alphabet and high byte characters that are not between <> characters. - Also retains English alphabet and high byte characters immediately - before occurrences of >. - This filter can be applied to all scripts which contain both English characters and extended ASCII characters, but is currently only used by ``Latin1Prober``. @@ -115,26 +119,24 @@ def filter_with_english_letters(buf): filtered = bytearray() in_tag = False prev = 0 + buf = memoryview(buf).cast("c") - for curr in range(len(buf)): - # Slice here to get bytes instead of an int with Python 3 - buf_char = buf[curr:curr + 1] - # Check if we're coming out of or entering an HTML tag - if buf_char == b'>': - in_tag = False - elif buf_char == b'<': - in_tag = True + for curr, buf_char in enumerate(buf): + # Check if we're coming out of or entering an XML tag - # If current character is not extended-ASCII and not alphabetic... - if buf_char < b'\x80' and not buf_char.isalpha(): - # ...and we're not in a tag + # https://github.com/python/typeshed/issues/8182 + if buf_char == b">": # type: ignore[comparison-overlap] + prev = curr + 1 + in_tag = False + # https://github.com/python/typeshed/issues/8182 + elif buf_char == b"<": # type: ignore[comparison-overlap] if curr > prev and not in_tag: # Keep everything after last non-extended-ASCII, # non-alphabetic character filtered.extend(buf[prev:curr]) # Output a space to delimit stretch we kept - filtered.extend(b' ') - prev = curr + 1 + filtered.extend(b" ") + in_tag = True # If we're not in a tag... if not in_tag: diff --git a/script.module.chardet/lib/chardet/cli/__init__.py b/script.module.chardet/lib/chardet/cli/__init__.py index 8b1378917..e69de29bb 100644 --- a/script.module.chardet/lib/chardet/cli/__init__.py +++ b/script.module.chardet/lib/chardet/cli/__init__.py @@ -1 +0,0 @@ - diff --git a/script.module.chardet/lib/chardet/cli/chardetect.py b/script.module.chardet/lib/chardet/cli/chardetect.py index e1d8cd69a..43f6e144f 100644 --- a/script.module.chardet/lib/chardet/cli/chardetect.py +++ b/script.module.chardet/lib/chardet/cli/chardetect.py @@ -12,17 +12,21 @@ """ -from __future__ import absolute_import, print_function, unicode_literals import argparse import sys +from typing import Iterable, List, Optional -from chardet import __version__ -from chardet.compat import PY2 -from chardet.universaldetector import UniversalDetector +from .. import __version__ +from ..universaldetector import UniversalDetector -def description_of(lines, name='stdin'): +def description_of( + lines: Iterable[bytes], + name: str = "stdin", + minimal: bool = False, + should_rename_legacy: bool = False, +) -> Optional[str]: """ Return a string describing the probable encoding of a file or list of strings. @@ -31,8 +35,11 @@ def description_of(lines, name='stdin'): :type lines: Iterable of bytes :param name: Name of file or collection of lines :type name: str + :param should_rename_legacy: Should we rename legacy encodings to + their more modern equivalents? + :type should_rename_legacy: ``bool`` """ - u = UniversalDetector() + u = UniversalDetector(should_rename_legacy=should_rename_legacy) for line in lines: line = bytearray(line) u.feed(line) @@ -41,16 +48,14 @@ def description_of(lines, name='stdin'): break u.close() result = u.result - if PY2: - name = name.decode(sys.getfilesystemencoding(), 'ignore') - if result['encoding']: - return '{}: {} with confidence {}'.format(name, result['encoding'], - result['confidence']) - else: - return '{}: no result'.format(name) + if minimal: + return result["encoding"] + if result["encoding"]: + return f'{name}: {result["encoding"]} with confidence {result["confidence"]}' + return f"{name}: no result" -def main(argv=None): +def main(argv: Optional[List[str]] = None) -> None: """ Handles command line arguments and gets things started. @@ -60,25 +65,48 @@ def main(argv=None): """ # Get command line arguments parser = argparse.ArgumentParser( - description="Takes one or more file paths and reports their detected \ - encodings") - parser.add_argument('input', - help='File whose encoding we would like to determine. \ - (default: stdin)', - type=argparse.FileType('rb'), nargs='*', - default=[sys.stdin if PY2 else sys.stdin.buffer]) - parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + description=( + "Takes one or more file paths and reports their detected encodings" + ) + ) + parser.add_argument( + "input", + help="File whose encoding we would like to determine. (default: stdin)", + type=argparse.FileType("rb"), + nargs="*", + default=[sys.stdin.buffer], + ) + parser.add_argument( + "--minimal", + help="Print only the encoding to standard output", + action="store_true", + ) + parser.add_argument( + "-l", + "--legacy", + help="Rename legacy encodings to more modern ones.", + action="store_true", + ) + parser.add_argument( + "--version", action="version", version=f"%(prog)s {__version__}" + ) args = parser.parse_args(argv) for f in args.input: if f.isatty(): - print("You are running chardetect interactively. Press " + - "CTRL-D twice at the start of a blank line to signal the " + - "end of your input. If you want help, run chardetect " + - "--help\n", file=sys.stderr) - print(description_of(f, f.name)) - - -if __name__ == '__main__': + print( + "You are running chardetect interactively. Press " + "CTRL-D twice at the start of a blank line to signal the " + "end of your input. If you want help, run chardetect " + "--help\n", + file=sys.stderr, + ) + print( + description_of( + f, f.name, minimal=args.minimal, should_rename_legacy=args.legacy + ) + ) + + +if __name__ == "__main__": main() diff --git a/script.module.chardet/lib/chardet/codingstatemachine.py b/script.module.chardet/lib/chardet/codingstatemachine.py index 68fba44f1..8ed4a8773 100644 --- a/script.module.chardet/lib/chardet/codingstatemachine.py +++ b/script.module.chardet/lib/chardet/codingstatemachine.py @@ -27,10 +27,11 @@ import logging +from .codingstatemachinedict import CodingStateMachineDict from .enums import MachineState -class CodingStateMachine(object): +class CodingStateMachine: """ A state machine to verify a byte sequence for a particular encoding. For each byte the detector receives, it will feed that byte to every active @@ -52,37 +53,38 @@ class CodingStateMachine(object): negative answer for this encoding. Detector will exclude this encoding from consideration from here on. """ - def __init__(self, sm): + + def __init__(self, sm: CodingStateMachineDict) -> None: self._model = sm self._curr_byte_pos = 0 self._curr_char_len = 0 - self._curr_state = None + self._curr_state = MachineState.START + self.active = True self.logger = logging.getLogger(__name__) self.reset() - def reset(self): + def reset(self) -> None: self._curr_state = MachineState.START - def next_state(self, c): + def next_state(self, c: int) -> int: # for each byte we get its class # if it is first byte, we also get byte length - byte_class = self._model['class_table'][c] + byte_class = self._model["class_table"][c] if self._curr_state == MachineState.START: self._curr_byte_pos = 0 - self._curr_char_len = self._model['char_len_table'][byte_class] + self._curr_char_len = self._model["char_len_table"][byte_class] # from byte's class and state_table, we get its next state - curr_state = (self._curr_state * self._model['class_factor'] - + byte_class) - self._curr_state = self._model['state_table'][curr_state] + curr_state = self._curr_state * self._model["class_factor"] + byte_class + self._curr_state = self._model["state_table"][curr_state] self._curr_byte_pos += 1 return self._curr_state - def get_current_charlen(self): + def get_current_charlen(self) -> int: return self._curr_char_len - def get_coding_state_machine(self): - return self._model['name'] + def get_coding_state_machine(self) -> str: + return self._model["name"] @property - def language(self): - return self._model['language'] + def language(self) -> str: + return self._model["language"] diff --git a/script.module.chardet/lib/chardet/codingstatemachinedict.py b/script.module.chardet/lib/chardet/codingstatemachinedict.py new file mode 100644 index 000000000..7a3c4c7e3 --- /dev/null +++ b/script.module.chardet/lib/chardet/codingstatemachinedict.py @@ -0,0 +1,19 @@ +from typing import TYPE_CHECKING, Tuple + +if TYPE_CHECKING: + # TypedDict was introduced in Python 3.8. + # + # TODO: Remove the else block and TYPE_CHECKING check when dropping support + # for Python 3.7. + from typing import TypedDict + + class CodingStateMachineDict(TypedDict, total=False): + class_table: Tuple[int, ...] + class_factor: int + state_table: Tuple[int, ...] + char_len_table: Tuple[int, ...] + name: str + language: str # Optional key + +else: + CodingStateMachineDict = dict diff --git a/script.module.chardet/lib/chardet/cp949prober.py b/script.module.chardet/lib/chardet/cp949prober.py index efd793abc..fa7307ed8 100644 --- a/script.module.chardet/lib/chardet/cp949prober.py +++ b/script.module.chardet/lib/chardet/cp949prober.py @@ -32,8 +32,8 @@ class CP949Prober(MultiByteCharSetProber): - def __init__(self): - super(CP949Prober, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(CP949_SM_MODEL) # NOTE: CP949 is a superset of EUC-KR, so the distribution should be # not different. @@ -41,9 +41,9 @@ def __init__(self): self.reset() @property - def charset_name(self): + def charset_name(self) -> str: return "CP949" @property - def language(self): + def language(self) -> str: return "Korean" diff --git a/script.module.chardet/lib/chardet/enums.py b/script.module.chardet/lib/chardet/enums.py index 045120722..5e3e19823 100644 --- a/script.module.chardet/lib/chardet/enums.py +++ b/script.module.chardet/lib/chardet/enums.py @@ -4,21 +4,26 @@ :author: Dan Blanchard (dan.blanchard@gmail.com) """ +from enum import Enum, Flag -class InputState(object): + +class InputState: """ This enum represents the different states a universal detector can be in. """ + PURE_ASCII = 0 ESC_ASCII = 1 HIGH_BYTE = 2 -class LanguageFilter(object): +class LanguageFilter(Flag): """ This enum represents the different language filters we can apply to a ``UniversalDetector``. """ + + NONE = 0x00 CHINESE_SIMPLIFIED = 0x01 CHINESE_TRADITIONAL = 0x02 JAPANESE = 0x04 @@ -29,46 +34,50 @@ class LanguageFilter(object): CJK = CHINESE | JAPANESE | KOREAN -class ProbingState(object): +class ProbingState(Enum): """ This enum represents the different states a prober can be in. """ + DETECTING = 0 FOUND_IT = 1 NOT_ME = 2 -class MachineState(object): +class MachineState: """ This enum represents the different states a state machine can be in. """ + START = 0 ERROR = 1 ITS_ME = 2 -class SequenceLikelihood(object): +class SequenceLikelihood: """ This enum represents the likelihood of a character following the previous one. """ + NEGATIVE = 0 UNLIKELY = 1 LIKELY = 2 POSITIVE = 3 @classmethod - def get_num_categories(cls): + def get_num_categories(cls) -> int: """:returns: The number of likelihood categories in the enum.""" return 4 -class CharacterCategory(object): +class CharacterCategory: """ This enum represents the different categories language models for ``SingleByteCharsetProber`` put characters into. Anything less than CONTROL is considered a letter. """ + UNDEFINED = 255 LINE_BREAK = 254 SYMBOL = 253 diff --git a/script.module.chardet/lib/chardet/escprober.py b/script.module.chardet/lib/chardet/escprober.py index c70493f2b..fd713830d 100644 --- a/script.module.chardet/lib/chardet/escprober.py +++ b/script.module.chardet/lib/chardet/escprober.py @@ -25,11 +25,17 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from typing import Optional, Union + from .charsetprober import CharSetProber from .codingstatemachine import CodingStateMachine -from .enums import LanguageFilter, ProbingState, MachineState -from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, - ISO2022KR_SM_MODEL) +from .enums import LanguageFilter, MachineState, ProbingState +from .escsm import ( + HZ_SM_MODEL, + ISO2022CN_SM_MODEL, + ISO2022JP_SM_MODEL, + ISO2022KR_SM_MODEL, +) class EscCharSetProber(CharSetProber): @@ -39,8 +45,8 @@ class EscCharSetProber(CharSetProber): identify these encodings. """ - def __init__(self, lang_filter=None): - super(EscCharSetProber, self).__init__(lang_filter=lang_filter) + def __init__(self, lang_filter: LanguageFilter = LanguageFilter.NONE) -> None: + super().__init__(lang_filter=lang_filter) self.coding_sm = [] if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) @@ -49,17 +55,15 @@ def __init__(self, lang_filter=None): self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) if self.lang_filter & LanguageFilter.KOREAN: self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) - self.active_sm_count = None - self._detected_charset = None - self._detected_language = None - self._state = None + self.active_sm_count = 0 + self._detected_charset: Optional[str] = None + self._detected_language: Optional[str] = None + self._state = ProbingState.DETECTING self.reset() - def reset(self): - super(EscCharSetProber, self).reset() + def reset(self) -> None: + super().reset() for coding_sm in self.coding_sm: - if not coding_sm: - continue coding_sm.active = True coding_sm.reset() self.active_sm_count = len(self.coding_sm) @@ -67,23 +71,20 @@ def reset(self): self._detected_language = None @property - def charset_name(self): + def charset_name(self) -> Optional[str]: return self._detected_charset @property - def language(self): + def language(self) -> Optional[str]: return self._detected_language - def get_confidence(self): - if self._detected_charset: - return 0.99 - else: - return 0.00 + def get_confidence(self) -> float: + return 0.99 if self._detected_charset else 0.00 - def feed(self, byte_str): + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: for c in byte_str: for coding_sm in self.coding_sm: - if not coding_sm or not coding_sm.active: + if not coding_sm.active: continue coding_state = coding_sm.next_state(c) if coding_state == MachineState.ERROR: diff --git a/script.module.chardet/lib/chardet/escsm.py b/script.module.chardet/lib/chardet/escsm.py index 0069523a0..11d4adf77 100644 --- a/script.module.chardet/lib/chardet/escsm.py +++ b/script.module.chardet/lib/chardet/escsm.py @@ -12,7 +12,7 @@ # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. +# version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,227 +20,242 @@ # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from .codingstatemachinedict import CodingStateMachineDict from .enums import MachineState +# fmt: off HZ_CLS = ( -1,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,0,0,0,0, # 20 - 27 -0,0,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,0,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,4,0,5,2,0, # 78 - 7f -1,1,1,1,1,1,1,1, # 80 - 87 -1,1,1,1,1,1,1,1, # 88 - 8f -1,1,1,1,1,1,1,1, # 90 - 97 -1,1,1,1,1,1,1,1, # 98 - 9f -1,1,1,1,1,1,1,1, # a0 - a7 -1,1,1,1,1,1,1,1, # a8 - af -1,1,1,1,1,1,1,1, # b0 - b7 -1,1,1,1,1,1,1,1, # b8 - bf -1,1,1,1,1,1,1,1, # c0 - c7 -1,1,1,1,1,1,1,1, # c8 - cf -1,1,1,1,1,1,1,1, # d0 - d7 -1,1,1,1,1,1,1,1, # d8 - df -1,1,1,1,1,1,1,1, # e0 - e7 -1,1,1,1,1,1,1,1, # e8 - ef -1,1,1,1,1,1,1,1, # f0 - f7 -1,1,1,1,1,1,1,1, # f8 - ff + 1, 0, 0, 0, 0, 0, 0, 0, # 00 - 07 + 0, 0, 0, 0, 0, 0, 0, 0, # 08 - 0f + 0, 0, 0, 0, 0, 0, 0, 0, # 10 - 17 + 0, 0, 0, 1, 0, 0, 0, 0, # 18 - 1f + 0, 0, 0, 0, 0, 0, 0, 0, # 20 - 27 + 0, 0, 0, 0, 0, 0, 0, 0, # 28 - 2f + 0, 0, 0, 0, 0, 0, 0, 0, # 30 - 37 + 0, 0, 0, 0, 0, 0, 0, 0, # 38 - 3f + 0, 0, 0, 0, 0, 0, 0, 0, # 40 - 47 + 0, 0, 0, 0, 0, 0, 0, 0, # 48 - 4f + 0, 0, 0, 0, 0, 0, 0, 0, # 50 - 57 + 0, 0, 0, 0, 0, 0, 0, 0, # 58 - 5f + 0, 0, 0, 0, 0, 0, 0, 0, # 60 - 67 + 0, 0, 0, 0, 0, 0, 0, 0, # 68 - 6f + 0, 0, 0, 0, 0, 0, 0, 0, # 70 - 77 + 0, 0, 0, 4, 0, 5, 2, 0, # 78 - 7f + 1, 1, 1, 1, 1, 1, 1, 1, # 80 - 87 + 1, 1, 1, 1, 1, 1, 1, 1, # 88 - 8f + 1, 1, 1, 1, 1, 1, 1, 1, # 90 - 97 + 1, 1, 1, 1, 1, 1, 1, 1, # 98 - 9f + 1, 1, 1, 1, 1, 1, 1, 1, # a0 - a7 + 1, 1, 1, 1, 1, 1, 1, 1, # a8 - af + 1, 1, 1, 1, 1, 1, 1, 1, # b0 - b7 + 1, 1, 1, 1, 1, 1, 1, 1, # b8 - bf + 1, 1, 1, 1, 1, 1, 1, 1, # c0 - c7 + 1, 1, 1, 1, 1, 1, 1, 1, # c8 - cf + 1, 1, 1, 1, 1, 1, 1, 1, # d0 - d7 + 1, 1, 1, 1, 1, 1, 1, 1, # d8 - df + 1, 1, 1, 1, 1, 1, 1, 1, # e0 - e7 + 1, 1, 1, 1, 1, 1, 1, 1, # e8 - ef + 1, 1, 1, 1, 1, 1, 1, 1, # f0 - f7 + 1, 1, 1, 1, 1, 1, 1, 1, # f8 - ff ) HZ_ST = ( -MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 - 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f - 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 - 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f +MachineState.START, MachineState.ERROR, 3, MachineState.START, MachineState.START, MachineState.START, MachineState.ERROR, MachineState.ERROR, # 00-07 +MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, # 08-0f +MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ERROR, MachineState.ERROR, MachineState.START, MachineState.START, 4, MachineState.ERROR, # 10-17 + 5, MachineState.ERROR, 6, MachineState.ERROR, 5, 5, 4, MachineState.ERROR, # 18-1f + 4, MachineState.ERROR, 4, 4, 4, MachineState.ERROR, 4, MachineState.ERROR, # 20-27 + 4, MachineState.ITS_ME, MachineState.START, MachineState.START, MachineState.START, MachineState.START, MachineState.START, MachineState.START, # 28-2f ) +# fmt: on HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) -HZ_SM_MODEL = {'class_table': HZ_CLS, - 'class_factor': 6, - 'state_table': HZ_ST, - 'char_len_table': HZ_CHAR_LEN_TABLE, - 'name': "HZ-GB-2312", - 'language': 'Chinese'} +HZ_SM_MODEL: CodingStateMachineDict = { + "class_table": HZ_CLS, + "class_factor": 6, + "state_table": HZ_ST, + "char_len_table": HZ_CHAR_LEN_TABLE, + "name": "HZ-GB-2312", + "language": "Chinese", +} +# fmt: off ISO2022CN_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,0,0,0,0, # 20 - 27 -0,3,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,4,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff + 2, 0, 0, 0, 0, 0, 0, 0, # 00 - 07 + 0, 0, 0, 0, 0, 0, 0, 0, # 08 - 0f + 0, 0, 0, 0, 0, 0, 0, 0, # 10 - 17 + 0, 0, 0, 1, 0, 0, 0, 0, # 18 - 1f + 0, 0, 0, 0, 0, 0, 0, 0, # 20 - 27 + 0, 3, 0, 0, 0, 0, 0, 0, # 28 - 2f + 0, 0, 0, 0, 0, 0, 0, 0, # 30 - 37 + 0, 0, 0, 0, 0, 0, 0, 0, # 38 - 3f + 0, 0, 0, 4, 0, 0, 0, 0, # 40 - 47 + 0, 0, 0, 0, 0, 0, 0, 0, # 48 - 4f + 0, 0, 0, 0, 0, 0, 0, 0, # 50 - 57 + 0, 0, 0, 0, 0, 0, 0, 0, # 58 - 5f + 0, 0, 0, 0, 0, 0, 0, 0, # 60 - 67 + 0, 0, 0, 0, 0, 0, 0, 0, # 68 - 6f + 0, 0, 0, 0, 0, 0, 0, 0, # 70 - 77 + 0, 0, 0, 0, 0, 0, 0, 0, # 78 - 7f + 2, 2, 2, 2, 2, 2, 2, 2, # 80 - 87 + 2, 2, 2, 2, 2, 2, 2, 2, # 88 - 8f + 2, 2, 2, 2, 2, 2, 2, 2, # 90 - 97 + 2, 2, 2, 2, 2, 2, 2, 2, # 98 - 9f + 2, 2, 2, 2, 2, 2, 2, 2, # a0 - a7 + 2, 2, 2, 2, 2, 2, 2, 2, # a8 - af + 2, 2, 2, 2, 2, 2, 2, 2, # b0 - b7 + 2, 2, 2, 2, 2, 2, 2, 2, # b8 - bf + 2, 2, 2, 2, 2, 2, 2, 2, # c0 - c7 + 2, 2, 2, 2, 2, 2, 2, 2, # c8 - cf + 2, 2, 2, 2, 2, 2, 2, 2, # d0 - d7 + 2, 2, 2, 2, 2, 2, 2, 2, # d8 - df + 2, 2, 2, 2, 2, 2, 2, 2, # e0 - e7 + 2, 2, 2, 2, 2, 2, 2, 2, # e8 - ef + 2, 2, 2, 2, 2, 2, 2, 2, # f0 - f7 + 2, 2, 2, 2, 2, 2, 2, 2, # f8 - ff ) ISO2022CN_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 -MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f -MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 - 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f + MachineState.START, 3, MachineState.ERROR, MachineState.START, MachineState.START, MachineState.START, MachineState.START, MachineState.START, # 00-07 + MachineState.START, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, # 08-0f + MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, # 10-17 + MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, 4, MachineState.ERROR, # 18-1f + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, # 20-27 + 5, 6, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, # 28-2f + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, # 30-37 + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ERROR, MachineState.START, # 38-3f ) +# fmt: on ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) -ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, - 'class_factor': 9, - 'state_table': ISO2022CN_ST, - 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, - 'name': "ISO-2022-CN", - 'language': 'Chinese'} +ISO2022CN_SM_MODEL: CodingStateMachineDict = { + "class_table": ISO2022CN_CLS, + "class_factor": 9, + "state_table": ISO2022CN_ST, + "char_len_table": ISO2022CN_CHAR_LEN_TABLE, + "name": "ISO-2022-CN", + "language": "Chinese", +} +# fmt: off ISO2022JP_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,2,2, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,7,0,0,0, # 20 - 27 -3,0,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -6,0,4,0,8,0,0,0, # 40 - 47 -0,9,5,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff + 2, 0, 0, 0, 0, 0, 0, 0, # 00 - 07 + 0, 0, 0, 0, 0, 0, 2, 2, # 08 - 0f + 0, 0, 0, 0, 0, 0, 0, 0, # 10 - 17 + 0, 0, 0, 1, 0, 0, 0, 0, # 18 - 1f + 0, 0, 0, 0, 7, 0, 0, 0, # 20 - 27 + 3, 0, 0, 0, 0, 0, 0, 0, # 28 - 2f + 0, 0, 0, 0, 0, 0, 0, 0, # 30 - 37 + 0, 0, 0, 0, 0, 0, 0, 0, # 38 - 3f + 6, 0, 4, 0, 8, 0, 0, 0, # 40 - 47 + 0, 9, 5, 0, 0, 0, 0, 0, # 48 - 4f + 0, 0, 0, 0, 0, 0, 0, 0, # 50 - 57 + 0, 0, 0, 0, 0, 0, 0, 0, # 58 - 5f + 0, 0, 0, 0, 0, 0, 0, 0, # 60 - 67 + 0, 0, 0, 0, 0, 0, 0, 0, # 68 - 6f + 0, 0, 0, 0, 0, 0, 0, 0, # 70 - 77 + 0, 0, 0, 0, 0, 0, 0, 0, # 78 - 7f + 2, 2, 2, 2, 2, 2, 2, 2, # 80 - 87 + 2, 2, 2, 2, 2, 2, 2, 2, # 88 - 8f + 2, 2, 2, 2, 2, 2, 2, 2, # 90 - 97 + 2, 2, 2, 2, 2, 2, 2, 2, # 98 - 9f + 2, 2, 2, 2, 2, 2, 2, 2, # a0 - a7 + 2, 2, 2, 2, 2, 2, 2, 2, # a8 - af + 2, 2, 2, 2, 2, 2, 2, 2, # b0 - b7 + 2, 2, 2, 2, 2, 2, 2, 2, # b8 - bf + 2, 2, 2, 2, 2, 2, 2, 2, # c0 - c7 + 2, 2, 2, 2, 2, 2, 2, 2, # c8 - cf + 2, 2, 2, 2, 2, 2, 2, 2, # d0 - d7 + 2, 2, 2, 2, 2, 2, 2, 2, # d8 - df + 2, 2, 2, 2, 2, 2, 2, 2, # e0 - e7 + 2, 2, 2, 2, 2, 2, 2, 2, # e8 - ef + 2, 2, 2, 2, 2, 2, 2, 2, # f0 - f7 + 2, 2, 2, 2, 2, 2, 2, 2, # f8 - ff ) ISO2022JP_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 -MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f -MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 + MachineState.START, 3, MachineState.ERROR, MachineState.START, MachineState.START, MachineState.START, MachineState.START, MachineState.START, # 00-07 + MachineState.START, MachineState.START, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, # 08-0f + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, # 10-17 + MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ERROR, MachineState.ERROR, # 18-1f + MachineState.ERROR, 5, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, 4, MachineState.ERROR, MachineState.ERROR, # 20-27 + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, 6, MachineState.ITS_ME, MachineState.ERROR, MachineState.ITS_ME, MachineState.ERROR, # 28-2f + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ITS_ME, # 30-37 + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, # 38-3f + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ERROR, MachineState.START, MachineState.START, # 40-47 ) +# fmt: on ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) -ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, - 'class_factor': 10, - 'state_table': ISO2022JP_ST, - 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, - 'name': "ISO-2022-JP", - 'language': 'Japanese'} +ISO2022JP_SM_MODEL: CodingStateMachineDict = { + "class_table": ISO2022JP_CLS, + "class_factor": 10, + "state_table": ISO2022JP_ST, + "char_len_table": ISO2022JP_CHAR_LEN_TABLE, + "name": "ISO-2022-JP", + "language": "Japanese", +} +# fmt: off ISO2022KR_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,3,0,0,0, # 20 - 27 -0,4,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,5,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff + 2, 0, 0, 0, 0, 0, 0, 0, # 00 - 07 + 0, 0, 0, 0, 0, 0, 0, 0, # 08 - 0f + 0, 0, 0, 0, 0, 0, 0, 0, # 10 - 17 + 0, 0, 0, 1, 0, 0, 0, 0, # 18 - 1f + 0, 0, 0, 0, 3, 0, 0, 0, # 20 - 27 + 0, 4, 0, 0, 0, 0, 0, 0, # 28 - 2f + 0, 0, 0, 0, 0, 0, 0, 0, # 30 - 37 + 0, 0, 0, 0, 0, 0, 0, 0, # 38 - 3f + 0, 0, 0, 5, 0, 0, 0, 0, # 40 - 47 + 0, 0, 0, 0, 0, 0, 0, 0, # 48 - 4f + 0, 0, 0, 0, 0, 0, 0, 0, # 50 - 57 + 0, 0, 0, 0, 0, 0, 0, 0, # 58 - 5f + 0, 0, 0, 0, 0, 0, 0, 0, # 60 - 67 + 0, 0, 0, 0, 0, 0, 0, 0, # 68 - 6f + 0, 0, 0, 0, 0, 0, 0, 0, # 70 - 77 + 0, 0, 0, 0, 0, 0, 0, 0, # 78 - 7f + 2, 2, 2, 2, 2, 2, 2, 2, # 80 - 87 + 2, 2, 2, 2, 2, 2, 2, 2, # 88 - 8f + 2, 2, 2, 2, 2, 2, 2, 2, # 90 - 97 + 2, 2, 2, 2, 2, 2, 2, 2, # 98 - 9f + 2, 2, 2, 2, 2, 2, 2, 2, # a0 - a7 + 2, 2, 2, 2, 2, 2, 2, 2, # a8 - af + 2, 2, 2, 2, 2, 2, 2, 2, # b0 - b7 + 2, 2, 2, 2, 2, 2, 2, 2, # b8 - bf + 2, 2, 2, 2, 2, 2, 2, 2, # c0 - c7 + 2, 2, 2, 2, 2, 2, 2, 2, # c8 - cf + 2, 2, 2, 2, 2, 2, 2, 2, # d0 - d7 + 2, 2, 2, 2, 2, 2, 2, 2, # d8 - df + 2, 2, 2, 2, 2, 2, 2, 2, # e0 - e7 + 2, 2, 2, 2, 2, 2, 2, 2, # e8 - ef + 2, 2, 2, 2, 2, 2, 2, 2, # f0 - f7 + 2, 2, 2, 2, 2, 2, 2, 2, # f8 - ff ) ISO2022KR_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 + MachineState.START, 3, MachineState.ERROR, MachineState.START, MachineState.START, MachineState.START, MachineState.ERROR, MachineState.ERROR, # 00-07 + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ITS_ME, # 08-0f + MachineState.ITS_ME, MachineState.ITS_ME, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, 4, MachineState.ERROR, MachineState.ERROR, # 10-17 + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, 5, MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, # 18-1f + MachineState.ERROR, MachineState.ERROR, MachineState.ERROR, MachineState.ITS_ME, MachineState.START, MachineState.START, MachineState.START, MachineState.START, # 20-27 ) +# fmt: on ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) -ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, - 'class_factor': 6, - 'state_table': ISO2022KR_ST, - 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, - 'name': "ISO-2022-KR", - 'language': 'Korean'} - - +ISO2022KR_SM_MODEL: CodingStateMachineDict = { + "class_table": ISO2022KR_CLS, + "class_factor": 6, + "state_table": ISO2022KR_ST, + "char_len_table": ISO2022KR_CHAR_LEN_TABLE, + "name": "ISO-2022-KR", + "language": "Korean", +} diff --git a/script.module.chardet/lib/chardet/eucjpprober.py b/script.module.chardet/lib/chardet/eucjpprober.py index 20ce8f7d1..39487f409 100644 --- a/script.module.chardet/lib/chardet/eucjpprober.py +++ b/script.module.chardet/lib/chardet/eucjpprober.py @@ -25,68 +25,78 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .enums import ProbingState, MachineState -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine +from typing import Union + from .chardistribution import EUCJPDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .enums import MachineState, ProbingState from .jpcntx import EUCJPContextAnalysis +from .mbcharsetprober import MultiByteCharSetProber from .mbcssm import EUCJP_SM_MODEL class EUCJPProber(MultiByteCharSetProber): - def __init__(self): - super(EUCJPProber, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) self.distribution_analyzer = EUCJPDistributionAnalysis() self.context_analyzer = EUCJPContextAnalysis() self.reset() - def reset(self): - super(EUCJPProber, self).reset() + def reset(self) -> None: + super().reset() self.context_analyzer.reset() @property - def charset_name(self): + def charset_name(self) -> str: return "EUC-JP" @property - def language(self): + def language(self) -> str: return "Japanese" - def feed(self, byte_str): - for i in range(len(byte_str)): - # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte - coding_state = self.coding_sm.next_state(byte_str[i]) + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: + assert self.coding_sm is not None + assert self.distribution_analyzer is not None + + for i, byte in enumerate(byte_str): + # PY3K: byte_str is a byte array, so byte is an int, not a byte + coding_state = self.coding_sm.next_state(byte) if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) + self.logger.debug( + "%s %s prober hit error at byte %s", + self.charset_name, + self.language, + i, + ) self._state = ProbingState.NOT_ME break - elif coding_state == MachineState.ITS_ME: + if coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break - elif coding_state == MachineState.START: + if coding_state == MachineState.START: char_len = self.coding_sm.get_current_charlen() if i == 0: - self._last_char[1] = byte_str[0] + self._last_char[1] = byte self.context_analyzer.feed(self._last_char, char_len) self.distribution_analyzer.feed(self._last_char, char_len) else: - self.context_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) + self.context_analyzer.feed(byte_str[i - 1 : i + 1], char_len) + self.distribution_analyzer.feed(byte_str[i - 1 : i + 1], char_len) self._last_char[0] = byte_str[-1] if self.state == ProbingState.DETECTING: - if (self.context_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + if self.context_analyzer.got_enough_data() and ( + self.get_confidence() > self.SHORTCUT_THRESHOLD + ): self._state = ProbingState.FOUND_IT return self.state - def get_confidence(self): + def get_confidence(self) -> float: + assert self.distribution_analyzer is not None + context_conf = self.context_analyzer.get_confidence() distrib_conf = self.distribution_analyzer.get_confidence() return max(context_conf, distrib_conf) diff --git a/script.module.chardet/lib/chardet/euckrfreq.py b/script.module.chardet/lib/chardet/euckrfreq.py index b68078cb9..7dc3b1038 100644 --- a/script.module.chardet/lib/chardet/euckrfreq.py +++ b/script.module.chardet/lib/chardet/euckrfreq.py @@ -43,6 +43,7 @@ EUCKR_TABLE_SIZE = 2352 # Char to FreqOrder table , +# fmt: off EUCKR_CHAR_TO_FREQ_ORDER = ( 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, 1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, @@ -192,4 +193,4 @@ 2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 ) - +# fmt: on diff --git a/script.module.chardet/lib/chardet/euckrprober.py b/script.module.chardet/lib/chardet/euckrprober.py index 345a060d0..1fc5de046 100644 --- a/script.module.chardet/lib/chardet/euckrprober.py +++ b/script.module.chardet/lib/chardet/euckrprober.py @@ -25,23 +25,23 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine from .chardistribution import EUCKRDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber from .mbcssm import EUCKR_SM_MODEL class EUCKRProber(MultiByteCharSetProber): - def __init__(self): - super(EUCKRProber, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) self.distribution_analyzer = EUCKRDistributionAnalysis() self.reset() @property - def charset_name(self): + def charset_name(self) -> str: return "EUC-KR" @property - def language(self): + def language(self) -> str: return "Korean" diff --git a/script.module.chardet/lib/chardet/euctwfreq.py b/script.module.chardet/lib/chardet/euctwfreq.py index ed7a995a3..4900ccc16 100644 --- a/script.module.chardet/lib/chardet/euctwfreq.py +++ b/script.module.chardet/lib/chardet/euctwfreq.py @@ -43,345 +43,346 @@ EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 -# Char to FreqOrder table , +# Char to FreqOrder table EUCTW_TABLE_SIZE = 5376 +# fmt: off EUCTW_CHAR_TO_FREQ_ORDER = ( - 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 -3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 -1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 - 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 -3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 -4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 -7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 - 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 - 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 - 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 -2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 -1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 -3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 - 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 -1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 -3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 -2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 - 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 -3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 -1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 -7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 - 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 -7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 -1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 - 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 - 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 -3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 -3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 - 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 -2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 -2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 - 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 - 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 -3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 -1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 -1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 -1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 -2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 - 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 -4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 -1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 -7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 -2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 - 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 - 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 - 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 - 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 -7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 - 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 -1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 - 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 - 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 -7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 -1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 - 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 -3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 -4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 -3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 - 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 - 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 -1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 -4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 -3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 -3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 -2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 -7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 -3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 -7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 -1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 -2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 -1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 - 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 -1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 -4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 -3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 - 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 - 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 - 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 -2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 -7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 -1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 -2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 -1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 -1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 -7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 -7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 -7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 -3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 -4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 -1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 -7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 -2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 -7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 -3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 -3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 -7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 -2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 -7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 - 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 -4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 -2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 -7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 -3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 -2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 -2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 - 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 -2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 -1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 -1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 -2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 -1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 -7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 -7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 -2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 -4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 -1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 -7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 - 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 -4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 - 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 -2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 - 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 -1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 -1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 - 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 -3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 -3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 -1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 -3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 -7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 -7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 -1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 -2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 -1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 -3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 -2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 -3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 -2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 -4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 -4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 -3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 - 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 -3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 - 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 -3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 -3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 -3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 -1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 -7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 - 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 -7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 -1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 - 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 -4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 -3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 - 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 -2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 -2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 -3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 -1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 -4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 -2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 -1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 -1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 -2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 -3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 -1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 -7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 -1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 -4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 -1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 - 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 -1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 -3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 -3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 -2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 -1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 -4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 - 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 -7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 -2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 -3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 -4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 - 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 -7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 -7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 -1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 -4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 -3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 -2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 -3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 -3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 -2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 -1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 -4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 -3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 -3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 -2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 -4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 -7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 -3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 -2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 -3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 -1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 -2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 -3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 -4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 -2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 -2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 -7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 -1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 -2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 -1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 -3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 -4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 -2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 -3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 -3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 -2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 -4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 -2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 -3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 -4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 -7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 -3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 - 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 -1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 -4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 -1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 -4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 -7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 - 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 -7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 -2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 -1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 -1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 -3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 - 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 - 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 - 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 -3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 -2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 - 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 -7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 -1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 -3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 -7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 -1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 -7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 -4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 -1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 -2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 -2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 -4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 - 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 - 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 -3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 -3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 -1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 -2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 -7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 -1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 -1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 -3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 - 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 -1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 -4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 -7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 -2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 -3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 - 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 -1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 -2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 -2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 -7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 -7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 -7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 -2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 -2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 -1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 -4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 -3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 -3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 -4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 -4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 -2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 -2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 -7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 -4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 -7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 -2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 -1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 -3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 -4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 -2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 - 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 -2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 -1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 -2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 -2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 -4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 -7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 -1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 -3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 -7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 -1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 -8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 -2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 -8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 -2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 -2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 -8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 -8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 -8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 - 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 -8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 -4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 -3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 -8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 -1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 -8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 - 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 -1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 - 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 -4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 -1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 -4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 -1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 - 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 -3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 -4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 -8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 - 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 -3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 - 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 -2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 + 1, 1800, 1506, 255, 1431, 198, 9, 82, 6, 7310, 177, 202, 3615, 1256, 2808, 110, # 2742 + 3735, 33, 3241, 261, 76, 44, 2113, 16, 2931, 2184, 1176, 659, 3868, 26, 3404, 2643, # 2758 + 1198, 3869, 3313, 4060, 410, 2211, 302, 590, 361, 1963, 8, 204, 58, 4296, 7311, 1931, # 2774 + 63, 7312, 7313, 317, 1614, 75, 222, 159, 4061, 2412, 1480, 7314, 3500, 3068, 224, 2809, # 2790 + 3616, 3, 10, 3870, 1471, 29, 2774, 1135, 2852, 1939, 873, 130, 3242, 1123, 312, 7315, # 2806 + 4297, 2051, 507, 252, 682, 7316, 142, 1914, 124, 206, 2932, 34, 3501, 3173, 64, 604, # 2822 + 7317, 2494, 1976, 1977, 155, 1990, 645, 641, 1606, 7318, 3405, 337, 72, 406, 7319, 80, # 2838 + 630, 238, 3174, 1509, 263, 939, 1092, 2644, 756, 1440, 1094, 3406, 449, 69, 2969, 591, # 2854 + 179, 2095, 471, 115, 2034, 1843, 60, 50, 2970, 134, 806, 1868, 734, 2035, 3407, 180, # 2870 + 995, 1607, 156, 537, 2893, 688, 7320, 319, 1305, 779, 2144, 514, 2374, 298, 4298, 359, # 2886 + 2495, 90, 2707, 1338, 663, 11, 906, 1099, 2545, 20, 2436, 182, 532, 1716, 7321, 732, # 2902 + 1376, 4062, 1311, 1420, 3175, 25, 2312, 1056, 113, 399, 382, 1949, 242, 3408, 2467, 529, # 2918 + 3243, 475, 1447, 3617, 7322, 117, 21, 656, 810, 1297, 2295, 2329, 3502, 7323, 126, 4063, # 2934 + 706, 456, 150, 613, 4299, 71, 1118, 2036, 4064, 145, 3069, 85, 835, 486, 2114, 1246, # 2950 + 1426, 428, 727, 1285, 1015, 800, 106, 623, 303, 1281, 7324, 2127, 2354, 347, 3736, 221, # 2966 + 3503, 3110, 7325, 1955, 1153, 4065, 83, 296, 1199, 3070, 192, 624, 93, 7326, 822, 1897, # 2982 + 2810, 3111, 795, 2064, 991, 1554, 1542, 1592, 27, 43, 2853, 859, 139, 1456, 860, 4300, # 2998 + 437, 712, 3871, 164, 2392, 3112, 695, 211, 3017, 2096, 195, 3872, 1608, 3504, 3505, 3618, # 3014 + 3873, 234, 811, 2971, 2097, 3874, 2229, 1441, 3506, 1615, 2375, 668, 2076, 1638, 305, 228, # 3030 + 1664, 4301, 467, 415, 7327, 262, 2098, 1593, 239, 108, 300, 200, 1033, 512, 1247, 2077, # 3046 + 7328, 7329, 2173, 3176, 3619, 2673, 593, 845, 1062, 3244, 88, 1723, 2037, 3875, 1950, 212, # 3062 + 266, 152, 149, 468, 1898, 4066, 4302, 77, 187, 7330, 3018, 37, 5, 2972, 7331, 3876, # 3078 + 7332, 7333, 39, 2517, 4303, 2894, 3177, 2078, 55, 148, 74, 4304, 545, 483, 1474, 1029, # 3094 + 1665, 217, 1869, 1531, 3113, 1104, 2645, 4067, 24, 172, 3507, 900, 3877, 3508, 3509, 4305, # 3110 + 32, 1408, 2811, 1312, 329, 487, 2355, 2247, 2708, 784, 2674, 4, 3019, 3314, 1427, 1788, # 3126 + 188, 109, 499, 7334, 3620, 1717, 1789, 888, 1217, 3020, 4306, 7335, 3510, 7336, 3315, 1520, # 3142 + 3621, 3878, 196, 1034, 775, 7337, 7338, 929, 1815, 249, 439, 38, 7339, 1063, 7340, 794, # 3158 + 3879, 1435, 2296, 46, 178, 3245, 2065, 7341, 2376, 7342, 214, 1709, 4307, 804, 35, 707, # 3174 + 324, 3622, 1601, 2546, 140, 459, 4068, 7343, 7344, 1365, 839, 272, 978, 2257, 2572, 3409, # 3190 + 2128, 1363, 3623, 1423, 697, 100, 3071, 48, 70, 1231, 495, 3114, 2193, 7345, 1294, 7346, # 3206 + 2079, 462, 586, 1042, 3246, 853, 256, 988, 185, 2377, 3410, 1698, 434, 1084, 7347, 3411, # 3222 + 314, 2615, 2775, 4308, 2330, 2331, 569, 2280, 637, 1816, 2518, 757, 1162, 1878, 1616, 3412, # 3238 + 287, 1577, 2115, 768, 4309, 1671, 2854, 3511, 2519, 1321, 3737, 909, 2413, 7348, 4069, 933, # 3254 + 3738, 7349, 2052, 2356, 1222, 4310, 765, 2414, 1322, 786, 4311, 7350, 1919, 1462, 1677, 2895, # 3270 + 1699, 7351, 4312, 1424, 2437, 3115, 3624, 2590, 3316, 1774, 1940, 3413, 3880, 4070, 309, 1369, # 3286 + 1130, 2812, 364, 2230, 1653, 1299, 3881, 3512, 3882, 3883, 2646, 525, 1085, 3021, 902, 2000, # 3302 + 1475, 964, 4313, 421, 1844, 1415, 1057, 2281, 940, 1364, 3116, 376, 4314, 4315, 1381, 7, # 3318 + 2520, 983, 2378, 336, 1710, 2675, 1845, 321, 3414, 559, 1131, 3022, 2742, 1808, 1132, 1313, # 3334 + 265, 1481, 1857, 7352, 352, 1203, 2813, 3247, 167, 1089, 420, 2814, 776, 792, 1724, 3513, # 3350 + 4071, 2438, 3248, 7353, 4072, 7354, 446, 229, 333, 2743, 901, 3739, 1200, 1557, 4316, 2647, # 3366 + 1920, 395, 2744, 2676, 3740, 4073, 1835, 125, 916, 3178, 2616, 4317, 7355, 7356, 3741, 7357, # 3382 + 7358, 7359, 4318, 3117, 3625, 1133, 2547, 1757, 3415, 1510, 2313, 1409, 3514, 7360, 2145, 438, # 3398 + 2591, 2896, 2379, 3317, 1068, 958, 3023, 461, 311, 2855, 2677, 4074, 1915, 3179, 4075, 1978, # 3414 + 383, 750, 2745, 2617, 4076, 274, 539, 385, 1278, 1442, 7361, 1154, 1964, 384, 561, 210, # 3430 + 98, 1295, 2548, 3515, 7362, 1711, 2415, 1482, 3416, 3884, 2897, 1257, 129, 7363, 3742, 642, # 3446 + 523, 2776, 2777, 2648, 7364, 141, 2231, 1333, 68, 176, 441, 876, 907, 4077, 603, 2592, # 3462 + 710, 171, 3417, 404, 549, 18, 3118, 2393, 1410, 3626, 1666, 7365, 3516, 4319, 2898, 4320, # 3478 + 7366, 2973, 368, 7367, 146, 366, 99, 871, 3627, 1543, 748, 807, 1586, 1185, 22, 2258, # 3494 + 379, 3743, 3180, 7368, 3181, 505, 1941, 2618, 1991, 1382, 2314, 7369, 380, 2357, 218, 702, # 3510 + 1817, 1248, 3418, 3024, 3517, 3318, 3249, 7370, 2974, 3628, 930, 3250, 3744, 7371, 59, 7372, # 3526 + 585, 601, 4078, 497, 3419, 1112, 1314, 4321, 1801, 7373, 1223, 1472, 2174, 7374, 749, 1836, # 3542 + 690, 1899, 3745, 1772, 3885, 1476, 429, 1043, 1790, 2232, 2116, 917, 4079, 447, 1086, 1629, # 3558 + 7375, 556, 7376, 7377, 2020, 1654, 844, 1090, 105, 550, 966, 1758, 2815, 1008, 1782, 686, # 3574 + 1095, 7378, 2282, 793, 1602, 7379, 3518, 2593, 4322, 4080, 2933, 2297, 4323, 3746, 980, 2496, # 3590 + 544, 353, 527, 4324, 908, 2678, 2899, 7380, 381, 2619, 1942, 1348, 7381, 1341, 1252, 560, # 3606 + 3072, 7382, 3420, 2856, 7383, 2053, 973, 886, 2080, 143, 4325, 7384, 7385, 157, 3886, 496, # 3622 + 4081, 57, 840, 540, 2038, 4326, 4327, 3421, 2117, 1445, 970, 2259, 1748, 1965, 2081, 4082, # 3638 + 3119, 1234, 1775, 3251, 2816, 3629, 773, 1206, 2129, 1066, 2039, 1326, 3887, 1738, 1725, 4083, # 3654 + 279, 3120, 51, 1544, 2594, 423, 1578, 2130, 2066, 173, 4328, 1879, 7386, 7387, 1583, 264, # 3670 + 610, 3630, 4329, 2439, 280, 154, 7388, 7389, 7390, 1739, 338, 1282, 3073, 693, 2857, 1411, # 3686 + 1074, 3747, 2440, 7391, 4330, 7392, 7393, 1240, 952, 2394, 7394, 2900, 1538, 2679, 685, 1483, # 3702 + 4084, 2468, 1436, 953, 4085, 2054, 4331, 671, 2395, 79, 4086, 2441, 3252, 608, 567, 2680, # 3718 + 3422, 4087, 4088, 1691, 393, 1261, 1791, 2396, 7395, 4332, 7396, 7397, 7398, 7399, 1383, 1672, # 3734 + 3748, 3182, 1464, 522, 1119, 661, 1150, 216, 675, 4333, 3888, 1432, 3519, 609, 4334, 2681, # 3750 + 2397, 7400, 7401, 7402, 4089, 3025, 0, 7403, 2469, 315, 231, 2442, 301, 3319, 4335, 2380, # 3766 + 7404, 233, 4090, 3631, 1818, 4336, 4337, 7405, 96, 1776, 1315, 2082, 7406, 257, 7407, 1809, # 3782 + 3632, 2709, 1139, 1819, 4091, 2021, 1124, 2163, 2778, 1777, 2649, 7408, 3074, 363, 1655, 3183, # 3798 + 7409, 2975, 7410, 7411, 7412, 3889, 1567, 3890, 718, 103, 3184, 849, 1443, 341, 3320, 2934, # 3814 + 1484, 7413, 1712, 127, 67, 339, 4092, 2398, 679, 1412, 821, 7414, 7415, 834, 738, 351, # 3830 + 2976, 2146, 846, 235, 1497, 1880, 418, 1992, 3749, 2710, 186, 1100, 2147, 2746, 3520, 1545, # 3846 + 1355, 2935, 2858, 1377, 583, 3891, 4093, 2573, 2977, 7416, 1298, 3633, 1078, 2549, 3634, 2358, # 3862 + 78, 3750, 3751, 267, 1289, 2099, 2001, 1594, 4094, 348, 369, 1274, 2194, 2175, 1837, 4338, # 3878 + 1820, 2817, 3635, 2747, 2283, 2002, 4339, 2936, 2748, 144, 3321, 882, 4340, 3892, 2749, 3423, # 3894 + 4341, 2901, 7417, 4095, 1726, 320, 7418, 3893, 3026, 788, 2978, 7419, 2818, 1773, 1327, 2859, # 3910 + 3894, 2819, 7420, 1306, 4342, 2003, 1700, 3752, 3521, 2359, 2650, 787, 2022, 506, 824, 3636, # 3926 + 534, 323, 4343, 1044, 3322, 2023, 1900, 946, 3424, 7421, 1778, 1500, 1678, 7422, 1881, 4344, # 3942 + 165, 243, 4345, 3637, 2521, 123, 683, 4096, 764, 4346, 36, 3895, 1792, 589, 2902, 816, # 3958 + 626, 1667, 3027, 2233, 1639, 1555, 1622, 3753, 3896, 7423, 3897, 2860, 1370, 1228, 1932, 891, # 3974 + 2083, 2903, 304, 4097, 7424, 292, 2979, 2711, 3522, 691, 2100, 4098, 1115, 4347, 118, 662, # 3990 + 7425, 611, 1156, 854, 2381, 1316, 2861, 2, 386, 515, 2904, 7426, 7427, 3253, 868, 2234, # 4006 + 1486, 855, 2651, 785, 2212, 3028, 7428, 1040, 3185, 3523, 7429, 3121, 448, 7430, 1525, 7431, # 4022 + 2164, 4348, 7432, 3754, 7433, 4099, 2820, 3524, 3122, 503, 818, 3898, 3123, 1568, 814, 676, # 4038 + 1444, 306, 1749, 7434, 3755, 1416, 1030, 197, 1428, 805, 2821, 1501, 4349, 7435, 7436, 7437, # 4054 + 1993, 7438, 4350, 7439, 7440, 2195, 13, 2779, 3638, 2980, 3124, 1229, 1916, 7441, 3756, 2131, # 4070 + 7442, 4100, 4351, 2399, 3525, 7443, 2213, 1511, 1727, 1120, 7444, 7445, 646, 3757, 2443, 307, # 4086 + 7446, 7447, 1595, 3186, 7448, 7449, 7450, 3639, 1113, 1356, 3899, 1465, 2522, 2523, 7451, 519, # 4102 + 7452, 128, 2132, 92, 2284, 1979, 7453, 3900, 1512, 342, 3125, 2196, 7454, 2780, 2214, 1980, # 4118 + 3323, 7455, 290, 1656, 1317, 789, 827, 2360, 7456, 3758, 4352, 562, 581, 3901, 7457, 401, # 4134 + 4353, 2248, 94, 4354, 1399, 2781, 7458, 1463, 2024, 4355, 3187, 1943, 7459, 828, 1105, 4101, # 4150 + 1262, 1394, 7460, 4102, 605, 4356, 7461, 1783, 2862, 7462, 2822, 819, 2101, 578, 2197, 2937, # 4166 + 7463, 1502, 436, 3254, 4103, 3255, 2823, 3902, 2905, 3425, 3426, 7464, 2712, 2315, 7465, 7466, # 4182 + 2332, 2067, 23, 4357, 193, 826, 3759, 2102, 699, 1630, 4104, 3075, 390, 1793, 1064, 3526, # 4198 + 7467, 1579, 3076, 3077, 1400, 7468, 4105, 1838, 1640, 2863, 7469, 4358, 4359, 137, 4106, 598, # 4214 + 3078, 1966, 780, 104, 974, 2938, 7470, 278, 899, 253, 402, 572, 504, 493, 1339, 7471, # 4230 + 3903, 1275, 4360, 2574, 2550, 7472, 3640, 3029, 3079, 2249, 565, 1334, 2713, 863, 41, 7473, # 4246 + 7474, 4361, 7475, 1657, 2333, 19, 463, 2750, 4107, 606, 7476, 2981, 3256, 1087, 2084, 1323, # 4262 + 2652, 2982, 7477, 1631, 1623, 1750, 4108, 2682, 7478, 2864, 791, 2714, 2653, 2334, 232, 2416, # 4278 + 7479, 2983, 1498, 7480, 2654, 2620, 755, 1366, 3641, 3257, 3126, 2025, 1609, 119, 1917, 3427, # 4294 + 862, 1026, 4109, 7481, 3904, 3760, 4362, 3905, 4363, 2260, 1951, 2470, 7482, 1125, 817, 4110, # 4310 + 4111, 3906, 1513, 1766, 2040, 1487, 4112, 3030, 3258, 2824, 3761, 3127, 7483, 7484, 1507, 7485, # 4326 + 2683, 733, 40, 1632, 1106, 2865, 345, 4113, 841, 2524, 230, 4364, 2984, 1846, 3259, 3428, # 4342 + 7486, 1263, 986, 3429, 7487, 735, 879, 254, 1137, 857, 622, 1300, 1180, 1388, 1562, 3907, # 4358 + 3908, 2939, 967, 2751, 2655, 1349, 592, 2133, 1692, 3324, 2985, 1994, 4114, 1679, 3909, 1901, # 4374 + 2185, 7488, 739, 3642, 2715, 1296, 1290, 7489, 4115, 2198, 2199, 1921, 1563, 2595, 2551, 1870, # 4390 + 2752, 2986, 7490, 435, 7491, 343, 1108, 596, 17, 1751, 4365, 2235, 3430, 3643, 7492, 4366, # 4406 + 294, 3527, 2940, 1693, 477, 979, 281, 2041, 3528, 643, 2042, 3644, 2621, 2782, 2261, 1031, # 4422 + 2335, 2134, 2298, 3529, 4367, 367, 1249, 2552, 7493, 3530, 7494, 4368, 1283, 3325, 2004, 240, # 4438 + 1762, 3326, 4369, 4370, 836, 1069, 3128, 474, 7495, 2148, 2525, 268, 3531, 7496, 3188, 1521, # 4454 + 1284, 7497, 1658, 1546, 4116, 7498, 3532, 3533, 7499, 4117, 3327, 2684, 1685, 4118, 961, 1673, # 4470 + 2622, 190, 2005, 2200, 3762, 4371, 4372, 7500, 570, 2497, 3645, 1490, 7501, 4373, 2623, 3260, # 4486 + 1956, 4374, 584, 1514, 396, 1045, 1944, 7502, 4375, 1967, 2444, 7503, 7504, 4376, 3910, 619, # 4502 + 7505, 3129, 3261, 215, 2006, 2783, 2553, 3189, 4377, 3190, 4378, 763, 4119, 3763, 4379, 7506, # 4518 + 7507, 1957, 1767, 2941, 3328, 3646, 1174, 452, 1477, 4380, 3329, 3130, 7508, 2825, 1253, 2382, # 4534 + 2186, 1091, 2285, 4120, 492, 7509, 638, 1169, 1824, 2135, 1752, 3911, 648, 926, 1021, 1324, # 4550 + 4381, 520, 4382, 997, 847, 1007, 892, 4383, 3764, 2262, 1871, 3647, 7510, 2400, 1784, 4384, # 4566 + 1952, 2942, 3080, 3191, 1728, 4121, 2043, 3648, 4385, 2007, 1701, 3131, 1551, 30, 2263, 4122, # 4582 + 7511, 2026, 4386, 3534, 7512, 501, 7513, 4123, 594, 3431, 2165, 1821, 3535, 3432, 3536, 3192, # 4598 + 829, 2826, 4124, 7514, 1680, 3132, 1225, 4125, 7515, 3262, 4387, 4126, 3133, 2336, 7516, 4388, # 4614 + 4127, 7517, 3912, 3913, 7518, 1847, 2383, 2596, 3330, 7519, 4389, 374, 3914, 652, 4128, 4129, # 4630 + 375, 1140, 798, 7520, 7521, 7522, 2361, 4390, 2264, 546, 1659, 138, 3031, 2445, 4391, 7523, # 4646 + 2250, 612, 1848, 910, 796, 3765, 1740, 1371, 825, 3766, 3767, 7524, 2906, 2554, 7525, 692, # 4662 + 444, 3032, 2624, 801, 4392, 4130, 7526, 1491, 244, 1053, 3033, 4131, 4132, 340, 7527, 3915, # 4678 + 1041, 2987, 293, 1168, 87, 1357, 7528, 1539, 959, 7529, 2236, 721, 694, 4133, 3768, 219, # 4694 + 1478, 644, 1417, 3331, 2656, 1413, 1401, 1335, 1389, 3916, 7530, 7531, 2988, 2362, 3134, 1825, # 4710 + 730, 1515, 184, 2827, 66, 4393, 7532, 1660, 2943, 246, 3332, 378, 1457, 226, 3433, 975, # 4726 + 3917, 2944, 1264, 3537, 674, 696, 7533, 163, 7534, 1141, 2417, 2166, 713, 3538, 3333, 4394, # 4742 + 3918, 7535, 7536, 1186, 15, 7537, 1079, 1070, 7538, 1522, 3193, 3539, 276, 1050, 2716, 758, # 4758 + 1126, 653, 2945, 3263, 7539, 2337, 889, 3540, 3919, 3081, 2989, 903, 1250, 4395, 3920, 3434, # 4774 + 3541, 1342, 1681, 1718, 766, 3264, 286, 89, 2946, 3649, 7540, 1713, 7541, 2597, 3334, 2990, # 4790 + 7542, 2947, 2215, 3194, 2866, 7543, 4396, 2498, 2526, 181, 387, 1075, 3921, 731, 2187, 3335, # 4806 + 7544, 3265, 310, 313, 3435, 2299, 770, 4134, 54, 3034, 189, 4397, 3082, 3769, 3922, 7545, # 4822 + 1230, 1617, 1849, 355, 3542, 4135, 4398, 3336, 111, 4136, 3650, 1350, 3135, 3436, 3035, 4137, # 4838 + 2149, 3266, 3543, 7546, 2784, 3923, 3924, 2991, 722, 2008, 7547, 1071, 247, 1207, 2338, 2471, # 4854 + 1378, 4399, 2009, 864, 1437, 1214, 4400, 373, 3770, 1142, 2216, 667, 4401, 442, 2753, 2555, # 4870 + 3771, 3925, 1968, 4138, 3267, 1839, 837, 170, 1107, 934, 1336, 1882, 7548, 7549, 2118, 4139, # 4886 + 2828, 743, 1569, 7550, 4402, 4140, 582, 2384, 1418, 3437, 7551, 1802, 7552, 357, 1395, 1729, # 4902 + 3651, 3268, 2418, 1564, 2237, 7553, 3083, 3772, 1633, 4403, 1114, 2085, 4141, 1532, 7554, 482, # 4918 + 2446, 4404, 7555, 7556, 1492, 833, 1466, 7557, 2717, 3544, 1641, 2829, 7558, 1526, 1272, 3652, # 4934 + 4142, 1686, 1794, 416, 2556, 1902, 1953, 1803, 7559, 3773, 2785, 3774, 1159, 2316, 7560, 2867, # 4950 + 4405, 1610, 1584, 3036, 2419, 2754, 443, 3269, 1163, 3136, 7561, 7562, 3926, 7563, 4143, 2499, # 4966 + 3037, 4406, 3927, 3137, 2103, 1647, 3545, 2010, 1872, 4144, 7564, 4145, 431, 3438, 7565, 250, # 4982 + 97, 81, 4146, 7566, 1648, 1850, 1558, 160, 848, 7567, 866, 740, 1694, 7568, 2201, 2830, # 4998 + 3195, 4147, 4407, 3653, 1687, 950, 2472, 426, 469, 3196, 3654, 3655, 3928, 7569, 7570, 1188, # 5014 + 424, 1995, 861, 3546, 4148, 3775, 2202, 2685, 168, 1235, 3547, 4149, 7571, 2086, 1674, 4408, # 5030 + 3337, 3270, 220, 2557, 1009, 7572, 3776, 670, 2992, 332, 1208, 717, 7573, 7574, 3548, 2447, # 5046 + 3929, 3338, 7575, 513, 7576, 1209, 2868, 3339, 3138, 4409, 1080, 7577, 7578, 7579, 7580, 2527, # 5062 + 3656, 3549, 815, 1587, 3930, 3931, 7581, 3550, 3439, 3777, 1254, 4410, 1328, 3038, 1390, 3932, # 5078 + 1741, 3933, 3778, 3934, 7582, 236, 3779, 2448, 3271, 7583, 7584, 3657, 3780, 1273, 3781, 4411, # 5094 + 7585, 308, 7586, 4412, 245, 4413, 1851, 2473, 1307, 2575, 430, 715, 2136, 2449, 7587, 270, # 5110 + 199, 2869, 3935, 7588, 3551, 2718, 1753, 761, 1754, 725, 1661, 1840, 4414, 3440, 3658, 7589, # 5126 + 7590, 587, 14, 3272, 227, 2598, 326, 480, 2265, 943, 2755, 3552, 291, 650, 1883, 7591, # 5142 + 1702, 1226, 102, 1547, 62, 3441, 904, 4415, 3442, 1164, 4150, 7592, 7593, 1224, 1548, 2756, # 5158 + 391, 498, 1493, 7594, 1386, 1419, 7595, 2055, 1177, 4416, 813, 880, 1081, 2363, 566, 1145, # 5174 + 4417, 2286, 1001, 1035, 2558, 2599, 2238, 394, 1286, 7596, 7597, 2068, 7598, 86, 1494, 1730, # 5190 + 3936, 491, 1588, 745, 897, 2948, 843, 3340, 3937, 2757, 2870, 3273, 1768, 998, 2217, 2069, # 5206 + 397, 1826, 1195, 1969, 3659, 2993, 3341, 284, 7599, 3782, 2500, 2137, 2119, 1903, 7600, 3938, # 5222 + 2150, 3939, 4151, 1036, 3443, 1904, 114, 2559, 4152, 209, 1527, 7601, 7602, 2949, 2831, 2625, # 5238 + 2385, 2719, 3139, 812, 2560, 7603, 3274, 7604, 1559, 737, 1884, 3660, 1210, 885, 28, 2686, # 5254 + 3553, 3783, 7605, 4153, 1004, 1779, 4418, 7606, 346, 1981, 2218, 2687, 4419, 3784, 1742, 797, # 5270 + 1642, 3940, 1933, 1072, 1384, 2151, 896, 3941, 3275, 3661, 3197, 2871, 3554, 7607, 2561, 1958, # 5286 + 4420, 2450, 1785, 7608, 7609, 7610, 3942, 4154, 1005, 1308, 3662, 4155, 2720, 4421, 4422, 1528, # 5302 + 2600, 161, 1178, 4156, 1982, 987, 4423, 1101, 4157, 631, 3943, 1157, 3198, 2420, 1343, 1241, # 5318 + 1016, 2239, 2562, 372, 877, 2339, 2501, 1160, 555, 1934, 911, 3944, 7611, 466, 1170, 169, # 5334 + 1051, 2907, 2688, 3663, 2474, 2994, 1182, 2011, 2563, 1251, 2626, 7612, 992, 2340, 3444, 1540, # 5350 + 2721, 1201, 2070, 2401, 1996, 2475, 7613, 4424, 528, 1922, 2188, 1503, 1873, 1570, 2364, 3342, # 5366 + 3276, 7614, 557, 1073, 7615, 1827, 3445, 2087, 2266, 3140, 3039, 3084, 767, 3085, 2786, 4425, # 5382 + 1006, 4158, 4426, 2341, 1267, 2176, 3664, 3199, 778, 3945, 3200, 2722, 1597, 2657, 7616, 4427, # 5398 + 7617, 3446, 7618, 7619, 7620, 3277, 2689, 1433, 3278, 131, 95, 1504, 3946, 723, 4159, 3141, # 5414 + 1841, 3555, 2758, 2189, 3947, 2027, 2104, 3665, 7621, 2995, 3948, 1218, 7622, 3343, 3201, 3949, # 5430 + 4160, 2576, 248, 1634, 3785, 912, 7623, 2832, 3666, 3040, 3786, 654, 53, 7624, 2996, 7625, # 5446 + 1688, 4428, 777, 3447, 1032, 3950, 1425, 7626, 191, 820, 2120, 2833, 971, 4429, 931, 3202, # 5462 + 135, 664, 783, 3787, 1997, 772, 2908, 1935, 3951, 3788, 4430, 2909, 3203, 282, 2723, 640, # 5478 + 1372, 3448, 1127, 922, 325, 3344, 7627, 7628, 711, 2044, 7629, 7630, 3952, 2219, 2787, 1936, # 5494 + 3953, 3345, 2220, 2251, 3789, 2300, 7631, 4431, 3790, 1258, 3279, 3954, 3204, 2138, 2950, 3955, # 5510 + 3956, 7632, 2221, 258, 3205, 4432, 101, 1227, 7633, 3280, 1755, 7634, 1391, 3281, 7635, 2910, # 5526 + 2056, 893, 7636, 7637, 7638, 1402, 4161, 2342, 7639, 7640, 3206, 3556, 7641, 7642, 878, 1325, # 5542 + 1780, 2788, 4433, 259, 1385, 2577, 744, 1183, 2267, 4434, 7643, 3957, 2502, 7644, 684, 1024, # 5558 + 4162, 7645, 472, 3557, 3449, 1165, 3282, 3958, 3959, 322, 2152, 881, 455, 1695, 1152, 1340, # 5574 + 660, 554, 2153, 4435, 1058, 4436, 4163, 830, 1065, 3346, 3960, 4437, 1923, 7646, 1703, 1918, # 5590 + 7647, 932, 2268, 122, 7648, 4438, 947, 677, 7649, 3791, 2627, 297, 1905, 1924, 2269, 4439, # 5606 + 2317, 3283, 7650, 7651, 4164, 7652, 4165, 84, 4166, 112, 989, 7653, 547, 1059, 3961, 701, # 5622 + 3558, 1019, 7654, 4167, 7655, 3450, 942, 639, 457, 2301, 2451, 993, 2951, 407, 851, 494, # 5638 + 4440, 3347, 927, 7656, 1237, 7657, 2421, 3348, 573, 4168, 680, 921, 2911, 1279, 1874, 285, # 5654 + 790, 1448, 1983, 719, 2167, 7658, 7659, 4441, 3962, 3963, 1649, 7660, 1541, 563, 7661, 1077, # 5670 + 7662, 3349, 3041, 3451, 511, 2997, 3964, 3965, 3667, 3966, 1268, 2564, 3350, 3207, 4442, 4443, # 5686 + 7663, 535, 1048, 1276, 1189, 2912, 2028, 3142, 1438, 1373, 2834, 2952, 1134, 2012, 7664, 4169, # 5702 + 1238, 2578, 3086, 1259, 7665, 700, 7666, 2953, 3143, 3668, 4170, 7667, 4171, 1146, 1875, 1906, # 5718 + 4444, 2601, 3967, 781, 2422, 132, 1589, 203, 147, 273, 2789, 2402, 898, 1786, 2154, 3968, # 5734 + 3969, 7668, 3792, 2790, 7669, 7670, 4445, 4446, 7671, 3208, 7672, 1635, 3793, 965, 7673, 1804, # 5750 + 2690, 1516, 3559, 1121, 1082, 1329, 3284, 3970, 1449, 3794, 65, 1128, 2835, 2913, 2759, 1590, # 5766 + 3795, 7674, 7675, 12, 2658, 45, 976, 2579, 3144, 4447, 517, 2528, 1013, 1037, 3209, 7676, # 5782 + 3796, 2836, 7677, 3797, 7678, 3452, 7679, 2602, 614, 1998, 2318, 3798, 3087, 2724, 2628, 7680, # 5798 + 2580, 4172, 599, 1269, 7681, 1810, 3669, 7682, 2691, 3088, 759, 1060, 489, 1805, 3351, 3285, # 5814 + 1358, 7683, 7684, 2386, 1387, 1215, 2629, 2252, 490, 7685, 7686, 4173, 1759, 2387, 2343, 7687, # 5830 + 4448, 3799, 1907, 3971, 2630, 1806, 3210, 4449, 3453, 3286, 2760, 2344, 874, 7688, 7689, 3454, # 5846 + 3670, 1858, 91, 2914, 3671, 3042, 3800, 4450, 7690, 3145, 3972, 2659, 7691, 3455, 1202, 1403, # 5862 + 3801, 2954, 2529, 1517, 2503, 4451, 3456, 2504, 7692, 4452, 7693, 2692, 1885, 1495, 1731, 3973, # 5878 + 2365, 4453, 7694, 2029, 7695, 7696, 3974, 2693, 1216, 237, 2581, 4174, 2319, 3975, 3802, 4454, # 5894 + 4455, 2694, 3560, 3457, 445, 4456, 7697, 7698, 7699, 7700, 2761, 61, 3976, 3672, 1822, 3977, # 5910 + 7701, 687, 2045, 935, 925, 405, 2660, 703, 1096, 1859, 2725, 4457, 3978, 1876, 1367, 2695, # 5926 + 3352, 918, 2105, 1781, 2476, 334, 3287, 1611, 1093, 4458, 564, 3146, 3458, 3673, 3353, 945, # 5942 + 2631, 2057, 4459, 7702, 1925, 872, 4175, 7703, 3459, 2696, 3089, 349, 4176, 3674, 3979, 4460, # 5958 + 3803, 4177, 3675, 2155, 3980, 4461, 4462, 4178, 4463, 2403, 2046, 782, 3981, 400, 251, 4179, # 5974 + 1624, 7704, 7705, 277, 3676, 299, 1265, 476, 1191, 3804, 2121, 4180, 4181, 1109, 205, 7706, # 5990 + 2582, 1000, 2156, 3561, 1860, 7707, 7708, 7709, 4464, 7710, 4465, 2565, 107, 2477, 2157, 3982, # 6006 + 3460, 3147, 7711, 1533, 541, 1301, 158, 753, 4182, 2872, 3562, 7712, 1696, 370, 1088, 4183, # 6022 + 4466, 3563, 579, 327, 440, 162, 2240, 269, 1937, 1374, 3461, 968, 3043, 56, 1396, 3090, # 6038 + 2106, 3288, 3354, 7713, 1926, 2158, 4467, 2998, 7714, 3564, 7715, 7716, 3677, 4468, 2478, 7717, # 6054 + 2791, 7718, 1650, 4469, 7719, 2603, 7720, 7721, 3983, 2661, 3355, 1149, 3356, 3984, 3805, 3985, # 6070 + 7722, 1076, 49, 7723, 951, 3211, 3289, 3290, 450, 2837, 920, 7724, 1811, 2792, 2366, 4184, # 6086 + 1908, 1138, 2367, 3806, 3462, 7725, 3212, 4470, 1909, 1147, 1518, 2423, 4471, 3807, 7726, 4472, # 6102 + 2388, 2604, 260, 1795, 3213, 7727, 7728, 3808, 3291, 708, 7729, 3565, 1704, 7730, 3566, 1351, # 6118 + 1618, 3357, 2999, 1886, 944, 4185, 3358, 4186, 3044, 3359, 4187, 7731, 3678, 422, 413, 1714, # 6134 + 3292, 500, 2058, 2345, 4188, 2479, 7732, 1344, 1910, 954, 7733, 1668, 7734, 7735, 3986, 2404, # 6150 + 4189, 3567, 3809, 4190, 7736, 2302, 1318, 2505, 3091, 133, 3092, 2873, 4473, 629, 31, 2838, # 6166 + 2697, 3810, 4474, 850, 949, 4475, 3987, 2955, 1732, 2088, 4191, 1496, 1852, 7737, 3988, 620, # 6182 + 3214, 981, 1242, 3679, 3360, 1619, 3680, 1643, 3293, 2139, 2452, 1970, 1719, 3463, 2168, 7738, # 6198 + 3215, 7739, 7740, 3361, 1828, 7741, 1277, 4476, 1565, 2047, 7742, 1636, 3568, 3093, 7743, 869, # 6214 + 2839, 655, 3811, 3812, 3094, 3989, 3000, 3813, 1310, 3569, 4477, 7744, 7745, 7746, 1733, 558, # 6230 + 4478, 3681, 335, 1549, 3045, 1756, 4192, 3682, 1945, 3464, 1829, 1291, 1192, 470, 2726, 2107, # 6246 + 2793, 913, 1054, 3990, 7747, 1027, 7748, 3046, 3991, 4479, 982, 2662, 3362, 3148, 3465, 3216, # 6262 + 3217, 1946, 2794, 7749, 571, 4480, 7750, 1830, 7751, 3570, 2583, 1523, 2424, 7752, 2089, 984, # 6278 + 4481, 3683, 1959, 7753, 3684, 852, 923, 2795, 3466, 3685, 969, 1519, 999, 2048, 2320, 1705, # 6294 + 7754, 3095, 615, 1662, 151, 597, 3992, 2405, 2321, 1049, 275, 4482, 3686, 4193, 568, 3687, # 6310 + 3571, 2480, 4194, 3688, 7755, 2425, 2270, 409, 3218, 7756, 1566, 2874, 3467, 1002, 769, 2840, # 6326 + 194, 2090, 3149, 3689, 2222, 3294, 4195, 628, 1505, 7757, 7758, 1763, 2177, 3001, 3993, 521, # 6342 + 1161, 2584, 1787, 2203, 2406, 4483, 3994, 1625, 4196, 4197, 412, 42, 3096, 464, 7759, 2632, # 6358 + 4484, 3363, 1760, 1571, 2875, 3468, 2530, 1219, 2204, 3814, 2633, 2140, 2368, 4485, 4486, 3295, # 6374 + 1651, 3364, 3572, 7760, 7761, 3573, 2481, 3469, 7762, 3690, 7763, 7764, 2271, 2091, 460, 7765, # 6390 + 4487, 7766, 3002, 962, 588, 3574, 289, 3219, 2634, 1116, 52, 7767, 3047, 1796, 7768, 7769, # 6406 + 7770, 1467, 7771, 1598, 1143, 3691, 4198, 1984, 1734, 1067, 4488, 1280, 3365, 465, 4489, 1572, # 6422 + 510, 7772, 1927, 2241, 1812, 1644, 3575, 7773, 4490, 3692, 7774, 7775, 2663, 1573, 1534, 7776, # 6438 + 7777, 4199, 536, 1807, 1761, 3470, 3815, 3150, 2635, 7778, 7779, 7780, 4491, 3471, 2915, 1911, # 6454 + 2796, 7781, 3296, 1122, 377, 3220, 7782, 360, 7783, 7784, 4200, 1529, 551, 7785, 2059, 3693, # 6470 + 1769, 2426, 7786, 2916, 4201, 3297, 3097, 2322, 2108, 2030, 4492, 1404, 136, 1468, 1479, 672, # 6486 + 1171, 3221, 2303, 271, 3151, 7787, 2762, 7788, 2049, 678, 2727, 865, 1947, 4493, 7789, 2013, # 6502 + 3995, 2956, 7790, 2728, 2223, 1397, 3048, 3694, 4494, 4495, 1735, 2917, 3366, 3576, 7791, 3816, # 6518 + 509, 2841, 2453, 2876, 3817, 7792, 7793, 3152, 3153, 4496, 4202, 2531, 4497, 2304, 1166, 1010, # 6534 + 552, 681, 1887, 7794, 7795, 2957, 2958, 3996, 1287, 1596, 1861, 3154, 358, 453, 736, 175, # 6550 + 478, 1117, 905, 1167, 1097, 7796, 1853, 1530, 7797, 1706, 7798, 2178, 3472, 2287, 3695, 3473, # 6566 + 3577, 4203, 2092, 4204, 7799, 3367, 1193, 2482, 4205, 1458, 2190, 2205, 1862, 1888, 1421, 3298, # 6582 + 2918, 3049, 2179, 3474, 595, 2122, 7800, 3997, 7801, 7802, 4206, 1707, 2636, 223, 3696, 1359, # 6598 + 751, 3098, 183, 3475, 7803, 2797, 3003, 419, 2369, 633, 704, 3818, 2389, 241, 7804, 7805, # 6614 + 7806, 838, 3004, 3697, 2272, 2763, 2454, 3819, 1938, 2050, 3998, 1309, 3099, 2242, 1181, 7807, # 6630 + 1136, 2206, 3820, 2370, 1446, 4207, 2305, 4498, 7808, 7809, 4208, 1055, 2605, 484, 3698, 7810, # 6646 + 3999, 625, 4209, 2273, 3368, 1499, 4210, 4000, 7811, 4001, 4211, 3222, 2274, 2275, 3476, 7812, # 6662 + 7813, 2764, 808, 2606, 3699, 3369, 4002, 4212, 3100, 2532, 526, 3370, 3821, 4213, 955, 7814, # 6678 + 1620, 4214, 2637, 2427, 7815, 1429, 3700, 1669, 1831, 994, 928, 7816, 3578, 1260, 7817, 7818, # 6694 + 7819, 1948, 2288, 741, 2919, 1626, 4215, 2729, 2455, 867, 1184, 362, 3371, 1392, 7820, 7821, # 6710 + 4003, 4216, 1770, 1736, 3223, 2920, 4499, 4500, 1928, 2698, 1459, 1158, 7822, 3050, 3372, 2877, # 6726 + 1292, 1929, 2506, 2842, 3701, 1985, 1187, 2071, 2014, 2607, 4217, 7823, 2566, 2507, 2169, 3702, # 6742 + 2483, 3299, 7824, 3703, 4501, 7825, 7826, 666, 1003, 3005, 1022, 3579, 4218, 7827, 4502, 1813, # 6758 + 2253, 574, 3822, 1603, 295, 1535, 705, 3823, 4219, 283, 858, 417, 7828, 7829, 3224, 4503, # 6774 + 4504, 3051, 1220, 1889, 1046, 2276, 2456, 4004, 1393, 1599, 689, 2567, 388, 4220, 7830, 2484, # 6790 + 802, 7831, 2798, 3824, 2060, 1405, 2254, 7832, 4505, 3825, 2109, 1052, 1345, 3225, 1585, 7833, # 6806 + 809, 7834, 7835, 7836, 575, 2730, 3477, 956, 1552, 1469, 1144, 2323, 7837, 2324, 1560, 2457, # 6822 + 3580, 3226, 4005, 616, 2207, 3155, 2180, 2289, 7838, 1832, 7839, 3478, 4506, 7840, 1319, 3704, # 6838 + 3705, 1211, 3581, 1023, 3227, 1293, 2799, 7841, 7842, 7843, 3826, 607, 2306, 3827, 762, 2878, # 6854 + 1439, 4221, 1360, 7844, 1485, 3052, 7845, 4507, 1038, 4222, 1450, 2061, 2638, 4223, 1379, 4508, # 6870 + 2585, 7846, 7847, 4224, 1352, 1414, 2325, 2921, 1172, 7848, 7849, 3828, 3829, 7850, 1797, 1451, # 6886 + 7851, 7852, 7853, 7854, 2922, 4006, 4007, 2485, 2346, 411, 4008, 4009, 3582, 3300, 3101, 4509, # 6902 + 1561, 2664, 1452, 4010, 1375, 7855, 7856, 47, 2959, 316, 7857, 1406, 1591, 2923, 3156, 7858, # 6918 + 1025, 2141, 3102, 3157, 354, 2731, 884, 2224, 4225, 2407, 508, 3706, 726, 3583, 996, 2428, # 6934 + 3584, 729, 7859, 392, 2191, 1453, 4011, 4510, 3707, 7860, 7861, 2458, 3585, 2608, 1675, 2800, # 6950 + 919, 2347, 2960, 2348, 1270, 4511, 4012, 73, 7862, 7863, 647, 7864, 3228, 2843, 2255, 1550, # 6966 + 1346, 3006, 7865, 1332, 883, 3479, 7866, 7867, 7868, 7869, 3301, 2765, 7870, 1212, 831, 1347, # 6982 + 4226, 4512, 2326, 3830, 1863, 3053, 720, 3831, 4513, 4514, 3832, 7871, 4227, 7872, 7873, 4515, # 6998 + 7874, 7875, 1798, 4516, 3708, 2609, 4517, 3586, 1645, 2371, 7876, 7877, 2924, 669, 2208, 2665, # 7014 + 2429, 7878, 2879, 7879, 7880, 1028, 3229, 7881, 4228, 2408, 7882, 2256, 1353, 7883, 7884, 4518, # 7030 + 3158, 518, 7885, 4013, 7886, 4229, 1960, 7887, 2142, 4230, 7888, 7889, 3007, 2349, 2350, 3833, # 7046 + 516, 1833, 1454, 4014, 2699, 4231, 4519, 2225, 2610, 1971, 1129, 3587, 7890, 2766, 7891, 2961, # 7062 + 1422, 577, 1470, 3008, 1524, 3373, 7892, 7893, 432, 4232, 3054, 3480, 7894, 2586, 1455, 2508, # 7078 + 2226, 1972, 1175, 7895, 1020, 2732, 4015, 3481, 4520, 7896, 2733, 7897, 1743, 1361, 3055, 3482, # 7094 + 2639, 4016, 4233, 4521, 2290, 895, 924, 4234, 2170, 331, 2243, 3056, 166, 1627, 3057, 1098, # 7110 + 7898, 1232, 2880, 2227, 3374, 4522, 657, 403, 1196, 2372, 542, 3709, 3375, 1600, 4235, 3483, # 7126 + 7899, 4523, 2767, 3230, 576, 530, 1362, 7900, 4524, 2533, 2666, 3710, 4017, 7901, 842, 3834, # 7142 + 7902, 2801, 2031, 1014, 4018, 213, 2700, 3376, 665, 621, 4236, 7903, 3711, 2925, 2430, 7904, # 7158 + 2431, 3302, 3588, 3377, 7905, 4237, 2534, 4238, 4525, 3589, 1682, 4239, 3484, 1380, 7906, 724, # 7174 + 2277, 600, 1670, 7907, 1337, 1233, 4526, 3103, 2244, 7908, 1621, 4527, 7909, 651, 4240, 7910, # 7190 + 1612, 4241, 2611, 7911, 2844, 7912, 2734, 2307, 3058, 7913, 716, 2459, 3059, 174, 1255, 2701, # 7206 + 4019, 3590, 548, 1320, 1398, 728, 4020, 1574, 7914, 1890, 1197, 3060, 4021, 7915, 3061, 3062, # 7222 + 3712, 3591, 3713, 747, 7916, 635, 4242, 4528, 7917, 7918, 7919, 4243, 7920, 7921, 4529, 7922, # 7238 + 3378, 4530, 2432, 451, 7923, 3714, 2535, 2072, 4244, 2735, 4245, 4022, 7924, 1764, 4531, 7925, # 7254 + 4246, 350, 7926, 2278, 2390, 2486, 7927, 4247, 4023, 2245, 1434, 4024, 488, 4532, 458, 4248, # 7270 + 4025, 3715, 771, 1330, 2391, 3835, 2568, 3159, 2159, 2409, 1553, 2667, 3160, 4249, 7928, 2487, # 7286 + 2881, 2612, 1720, 2702, 4250, 3379, 4533, 7929, 2536, 4251, 7930, 3231, 4252, 2768, 7931, 2015, # 7302 + 2736, 7932, 1155, 1017, 3716, 3836, 7933, 3303, 2308, 201, 1864, 4253, 1430, 7934, 4026, 7935, # 7318 + 7936, 7937, 7938, 7939, 4254, 1604, 7940, 414, 1865, 371, 2587, 4534, 4535, 3485, 2016, 3104, # 7334 + 4536, 1708, 960, 4255, 887, 389, 2171, 1536, 1663, 1721, 7941, 2228, 4027, 2351, 2926, 1580, # 7350 + 7942, 7943, 7944, 1744, 7945, 2537, 4537, 4538, 7946, 4539, 7947, 2073, 7948, 7949, 3592, 3380, # 7366 + 2882, 4256, 7950, 4257, 2640, 3381, 2802, 673, 2703, 2460, 709, 3486, 4028, 3593, 4258, 7951, # 7382 + 1148, 502, 634, 7952, 7953, 1204, 4540, 3594, 1575, 4541, 2613, 3717, 7954, 3718, 3105, 948, # 7398 + 3232, 121, 1745, 3837, 1110, 7955, 4259, 3063, 2509, 3009, 4029, 3719, 1151, 1771, 3838, 1488, # 7414 + 4030, 1986, 7956, 2433, 3487, 7957, 7958, 2093, 7959, 4260, 3839, 1213, 1407, 2803, 531, 2737, # 7430 + 2538, 3233, 1011, 1537, 7960, 2769, 4261, 3106, 1061, 7961, 3720, 3721, 1866, 2883, 7962, 2017, # 7446 + 120, 4262, 4263, 2062, 3595, 3234, 2309, 3840, 2668, 3382, 1954, 4542, 7963, 7964, 3488, 1047, # 7462 + 2704, 1266, 7965, 1368, 4543, 2845, 649, 3383, 3841, 2539, 2738, 1102, 2846, 2669, 7966, 7967, # 7478 + 1999, 7968, 1111, 3596, 2962, 7969, 2488, 3842, 3597, 2804, 1854, 3384, 3722, 7970, 7971, 3385, # 7494 + 2410, 2884, 3304, 3235, 3598, 7972, 2569, 7973, 3599, 2805, 4031, 1460, 856, 7974, 3600, 7975, # 7510 + 2885, 2963, 7976, 2886, 3843, 7977, 4264, 632, 2510, 875, 3844, 1697, 3845, 2291, 7978, 7979, # 7526 + 4544, 3010, 1239, 580, 4545, 4265, 7980, 914, 936, 2074, 1190, 4032, 1039, 2123, 7981, 7982, # 7542 + 7983, 3386, 1473, 7984, 1354, 4266, 3846, 7985, 2172, 3064, 4033, 915, 3305, 4267, 4268, 3306, # 7558 + 1605, 1834, 7986, 2739, 398, 3601, 4269, 3847, 4034, 328, 1912, 2847, 4035, 3848, 1331, 4270, # 7574 + 3011, 937, 4271, 7987, 3602, 4036, 4037, 3387, 2160, 4546, 3388, 524, 742, 538, 3065, 1012, # 7590 + 7988, 7989, 3849, 2461, 7990, 658, 1103, 225, 3850, 7991, 7992, 4547, 7993, 4548, 7994, 3236, # 7606 + 1243, 7995, 4038, 963, 2246, 4549, 7996, 2705, 3603, 3161, 7997, 7998, 2588, 2327, 7999, 4550, # 7622 + 8000, 8001, 8002, 3489, 3307, 957, 3389, 2540, 2032, 1930, 2927, 2462, 870, 2018, 3604, 1746, # 7638 + 2770, 2771, 2434, 2463, 8003, 3851, 8004, 3723, 3107, 3724, 3490, 3390, 3725, 8005, 1179, 3066, # 7654 + 8006, 3162, 2373, 4272, 3726, 2541, 3163, 3108, 2740, 4039, 8007, 3391, 1556, 2542, 2292, 977, # 7670 + 2887, 2033, 4040, 1205, 3392, 8008, 1765, 3393, 3164, 2124, 1271, 1689, 714, 4551, 3491, 8009, # 7686 + 2328, 3852, 533, 4273, 3605, 2181, 617, 8010, 2464, 3308, 3492, 2310, 8011, 8012, 3165, 8013, # 7702 + 8014, 3853, 1987, 618, 427, 2641, 3493, 3394, 8015, 8016, 1244, 1690, 8017, 2806, 4274, 4552, # 7718 + 8018, 3494, 8019, 8020, 2279, 1576, 473, 3606, 4275, 3395, 972, 8021, 3607, 8022, 3067, 8023, # 7734 + 8024, 4553, 4554, 8025, 3727, 4041, 4042, 8026, 153, 4555, 356, 8027, 1891, 2888, 4276, 2143, # 7750 + 408, 803, 2352, 8028, 3854, 8029, 4277, 1646, 2570, 2511, 4556, 4557, 3855, 8030, 3856, 4278, # 7766 + 8031, 2411, 3396, 752, 8032, 8033, 1961, 2964, 8034, 746, 3012, 2465, 8035, 4279, 3728, 698, # 7782 + 4558, 1892, 4280, 3608, 2543, 4559, 3609, 3857, 8036, 3166, 3397, 8037, 1823, 1302, 4043, 2706, # 7798 + 3858, 1973, 4281, 8038, 4282, 3167, 823, 1303, 1288, 1236, 2848, 3495, 4044, 3398, 774, 3859, # 7814 + 8039, 1581, 4560, 1304, 2849, 3860, 4561, 8040, 2435, 2161, 1083, 3237, 4283, 4045, 4284, 344, # 7830 + 1173, 288, 2311, 454, 1683, 8041, 8042, 1461, 4562, 4046, 2589, 8043, 8044, 4563, 985, 894, # 7846 + 8045, 3399, 3168, 8046, 1913, 2928, 3729, 1988, 8047, 2110, 1974, 8048, 4047, 8049, 2571, 1194, # 7862 + 425, 8050, 4564, 3169, 1245, 3730, 4285, 8051, 8052, 2850, 8053, 636, 4565, 1855, 3861, 760, # 7878 + 1799, 8054, 4286, 2209, 1508, 4566, 4048, 1893, 1684, 2293, 8055, 8056, 8057, 4287, 4288, 2210, # 7894 + 479, 8058, 8059, 832, 8060, 4049, 2489, 8061, 2965, 2490, 3731, 990, 3109, 627, 1814, 2642, # 7910 + 4289, 1582, 4290, 2125, 2111, 3496, 4567, 8062, 799, 4291, 3170, 8063, 4568, 2112, 1737, 3013, # 7926 + 1018, 543, 754, 4292, 3309, 1676, 4569, 4570, 4050, 8064, 1489, 8065, 3497, 8066, 2614, 2889, # 7942 + 4051, 8067, 8068, 2966, 8069, 8070, 8071, 8072, 3171, 4571, 4572, 2182, 1722, 8073, 3238, 3239, # 7958 + 1842, 3610, 1715, 481, 365, 1975, 1856, 8074, 8075, 1962, 2491, 4573, 8076, 2126, 3611, 3240, # 7974 + 433, 1894, 2063, 2075, 8077, 602, 2741, 8078, 8079, 8080, 8081, 8082, 3014, 1628, 3400, 8083, # 7990 + 3172, 4574, 4052, 2890, 4575, 2512, 8084, 2544, 2772, 8085, 8086, 8087, 3310, 4576, 2891, 8088, # 8006 + 4577, 8089, 2851, 4578, 4579, 1221, 2967, 4053, 2513, 8090, 8091, 8092, 1867, 1989, 8093, 8094, # 8022 + 8095, 1895, 8096, 8097, 4580, 1896, 4054, 318, 8098, 2094, 4055, 4293, 8099, 8100, 485, 8101, # 8038 + 938, 3862, 553, 2670, 116, 8102, 3863, 3612, 8103, 3498, 2671, 2773, 3401, 3311, 2807, 8104, # 8054 + 3613, 2929, 4056, 1747, 2930, 2968, 8105, 8106, 207, 8107, 8108, 2672, 4581, 2514, 8109, 3015, # 8070 + 890, 3614, 3864, 8110, 1877, 3732, 3402, 8111, 2183, 2353, 3403, 1652, 8112, 8113, 8114, 941, # 8086 + 2294, 208, 3499, 4057, 2019, 330, 4294, 3865, 2892, 2492, 3733, 4295, 8115, 8116, 8117, 8118, # 8102 ) - +# fmt: on diff --git a/script.module.chardet/lib/chardet/euctwprober.py b/script.module.chardet/lib/chardet/euctwprober.py index 35669cc4d..a37ab1899 100644 --- a/script.module.chardet/lib/chardet/euctwprober.py +++ b/script.module.chardet/lib/chardet/euctwprober.py @@ -25,22 +25,23 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine from .chardistribution import EUCTWDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber from .mbcssm import EUCTW_SM_MODEL + class EUCTWProber(MultiByteCharSetProber): - def __init__(self): - super(EUCTWProber, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) self.distribution_analyzer = EUCTWDistributionAnalysis() self.reset() @property - def charset_name(self): + def charset_name(self) -> str: return "EUC-TW" @property - def language(self): + def language(self) -> str: return "Taiwan" diff --git a/script.module.chardet/lib/chardet/gb2312freq.py b/script.module.chardet/lib/chardet/gb2312freq.py index 697837bd9..b32bfc742 100644 --- a/script.module.chardet/lib/chardet/gb2312freq.py +++ b/script.module.chardet/lib/chardet/gb2312freq.py @@ -43,6 +43,7 @@ GB2312_TABLE_SIZE = 3760 +# fmt: off GB2312_CHAR_TO_FREQ_ORDER = ( 1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, 2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, @@ -280,4 +281,4 @@ 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 ) - +# fmt: on diff --git a/script.module.chardet/lib/chardet/gb2312prober.py b/script.module.chardet/lib/chardet/gb2312prober.py index 8446d2dd9..d423e7311 100644 --- a/script.module.chardet/lib/chardet/gb2312prober.py +++ b/script.module.chardet/lib/chardet/gb2312prober.py @@ -25,22 +25,23 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine from .chardistribution import GB2312DistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber from .mbcssm import GB2312_SM_MODEL + class GB2312Prober(MultiByteCharSetProber): - def __init__(self): - super(GB2312Prober, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) self.distribution_analyzer = GB2312DistributionAnalysis() self.reset() @property - def charset_name(self): + def charset_name(self) -> str: return "GB2312" @property - def language(self): + def language(self) -> str: return "Chinese" diff --git a/script.module.chardet/lib/chardet/hebrewprober.py b/script.module.chardet/lib/chardet/hebrewprober.py index b0e1bf492..785d0057b 100644 --- a/script.module.chardet/lib/chardet/hebrewprober.py +++ b/script.module.chardet/lib/chardet/hebrewprober.py @@ -25,8 +25,11 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from typing import Optional, Union + from .charsetprober import CharSetProber from .enums import ProbingState +from .sbcharsetprober import SingleByteCharSetProber # This prober doesn't actually recognize a language or a charset. # It is a helper prober for the use of the Hebrew model probers @@ -125,18 +128,20 @@ # model probers scores. The answer is returned in the form of the name of the # charset identified, either "windows-1255" or "ISO-8859-8". + class HebrewProber(CharSetProber): + SPACE = 0x20 # windows-1255 / ISO-8859-8 code points of interest - FINAL_KAF = 0xea - NORMAL_KAF = 0xeb - FINAL_MEM = 0xed - NORMAL_MEM = 0xee - FINAL_NUN = 0xef - NORMAL_NUN = 0xf0 - FINAL_PE = 0xf3 - NORMAL_PE = 0xf4 - FINAL_TSADI = 0xf5 - NORMAL_TSADI = 0xf6 + FINAL_KAF = 0xEA + NORMAL_KAF = 0xEB + FINAL_MEM = 0xED + NORMAL_MEM = 0xEE + FINAL_NUN = 0xEF + NORMAL_NUN = 0xF0 + FINAL_PE = 0xF3 + NORMAL_PE = 0xF4 + FINAL_TSADI = 0xF5 + NORMAL_TSADI = 0xF6 # Minimum Visual vs Logical final letter score difference. # If the difference is below this, don't rely solely on the final letter score @@ -151,35 +156,44 @@ class HebrewProber(CharSetProber): VISUAL_HEBREW_NAME = "ISO-8859-8" LOGICAL_HEBREW_NAME = "windows-1255" - def __init__(self): - super(HebrewProber, self).__init__() - self._final_char_logical_score = None - self._final_char_visual_score = None - self._prev = None - self._before_prev = None - self._logical_prober = None - self._visual_prober = None + def __init__(self) -> None: + super().__init__() + self._final_char_logical_score = 0 + self._final_char_visual_score = 0 + self._prev = self.SPACE + self._before_prev = self.SPACE + self._logical_prober: Optional[SingleByteCharSetProber] = None + self._visual_prober: Optional[SingleByteCharSetProber] = None self.reset() - def reset(self): + def reset(self) -> None: self._final_char_logical_score = 0 self._final_char_visual_score = 0 # The two last characters seen in the previous buffer, # mPrev and mBeforePrev are initialized to space in order to simulate # a word delimiter at the beginning of the data - self._prev = ' ' - self._before_prev = ' ' + self._prev = self.SPACE + self._before_prev = self.SPACE # These probers are owned by the group prober. - def set_model_probers(self, logicalProber, visualProber): - self._logical_prober = logicalProber - self._visual_prober = visualProber + def set_model_probers( + self, + logical_prober: SingleByteCharSetProber, + visual_prober: SingleByteCharSetProber, + ) -> None: + self._logical_prober = logical_prober + self._visual_prober = visual_prober - def is_final(self, c): - return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, - self.FINAL_PE, self.FINAL_TSADI] + def is_final(self, c: int) -> bool: + return c in [ + self.FINAL_KAF, + self.FINAL_MEM, + self.FINAL_NUN, + self.FINAL_PE, + self.FINAL_TSADI, + ] - def is_non_final(self, c): + def is_non_final(self, c: int) -> bool: # The normal Tsadi is not a good Non-Final letter due to words like # 'lechotet' (to chat) containing an apostrophe after the tsadi. This # apostrophe is converted to a space in FilterWithoutEnglishLetters @@ -190,10 +204,9 @@ def is_non_final(self, c): # for example legally end with a Non-Final Pe or Kaf. However, the # benefit of these letters as Non-Final letters outweighs the damage # since these words are quite rare. - return c in [self.NORMAL_KAF, self.NORMAL_MEM, - self.NORMAL_NUN, self.NORMAL_PE] + return c in [self.NORMAL_KAF, self.NORMAL_MEM, self.NORMAL_NUN, self.NORMAL_PE] - def feed(self, byte_str): + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: # Final letter analysis for logical-visual decision. # Look for evidence that the received buffer is either logical Hebrew # or visual Hebrew. @@ -227,9 +240,9 @@ def feed(self, byte_str): byte_str = self.filter_high_byte_only(byte_str) for cur in byte_str: - if cur == ' ': + if cur == self.SPACE: # We stand on a space - a word just ended - if self._before_prev != ' ': + if self._before_prev != self.SPACE: # next-to-last char was not a space so self._prev is not a # 1 letter word if self.is_final(self._prev): @@ -241,8 +254,11 @@ def feed(self, byte_str): self._final_char_visual_score += 1 else: # Not standing on a space - if ((self._before_prev == ' ') and - (self.is_final(self._prev)) and (cur != ' ')): + if ( + (self._before_prev == self.SPACE) + and (self.is_final(self._prev)) + and (cur != self.SPACE) + ): # case (3) [-2:space][-1:final letter][cur:not space] self._final_char_visual_score += 1 self._before_prev = self._prev @@ -253,7 +269,10 @@ def feed(self, byte_str): return ProbingState.DETECTING @property - def charset_name(self): + def charset_name(self) -> str: + assert self._logical_prober is not None + assert self._visual_prober is not None + # Make the decision: is it Logical or Visual? # If the final letter score distance is dominant enough, rely on it. finalsub = self._final_char_logical_score - self._final_char_visual_score @@ -263,8 +282,9 @@ def charset_name(self): return self.VISUAL_HEBREW_NAME # It's not dominant enough, try to rely on the model scores instead. - modelsub = (self._logical_prober.get_confidence() - - self._visual_prober.get_confidence()) + modelsub = ( + self._logical_prober.get_confidence() - self._visual_prober.get_confidence() + ) if modelsub > self.MIN_MODEL_DISTANCE: return self.LOGICAL_HEBREW_NAME if modelsub < -self.MIN_MODEL_DISTANCE: @@ -280,13 +300,17 @@ def charset_name(self): return self.LOGICAL_HEBREW_NAME @property - def language(self): - return 'Hebrew' + def language(self) -> str: + return "Hebrew" @property - def state(self): + def state(self) -> ProbingState: + assert self._logical_prober is not None + assert self._visual_prober is not None + # Remain active as long as any of the model probers are active. - if (self._logical_prober.state == ProbingState.NOT_ME) and \ - (self._visual_prober.state == ProbingState.NOT_ME): + if (self._logical_prober.state == ProbingState.NOT_ME) and ( + self._visual_prober.state == ProbingState.NOT_ME + ): return ProbingState.NOT_ME return ProbingState.DETECTING diff --git a/script.module.chardet/lib/chardet/jisfreq.py b/script.module.chardet/lib/chardet/jisfreq.py index 83fc082b5..3293576e0 100644 --- a/script.module.chardet/lib/chardet/jisfreq.py +++ b/script.module.chardet/lib/chardet/jisfreq.py @@ -46,6 +46,7 @@ # Char to FreqOrder table , JIS_TABLE_SIZE = 4368 +# fmt: off JIS_CHAR_TO_FREQ_ORDER = ( 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 @@ -321,5 +322,4 @@ 1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 ) - - +# fmt: on diff --git a/script.module.chardet/lib/chardet/johabfreq.py b/script.module.chardet/lib/chardet/johabfreq.py new file mode 100644 index 000000000..c12969990 --- /dev/null +++ b/script.module.chardet/lib/chardet/johabfreq.py @@ -0,0 +1,2382 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# The frequency data itself is the same as euc-kr. +# This is just a mapping table to euc-kr. + +JOHAB_TO_EUCKR_ORDER_TABLE = { + 0x8861: 0, + 0x8862: 1, + 0x8865: 2, + 0x8868: 3, + 0x8869: 4, + 0x886A: 5, + 0x886B: 6, + 0x8871: 7, + 0x8873: 8, + 0x8874: 9, + 0x8875: 10, + 0x8876: 11, + 0x8877: 12, + 0x8878: 13, + 0x8879: 14, + 0x887B: 15, + 0x887C: 16, + 0x887D: 17, + 0x8881: 18, + 0x8882: 19, + 0x8885: 20, + 0x8889: 21, + 0x8891: 22, + 0x8893: 23, + 0x8895: 24, + 0x8896: 25, + 0x8897: 26, + 0x88A1: 27, + 0x88A2: 28, + 0x88A5: 29, + 0x88A9: 30, + 0x88B5: 31, + 0x88B7: 32, + 0x88C1: 33, + 0x88C5: 34, + 0x88C9: 35, + 0x88E1: 36, + 0x88E2: 37, + 0x88E5: 38, + 0x88E8: 39, + 0x88E9: 40, + 0x88EB: 41, + 0x88F1: 42, + 0x88F3: 43, + 0x88F5: 44, + 0x88F6: 45, + 0x88F7: 46, + 0x88F8: 47, + 0x88FB: 48, + 0x88FC: 49, + 0x88FD: 50, + 0x8941: 51, + 0x8945: 52, + 0x8949: 53, + 0x8951: 54, + 0x8953: 55, + 0x8955: 56, + 0x8956: 57, + 0x8957: 58, + 0x8961: 59, + 0x8962: 60, + 0x8963: 61, + 0x8965: 62, + 0x8968: 63, + 0x8969: 64, + 0x8971: 65, + 0x8973: 66, + 0x8975: 67, + 0x8976: 68, + 0x8977: 69, + 0x897B: 70, + 0x8981: 71, + 0x8985: 72, + 0x8989: 73, + 0x8993: 74, + 0x8995: 75, + 0x89A1: 76, + 0x89A2: 77, + 0x89A5: 78, + 0x89A8: 79, + 0x89A9: 80, + 0x89AB: 81, + 0x89AD: 82, + 0x89B0: 83, + 0x89B1: 84, + 0x89B3: 85, + 0x89B5: 86, + 0x89B7: 87, + 0x89B8: 88, + 0x89C1: 89, + 0x89C2: 90, + 0x89C5: 91, + 0x89C9: 92, + 0x89CB: 93, + 0x89D1: 94, + 0x89D3: 95, + 0x89D5: 96, + 0x89D7: 97, + 0x89E1: 98, + 0x89E5: 99, + 0x89E9: 100, + 0x89F3: 101, + 0x89F6: 102, + 0x89F7: 103, + 0x8A41: 104, + 0x8A42: 105, + 0x8A45: 106, + 0x8A49: 107, + 0x8A51: 108, + 0x8A53: 109, + 0x8A55: 110, + 0x8A57: 111, + 0x8A61: 112, + 0x8A65: 113, + 0x8A69: 114, + 0x8A73: 115, + 0x8A75: 116, + 0x8A81: 117, + 0x8A82: 118, + 0x8A85: 119, + 0x8A88: 120, + 0x8A89: 121, + 0x8A8A: 122, + 0x8A8B: 123, + 0x8A90: 124, + 0x8A91: 125, + 0x8A93: 126, + 0x8A95: 127, + 0x8A97: 128, + 0x8A98: 129, + 0x8AA1: 130, + 0x8AA2: 131, + 0x8AA5: 132, + 0x8AA9: 133, + 0x8AB6: 134, + 0x8AB7: 135, + 0x8AC1: 136, + 0x8AD5: 137, + 0x8AE1: 138, + 0x8AE2: 139, + 0x8AE5: 140, + 0x8AE9: 141, + 0x8AF1: 142, + 0x8AF3: 143, + 0x8AF5: 144, + 0x8B41: 145, + 0x8B45: 146, + 0x8B49: 147, + 0x8B61: 148, + 0x8B62: 149, + 0x8B65: 150, + 0x8B68: 151, + 0x8B69: 152, + 0x8B6A: 153, + 0x8B71: 154, + 0x8B73: 155, + 0x8B75: 156, + 0x8B77: 157, + 0x8B81: 158, + 0x8BA1: 159, + 0x8BA2: 160, + 0x8BA5: 161, + 0x8BA8: 162, + 0x8BA9: 163, + 0x8BAB: 164, + 0x8BB1: 165, + 0x8BB3: 166, + 0x8BB5: 167, + 0x8BB7: 168, + 0x8BB8: 169, + 0x8BBC: 170, + 0x8C61: 171, + 0x8C62: 172, + 0x8C63: 173, + 0x8C65: 174, + 0x8C69: 175, + 0x8C6B: 176, + 0x8C71: 177, + 0x8C73: 178, + 0x8C75: 179, + 0x8C76: 180, + 0x8C77: 181, + 0x8C7B: 182, + 0x8C81: 183, + 0x8C82: 184, + 0x8C85: 185, + 0x8C89: 186, + 0x8C91: 187, + 0x8C93: 188, + 0x8C95: 189, + 0x8C96: 190, + 0x8C97: 191, + 0x8CA1: 192, + 0x8CA2: 193, + 0x8CA9: 194, + 0x8CE1: 195, + 0x8CE2: 196, + 0x8CE3: 197, + 0x8CE5: 198, + 0x8CE9: 199, + 0x8CF1: 200, + 0x8CF3: 201, + 0x8CF5: 202, + 0x8CF6: 203, + 0x8CF7: 204, + 0x8D41: 205, + 0x8D42: 206, + 0x8D45: 207, + 0x8D51: 208, + 0x8D55: 209, + 0x8D57: 210, + 0x8D61: 211, + 0x8D65: 212, + 0x8D69: 213, + 0x8D75: 214, + 0x8D76: 215, + 0x8D7B: 216, + 0x8D81: 217, + 0x8DA1: 218, + 0x8DA2: 219, + 0x8DA5: 220, + 0x8DA7: 221, + 0x8DA9: 222, + 0x8DB1: 223, + 0x8DB3: 224, + 0x8DB5: 225, + 0x8DB7: 226, + 0x8DB8: 227, + 0x8DB9: 228, + 0x8DC1: 229, + 0x8DC2: 230, + 0x8DC9: 231, + 0x8DD6: 232, + 0x8DD7: 233, + 0x8DE1: 234, + 0x8DE2: 235, + 0x8DF7: 236, + 0x8E41: 237, + 0x8E45: 238, + 0x8E49: 239, + 0x8E51: 240, + 0x8E53: 241, + 0x8E57: 242, + 0x8E61: 243, + 0x8E81: 244, + 0x8E82: 245, + 0x8E85: 246, + 0x8E89: 247, + 0x8E90: 248, + 0x8E91: 249, + 0x8E93: 250, + 0x8E95: 251, + 0x8E97: 252, + 0x8E98: 253, + 0x8EA1: 254, + 0x8EA9: 255, + 0x8EB6: 256, + 0x8EB7: 257, + 0x8EC1: 258, + 0x8EC2: 259, + 0x8EC5: 260, + 0x8EC9: 261, + 0x8ED1: 262, + 0x8ED3: 263, + 0x8ED6: 264, + 0x8EE1: 265, + 0x8EE5: 266, + 0x8EE9: 267, + 0x8EF1: 268, + 0x8EF3: 269, + 0x8F41: 270, + 0x8F61: 271, + 0x8F62: 272, + 0x8F65: 273, + 0x8F67: 274, + 0x8F69: 275, + 0x8F6B: 276, + 0x8F70: 277, + 0x8F71: 278, + 0x8F73: 279, + 0x8F75: 280, + 0x8F77: 281, + 0x8F7B: 282, + 0x8FA1: 283, + 0x8FA2: 284, + 0x8FA5: 285, + 0x8FA9: 286, + 0x8FB1: 287, + 0x8FB3: 288, + 0x8FB5: 289, + 0x8FB7: 290, + 0x9061: 291, + 0x9062: 292, + 0x9063: 293, + 0x9065: 294, + 0x9068: 295, + 0x9069: 296, + 0x906A: 297, + 0x906B: 298, + 0x9071: 299, + 0x9073: 300, + 0x9075: 301, + 0x9076: 302, + 0x9077: 303, + 0x9078: 304, + 0x9079: 305, + 0x907B: 306, + 0x907D: 307, + 0x9081: 308, + 0x9082: 309, + 0x9085: 310, + 0x9089: 311, + 0x9091: 312, + 0x9093: 313, + 0x9095: 314, + 0x9096: 315, + 0x9097: 316, + 0x90A1: 317, + 0x90A2: 318, + 0x90A5: 319, + 0x90A9: 320, + 0x90B1: 321, + 0x90B7: 322, + 0x90E1: 323, + 0x90E2: 324, + 0x90E4: 325, + 0x90E5: 326, + 0x90E9: 327, + 0x90EB: 328, + 0x90EC: 329, + 0x90F1: 330, + 0x90F3: 331, + 0x90F5: 332, + 0x90F6: 333, + 0x90F7: 334, + 0x90FD: 335, + 0x9141: 336, + 0x9142: 337, + 0x9145: 338, + 0x9149: 339, + 0x9151: 340, + 0x9153: 341, + 0x9155: 342, + 0x9156: 343, + 0x9157: 344, + 0x9161: 345, + 0x9162: 346, + 0x9165: 347, + 0x9169: 348, + 0x9171: 349, + 0x9173: 350, + 0x9176: 351, + 0x9177: 352, + 0x917A: 353, + 0x9181: 354, + 0x9185: 355, + 0x91A1: 356, + 0x91A2: 357, + 0x91A5: 358, + 0x91A9: 359, + 0x91AB: 360, + 0x91B1: 361, + 0x91B3: 362, + 0x91B5: 363, + 0x91B7: 364, + 0x91BC: 365, + 0x91BD: 366, + 0x91C1: 367, + 0x91C5: 368, + 0x91C9: 369, + 0x91D6: 370, + 0x9241: 371, + 0x9245: 372, + 0x9249: 373, + 0x9251: 374, + 0x9253: 375, + 0x9255: 376, + 0x9261: 377, + 0x9262: 378, + 0x9265: 379, + 0x9269: 380, + 0x9273: 381, + 0x9275: 382, + 0x9277: 383, + 0x9281: 384, + 0x9282: 385, + 0x9285: 386, + 0x9288: 387, + 0x9289: 388, + 0x9291: 389, + 0x9293: 390, + 0x9295: 391, + 0x9297: 392, + 0x92A1: 393, + 0x92B6: 394, + 0x92C1: 395, + 0x92E1: 396, + 0x92E5: 397, + 0x92E9: 398, + 0x92F1: 399, + 0x92F3: 400, + 0x9341: 401, + 0x9342: 402, + 0x9349: 403, + 0x9351: 404, + 0x9353: 405, + 0x9357: 406, + 0x9361: 407, + 0x9362: 408, + 0x9365: 409, + 0x9369: 410, + 0x936A: 411, + 0x936B: 412, + 0x9371: 413, + 0x9373: 414, + 0x9375: 415, + 0x9377: 416, + 0x9378: 417, + 0x937C: 418, + 0x9381: 419, + 0x9385: 420, + 0x9389: 421, + 0x93A1: 422, + 0x93A2: 423, + 0x93A5: 424, + 0x93A9: 425, + 0x93AB: 426, + 0x93B1: 427, + 0x93B3: 428, + 0x93B5: 429, + 0x93B7: 430, + 0x93BC: 431, + 0x9461: 432, + 0x9462: 433, + 0x9463: 434, + 0x9465: 435, + 0x9468: 436, + 0x9469: 437, + 0x946A: 438, + 0x946B: 439, + 0x946C: 440, + 0x9470: 441, + 0x9471: 442, + 0x9473: 443, + 0x9475: 444, + 0x9476: 445, + 0x9477: 446, + 0x9478: 447, + 0x9479: 448, + 0x947D: 449, + 0x9481: 450, + 0x9482: 451, + 0x9485: 452, + 0x9489: 453, + 0x9491: 454, + 0x9493: 455, + 0x9495: 456, + 0x9496: 457, + 0x9497: 458, + 0x94A1: 459, + 0x94E1: 460, + 0x94E2: 461, + 0x94E3: 462, + 0x94E5: 463, + 0x94E8: 464, + 0x94E9: 465, + 0x94EB: 466, + 0x94EC: 467, + 0x94F1: 468, + 0x94F3: 469, + 0x94F5: 470, + 0x94F7: 471, + 0x94F9: 472, + 0x94FC: 473, + 0x9541: 474, + 0x9542: 475, + 0x9545: 476, + 0x9549: 477, + 0x9551: 478, + 0x9553: 479, + 0x9555: 480, + 0x9556: 481, + 0x9557: 482, + 0x9561: 483, + 0x9565: 484, + 0x9569: 485, + 0x9576: 486, + 0x9577: 487, + 0x9581: 488, + 0x9585: 489, + 0x95A1: 490, + 0x95A2: 491, + 0x95A5: 492, + 0x95A8: 493, + 0x95A9: 494, + 0x95AB: 495, + 0x95AD: 496, + 0x95B1: 497, + 0x95B3: 498, + 0x95B5: 499, + 0x95B7: 500, + 0x95B9: 501, + 0x95BB: 502, + 0x95C1: 503, + 0x95C5: 504, + 0x95C9: 505, + 0x95E1: 506, + 0x95F6: 507, + 0x9641: 508, + 0x9645: 509, + 0x9649: 510, + 0x9651: 511, + 0x9653: 512, + 0x9655: 513, + 0x9661: 514, + 0x9681: 515, + 0x9682: 516, + 0x9685: 517, + 0x9689: 518, + 0x9691: 519, + 0x9693: 520, + 0x9695: 521, + 0x9697: 522, + 0x96A1: 523, + 0x96B6: 524, + 0x96C1: 525, + 0x96D7: 526, + 0x96E1: 527, + 0x96E5: 528, + 0x96E9: 529, + 0x96F3: 530, + 0x96F5: 531, + 0x96F7: 532, + 0x9741: 533, + 0x9745: 534, + 0x9749: 535, + 0x9751: 536, + 0x9757: 537, + 0x9761: 538, + 0x9762: 539, + 0x9765: 540, + 0x9768: 541, + 0x9769: 542, + 0x976B: 543, + 0x9771: 544, + 0x9773: 545, + 0x9775: 546, + 0x9777: 547, + 0x9781: 548, + 0x97A1: 549, + 0x97A2: 550, + 0x97A5: 551, + 0x97A8: 552, + 0x97A9: 553, + 0x97B1: 554, + 0x97B3: 555, + 0x97B5: 556, + 0x97B6: 557, + 0x97B7: 558, + 0x97B8: 559, + 0x9861: 560, + 0x9862: 561, + 0x9865: 562, + 0x9869: 563, + 0x9871: 564, + 0x9873: 565, + 0x9875: 566, + 0x9876: 567, + 0x9877: 568, + 0x987D: 569, + 0x9881: 570, + 0x9882: 571, + 0x9885: 572, + 0x9889: 573, + 0x9891: 574, + 0x9893: 575, + 0x9895: 576, + 0x9896: 577, + 0x9897: 578, + 0x98E1: 579, + 0x98E2: 580, + 0x98E5: 581, + 0x98E9: 582, + 0x98EB: 583, + 0x98EC: 584, + 0x98F1: 585, + 0x98F3: 586, + 0x98F5: 587, + 0x98F6: 588, + 0x98F7: 589, + 0x98FD: 590, + 0x9941: 591, + 0x9942: 592, + 0x9945: 593, + 0x9949: 594, + 0x9951: 595, + 0x9953: 596, + 0x9955: 597, + 0x9956: 598, + 0x9957: 599, + 0x9961: 600, + 0x9976: 601, + 0x99A1: 602, + 0x99A2: 603, + 0x99A5: 604, + 0x99A9: 605, + 0x99B7: 606, + 0x99C1: 607, + 0x99C9: 608, + 0x99E1: 609, + 0x9A41: 610, + 0x9A45: 611, + 0x9A81: 612, + 0x9A82: 613, + 0x9A85: 614, + 0x9A89: 615, + 0x9A90: 616, + 0x9A91: 617, + 0x9A97: 618, + 0x9AC1: 619, + 0x9AE1: 620, + 0x9AE5: 621, + 0x9AE9: 622, + 0x9AF1: 623, + 0x9AF3: 624, + 0x9AF7: 625, + 0x9B61: 626, + 0x9B62: 627, + 0x9B65: 628, + 0x9B68: 629, + 0x9B69: 630, + 0x9B71: 631, + 0x9B73: 632, + 0x9B75: 633, + 0x9B81: 634, + 0x9B85: 635, + 0x9B89: 636, + 0x9B91: 637, + 0x9B93: 638, + 0x9BA1: 639, + 0x9BA5: 640, + 0x9BA9: 641, + 0x9BB1: 642, + 0x9BB3: 643, + 0x9BB5: 644, + 0x9BB7: 645, + 0x9C61: 646, + 0x9C62: 647, + 0x9C65: 648, + 0x9C69: 649, + 0x9C71: 650, + 0x9C73: 651, + 0x9C75: 652, + 0x9C76: 653, + 0x9C77: 654, + 0x9C78: 655, + 0x9C7C: 656, + 0x9C7D: 657, + 0x9C81: 658, + 0x9C82: 659, + 0x9C85: 660, + 0x9C89: 661, + 0x9C91: 662, + 0x9C93: 663, + 0x9C95: 664, + 0x9C96: 665, + 0x9C97: 666, + 0x9CA1: 667, + 0x9CA2: 668, + 0x9CA5: 669, + 0x9CB5: 670, + 0x9CB7: 671, + 0x9CE1: 672, + 0x9CE2: 673, + 0x9CE5: 674, + 0x9CE9: 675, + 0x9CF1: 676, + 0x9CF3: 677, + 0x9CF5: 678, + 0x9CF6: 679, + 0x9CF7: 680, + 0x9CFD: 681, + 0x9D41: 682, + 0x9D42: 683, + 0x9D45: 684, + 0x9D49: 685, + 0x9D51: 686, + 0x9D53: 687, + 0x9D55: 688, + 0x9D57: 689, + 0x9D61: 690, + 0x9D62: 691, + 0x9D65: 692, + 0x9D69: 693, + 0x9D71: 694, + 0x9D73: 695, + 0x9D75: 696, + 0x9D76: 697, + 0x9D77: 698, + 0x9D81: 699, + 0x9D85: 700, + 0x9D93: 701, + 0x9D95: 702, + 0x9DA1: 703, + 0x9DA2: 704, + 0x9DA5: 705, + 0x9DA9: 706, + 0x9DB1: 707, + 0x9DB3: 708, + 0x9DB5: 709, + 0x9DB7: 710, + 0x9DC1: 711, + 0x9DC5: 712, + 0x9DD7: 713, + 0x9DF6: 714, + 0x9E41: 715, + 0x9E45: 716, + 0x9E49: 717, + 0x9E51: 718, + 0x9E53: 719, + 0x9E55: 720, + 0x9E57: 721, + 0x9E61: 722, + 0x9E65: 723, + 0x9E69: 724, + 0x9E73: 725, + 0x9E75: 726, + 0x9E77: 727, + 0x9E81: 728, + 0x9E82: 729, + 0x9E85: 730, + 0x9E89: 731, + 0x9E91: 732, + 0x9E93: 733, + 0x9E95: 734, + 0x9E97: 735, + 0x9EA1: 736, + 0x9EB6: 737, + 0x9EC1: 738, + 0x9EE1: 739, + 0x9EE2: 740, + 0x9EE5: 741, + 0x9EE9: 742, + 0x9EF1: 743, + 0x9EF5: 744, + 0x9EF7: 745, + 0x9F41: 746, + 0x9F42: 747, + 0x9F45: 748, + 0x9F49: 749, + 0x9F51: 750, + 0x9F53: 751, + 0x9F55: 752, + 0x9F57: 753, + 0x9F61: 754, + 0x9F62: 755, + 0x9F65: 756, + 0x9F69: 757, + 0x9F71: 758, + 0x9F73: 759, + 0x9F75: 760, + 0x9F77: 761, + 0x9F78: 762, + 0x9F7B: 763, + 0x9F7C: 764, + 0x9FA1: 765, + 0x9FA2: 766, + 0x9FA5: 767, + 0x9FA9: 768, + 0x9FB1: 769, + 0x9FB3: 770, + 0x9FB5: 771, + 0x9FB7: 772, + 0xA061: 773, + 0xA062: 774, + 0xA065: 775, + 0xA067: 776, + 0xA068: 777, + 0xA069: 778, + 0xA06A: 779, + 0xA06B: 780, + 0xA071: 781, + 0xA073: 782, + 0xA075: 783, + 0xA077: 784, + 0xA078: 785, + 0xA07B: 786, + 0xA07D: 787, + 0xA081: 788, + 0xA082: 789, + 0xA085: 790, + 0xA089: 791, + 0xA091: 792, + 0xA093: 793, + 0xA095: 794, + 0xA096: 795, + 0xA097: 796, + 0xA098: 797, + 0xA0A1: 798, + 0xA0A2: 799, + 0xA0A9: 800, + 0xA0B7: 801, + 0xA0E1: 802, + 0xA0E2: 803, + 0xA0E5: 804, + 0xA0E9: 805, + 0xA0EB: 806, + 0xA0F1: 807, + 0xA0F3: 808, + 0xA0F5: 809, + 0xA0F7: 810, + 0xA0F8: 811, + 0xA0FD: 812, + 0xA141: 813, + 0xA142: 814, + 0xA145: 815, + 0xA149: 816, + 0xA151: 817, + 0xA153: 818, + 0xA155: 819, + 0xA156: 820, + 0xA157: 821, + 0xA161: 822, + 0xA162: 823, + 0xA165: 824, + 0xA169: 825, + 0xA175: 826, + 0xA176: 827, + 0xA177: 828, + 0xA179: 829, + 0xA181: 830, + 0xA1A1: 831, + 0xA1A2: 832, + 0xA1A4: 833, + 0xA1A5: 834, + 0xA1A9: 835, + 0xA1AB: 836, + 0xA1B1: 837, + 0xA1B3: 838, + 0xA1B5: 839, + 0xA1B7: 840, + 0xA1C1: 841, + 0xA1C5: 842, + 0xA1D6: 843, + 0xA1D7: 844, + 0xA241: 845, + 0xA245: 846, + 0xA249: 847, + 0xA253: 848, + 0xA255: 849, + 0xA257: 850, + 0xA261: 851, + 0xA265: 852, + 0xA269: 853, + 0xA273: 854, + 0xA275: 855, + 0xA281: 856, + 0xA282: 857, + 0xA283: 858, + 0xA285: 859, + 0xA288: 860, + 0xA289: 861, + 0xA28A: 862, + 0xA28B: 863, + 0xA291: 864, + 0xA293: 865, + 0xA295: 866, + 0xA297: 867, + 0xA29B: 868, + 0xA29D: 869, + 0xA2A1: 870, + 0xA2A5: 871, + 0xA2A9: 872, + 0xA2B3: 873, + 0xA2B5: 874, + 0xA2C1: 875, + 0xA2E1: 876, + 0xA2E5: 877, + 0xA2E9: 878, + 0xA341: 879, + 0xA345: 880, + 0xA349: 881, + 0xA351: 882, + 0xA355: 883, + 0xA361: 884, + 0xA365: 885, + 0xA369: 886, + 0xA371: 887, + 0xA375: 888, + 0xA3A1: 889, + 0xA3A2: 890, + 0xA3A5: 891, + 0xA3A8: 892, + 0xA3A9: 893, + 0xA3AB: 894, + 0xA3B1: 895, + 0xA3B3: 896, + 0xA3B5: 897, + 0xA3B6: 898, + 0xA3B7: 899, + 0xA3B9: 900, + 0xA3BB: 901, + 0xA461: 902, + 0xA462: 903, + 0xA463: 904, + 0xA464: 905, + 0xA465: 906, + 0xA468: 907, + 0xA469: 908, + 0xA46A: 909, + 0xA46B: 910, + 0xA46C: 911, + 0xA471: 912, + 0xA473: 913, + 0xA475: 914, + 0xA477: 915, + 0xA47B: 916, + 0xA481: 917, + 0xA482: 918, + 0xA485: 919, + 0xA489: 920, + 0xA491: 921, + 0xA493: 922, + 0xA495: 923, + 0xA496: 924, + 0xA497: 925, + 0xA49B: 926, + 0xA4A1: 927, + 0xA4A2: 928, + 0xA4A5: 929, + 0xA4B3: 930, + 0xA4E1: 931, + 0xA4E2: 932, + 0xA4E5: 933, + 0xA4E8: 934, + 0xA4E9: 935, + 0xA4EB: 936, + 0xA4F1: 937, + 0xA4F3: 938, + 0xA4F5: 939, + 0xA4F7: 940, + 0xA4F8: 941, + 0xA541: 942, + 0xA542: 943, + 0xA545: 944, + 0xA548: 945, + 0xA549: 946, + 0xA551: 947, + 0xA553: 948, + 0xA555: 949, + 0xA556: 950, + 0xA557: 951, + 0xA561: 952, + 0xA562: 953, + 0xA565: 954, + 0xA569: 955, + 0xA573: 956, + 0xA575: 957, + 0xA576: 958, + 0xA577: 959, + 0xA57B: 960, + 0xA581: 961, + 0xA585: 962, + 0xA5A1: 963, + 0xA5A2: 964, + 0xA5A3: 965, + 0xA5A5: 966, + 0xA5A9: 967, + 0xA5B1: 968, + 0xA5B3: 969, + 0xA5B5: 970, + 0xA5B7: 971, + 0xA5C1: 972, + 0xA5C5: 973, + 0xA5D6: 974, + 0xA5E1: 975, + 0xA5F6: 976, + 0xA641: 977, + 0xA642: 978, + 0xA645: 979, + 0xA649: 980, + 0xA651: 981, + 0xA653: 982, + 0xA661: 983, + 0xA665: 984, + 0xA681: 985, + 0xA682: 986, + 0xA685: 987, + 0xA688: 988, + 0xA689: 989, + 0xA68A: 990, + 0xA68B: 991, + 0xA691: 992, + 0xA693: 993, + 0xA695: 994, + 0xA697: 995, + 0xA69B: 996, + 0xA69C: 997, + 0xA6A1: 998, + 0xA6A9: 999, + 0xA6B6: 1000, + 0xA6C1: 1001, + 0xA6E1: 1002, + 0xA6E2: 1003, + 0xA6E5: 1004, + 0xA6E9: 1005, + 0xA6F7: 1006, + 0xA741: 1007, + 0xA745: 1008, + 0xA749: 1009, + 0xA751: 1010, + 0xA755: 1011, + 0xA757: 1012, + 0xA761: 1013, + 0xA762: 1014, + 0xA765: 1015, + 0xA769: 1016, + 0xA771: 1017, + 0xA773: 1018, + 0xA775: 1019, + 0xA7A1: 1020, + 0xA7A2: 1021, + 0xA7A5: 1022, + 0xA7A9: 1023, + 0xA7AB: 1024, + 0xA7B1: 1025, + 0xA7B3: 1026, + 0xA7B5: 1027, + 0xA7B7: 1028, + 0xA7B8: 1029, + 0xA7B9: 1030, + 0xA861: 1031, + 0xA862: 1032, + 0xA865: 1033, + 0xA869: 1034, + 0xA86B: 1035, + 0xA871: 1036, + 0xA873: 1037, + 0xA875: 1038, + 0xA876: 1039, + 0xA877: 1040, + 0xA87D: 1041, + 0xA881: 1042, + 0xA882: 1043, + 0xA885: 1044, + 0xA889: 1045, + 0xA891: 1046, + 0xA893: 1047, + 0xA895: 1048, + 0xA896: 1049, + 0xA897: 1050, + 0xA8A1: 1051, + 0xA8A2: 1052, + 0xA8B1: 1053, + 0xA8E1: 1054, + 0xA8E2: 1055, + 0xA8E5: 1056, + 0xA8E8: 1057, + 0xA8E9: 1058, + 0xA8F1: 1059, + 0xA8F5: 1060, + 0xA8F6: 1061, + 0xA8F7: 1062, + 0xA941: 1063, + 0xA957: 1064, + 0xA961: 1065, + 0xA962: 1066, + 0xA971: 1067, + 0xA973: 1068, + 0xA975: 1069, + 0xA976: 1070, + 0xA977: 1071, + 0xA9A1: 1072, + 0xA9A2: 1073, + 0xA9A5: 1074, + 0xA9A9: 1075, + 0xA9B1: 1076, + 0xA9B3: 1077, + 0xA9B7: 1078, + 0xAA41: 1079, + 0xAA61: 1080, + 0xAA77: 1081, + 0xAA81: 1082, + 0xAA82: 1083, + 0xAA85: 1084, + 0xAA89: 1085, + 0xAA91: 1086, + 0xAA95: 1087, + 0xAA97: 1088, + 0xAB41: 1089, + 0xAB57: 1090, + 0xAB61: 1091, + 0xAB65: 1092, + 0xAB69: 1093, + 0xAB71: 1094, + 0xAB73: 1095, + 0xABA1: 1096, + 0xABA2: 1097, + 0xABA5: 1098, + 0xABA9: 1099, + 0xABB1: 1100, + 0xABB3: 1101, + 0xABB5: 1102, + 0xABB7: 1103, + 0xAC61: 1104, + 0xAC62: 1105, + 0xAC64: 1106, + 0xAC65: 1107, + 0xAC68: 1108, + 0xAC69: 1109, + 0xAC6A: 1110, + 0xAC6B: 1111, + 0xAC71: 1112, + 0xAC73: 1113, + 0xAC75: 1114, + 0xAC76: 1115, + 0xAC77: 1116, + 0xAC7B: 1117, + 0xAC81: 1118, + 0xAC82: 1119, + 0xAC85: 1120, + 0xAC89: 1121, + 0xAC91: 1122, + 0xAC93: 1123, + 0xAC95: 1124, + 0xAC96: 1125, + 0xAC97: 1126, + 0xACA1: 1127, + 0xACA2: 1128, + 0xACA5: 1129, + 0xACA9: 1130, + 0xACB1: 1131, + 0xACB3: 1132, + 0xACB5: 1133, + 0xACB7: 1134, + 0xACC1: 1135, + 0xACC5: 1136, + 0xACC9: 1137, + 0xACD1: 1138, + 0xACD7: 1139, + 0xACE1: 1140, + 0xACE2: 1141, + 0xACE3: 1142, + 0xACE4: 1143, + 0xACE5: 1144, + 0xACE8: 1145, + 0xACE9: 1146, + 0xACEB: 1147, + 0xACEC: 1148, + 0xACF1: 1149, + 0xACF3: 1150, + 0xACF5: 1151, + 0xACF6: 1152, + 0xACF7: 1153, + 0xACFC: 1154, + 0xAD41: 1155, + 0xAD42: 1156, + 0xAD45: 1157, + 0xAD49: 1158, + 0xAD51: 1159, + 0xAD53: 1160, + 0xAD55: 1161, + 0xAD56: 1162, + 0xAD57: 1163, + 0xAD61: 1164, + 0xAD62: 1165, + 0xAD65: 1166, + 0xAD69: 1167, + 0xAD71: 1168, + 0xAD73: 1169, + 0xAD75: 1170, + 0xAD76: 1171, + 0xAD77: 1172, + 0xAD81: 1173, + 0xAD85: 1174, + 0xAD89: 1175, + 0xAD97: 1176, + 0xADA1: 1177, + 0xADA2: 1178, + 0xADA3: 1179, + 0xADA5: 1180, + 0xADA9: 1181, + 0xADAB: 1182, + 0xADB1: 1183, + 0xADB3: 1184, + 0xADB5: 1185, + 0xADB7: 1186, + 0xADBB: 1187, + 0xADC1: 1188, + 0xADC2: 1189, + 0xADC5: 1190, + 0xADC9: 1191, + 0xADD7: 1192, + 0xADE1: 1193, + 0xADE5: 1194, + 0xADE9: 1195, + 0xADF1: 1196, + 0xADF5: 1197, + 0xADF6: 1198, + 0xAE41: 1199, + 0xAE45: 1200, + 0xAE49: 1201, + 0xAE51: 1202, + 0xAE53: 1203, + 0xAE55: 1204, + 0xAE61: 1205, + 0xAE62: 1206, + 0xAE65: 1207, + 0xAE69: 1208, + 0xAE71: 1209, + 0xAE73: 1210, + 0xAE75: 1211, + 0xAE77: 1212, + 0xAE81: 1213, + 0xAE82: 1214, + 0xAE85: 1215, + 0xAE88: 1216, + 0xAE89: 1217, + 0xAE91: 1218, + 0xAE93: 1219, + 0xAE95: 1220, + 0xAE97: 1221, + 0xAE99: 1222, + 0xAE9B: 1223, + 0xAE9C: 1224, + 0xAEA1: 1225, + 0xAEB6: 1226, + 0xAEC1: 1227, + 0xAEC2: 1228, + 0xAEC5: 1229, + 0xAEC9: 1230, + 0xAED1: 1231, + 0xAED7: 1232, + 0xAEE1: 1233, + 0xAEE2: 1234, + 0xAEE5: 1235, + 0xAEE9: 1236, + 0xAEF1: 1237, + 0xAEF3: 1238, + 0xAEF5: 1239, + 0xAEF7: 1240, + 0xAF41: 1241, + 0xAF42: 1242, + 0xAF49: 1243, + 0xAF51: 1244, + 0xAF55: 1245, + 0xAF57: 1246, + 0xAF61: 1247, + 0xAF62: 1248, + 0xAF65: 1249, + 0xAF69: 1250, + 0xAF6A: 1251, + 0xAF71: 1252, + 0xAF73: 1253, + 0xAF75: 1254, + 0xAF77: 1255, + 0xAFA1: 1256, + 0xAFA2: 1257, + 0xAFA5: 1258, + 0xAFA8: 1259, + 0xAFA9: 1260, + 0xAFB0: 1261, + 0xAFB1: 1262, + 0xAFB3: 1263, + 0xAFB5: 1264, + 0xAFB7: 1265, + 0xAFBC: 1266, + 0xB061: 1267, + 0xB062: 1268, + 0xB064: 1269, + 0xB065: 1270, + 0xB069: 1271, + 0xB071: 1272, + 0xB073: 1273, + 0xB076: 1274, + 0xB077: 1275, + 0xB07D: 1276, + 0xB081: 1277, + 0xB082: 1278, + 0xB085: 1279, + 0xB089: 1280, + 0xB091: 1281, + 0xB093: 1282, + 0xB096: 1283, + 0xB097: 1284, + 0xB0B7: 1285, + 0xB0E1: 1286, + 0xB0E2: 1287, + 0xB0E5: 1288, + 0xB0E9: 1289, + 0xB0EB: 1290, + 0xB0F1: 1291, + 0xB0F3: 1292, + 0xB0F6: 1293, + 0xB0F7: 1294, + 0xB141: 1295, + 0xB145: 1296, + 0xB149: 1297, + 0xB185: 1298, + 0xB1A1: 1299, + 0xB1A2: 1300, + 0xB1A5: 1301, + 0xB1A8: 1302, + 0xB1A9: 1303, + 0xB1AB: 1304, + 0xB1B1: 1305, + 0xB1B3: 1306, + 0xB1B7: 1307, + 0xB1C1: 1308, + 0xB1C2: 1309, + 0xB1C5: 1310, + 0xB1D6: 1311, + 0xB1E1: 1312, + 0xB1F6: 1313, + 0xB241: 1314, + 0xB245: 1315, + 0xB249: 1316, + 0xB251: 1317, + 0xB253: 1318, + 0xB261: 1319, + 0xB281: 1320, + 0xB282: 1321, + 0xB285: 1322, + 0xB289: 1323, + 0xB291: 1324, + 0xB293: 1325, + 0xB297: 1326, + 0xB2A1: 1327, + 0xB2B6: 1328, + 0xB2C1: 1329, + 0xB2E1: 1330, + 0xB2E5: 1331, + 0xB357: 1332, + 0xB361: 1333, + 0xB362: 1334, + 0xB365: 1335, + 0xB369: 1336, + 0xB36B: 1337, + 0xB370: 1338, + 0xB371: 1339, + 0xB373: 1340, + 0xB381: 1341, + 0xB385: 1342, + 0xB389: 1343, + 0xB391: 1344, + 0xB3A1: 1345, + 0xB3A2: 1346, + 0xB3A5: 1347, + 0xB3A9: 1348, + 0xB3B1: 1349, + 0xB3B3: 1350, + 0xB3B5: 1351, + 0xB3B7: 1352, + 0xB461: 1353, + 0xB462: 1354, + 0xB465: 1355, + 0xB466: 1356, + 0xB467: 1357, + 0xB469: 1358, + 0xB46A: 1359, + 0xB46B: 1360, + 0xB470: 1361, + 0xB471: 1362, + 0xB473: 1363, + 0xB475: 1364, + 0xB476: 1365, + 0xB477: 1366, + 0xB47B: 1367, + 0xB47C: 1368, + 0xB481: 1369, + 0xB482: 1370, + 0xB485: 1371, + 0xB489: 1372, + 0xB491: 1373, + 0xB493: 1374, + 0xB495: 1375, + 0xB496: 1376, + 0xB497: 1377, + 0xB4A1: 1378, + 0xB4A2: 1379, + 0xB4A5: 1380, + 0xB4A9: 1381, + 0xB4AC: 1382, + 0xB4B1: 1383, + 0xB4B3: 1384, + 0xB4B5: 1385, + 0xB4B7: 1386, + 0xB4BB: 1387, + 0xB4BD: 1388, + 0xB4C1: 1389, + 0xB4C5: 1390, + 0xB4C9: 1391, + 0xB4D3: 1392, + 0xB4E1: 1393, + 0xB4E2: 1394, + 0xB4E5: 1395, + 0xB4E6: 1396, + 0xB4E8: 1397, + 0xB4E9: 1398, + 0xB4EA: 1399, + 0xB4EB: 1400, + 0xB4F1: 1401, + 0xB4F3: 1402, + 0xB4F4: 1403, + 0xB4F5: 1404, + 0xB4F6: 1405, + 0xB4F7: 1406, + 0xB4F8: 1407, + 0xB4FA: 1408, + 0xB4FC: 1409, + 0xB541: 1410, + 0xB542: 1411, + 0xB545: 1412, + 0xB549: 1413, + 0xB551: 1414, + 0xB553: 1415, + 0xB555: 1416, + 0xB557: 1417, + 0xB561: 1418, + 0xB562: 1419, + 0xB563: 1420, + 0xB565: 1421, + 0xB569: 1422, + 0xB56B: 1423, + 0xB56C: 1424, + 0xB571: 1425, + 0xB573: 1426, + 0xB574: 1427, + 0xB575: 1428, + 0xB576: 1429, + 0xB577: 1430, + 0xB57B: 1431, + 0xB57C: 1432, + 0xB57D: 1433, + 0xB581: 1434, + 0xB585: 1435, + 0xB589: 1436, + 0xB591: 1437, + 0xB593: 1438, + 0xB595: 1439, + 0xB596: 1440, + 0xB5A1: 1441, + 0xB5A2: 1442, + 0xB5A5: 1443, + 0xB5A9: 1444, + 0xB5AA: 1445, + 0xB5AB: 1446, + 0xB5AD: 1447, + 0xB5B0: 1448, + 0xB5B1: 1449, + 0xB5B3: 1450, + 0xB5B5: 1451, + 0xB5B7: 1452, + 0xB5B9: 1453, + 0xB5C1: 1454, + 0xB5C2: 1455, + 0xB5C5: 1456, + 0xB5C9: 1457, + 0xB5D1: 1458, + 0xB5D3: 1459, + 0xB5D5: 1460, + 0xB5D6: 1461, + 0xB5D7: 1462, + 0xB5E1: 1463, + 0xB5E2: 1464, + 0xB5E5: 1465, + 0xB5F1: 1466, + 0xB5F5: 1467, + 0xB5F7: 1468, + 0xB641: 1469, + 0xB642: 1470, + 0xB645: 1471, + 0xB649: 1472, + 0xB651: 1473, + 0xB653: 1474, + 0xB655: 1475, + 0xB657: 1476, + 0xB661: 1477, + 0xB662: 1478, + 0xB665: 1479, + 0xB669: 1480, + 0xB671: 1481, + 0xB673: 1482, + 0xB675: 1483, + 0xB677: 1484, + 0xB681: 1485, + 0xB682: 1486, + 0xB685: 1487, + 0xB689: 1488, + 0xB68A: 1489, + 0xB68B: 1490, + 0xB691: 1491, + 0xB693: 1492, + 0xB695: 1493, + 0xB697: 1494, + 0xB6A1: 1495, + 0xB6A2: 1496, + 0xB6A5: 1497, + 0xB6A9: 1498, + 0xB6B1: 1499, + 0xB6B3: 1500, + 0xB6B6: 1501, + 0xB6B7: 1502, + 0xB6C1: 1503, + 0xB6C2: 1504, + 0xB6C5: 1505, + 0xB6C9: 1506, + 0xB6D1: 1507, + 0xB6D3: 1508, + 0xB6D7: 1509, + 0xB6E1: 1510, + 0xB6E2: 1511, + 0xB6E5: 1512, + 0xB6E9: 1513, + 0xB6F1: 1514, + 0xB6F3: 1515, + 0xB6F5: 1516, + 0xB6F7: 1517, + 0xB741: 1518, + 0xB742: 1519, + 0xB745: 1520, + 0xB749: 1521, + 0xB751: 1522, + 0xB753: 1523, + 0xB755: 1524, + 0xB757: 1525, + 0xB759: 1526, + 0xB761: 1527, + 0xB762: 1528, + 0xB765: 1529, + 0xB769: 1530, + 0xB76F: 1531, + 0xB771: 1532, + 0xB773: 1533, + 0xB775: 1534, + 0xB777: 1535, + 0xB778: 1536, + 0xB779: 1537, + 0xB77A: 1538, + 0xB77B: 1539, + 0xB77C: 1540, + 0xB77D: 1541, + 0xB781: 1542, + 0xB785: 1543, + 0xB789: 1544, + 0xB791: 1545, + 0xB795: 1546, + 0xB7A1: 1547, + 0xB7A2: 1548, + 0xB7A5: 1549, + 0xB7A9: 1550, + 0xB7AA: 1551, + 0xB7AB: 1552, + 0xB7B0: 1553, + 0xB7B1: 1554, + 0xB7B3: 1555, + 0xB7B5: 1556, + 0xB7B6: 1557, + 0xB7B7: 1558, + 0xB7B8: 1559, + 0xB7BC: 1560, + 0xB861: 1561, + 0xB862: 1562, + 0xB865: 1563, + 0xB867: 1564, + 0xB868: 1565, + 0xB869: 1566, + 0xB86B: 1567, + 0xB871: 1568, + 0xB873: 1569, + 0xB875: 1570, + 0xB876: 1571, + 0xB877: 1572, + 0xB878: 1573, + 0xB881: 1574, + 0xB882: 1575, + 0xB885: 1576, + 0xB889: 1577, + 0xB891: 1578, + 0xB893: 1579, + 0xB895: 1580, + 0xB896: 1581, + 0xB897: 1582, + 0xB8A1: 1583, + 0xB8A2: 1584, + 0xB8A5: 1585, + 0xB8A7: 1586, + 0xB8A9: 1587, + 0xB8B1: 1588, + 0xB8B7: 1589, + 0xB8C1: 1590, + 0xB8C5: 1591, + 0xB8C9: 1592, + 0xB8E1: 1593, + 0xB8E2: 1594, + 0xB8E5: 1595, + 0xB8E9: 1596, + 0xB8EB: 1597, + 0xB8F1: 1598, + 0xB8F3: 1599, + 0xB8F5: 1600, + 0xB8F7: 1601, + 0xB8F8: 1602, + 0xB941: 1603, + 0xB942: 1604, + 0xB945: 1605, + 0xB949: 1606, + 0xB951: 1607, + 0xB953: 1608, + 0xB955: 1609, + 0xB957: 1610, + 0xB961: 1611, + 0xB965: 1612, + 0xB969: 1613, + 0xB971: 1614, + 0xB973: 1615, + 0xB976: 1616, + 0xB977: 1617, + 0xB981: 1618, + 0xB9A1: 1619, + 0xB9A2: 1620, + 0xB9A5: 1621, + 0xB9A9: 1622, + 0xB9AB: 1623, + 0xB9B1: 1624, + 0xB9B3: 1625, + 0xB9B5: 1626, + 0xB9B7: 1627, + 0xB9B8: 1628, + 0xB9B9: 1629, + 0xB9BD: 1630, + 0xB9C1: 1631, + 0xB9C2: 1632, + 0xB9C9: 1633, + 0xB9D3: 1634, + 0xB9D5: 1635, + 0xB9D7: 1636, + 0xB9E1: 1637, + 0xB9F6: 1638, + 0xB9F7: 1639, + 0xBA41: 1640, + 0xBA45: 1641, + 0xBA49: 1642, + 0xBA51: 1643, + 0xBA53: 1644, + 0xBA55: 1645, + 0xBA57: 1646, + 0xBA61: 1647, + 0xBA62: 1648, + 0xBA65: 1649, + 0xBA77: 1650, + 0xBA81: 1651, + 0xBA82: 1652, + 0xBA85: 1653, + 0xBA89: 1654, + 0xBA8A: 1655, + 0xBA8B: 1656, + 0xBA91: 1657, + 0xBA93: 1658, + 0xBA95: 1659, + 0xBA97: 1660, + 0xBAA1: 1661, + 0xBAB6: 1662, + 0xBAC1: 1663, + 0xBAE1: 1664, + 0xBAE2: 1665, + 0xBAE5: 1666, + 0xBAE9: 1667, + 0xBAF1: 1668, + 0xBAF3: 1669, + 0xBAF5: 1670, + 0xBB41: 1671, + 0xBB45: 1672, + 0xBB49: 1673, + 0xBB51: 1674, + 0xBB61: 1675, + 0xBB62: 1676, + 0xBB65: 1677, + 0xBB69: 1678, + 0xBB71: 1679, + 0xBB73: 1680, + 0xBB75: 1681, + 0xBB77: 1682, + 0xBBA1: 1683, + 0xBBA2: 1684, + 0xBBA5: 1685, + 0xBBA8: 1686, + 0xBBA9: 1687, + 0xBBAB: 1688, + 0xBBB1: 1689, + 0xBBB3: 1690, + 0xBBB5: 1691, + 0xBBB7: 1692, + 0xBBB8: 1693, + 0xBBBB: 1694, + 0xBBBC: 1695, + 0xBC61: 1696, + 0xBC62: 1697, + 0xBC65: 1698, + 0xBC67: 1699, + 0xBC69: 1700, + 0xBC6C: 1701, + 0xBC71: 1702, + 0xBC73: 1703, + 0xBC75: 1704, + 0xBC76: 1705, + 0xBC77: 1706, + 0xBC81: 1707, + 0xBC82: 1708, + 0xBC85: 1709, + 0xBC89: 1710, + 0xBC91: 1711, + 0xBC93: 1712, + 0xBC95: 1713, + 0xBC96: 1714, + 0xBC97: 1715, + 0xBCA1: 1716, + 0xBCA5: 1717, + 0xBCB7: 1718, + 0xBCE1: 1719, + 0xBCE2: 1720, + 0xBCE5: 1721, + 0xBCE9: 1722, + 0xBCF1: 1723, + 0xBCF3: 1724, + 0xBCF5: 1725, + 0xBCF6: 1726, + 0xBCF7: 1727, + 0xBD41: 1728, + 0xBD57: 1729, + 0xBD61: 1730, + 0xBD76: 1731, + 0xBDA1: 1732, + 0xBDA2: 1733, + 0xBDA5: 1734, + 0xBDA9: 1735, + 0xBDB1: 1736, + 0xBDB3: 1737, + 0xBDB5: 1738, + 0xBDB7: 1739, + 0xBDB9: 1740, + 0xBDC1: 1741, + 0xBDC2: 1742, + 0xBDC9: 1743, + 0xBDD6: 1744, + 0xBDE1: 1745, + 0xBDF6: 1746, + 0xBE41: 1747, + 0xBE45: 1748, + 0xBE49: 1749, + 0xBE51: 1750, + 0xBE53: 1751, + 0xBE77: 1752, + 0xBE81: 1753, + 0xBE82: 1754, + 0xBE85: 1755, + 0xBE89: 1756, + 0xBE91: 1757, + 0xBE93: 1758, + 0xBE97: 1759, + 0xBEA1: 1760, + 0xBEB6: 1761, + 0xBEB7: 1762, + 0xBEE1: 1763, + 0xBF41: 1764, + 0xBF61: 1765, + 0xBF71: 1766, + 0xBF75: 1767, + 0xBF77: 1768, + 0xBFA1: 1769, + 0xBFA2: 1770, + 0xBFA5: 1771, + 0xBFA9: 1772, + 0xBFB1: 1773, + 0xBFB3: 1774, + 0xBFB7: 1775, + 0xBFB8: 1776, + 0xBFBD: 1777, + 0xC061: 1778, + 0xC062: 1779, + 0xC065: 1780, + 0xC067: 1781, + 0xC069: 1782, + 0xC071: 1783, + 0xC073: 1784, + 0xC075: 1785, + 0xC076: 1786, + 0xC077: 1787, + 0xC078: 1788, + 0xC081: 1789, + 0xC082: 1790, + 0xC085: 1791, + 0xC089: 1792, + 0xC091: 1793, + 0xC093: 1794, + 0xC095: 1795, + 0xC096: 1796, + 0xC097: 1797, + 0xC0A1: 1798, + 0xC0A5: 1799, + 0xC0A7: 1800, + 0xC0A9: 1801, + 0xC0B1: 1802, + 0xC0B7: 1803, + 0xC0E1: 1804, + 0xC0E2: 1805, + 0xC0E5: 1806, + 0xC0E9: 1807, + 0xC0F1: 1808, + 0xC0F3: 1809, + 0xC0F5: 1810, + 0xC0F6: 1811, + 0xC0F7: 1812, + 0xC141: 1813, + 0xC142: 1814, + 0xC145: 1815, + 0xC149: 1816, + 0xC151: 1817, + 0xC153: 1818, + 0xC155: 1819, + 0xC157: 1820, + 0xC161: 1821, + 0xC165: 1822, + 0xC176: 1823, + 0xC181: 1824, + 0xC185: 1825, + 0xC197: 1826, + 0xC1A1: 1827, + 0xC1A2: 1828, + 0xC1A5: 1829, + 0xC1A9: 1830, + 0xC1B1: 1831, + 0xC1B3: 1832, + 0xC1B5: 1833, + 0xC1B7: 1834, + 0xC1C1: 1835, + 0xC1C5: 1836, + 0xC1C9: 1837, + 0xC1D7: 1838, + 0xC241: 1839, + 0xC245: 1840, + 0xC249: 1841, + 0xC251: 1842, + 0xC253: 1843, + 0xC255: 1844, + 0xC257: 1845, + 0xC261: 1846, + 0xC271: 1847, + 0xC281: 1848, + 0xC282: 1849, + 0xC285: 1850, + 0xC289: 1851, + 0xC291: 1852, + 0xC293: 1853, + 0xC295: 1854, + 0xC297: 1855, + 0xC2A1: 1856, + 0xC2B6: 1857, + 0xC2C1: 1858, + 0xC2C5: 1859, + 0xC2E1: 1860, + 0xC2E5: 1861, + 0xC2E9: 1862, + 0xC2F1: 1863, + 0xC2F3: 1864, + 0xC2F5: 1865, + 0xC2F7: 1866, + 0xC341: 1867, + 0xC345: 1868, + 0xC349: 1869, + 0xC351: 1870, + 0xC357: 1871, + 0xC361: 1872, + 0xC362: 1873, + 0xC365: 1874, + 0xC369: 1875, + 0xC371: 1876, + 0xC373: 1877, + 0xC375: 1878, + 0xC377: 1879, + 0xC3A1: 1880, + 0xC3A2: 1881, + 0xC3A5: 1882, + 0xC3A8: 1883, + 0xC3A9: 1884, + 0xC3AA: 1885, + 0xC3B1: 1886, + 0xC3B3: 1887, + 0xC3B5: 1888, + 0xC3B7: 1889, + 0xC461: 1890, + 0xC462: 1891, + 0xC465: 1892, + 0xC469: 1893, + 0xC471: 1894, + 0xC473: 1895, + 0xC475: 1896, + 0xC477: 1897, + 0xC481: 1898, + 0xC482: 1899, + 0xC485: 1900, + 0xC489: 1901, + 0xC491: 1902, + 0xC493: 1903, + 0xC495: 1904, + 0xC496: 1905, + 0xC497: 1906, + 0xC4A1: 1907, + 0xC4A2: 1908, + 0xC4B7: 1909, + 0xC4E1: 1910, + 0xC4E2: 1911, + 0xC4E5: 1912, + 0xC4E8: 1913, + 0xC4E9: 1914, + 0xC4F1: 1915, + 0xC4F3: 1916, + 0xC4F5: 1917, + 0xC4F6: 1918, + 0xC4F7: 1919, + 0xC541: 1920, + 0xC542: 1921, + 0xC545: 1922, + 0xC549: 1923, + 0xC551: 1924, + 0xC553: 1925, + 0xC555: 1926, + 0xC557: 1927, + 0xC561: 1928, + 0xC565: 1929, + 0xC569: 1930, + 0xC571: 1931, + 0xC573: 1932, + 0xC575: 1933, + 0xC576: 1934, + 0xC577: 1935, + 0xC581: 1936, + 0xC5A1: 1937, + 0xC5A2: 1938, + 0xC5A5: 1939, + 0xC5A9: 1940, + 0xC5B1: 1941, + 0xC5B3: 1942, + 0xC5B5: 1943, + 0xC5B7: 1944, + 0xC5C1: 1945, + 0xC5C2: 1946, + 0xC5C5: 1947, + 0xC5C9: 1948, + 0xC5D1: 1949, + 0xC5D7: 1950, + 0xC5E1: 1951, + 0xC5F7: 1952, + 0xC641: 1953, + 0xC649: 1954, + 0xC661: 1955, + 0xC681: 1956, + 0xC682: 1957, + 0xC685: 1958, + 0xC689: 1959, + 0xC691: 1960, + 0xC693: 1961, + 0xC695: 1962, + 0xC697: 1963, + 0xC6A1: 1964, + 0xC6A5: 1965, + 0xC6A9: 1966, + 0xC6B7: 1967, + 0xC6C1: 1968, + 0xC6D7: 1969, + 0xC6E1: 1970, + 0xC6E2: 1971, + 0xC6E5: 1972, + 0xC6E9: 1973, + 0xC6F1: 1974, + 0xC6F3: 1975, + 0xC6F5: 1976, + 0xC6F7: 1977, + 0xC741: 1978, + 0xC745: 1979, + 0xC749: 1980, + 0xC751: 1981, + 0xC761: 1982, + 0xC762: 1983, + 0xC765: 1984, + 0xC769: 1985, + 0xC771: 1986, + 0xC773: 1987, + 0xC777: 1988, + 0xC7A1: 1989, + 0xC7A2: 1990, + 0xC7A5: 1991, + 0xC7A9: 1992, + 0xC7B1: 1993, + 0xC7B3: 1994, + 0xC7B5: 1995, + 0xC7B7: 1996, + 0xC861: 1997, + 0xC862: 1998, + 0xC865: 1999, + 0xC869: 2000, + 0xC86A: 2001, + 0xC871: 2002, + 0xC873: 2003, + 0xC875: 2004, + 0xC876: 2005, + 0xC877: 2006, + 0xC881: 2007, + 0xC882: 2008, + 0xC885: 2009, + 0xC889: 2010, + 0xC891: 2011, + 0xC893: 2012, + 0xC895: 2013, + 0xC896: 2014, + 0xC897: 2015, + 0xC8A1: 2016, + 0xC8B7: 2017, + 0xC8E1: 2018, + 0xC8E2: 2019, + 0xC8E5: 2020, + 0xC8E9: 2021, + 0xC8EB: 2022, + 0xC8F1: 2023, + 0xC8F3: 2024, + 0xC8F5: 2025, + 0xC8F6: 2026, + 0xC8F7: 2027, + 0xC941: 2028, + 0xC942: 2029, + 0xC945: 2030, + 0xC949: 2031, + 0xC951: 2032, + 0xC953: 2033, + 0xC955: 2034, + 0xC957: 2035, + 0xC961: 2036, + 0xC965: 2037, + 0xC976: 2038, + 0xC981: 2039, + 0xC985: 2040, + 0xC9A1: 2041, + 0xC9A2: 2042, + 0xC9A5: 2043, + 0xC9A9: 2044, + 0xC9B1: 2045, + 0xC9B3: 2046, + 0xC9B5: 2047, + 0xC9B7: 2048, + 0xC9BC: 2049, + 0xC9C1: 2050, + 0xC9C5: 2051, + 0xC9E1: 2052, + 0xCA41: 2053, + 0xCA45: 2054, + 0xCA55: 2055, + 0xCA57: 2056, + 0xCA61: 2057, + 0xCA81: 2058, + 0xCA82: 2059, + 0xCA85: 2060, + 0xCA89: 2061, + 0xCA91: 2062, + 0xCA93: 2063, + 0xCA95: 2064, + 0xCA97: 2065, + 0xCAA1: 2066, + 0xCAB6: 2067, + 0xCAC1: 2068, + 0xCAE1: 2069, + 0xCAE2: 2070, + 0xCAE5: 2071, + 0xCAE9: 2072, + 0xCAF1: 2073, + 0xCAF3: 2074, + 0xCAF7: 2075, + 0xCB41: 2076, + 0xCB45: 2077, + 0xCB49: 2078, + 0xCB51: 2079, + 0xCB57: 2080, + 0xCB61: 2081, + 0xCB62: 2082, + 0xCB65: 2083, + 0xCB68: 2084, + 0xCB69: 2085, + 0xCB6B: 2086, + 0xCB71: 2087, + 0xCB73: 2088, + 0xCB75: 2089, + 0xCB81: 2090, + 0xCB85: 2091, + 0xCB89: 2092, + 0xCB91: 2093, + 0xCB93: 2094, + 0xCBA1: 2095, + 0xCBA2: 2096, + 0xCBA5: 2097, + 0xCBA9: 2098, + 0xCBB1: 2099, + 0xCBB3: 2100, + 0xCBB5: 2101, + 0xCBB7: 2102, + 0xCC61: 2103, + 0xCC62: 2104, + 0xCC63: 2105, + 0xCC65: 2106, + 0xCC69: 2107, + 0xCC6B: 2108, + 0xCC71: 2109, + 0xCC73: 2110, + 0xCC75: 2111, + 0xCC76: 2112, + 0xCC77: 2113, + 0xCC7B: 2114, + 0xCC81: 2115, + 0xCC82: 2116, + 0xCC85: 2117, + 0xCC89: 2118, + 0xCC91: 2119, + 0xCC93: 2120, + 0xCC95: 2121, + 0xCC96: 2122, + 0xCC97: 2123, + 0xCCA1: 2124, + 0xCCA2: 2125, + 0xCCE1: 2126, + 0xCCE2: 2127, + 0xCCE5: 2128, + 0xCCE9: 2129, + 0xCCF1: 2130, + 0xCCF3: 2131, + 0xCCF5: 2132, + 0xCCF6: 2133, + 0xCCF7: 2134, + 0xCD41: 2135, + 0xCD42: 2136, + 0xCD45: 2137, + 0xCD49: 2138, + 0xCD51: 2139, + 0xCD53: 2140, + 0xCD55: 2141, + 0xCD57: 2142, + 0xCD61: 2143, + 0xCD65: 2144, + 0xCD69: 2145, + 0xCD71: 2146, + 0xCD73: 2147, + 0xCD76: 2148, + 0xCD77: 2149, + 0xCD81: 2150, + 0xCD89: 2151, + 0xCD93: 2152, + 0xCD95: 2153, + 0xCDA1: 2154, + 0xCDA2: 2155, + 0xCDA5: 2156, + 0xCDA9: 2157, + 0xCDB1: 2158, + 0xCDB3: 2159, + 0xCDB5: 2160, + 0xCDB7: 2161, + 0xCDC1: 2162, + 0xCDD7: 2163, + 0xCE41: 2164, + 0xCE45: 2165, + 0xCE61: 2166, + 0xCE65: 2167, + 0xCE69: 2168, + 0xCE73: 2169, + 0xCE75: 2170, + 0xCE81: 2171, + 0xCE82: 2172, + 0xCE85: 2173, + 0xCE88: 2174, + 0xCE89: 2175, + 0xCE8B: 2176, + 0xCE91: 2177, + 0xCE93: 2178, + 0xCE95: 2179, + 0xCE97: 2180, + 0xCEA1: 2181, + 0xCEB7: 2182, + 0xCEE1: 2183, + 0xCEE5: 2184, + 0xCEE9: 2185, + 0xCEF1: 2186, + 0xCEF5: 2187, + 0xCF41: 2188, + 0xCF45: 2189, + 0xCF49: 2190, + 0xCF51: 2191, + 0xCF55: 2192, + 0xCF57: 2193, + 0xCF61: 2194, + 0xCF65: 2195, + 0xCF69: 2196, + 0xCF71: 2197, + 0xCF73: 2198, + 0xCF75: 2199, + 0xCFA1: 2200, + 0xCFA2: 2201, + 0xCFA5: 2202, + 0xCFA9: 2203, + 0xCFB1: 2204, + 0xCFB3: 2205, + 0xCFB5: 2206, + 0xCFB7: 2207, + 0xD061: 2208, + 0xD062: 2209, + 0xD065: 2210, + 0xD069: 2211, + 0xD06E: 2212, + 0xD071: 2213, + 0xD073: 2214, + 0xD075: 2215, + 0xD077: 2216, + 0xD081: 2217, + 0xD082: 2218, + 0xD085: 2219, + 0xD089: 2220, + 0xD091: 2221, + 0xD093: 2222, + 0xD095: 2223, + 0xD096: 2224, + 0xD097: 2225, + 0xD0A1: 2226, + 0xD0B7: 2227, + 0xD0E1: 2228, + 0xD0E2: 2229, + 0xD0E5: 2230, + 0xD0E9: 2231, + 0xD0EB: 2232, + 0xD0F1: 2233, + 0xD0F3: 2234, + 0xD0F5: 2235, + 0xD0F7: 2236, + 0xD141: 2237, + 0xD142: 2238, + 0xD145: 2239, + 0xD149: 2240, + 0xD151: 2241, + 0xD153: 2242, + 0xD155: 2243, + 0xD157: 2244, + 0xD161: 2245, + 0xD162: 2246, + 0xD165: 2247, + 0xD169: 2248, + 0xD171: 2249, + 0xD173: 2250, + 0xD175: 2251, + 0xD176: 2252, + 0xD177: 2253, + 0xD181: 2254, + 0xD185: 2255, + 0xD189: 2256, + 0xD193: 2257, + 0xD1A1: 2258, + 0xD1A2: 2259, + 0xD1A5: 2260, + 0xD1A9: 2261, + 0xD1AE: 2262, + 0xD1B1: 2263, + 0xD1B3: 2264, + 0xD1B5: 2265, + 0xD1B7: 2266, + 0xD1BB: 2267, + 0xD1C1: 2268, + 0xD1C2: 2269, + 0xD1C5: 2270, + 0xD1C9: 2271, + 0xD1D5: 2272, + 0xD1D7: 2273, + 0xD1E1: 2274, + 0xD1E2: 2275, + 0xD1E5: 2276, + 0xD1F5: 2277, + 0xD1F7: 2278, + 0xD241: 2279, + 0xD242: 2280, + 0xD245: 2281, + 0xD249: 2282, + 0xD253: 2283, + 0xD255: 2284, + 0xD257: 2285, + 0xD261: 2286, + 0xD265: 2287, + 0xD269: 2288, + 0xD273: 2289, + 0xD275: 2290, + 0xD281: 2291, + 0xD282: 2292, + 0xD285: 2293, + 0xD289: 2294, + 0xD28E: 2295, + 0xD291: 2296, + 0xD295: 2297, + 0xD297: 2298, + 0xD2A1: 2299, + 0xD2A5: 2300, + 0xD2A9: 2301, + 0xD2B1: 2302, + 0xD2B7: 2303, + 0xD2C1: 2304, + 0xD2C2: 2305, + 0xD2C5: 2306, + 0xD2C9: 2307, + 0xD2D7: 2308, + 0xD2E1: 2309, + 0xD2E2: 2310, + 0xD2E5: 2311, + 0xD2E9: 2312, + 0xD2F1: 2313, + 0xD2F3: 2314, + 0xD2F5: 2315, + 0xD2F7: 2316, + 0xD341: 2317, + 0xD342: 2318, + 0xD345: 2319, + 0xD349: 2320, + 0xD351: 2321, + 0xD355: 2322, + 0xD357: 2323, + 0xD361: 2324, + 0xD362: 2325, + 0xD365: 2326, + 0xD367: 2327, + 0xD368: 2328, + 0xD369: 2329, + 0xD36A: 2330, + 0xD371: 2331, + 0xD373: 2332, + 0xD375: 2333, + 0xD377: 2334, + 0xD37B: 2335, + 0xD381: 2336, + 0xD385: 2337, + 0xD389: 2338, + 0xD391: 2339, + 0xD393: 2340, + 0xD397: 2341, + 0xD3A1: 2342, + 0xD3A2: 2343, + 0xD3A5: 2344, + 0xD3A9: 2345, + 0xD3B1: 2346, + 0xD3B3: 2347, + 0xD3B5: 2348, + 0xD3B7: 2349, +} diff --git a/script.module.chardet/lib/chardet/compat.py b/script.module.chardet/lib/chardet/johabprober.py similarity index 50% rename from script.module.chardet/lib/chardet/compat.py rename to script.module.chardet/lib/chardet/johabprober.py index 8941572b3..d7364ba61 100644 --- a/script.module.chardet/lib/chardet/compat.py +++ b/script.module.chardet/lib/chardet/johabprober.py @@ -1,7 +1,13 @@ ######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# # Contributor(s): -# Dan Blanchard -# Ian Cordasco +# Mark Pilgrim - port to Python # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -19,18 +25,23 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -import sys +from .chardistribution import JOHABDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber +from .mbcssm import JOHAB_SM_MODEL + + +class JOHABProber(MultiByteCharSetProber): + def __init__(self) -> None: + super().__init__() + self.coding_sm = CodingStateMachine(JOHAB_SM_MODEL) + self.distribution_analyzer = JOHABDistributionAnalysis() + self.reset() + @property + def charset_name(self) -> str: + return "Johab" -if sys.version_info < (3, 0): - PY2 = True - PY3 = False - string_types = (str, unicode) - text_type = unicode - iteritems = dict.iteritems -else: - PY2 = False - PY3 = True - string_types = (bytes, str) - text_type = str - iteritems = dict.items + @property + def language(self) -> str: + return "Korean" diff --git a/script.module.chardet/lib/chardet/jpcntx.py b/script.module.chardet/lib/chardet/jpcntx.py index 20044e4bc..2f53bdda0 100644 --- a/script.module.chardet/lib/chardet/jpcntx.py +++ b/script.module.chardet/lib/chardet/jpcntx.py @@ -25,110 +25,114 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from typing import List, Tuple, Union # This is hiragana 2-char sequence table, the number in each cell represents its frequency category -jp2CharContext = ( -(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), -(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), -(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), -(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), -(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), -(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), -(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), -(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), -(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), -(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), -(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), -(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), -(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), -(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), -(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), -(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), -(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), -(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), -(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), -(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), -(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), -(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), -(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), -(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), -(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), -(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), -(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), -(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), -(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), -(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), -(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), -(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), -(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), -(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), -(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), -(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), -(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), -(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), -(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), -(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), -(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), -(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), -(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), -(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), -(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), -(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), -(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), -(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), -(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), -(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), -(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), -(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), -(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), -(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), -(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), -(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), -(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), -(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), -(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), -(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), -(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), -(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), -(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), -(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), -(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), -(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), -(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), -(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), -(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), -(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), -(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), -(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), -(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), -(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), +# fmt: off +jp2_char_context = ( + (0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), + (2, 4, 0, 4, 0, 3, 0, 4, 0, 3, 4, 4, 4, 2, 4, 3, 3, 4, 3, 2, 3, 3, 4, 2, 3, 3, 3, 2, 4, 1, 4, 3, 3, 1, 5, 4, 3, 4, 3, 4, 3, 5, 3, 0, 3, 5, 4, 2, 0, 3, 1, 0, 3, 3, 0, 3, 3, 0, 1, 1, 0, 4, 3, 0, 3, 3, 0, 4, 0, 2, 0, 3, 5, 5, 5, 5, 4, 0, 4, 1, 0, 3, 4), + (0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2), + (0, 4, 0, 5, 0, 5, 0, 4, 0, 4, 5, 4, 4, 3, 5, 3, 5, 1, 5, 3, 4, 3, 4, 4, 3, 4, 3, 3, 4, 3, 5, 4, 4, 3, 5, 5, 3, 5, 5, 5, 3, 5, 5, 3, 4, 5, 5, 3, 1, 3, 2, 0, 3, 4, 0, 4, 2, 0, 4, 2, 1, 5, 3, 2, 3, 5, 0, 4, 0, 2, 0, 5, 4, 4, 5, 4, 5, 0, 4, 0, 0, 4, 4), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (0, 3, 0, 4, 0, 3, 0, 3, 0, 4, 5, 4, 3, 3, 3, 3, 4, 3, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 4, 4, 4, 4, 5, 3, 4, 4, 3, 4, 5, 5, 4, 5, 5, 1, 4, 5, 4, 3, 0, 3, 3, 1, 3, 3, 0, 4, 4, 0, 3, 3, 1, 5, 3, 3, 3, 5, 0, 4, 0, 3, 0, 4, 4, 3, 4, 3, 3, 0, 4, 1, 1, 3, 4), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (0, 4, 0, 3, 0, 3, 0, 4, 0, 3, 4, 4, 3, 2, 2, 1, 2, 1, 3, 1, 3, 3, 3, 3, 3, 4, 3, 1, 3, 3, 5, 3, 3, 0, 4, 3, 0, 5, 4, 3, 3, 5, 4, 4, 3, 4, 4, 5, 0, 1, 2, 0, 1, 2, 0, 2, 2, 0, 1, 0, 0, 5, 2, 2, 1, 4, 0, 3, 0, 1, 0, 4, 4, 3, 5, 4, 3, 0, 2, 1, 0, 4, 3), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (0, 3, 0, 5, 0, 4, 0, 2, 1, 4, 4, 2, 4, 1, 4, 2, 4, 2, 4, 3, 3, 3, 4, 3, 3, 3, 3, 1, 4, 2, 3, 3, 3, 1, 4, 4, 1, 1, 1, 4, 3, 3, 2, 0, 2, 4, 3, 2, 0, 3, 3, 0, 3, 1, 1, 0, 0, 0, 3, 3, 0, 4, 2, 2, 3, 4, 0, 4, 0, 3, 0, 4, 4, 5, 3, 4, 4, 0, 3, 0, 0, 1, 4), + (1, 4, 0, 4, 0, 4, 0, 4, 0, 3, 5, 4, 4, 3, 4, 3, 5, 4, 3, 3, 4, 3, 5, 4, 4, 4, 4, 3, 4, 2, 4, 3, 3, 1, 5, 4, 3, 2, 4, 5, 4, 5, 5, 4, 4, 5, 4, 4, 0, 3, 2, 2, 3, 3, 0, 4, 3, 1, 3, 2, 1, 4, 3, 3, 4, 5, 0, 3, 0, 2, 0, 4, 5, 5, 4, 5, 4, 0, 4, 0, 0, 5, 4), + (0, 5, 0, 5, 0, 4, 0, 3, 0, 4, 4, 3, 4, 3, 3, 3, 4, 0, 4, 4, 4, 3, 4, 3, 4, 3, 3, 1, 4, 2, 4, 3, 4, 0, 5, 4, 1, 4, 5, 4, 4, 5, 3, 2, 4, 3, 4, 3, 2, 4, 1, 3, 3, 3, 2, 3, 2, 0, 4, 3, 3, 4, 3, 3, 3, 4, 0, 4, 0, 3, 0, 4, 5, 4, 4, 4, 3, 0, 4, 1, 0, 1, 3), + (0, 3, 1, 4, 0, 3, 0, 2, 0, 3, 4, 4, 3, 1, 4, 2, 3, 3, 4, 3, 4, 3, 4, 3, 4, 4, 3, 2, 3, 1, 5, 4, 4, 1, 4, 4, 3, 5, 4, 4, 3, 5, 5, 4, 3, 4, 4, 3, 1, 2, 3, 1, 2, 2, 0, 3, 2, 0, 3, 1, 0, 5, 3, 3, 3, 4, 3, 3, 3, 3, 4, 4, 4, 4, 5, 4, 2, 0, 3, 3, 2, 4, 3), + (0, 2, 0, 3, 0, 1, 0, 1, 0, 0, 3, 2, 0, 0, 2, 0, 1, 0, 2, 1, 3, 3, 3, 1, 2, 3, 1, 0, 1, 0, 4, 2, 1, 1, 3, 3, 0, 4, 3, 3, 1, 4, 3, 3, 0, 3, 3, 2, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 4, 1, 0, 2, 3, 2, 2, 2, 1, 3, 3, 3, 4, 4, 3, 2, 0, 3, 1, 0, 3, 3), + (0, 4, 0, 4, 0, 3, 0, 3, 0, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 2, 4, 3, 4, 3, 3, 2, 4, 3, 4, 5, 4, 1, 4, 5, 3, 5, 4, 5, 3, 5, 4, 0, 3, 5, 5, 3, 1, 3, 3, 2, 2, 3, 0, 3, 4, 1, 3, 3, 2, 4, 3, 3, 3, 4, 0, 4, 0, 3, 0, 4, 5, 4, 4, 5, 3, 0, 4, 1, 0, 3, 4), + (0, 2, 0, 3, 0, 3, 0, 0, 0, 2, 2, 2, 1, 0, 1, 0, 0, 0, 3, 0, 3, 0, 3, 0, 1, 3, 1, 0, 3, 1, 3, 3, 3, 1, 3, 3, 3, 0, 1, 3, 1, 3, 4, 0, 0, 3, 1, 1, 0, 3, 2, 0, 0, 0, 0, 1, 3, 0, 1, 0, 0, 3, 3, 2, 0, 3, 0, 0, 0, 0, 0, 3, 4, 3, 4, 3, 3, 0, 3, 0, 0, 2, 3), + (2, 3, 0, 3, 0, 2, 0, 1, 0, 3, 3, 4, 3, 1, 3, 1, 1, 1, 3, 1, 4, 3, 4, 3, 3, 3, 0, 0, 3, 1, 5, 4, 3, 1, 4, 3, 2, 5, 5, 4, 4, 4, 4, 3, 3, 4, 4, 4, 0, 2, 1, 1, 3, 2, 0, 1, 2, 0, 0, 1, 0, 4, 1, 3, 3, 3, 0, 3, 0, 1, 0, 4, 4, 4, 5, 5, 3, 0, 2, 0, 0, 4, 4), + (0, 2, 0, 1, 0, 3, 1, 3, 0, 2, 3, 3, 3, 0, 3, 1, 0, 0, 3, 0, 3, 2, 3, 1, 3, 2, 1, 1, 0, 0, 4, 2, 1, 0, 2, 3, 1, 4, 3, 2, 0, 4, 4, 3, 1, 3, 1, 3, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4, 1, 1, 1, 2, 0, 3, 0, 0, 0, 3, 4, 2, 4, 3, 2, 0, 1, 0, 0, 3, 3), + (0, 1, 0, 4, 0, 5, 0, 4, 0, 2, 4, 4, 2, 3, 3, 2, 3, 3, 5, 3, 3, 3, 4, 3, 4, 2, 3, 0, 4, 3, 3, 3, 4, 1, 4, 3, 2, 1, 5, 5, 3, 4, 5, 1, 3, 5, 4, 2, 0, 3, 3, 0, 1, 3, 0, 4, 2, 0, 1, 3, 1, 4, 3, 3, 3, 3, 0, 3, 0, 1, 0, 3, 4, 4, 4, 5, 5, 0, 3, 0, 1, 4, 5), + (0, 2, 0, 3, 0, 3, 0, 0, 0, 2, 3, 1, 3, 0, 4, 0, 1, 1, 3, 0, 3, 4, 3, 2, 3, 1, 0, 3, 3, 2, 3, 1, 3, 0, 2, 3, 0, 2, 1, 4, 1, 2, 2, 0, 0, 3, 3, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 2, 2, 0, 3, 2, 1, 3, 3, 0, 2, 0, 2, 0, 0, 3, 3, 1, 2, 4, 0, 3, 0, 2, 2, 3), + (2, 4, 0, 5, 0, 4, 0, 4, 0, 2, 4, 4, 4, 3, 4, 3, 3, 3, 1, 2, 4, 3, 4, 3, 4, 4, 5, 0, 3, 3, 3, 3, 2, 0, 4, 3, 1, 4, 3, 4, 1, 4, 4, 3, 3, 4, 4, 3, 1, 2, 3, 0, 4, 2, 0, 4, 1, 0, 3, 3, 0, 4, 3, 3, 3, 4, 0, 4, 0, 2, 0, 3, 5, 3, 4, 5, 2, 0, 3, 0, 0, 4, 5), + (0, 3, 0, 4, 0, 1, 0, 1, 0, 1, 3, 2, 2, 1, 3, 0, 3, 0, 2, 0, 2, 0, 3, 0, 2, 0, 0, 0, 1, 0, 1, 1, 0, 0, 3, 1, 0, 0, 0, 4, 0, 3, 1, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 3, 1, 0, 3, 0, 0, 0, 1, 4, 4, 4, 3, 0, 0, 4, 0, 0, 1, 4), + (1, 4, 1, 5, 0, 3, 0, 3, 0, 4, 5, 4, 4, 3, 5, 3, 3, 4, 4, 3, 4, 1, 3, 3, 3, 3, 2, 1, 4, 1, 5, 4, 3, 1, 4, 4, 3, 5, 4, 4, 3, 5, 4, 3, 3, 4, 4, 4, 0, 3, 3, 1, 2, 3, 0, 3, 1, 0, 3, 3, 0, 5, 4, 4, 4, 4, 4, 4, 3, 3, 5, 4, 4, 3, 3, 5, 4, 0, 3, 2, 0, 4, 4), + (0, 2, 0, 3, 0, 1, 0, 0, 0, 1, 3, 3, 3, 2, 4, 1, 3, 0, 3, 1, 3, 0, 2, 2, 1, 1, 0, 0, 2, 0, 4, 3, 1, 0, 4, 3, 0, 4, 4, 4, 1, 4, 3, 1, 1, 3, 3, 1, 0, 2, 0, 0, 1, 3, 0, 0, 0, 0, 2, 0, 0, 4, 3, 2, 4, 3, 5, 4, 3, 3, 3, 4, 3, 3, 4, 3, 3, 0, 2, 1, 0, 3, 3), + (0, 2, 0, 4, 0, 3, 0, 2, 0, 2, 5, 5, 3, 4, 4, 4, 4, 1, 4, 3, 3, 0, 4, 3, 4, 3, 1, 3, 3, 2, 4, 3, 0, 3, 4, 3, 0, 3, 4, 4, 2, 4, 4, 0, 4, 5, 3, 3, 2, 2, 1, 1, 1, 2, 0, 1, 5, 0, 3, 3, 2, 4, 3, 3, 3, 4, 0, 3, 0, 2, 0, 4, 4, 3, 5, 5, 0, 0, 3, 0, 2, 3, 3), + (0, 3, 0, 4, 0, 3, 0, 1, 0, 3, 4, 3, 3, 1, 3, 3, 3, 0, 3, 1, 3, 0, 4, 3, 3, 1, 1, 0, 3, 0, 3, 3, 0, 0, 4, 4, 0, 1, 5, 4, 3, 3, 5, 0, 3, 3, 4, 3, 0, 2, 0, 1, 1, 1, 0, 1, 3, 0, 1, 2, 1, 3, 3, 2, 3, 3, 0, 3, 0, 1, 0, 1, 3, 3, 4, 4, 1, 0, 1, 2, 2, 1, 3), + (0, 1, 0, 4, 0, 4, 0, 3, 0, 1, 3, 3, 3, 2, 3, 1, 1, 0, 3, 0, 3, 3, 4, 3, 2, 4, 2, 0, 1, 0, 4, 3, 2, 0, 4, 3, 0, 5, 3, 3, 2, 4, 4, 4, 3, 3, 3, 4, 0, 1, 3, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 4, 2, 3, 3, 3, 0, 3, 0, 0, 0, 4, 4, 4, 5, 3, 2, 0, 3, 3, 0, 3, 5), + (0, 2, 0, 3, 0, 0, 0, 3, 0, 1, 3, 0, 2, 0, 0, 0, 1, 0, 3, 1, 1, 3, 3, 0, 0, 3, 0, 0, 3, 0, 2, 3, 1, 0, 3, 1, 0, 3, 3, 2, 0, 4, 2, 2, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 1, 0, 1, 0, 0, 0, 1, 3, 1, 2, 0, 0, 0, 1, 0, 0, 1, 4), + (0, 3, 0, 3, 0, 5, 0, 1, 0, 2, 4, 3, 1, 3, 3, 2, 1, 1, 5, 2, 1, 0, 5, 1, 2, 0, 0, 0, 3, 3, 2, 2, 3, 2, 4, 3, 0, 0, 3, 3, 1, 3, 3, 0, 2, 5, 3, 4, 0, 3, 3, 0, 1, 2, 0, 2, 2, 0, 3, 2, 0, 2, 2, 3, 3, 3, 0, 2, 0, 1, 0, 3, 4, 4, 2, 5, 4, 0, 3, 0, 0, 3, 5), + (0, 3, 0, 3, 0, 3, 0, 1, 0, 3, 3, 3, 3, 0, 3, 0, 2, 0, 2, 1, 1, 0, 2, 0, 1, 0, 0, 0, 2, 1, 0, 0, 1, 0, 3, 2, 0, 0, 3, 3, 1, 2, 3, 1, 0, 3, 3, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 3, 1, 2, 3, 0, 3, 0, 1, 0, 3, 2, 1, 0, 4, 3, 0, 1, 1, 0, 3, 3), + (0, 4, 0, 5, 0, 3, 0, 3, 0, 4, 5, 5, 4, 3, 5, 3, 4, 3, 5, 3, 3, 2, 5, 3, 4, 4, 4, 3, 4, 3, 4, 5, 5, 3, 4, 4, 3, 4, 4, 5, 4, 4, 4, 3, 4, 5, 5, 4, 2, 3, 4, 2, 3, 4, 0, 3, 3, 1, 4, 3, 2, 4, 3, 3, 5, 5, 0, 3, 0, 3, 0, 5, 5, 5, 5, 4, 4, 0, 4, 0, 1, 4, 4), + (0, 4, 0, 4, 0, 3, 0, 3, 0, 3, 5, 4, 4, 2, 3, 2, 5, 1, 3, 2, 5, 1, 4, 2, 3, 2, 3, 3, 4, 3, 3, 3, 3, 2, 5, 4, 1, 3, 3, 5, 3, 4, 4, 0, 4, 4, 3, 1, 1, 3, 1, 0, 2, 3, 0, 2, 3, 0, 3, 0, 0, 4, 3, 1, 3, 4, 0, 3, 0, 2, 0, 4, 4, 4, 3, 4, 5, 0, 4, 0, 0, 3, 4), + (0, 3, 0, 3, 0, 3, 1, 2, 0, 3, 4, 4, 3, 3, 3, 0, 2, 2, 4, 3, 3, 1, 3, 3, 3, 1, 1, 0, 3, 1, 4, 3, 2, 3, 4, 4, 2, 4, 4, 4, 3, 4, 4, 3, 2, 4, 4, 3, 1, 3, 3, 1, 3, 3, 0, 4, 1, 0, 2, 2, 1, 4, 3, 2, 3, 3, 5, 4, 3, 3, 5, 4, 4, 3, 3, 0, 4, 0, 3, 2, 2, 4, 4), + (0, 2, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 2, 0, 1, 2, 1, 0, 0, 1, 0, 0, 0, 0, 3, 0, 0, 1, 0, 1, 1, 3, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 0, 3, 4, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1), + (0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4, 0, 4, 1, 4, 0, 3, 0, 4, 0, 3, 0, 4, 0, 3, 0, 3, 0, 4, 1, 5, 1, 4, 0, 0, 3, 0, 5, 0, 5, 2, 0, 1, 0, 0, 0, 2, 1, 4, 0, 1, 3, 0, 0, 3, 0, 0, 3, 1, 1, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0), + (1, 4, 0, 5, 0, 3, 0, 2, 0, 3, 5, 4, 4, 3, 4, 3, 5, 3, 4, 3, 3, 0, 4, 3, 3, 3, 3, 3, 3, 2, 4, 4, 3, 1, 3, 4, 4, 5, 4, 4, 3, 4, 4, 1, 3, 5, 4, 3, 3, 3, 1, 2, 2, 3, 3, 1, 3, 1, 3, 3, 3, 5, 3, 3, 4, 5, 0, 3, 0, 3, 0, 3, 4, 3, 4, 4, 3, 0, 3, 0, 2, 4, 3), + (0, 1, 0, 4, 0, 0, 0, 0, 0, 1, 4, 0, 4, 1, 4, 2, 4, 0, 3, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 1, 1, 1, 0, 3, 0, 0, 0, 1, 2, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 3, 0, 0, 0, 0, 3, 2, 0, 2, 2, 0, 1, 0, 0, 0, 2, 3, 2, 3, 3, 0, 0, 0, 0, 2, 1, 0), + (0, 5, 1, 5, 0, 3, 0, 3, 0, 5, 4, 4, 5, 1, 5, 3, 3, 0, 4, 3, 4, 3, 5, 3, 4, 3, 3, 2, 4, 3, 4, 3, 3, 0, 3, 3, 1, 4, 4, 3, 4, 4, 4, 3, 4, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 3, 1, 1, 3, 3, 2, 4, 5, 3, 3, 5, 0, 4, 0, 3, 0, 4, 4, 3, 5, 3, 3, 0, 3, 4, 0, 4, 3), + (0, 5, 0, 5, 0, 3, 0, 2, 0, 4, 4, 3, 5, 2, 4, 3, 3, 3, 4, 4, 4, 3, 5, 3, 5, 3, 3, 1, 4, 0, 4, 3, 3, 0, 3, 3, 0, 4, 4, 4, 4, 5, 4, 3, 3, 5, 5, 3, 2, 3, 1, 2, 3, 2, 0, 1, 0, 0, 3, 2, 2, 4, 4, 3, 1, 5, 0, 4, 0, 3, 0, 4, 3, 1, 3, 2, 1, 0, 3, 3, 0, 3, 3), + (0, 4, 0, 5, 0, 5, 0, 4, 0, 4, 5, 5, 5, 3, 4, 3, 3, 2, 5, 4, 4, 3, 5, 3, 5, 3, 4, 0, 4, 3, 4, 4, 3, 2, 4, 4, 3, 4, 5, 4, 4, 5, 5, 0, 3, 5, 5, 4, 1, 3, 3, 2, 3, 3, 1, 3, 1, 0, 4, 3, 1, 4, 4, 3, 4, 5, 0, 4, 0, 2, 0, 4, 3, 4, 4, 3, 3, 0, 4, 0, 0, 5, 5), + (0, 4, 0, 4, 0, 5, 0, 1, 1, 3, 3, 4, 4, 3, 4, 1, 3, 0, 5, 1, 3, 0, 3, 1, 3, 1, 1, 0, 3, 0, 3, 3, 4, 0, 4, 3, 0, 4, 4, 4, 3, 4, 4, 0, 3, 5, 4, 1, 0, 3, 0, 0, 2, 3, 0, 3, 1, 0, 3, 1, 0, 3, 2, 1, 3, 5, 0, 3, 0, 1, 0, 3, 2, 3, 3, 4, 4, 0, 2, 2, 0, 4, 4), + (2, 4, 0, 5, 0, 4, 0, 3, 0, 4, 5, 5, 4, 3, 5, 3, 5, 3, 5, 3, 5, 2, 5, 3, 4, 3, 3, 4, 3, 4, 5, 3, 2, 1, 5, 4, 3, 2, 3, 4, 5, 3, 4, 1, 2, 5, 4, 3, 0, 3, 3, 0, 3, 2, 0, 2, 3, 0, 4, 1, 0, 3, 4, 3, 3, 5, 0, 3, 0, 1, 0, 4, 5, 5, 5, 4, 3, 0, 4, 2, 0, 3, 5), + (0, 5, 0, 4, 0, 4, 0, 2, 0, 5, 4, 3, 4, 3, 4, 3, 3, 3, 4, 3, 4, 2, 5, 3, 5, 3, 4, 1, 4, 3, 4, 4, 4, 0, 3, 5, 0, 4, 4, 4, 4, 5, 3, 1, 3, 4, 5, 3, 3, 3, 3, 3, 3, 3, 0, 2, 2, 0, 3, 3, 2, 4, 3, 3, 3, 5, 3, 4, 1, 3, 3, 5, 3, 2, 0, 0, 0, 0, 4, 3, 1, 3, 3), + (0, 1, 0, 3, 0, 3, 0, 1, 0, 1, 3, 3, 3, 2, 3, 3, 3, 0, 3, 0, 0, 0, 3, 1, 3, 0, 0, 0, 2, 2, 2, 3, 0, 0, 3, 2, 0, 1, 2, 4, 1, 3, 3, 0, 0, 3, 3, 3, 0, 1, 0, 0, 2, 1, 0, 0, 3, 0, 3, 1, 0, 3, 0, 0, 1, 3, 0, 2, 0, 1, 0, 3, 3, 1, 3, 3, 0, 0, 1, 1, 0, 3, 3), + (0, 2, 0, 3, 0, 2, 1, 4, 0, 2, 2, 3, 1, 1, 3, 1, 1, 0, 2, 0, 3, 1, 2, 3, 1, 3, 0, 0, 1, 0, 4, 3, 2, 3, 3, 3, 1, 4, 2, 3, 3, 3, 3, 1, 0, 3, 1, 4, 0, 1, 1, 0, 1, 2, 0, 1, 1, 0, 1, 1, 0, 3, 1, 3, 2, 2, 0, 1, 0, 0, 0, 2, 3, 3, 3, 1, 0, 0, 0, 0, 0, 2, 3), + (0, 5, 0, 4, 0, 5, 0, 2, 0, 4, 5, 5, 3, 3, 4, 3, 3, 1, 5, 4, 4, 2, 4, 4, 4, 3, 4, 2, 4, 3, 5, 5, 4, 3, 3, 4, 3, 3, 5, 5, 4, 5, 5, 1, 3, 4, 5, 3, 1, 4, 3, 1, 3, 3, 0, 3, 3, 1, 4, 3, 1, 4, 5, 3, 3, 5, 0, 4, 0, 3, 0, 5, 3, 3, 1, 4, 3, 0, 4, 0, 1, 5, 3), + (0, 5, 0, 5, 0, 4, 0, 2, 0, 4, 4, 3, 4, 3, 3, 3, 3, 3, 5, 4, 4, 4, 4, 4, 4, 5, 3, 3, 5, 2, 4, 4, 4, 3, 4, 4, 3, 3, 4, 4, 5, 5, 3, 3, 4, 3, 4, 3, 3, 4, 3, 3, 3, 3, 1, 2, 2, 1, 4, 3, 3, 5, 4, 4, 3, 4, 0, 4, 0, 3, 0, 4, 4, 4, 4, 4, 1, 0, 4, 2, 0, 2, 4), + (0, 4, 0, 4, 0, 3, 0, 1, 0, 3, 5, 2, 3, 0, 3, 0, 2, 1, 4, 2, 3, 3, 4, 1, 4, 3, 3, 2, 4, 1, 3, 3, 3, 0, 3, 3, 0, 0, 3, 3, 3, 5, 3, 3, 3, 3, 3, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 1, 0, 0, 3, 1, 2, 2, 3, 0, 3, 0, 2, 0, 4, 4, 3, 3, 4, 1, 0, 3, 0, 0, 2, 4), + (0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 3, 1, 3, 0, 3, 2, 0, 0, 0, 1, 0, 3, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 0, 2, 0, 0, 0, 0, 0, 0, 2), + (0, 2, 1, 3, 0, 2, 0, 2, 0, 3, 3, 3, 3, 1, 3, 1, 3, 3, 3, 3, 3, 3, 4, 2, 2, 1, 2, 1, 4, 0, 4, 3, 1, 3, 3, 3, 2, 4, 3, 5, 4, 3, 3, 3, 3, 3, 3, 3, 0, 1, 3, 0, 2, 0, 0, 1, 0, 0, 1, 0, 0, 4, 2, 0, 2, 3, 0, 3, 3, 0, 3, 3, 4, 2, 3, 1, 4, 0, 1, 2, 0, 2, 3), + (0, 3, 0, 3, 0, 1, 0, 3, 0, 2, 3, 3, 3, 0, 3, 1, 2, 0, 3, 3, 2, 3, 3, 2, 3, 2, 3, 1, 3, 0, 4, 3, 2, 0, 3, 3, 1, 4, 3, 3, 2, 3, 4, 3, 1, 3, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 4, 1, 1, 0, 3, 0, 3, 1, 0, 2, 3, 3, 3, 3, 3, 1, 0, 0, 2, 0, 3, 3), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 2, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3), + (0, 2, 0, 3, 1, 3, 0, 3, 0, 2, 3, 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 1, 3, 0, 2, 3, 1, 1, 4, 3, 3, 2, 3, 3, 1, 2, 2, 4, 1, 3, 3, 0, 1, 4, 2, 3, 0, 1, 3, 0, 3, 0, 0, 1, 3, 0, 2, 0, 0, 3, 3, 2, 1, 3, 0, 3, 0, 2, 0, 3, 4, 4, 4, 3, 1, 0, 3, 0, 0, 3, 3), + (0, 2, 0, 1, 0, 2, 0, 0, 0, 1, 3, 2, 2, 1, 3, 0, 1, 1, 3, 0, 3, 2, 3, 1, 2, 0, 2, 0, 1, 1, 3, 3, 3, 0, 3, 3, 1, 1, 2, 3, 2, 3, 3, 1, 2, 3, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 2, 1, 2, 1, 3, 0, 3, 0, 0, 0, 3, 4, 4, 4, 3, 2, 0, 2, 0, 0, 2, 4), + (0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 3, 1, 0, 0, 0, 0, 0, 0, 0, 3), + (0, 3, 0, 3, 0, 2, 0, 3, 0, 3, 3, 3, 2, 3, 2, 2, 2, 0, 3, 1, 3, 3, 3, 2, 3, 3, 0, 0, 3, 0, 3, 2, 2, 0, 2, 3, 1, 4, 3, 4, 3, 3, 2, 3, 1, 5, 4, 4, 0, 3, 1, 2, 1, 3, 0, 3, 1, 1, 2, 0, 2, 3, 1, 3, 1, 3, 0, 3, 0, 1, 0, 3, 3, 4, 4, 2, 1, 0, 2, 1, 0, 2, 4), + (0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 4, 2, 5, 1, 4, 0, 2, 0, 2, 1, 3, 1, 4, 0, 2, 1, 0, 0, 2, 1, 4, 1, 1, 0, 3, 3, 0, 5, 1, 3, 2, 3, 3, 1, 0, 3, 2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 4, 0, 1, 0, 3, 0, 2, 0, 1, 0, 3, 3, 3, 4, 3, 3, 0, 0, 0, 0, 2, 3), + (0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3), + (0, 1, 0, 3, 0, 4, 0, 3, 0, 2, 4, 3, 1, 0, 3, 2, 2, 1, 3, 1, 2, 2, 3, 1, 1, 1, 2, 1, 3, 0, 1, 2, 0, 1, 3, 2, 1, 3, 0, 5, 5, 1, 0, 0, 1, 3, 2, 1, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0, 3, 4, 0, 1, 1, 1, 3, 2, 0, 2, 0, 1, 0, 2, 3, 3, 1, 2, 3, 0, 1, 0, 1, 0, 4), + (0, 0, 0, 1, 0, 3, 0, 3, 0, 2, 2, 1, 0, 0, 4, 0, 3, 0, 3, 1, 3, 0, 3, 0, 3, 0, 1, 0, 3, 0, 3, 1, 3, 0, 3, 3, 0, 0, 1, 2, 1, 1, 1, 0, 1, 2, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 2, 0, 0, 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, 1, 4), + (0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 3, 1, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 2, 0, 2, 3, 0, 0, 2, 2, 3, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 0, 0, 0, 0, 2, 3), + (2, 4, 0, 5, 0, 5, 0, 4, 0, 3, 4, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 4, 5, 4, 5, 5, 5, 2, 3, 0, 5, 5, 4, 1, 5, 4, 3, 1, 5, 4, 3, 4, 4, 3, 3, 4, 3, 3, 0, 3, 2, 0, 2, 3, 0, 3, 0, 0, 3, 3, 0, 5, 3, 2, 3, 3, 0, 3, 0, 3, 0, 3, 4, 5, 4, 5, 3, 0, 4, 3, 0, 3, 4), + (0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 3, 4, 3, 2, 3, 2, 3, 0, 4, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 2, 4, 3, 3, 1, 3, 4, 3, 4, 4, 4, 3, 4, 4, 3, 2, 4, 4, 1, 0, 2, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0, 5, 3, 2, 1, 3, 0, 3, 0, 1, 2, 4, 3, 2, 4, 3, 3, 0, 3, 2, 0, 4, 4), + (0, 3, 0, 3, 0, 1, 0, 0, 0, 1, 4, 3, 3, 2, 3, 1, 3, 1, 4, 2, 3, 2, 4, 2, 3, 4, 3, 0, 2, 2, 3, 3, 3, 0, 3, 3, 3, 0, 3, 4, 1, 3, 3, 0, 3, 4, 3, 3, 0, 1, 1, 0, 1, 0, 0, 0, 4, 0, 3, 0, 0, 3, 1, 2, 1, 3, 0, 4, 0, 1, 0, 4, 3, 3, 4, 3, 3, 0, 2, 0, 0, 3, 3), + (0, 3, 0, 4, 0, 1, 0, 3, 0, 3, 4, 3, 3, 0, 3, 3, 3, 1, 3, 1, 3, 3, 4, 3, 3, 3, 0, 0, 3, 1, 5, 3, 3, 1, 3, 3, 2, 5, 4, 3, 3, 4, 5, 3, 2, 5, 3, 4, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 0, 4, 2, 2, 1, 3, 0, 3, 0, 2, 0, 4, 4, 3, 5, 3, 2, 0, 1, 1, 0, 3, 4), + (0, 5, 0, 4, 0, 5, 0, 2, 0, 4, 4, 3, 3, 2, 3, 3, 3, 1, 4, 3, 4, 1, 5, 3, 4, 3, 4, 0, 4, 2, 4, 3, 4, 1, 5, 4, 0, 4, 4, 4, 4, 5, 4, 1, 3, 5, 4, 2, 1, 4, 1, 1, 3, 2, 0, 3, 1, 0, 3, 2, 1, 4, 3, 3, 3, 4, 0, 4, 0, 3, 0, 4, 4, 4, 3, 3, 3, 0, 4, 2, 0, 3, 4), + (1, 4, 0, 4, 0, 3, 0, 1, 0, 3, 3, 3, 1, 1, 3, 3, 2, 2, 3, 3, 1, 0, 3, 2, 2, 1, 2, 0, 3, 1, 2, 1, 2, 0, 3, 2, 0, 2, 2, 3, 3, 4, 3, 0, 3, 3, 1, 2, 0, 1, 1, 3, 1, 2, 0, 0, 3, 0, 1, 1, 0, 3, 2, 2, 3, 3, 0, 3, 0, 0, 0, 2, 3, 3, 4, 3, 3, 0, 1, 0, 0, 1, 4), + (0, 4, 0, 4, 0, 4, 0, 0, 0, 3, 4, 4, 3, 1, 4, 2, 3, 2, 3, 3, 3, 1, 4, 3, 4, 0, 3, 0, 4, 2, 3, 3, 2, 2, 5, 4, 2, 1, 3, 4, 3, 4, 3, 1, 3, 3, 4, 2, 0, 2, 1, 0, 3, 3, 0, 0, 2, 0, 3, 1, 0, 4, 4, 3, 4, 3, 0, 4, 0, 1, 0, 2, 4, 4, 4, 4, 4, 0, 3, 2, 0, 3, 3), + (0, 0, 0, 1, 0, 4, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2), + (0, 2, 0, 3, 0, 4, 0, 4, 0, 1, 3, 3, 3, 0, 4, 0, 2, 1, 2, 1, 1, 1, 2, 0, 3, 1, 1, 0, 1, 0, 3, 1, 0, 0, 3, 3, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 2, 0, 3, 1, 0, 0, 1, 0, 1, 1, 0, 1, 2, 0, 3, 0, 0, 0, 0, 1, 0, 0, 3, 3, 4, 3, 1, 0, 1, 0, 3, 0, 2), + (0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 1, 0, 2, 0, 3, 1, 0, 1, 3, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 4, 0, 0, 0, 2, 3, 0, 1, 4, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 3), + (0, 2, 0, 5, 0, 5, 0, 1, 0, 2, 4, 3, 3, 2, 5, 1, 3, 2, 3, 3, 3, 0, 4, 1, 2, 0, 3, 0, 4, 0, 2, 2, 1, 1, 5, 3, 0, 0, 1, 4, 2, 3, 2, 0, 3, 3, 3, 2, 0, 2, 4, 1, 1, 2, 0, 1, 1, 0, 3, 1, 0, 1, 3, 1, 2, 3, 0, 2, 0, 0, 0, 1, 3, 5, 4, 4, 4, 0, 3, 0, 0, 1, 3), + (0, 4, 0, 5, 0, 4, 0, 4, 0, 4, 5, 4, 3, 3, 4, 3, 3, 3, 4, 3, 4, 4, 5, 3, 4, 5, 4, 2, 4, 2, 3, 4, 3, 1, 4, 4, 1, 3, 5, 4, 4, 5, 5, 4, 4, 5, 5, 5, 2, 3, 3, 1, 4, 3, 1, 3, 3, 0, 3, 3, 1, 4, 3, 4, 4, 4, 0, 3, 0, 4, 0, 3, 3, 4, 4, 5, 0, 0, 4, 3, 0, 4, 5), + (0, 4, 0, 4, 0, 3, 0, 3, 0, 3, 4, 4, 4, 3, 3, 2, 4, 3, 4, 3, 4, 3, 5, 3, 4, 3, 2, 1, 4, 2, 4, 4, 3, 1, 3, 4, 2, 4, 5, 5, 3, 4, 5, 4, 1, 5, 4, 3, 0, 3, 2, 2, 3, 2, 1, 3, 1, 0, 3, 3, 3, 5, 3, 3, 3, 5, 4, 4, 2, 3, 3, 4, 3, 3, 3, 2, 1, 0, 3, 2, 1, 4, 3), + (0, 4, 0, 5, 0, 4, 0, 3, 0, 3, 5, 5, 3, 2, 4, 3, 4, 0, 5, 4, 4, 1, 4, 4, 4, 3, 3, 3, 4, 3, 5, 5, 2, 3, 3, 4, 1, 2, 5, 5, 3, 5, 5, 2, 3, 5, 5, 4, 0, 3, 2, 0, 3, 3, 1, 1, 5, 1, 4, 1, 0, 4, 3, 2, 3, 5, 0, 4, 0, 3, 0, 5, 4, 3, 4, 3, 0, 0, 4, 1, 0, 4, 4), + (1, 3, 0, 4, 0, 2, 0, 2, 0, 2, 5, 5, 3, 3, 3, 3, 3, 0, 4, 2, 3, 4, 4, 4, 3, 4, 0, 0, 3, 4, 5, 4, 3, 3, 3, 3, 2, 5, 5, 4, 5, 5, 5, 4, 3, 5, 5, 5, 1, 3, 1, 0, 1, 0, 0, 3, 2, 0, 4, 2, 0, 5, 2, 3, 2, 4, 1, 3, 0, 3, 0, 4, 5, 4, 5, 4, 3, 0, 4, 2, 0, 5, 4), + (0, 3, 0, 4, 0, 5, 0, 3, 0, 3, 4, 4, 3, 2, 3, 2, 3, 3, 3, 3, 3, 2, 4, 3, 3, 2, 2, 0, 3, 3, 3, 3, 3, 1, 3, 3, 3, 0, 4, 4, 3, 4, 4, 1, 1, 4, 4, 2, 0, 3, 1, 0, 1, 1, 0, 4, 1, 0, 2, 3, 1, 3, 3, 1, 3, 4, 0, 3, 0, 1, 0, 3, 1, 3, 0, 0, 1, 0, 2, 0, 0, 4, 4), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (0, 3, 0, 3, 0, 2, 0, 3, 0, 1, 5, 4, 3, 3, 3, 1, 4, 2, 1, 2, 3, 4, 4, 2, 4, 4, 5, 0, 3, 1, 4, 3, 4, 0, 4, 3, 3, 3, 2, 3, 2, 5, 3, 4, 3, 2, 2, 3, 0, 0, 3, 0, 2, 1, 0, 1, 2, 0, 0, 0, 0, 2, 1, 1, 3, 1, 0, 2, 0, 4, 0, 3, 4, 4, 4, 5, 2, 0, 2, 0, 0, 1, 3), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 4, 2, 1, 1, 0, 1, 0, 3, 2, 0, 0, 3, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 4, 0, 4, 2, 1, 0, 0, 0, 0, 0, 1), + (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 2, 0, 2, 1, 0, 0, 1, 2, 1, 0, 1, 1, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2), + (0, 4, 0, 4, 0, 4, 0, 3, 0, 4, 4, 3, 4, 2, 4, 3, 2, 0, 4, 4, 4, 3, 5, 3, 5, 3, 3, 2, 4, 2, 4, 3, 4, 3, 1, 4, 0, 2, 3, 4, 4, 4, 3, 3, 3, 4, 4, 4, 3, 4, 1, 3, 4, 3, 2, 1, 2, 1, 3, 3, 3, 4, 4, 3, 3, 5, 0, 4, 0, 3, 0, 4, 3, 3, 3, 2, 1, 0, 3, 0, 0, 3, 3), + (0, 4, 0, 3, 0, 3, 0, 3, 0, 3, 5, 5, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 4, 3, 5, 3, 3, 1, 3, 2, 4, 5, 5, 5, 5, 4, 3, 4, 5, 5, 3, 2, 2, 3, 3, 3, 3, 2, 3, 3, 1, 2, 3, 2, 4, 3, 3, 3, 4, 0, 4, 0, 2, 0, 4, 3, 2, 2, 1, 2, 0, 3, 0, 0, 4, 1), ) +# fmt: on -class JapaneseContextAnalysis(object): + +class JapaneseContextAnalysis: NUM_OF_CATEGORY = 6 DONT_KNOW = -1 ENOUGH_REL_THRESHOLD = 100 MAX_REL_THRESHOLD = 1000 MINIMUM_DATA_THRESHOLD = 4 - def __init__(self): - self._total_rel = None - self._rel_sample = None - self._need_to_skip_char_num = None - self._last_char_order = None - self._done = None + def __init__(self) -> None: + self._total_rel = 0 + self._rel_sample: List[int] = [] + self._need_to_skip_char_num = 0 + self._last_char_order = -1 + self._done = False self.reset() - def reset(self): + def reset(self) -> None: self._total_rel = 0 # total sequence received # category counters, each integer counts sequence in its category self._rel_sample = [0] * self.NUM_OF_CATEGORY @@ -140,7 +144,7 @@ def reset(self): # been made self._done = False - def feed(self, byte_str, num_bytes): + def feed(self, byte_str: Union[bytes, bytearray], num_bytes: int) -> None: if self._done: return @@ -153,7 +157,7 @@ def feed(self, byte_str, num_bytes): # this character will simply our logic and improve performance. i = self._need_to_skip_char_num while i < num_bytes: - order, char_len = self.get_order(byte_str[i:i + 2]) + order, char_len = self.get_order(byte_str[i : i + 2]) i += char_len if i > num_bytes: self._need_to_skip_char_num = i - num_bytes @@ -164,32 +168,34 @@ def feed(self, byte_str, num_bytes): if self._total_rel > self.MAX_REL_THRESHOLD: self._done = True break - self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 + self._rel_sample[ + jp2_char_context[self._last_char_order][order] + ] += 1 self._last_char_order = order - def got_enough_data(self): + def got_enough_data(self) -> bool: return self._total_rel > self.ENOUGH_REL_THRESHOLD - def get_confidence(self): + def get_confidence(self) -> float: # This is just one way to calculate confidence. It works well for me. if self._total_rel > self.MINIMUM_DATA_THRESHOLD: return (self._total_rel - self._rel_sample[0]) / self._total_rel - else: - return self.DONT_KNOW + return self.DONT_KNOW - def get_order(self, byte_str): + def get_order(self, _: Union[bytes, bytearray]) -> Tuple[int, int]: return -1, 1 + class SJISContextAnalysis(JapaneseContextAnalysis): - def __init__(self): - super(SJISContextAnalysis, self).__init__() + def __init__(self) -> None: + super().__init__() self._charset_name = "SHIFT_JIS" @property - def charset_name(self): + def charset_name(self) -> str: return self._charset_name - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> Tuple[int, int]: if not byte_str: return -1, 1 # find out current char's byte length @@ -209,8 +215,9 @@ def get_order(self, byte_str): return -1, char_len + class EUCJPContextAnalysis(JapaneseContextAnalysis): - def get_order(self, byte_str): + def get_order(self, byte_str: Union[bytes, bytearray]) -> Tuple[int, int]: if not byte_str: return -1, 1 # find out current char's byte length @@ -229,5 +236,3 @@ def get_order(self, byte_str): return second_char - 0xA1, char_len return -1, char_len - - diff --git a/script.module.chardet/lib/chardet/langbulgarianmodel.py b/script.module.chardet/lib/chardet/langbulgarianmodel.py index 561bfd905..2f771bb81 100644 --- a/script.module.chardet/lib/chardet/langbulgarianmodel.py +++ b/script.module.chardet/lib/chardet/langbulgarianmodel.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - from chardet.sbcharsetprober import SingleByteCharSetModel - # 3: Positive # 2: Likely # 1: Unlikely @@ -4115,536 +4111,539 @@ # Character Mapping Table(s): ISO_8859_5_BULGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 77, # 'A' - 66: 90, # 'B' - 67: 99, # 'C' - 68: 100, # 'D' - 69: 72, # 'E' - 70: 109, # 'F' - 71: 107, # 'G' - 72: 101, # 'H' - 73: 79, # 'I' - 74: 185, # 'J' - 75: 81, # 'K' - 76: 102, # 'L' - 77: 76, # 'M' - 78: 94, # 'N' - 79: 82, # 'O' - 80: 110, # 'P' - 81: 186, # 'Q' - 82: 108, # 'R' - 83: 91, # 'S' - 84: 74, # 'T' - 85: 119, # 'U' - 86: 84, # 'V' - 87: 96, # 'W' - 88: 111, # 'X' - 89: 187, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 65, # 'a' - 98: 69, # 'b' - 99: 70, # 'c' - 100: 66, # 'd' - 101: 63, # 'e' - 102: 68, # 'f' - 103: 112, # 'g' - 104: 103, # 'h' - 105: 92, # 'i' - 106: 194, # 'j' - 107: 104, # 'k' - 108: 95, # 'l' - 109: 86, # 'm' - 110: 87, # 'n' - 111: 71, # 'o' - 112: 116, # 'p' - 113: 195, # 'q' - 114: 85, # 'r' - 115: 93, # 's' - 116: 97, # 't' - 117: 113, # 'u' - 118: 196, # 'v' - 119: 197, # 'w' - 120: 198, # 'x' - 121: 199, # 'y' - 122: 200, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 194, # '\x80' - 129: 195, # '\x81' - 130: 196, # '\x82' - 131: 197, # '\x83' - 132: 198, # '\x84' - 133: 199, # '\x85' - 134: 200, # '\x86' - 135: 201, # '\x87' - 136: 202, # '\x88' - 137: 203, # '\x89' - 138: 204, # '\x8a' - 139: 205, # '\x8b' - 140: 206, # '\x8c' - 141: 207, # '\x8d' - 142: 208, # '\x8e' - 143: 209, # '\x8f' - 144: 210, # '\x90' - 145: 211, # '\x91' - 146: 212, # '\x92' - 147: 213, # '\x93' - 148: 214, # '\x94' - 149: 215, # '\x95' - 150: 216, # '\x96' - 151: 217, # '\x97' - 152: 218, # '\x98' - 153: 219, # '\x99' - 154: 220, # '\x9a' - 155: 221, # '\x9b' - 156: 222, # '\x9c' - 157: 223, # '\x9d' - 158: 224, # '\x9e' - 159: 225, # '\x9f' - 160: 81, # '\xa0' - 161: 226, # 'Ё' - 162: 227, # 'Ђ' - 163: 228, # 'Ѓ' - 164: 229, # 'Є' - 165: 230, # 'Ѕ' - 166: 105, # 'І' - 167: 231, # 'Ї' - 168: 232, # 'Ј' - 169: 233, # 'Љ' - 170: 234, # 'Њ' - 171: 235, # 'Ћ' - 172: 236, # 'Ќ' - 173: 45, # '\xad' - 174: 237, # 'Ў' - 175: 238, # 'Џ' - 176: 31, # 'А' - 177: 32, # 'Б' - 178: 35, # 'В' - 179: 43, # 'Г' - 180: 37, # 'Д' - 181: 44, # 'Е' - 182: 55, # 'Ж' - 183: 47, # 'З' - 184: 40, # 'И' - 185: 59, # 'Й' - 186: 33, # 'К' - 187: 46, # 'Л' - 188: 38, # 'М' - 189: 36, # 'Н' - 190: 41, # 'О' - 191: 30, # 'П' - 192: 39, # 'Р' - 193: 28, # 'С' - 194: 34, # 'Т' - 195: 51, # 'У' - 196: 48, # 'Ф' - 197: 49, # 'Х' - 198: 53, # 'Ц' - 199: 50, # 'Ч' - 200: 54, # 'Ш' - 201: 57, # 'Щ' - 202: 61, # 'Ъ' - 203: 239, # 'Ы' - 204: 67, # 'Ь' - 205: 240, # 'Э' - 206: 60, # 'Ю' - 207: 56, # 'Я' - 208: 1, # 'а' - 209: 18, # 'б' - 210: 9, # 'в' - 211: 20, # 'г' - 212: 11, # 'д' - 213: 3, # 'е' - 214: 23, # 'ж' - 215: 15, # 'з' - 216: 2, # 'и' - 217: 26, # 'й' - 218: 12, # 'к' - 219: 10, # 'л' - 220: 14, # 'м' - 221: 6, # 'н' - 222: 4, # 'о' - 223: 13, # 'п' - 224: 7, # 'р' - 225: 8, # 'с' - 226: 5, # 'т' - 227: 19, # 'у' - 228: 29, # 'ф' - 229: 25, # 'х' - 230: 22, # 'ц' - 231: 21, # 'ч' - 232: 27, # 'ш' - 233: 24, # 'щ' - 234: 17, # 'ъ' - 235: 75, # 'ы' - 236: 52, # 'ь' - 237: 241, # 'э' - 238: 42, # 'ю' - 239: 16, # 'я' - 240: 62, # '№' - 241: 242, # 'ё' - 242: 243, # 'ђ' - 243: 244, # 'ѓ' - 244: 58, # 'є' - 245: 245, # 'ѕ' - 246: 98, # 'і' - 247: 246, # 'ї' - 248: 247, # 'ј' - 249: 248, # 'љ' - 250: 249, # 'њ' - 251: 250, # 'ћ' - 252: 251, # 'ќ' - 253: 91, # '§' - 254: 252, # 'ў' - 255: 253, # 'џ' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 77, # 'A' + 66: 90, # 'B' + 67: 99, # 'C' + 68: 100, # 'D' + 69: 72, # 'E' + 70: 109, # 'F' + 71: 107, # 'G' + 72: 101, # 'H' + 73: 79, # 'I' + 74: 185, # 'J' + 75: 81, # 'K' + 76: 102, # 'L' + 77: 76, # 'M' + 78: 94, # 'N' + 79: 82, # 'O' + 80: 110, # 'P' + 81: 186, # 'Q' + 82: 108, # 'R' + 83: 91, # 'S' + 84: 74, # 'T' + 85: 119, # 'U' + 86: 84, # 'V' + 87: 96, # 'W' + 88: 111, # 'X' + 89: 187, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 65, # 'a' + 98: 69, # 'b' + 99: 70, # 'c' + 100: 66, # 'd' + 101: 63, # 'e' + 102: 68, # 'f' + 103: 112, # 'g' + 104: 103, # 'h' + 105: 92, # 'i' + 106: 194, # 'j' + 107: 104, # 'k' + 108: 95, # 'l' + 109: 86, # 'm' + 110: 87, # 'n' + 111: 71, # 'o' + 112: 116, # 'p' + 113: 195, # 'q' + 114: 85, # 'r' + 115: 93, # 's' + 116: 97, # 't' + 117: 113, # 'u' + 118: 196, # 'v' + 119: 197, # 'w' + 120: 198, # 'x' + 121: 199, # 'y' + 122: 200, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 194, # '\x80' + 129: 195, # '\x81' + 130: 196, # '\x82' + 131: 197, # '\x83' + 132: 198, # '\x84' + 133: 199, # '\x85' + 134: 200, # '\x86' + 135: 201, # '\x87' + 136: 202, # '\x88' + 137: 203, # '\x89' + 138: 204, # '\x8a' + 139: 205, # '\x8b' + 140: 206, # '\x8c' + 141: 207, # '\x8d' + 142: 208, # '\x8e' + 143: 209, # '\x8f' + 144: 210, # '\x90' + 145: 211, # '\x91' + 146: 212, # '\x92' + 147: 213, # '\x93' + 148: 214, # '\x94' + 149: 215, # '\x95' + 150: 216, # '\x96' + 151: 217, # '\x97' + 152: 218, # '\x98' + 153: 219, # '\x99' + 154: 220, # '\x9a' + 155: 221, # '\x9b' + 156: 222, # '\x9c' + 157: 223, # '\x9d' + 158: 224, # '\x9e' + 159: 225, # '\x9f' + 160: 81, # '\xa0' + 161: 226, # 'Ё' + 162: 227, # 'Ђ' + 163: 228, # 'Ѓ' + 164: 229, # 'Є' + 165: 230, # 'Ѕ' + 166: 105, # 'І' + 167: 231, # 'Ї' + 168: 232, # 'Ј' + 169: 233, # 'Љ' + 170: 234, # 'Њ' + 171: 235, # 'Ћ' + 172: 236, # 'Ќ' + 173: 45, # '\xad' + 174: 237, # 'Ў' + 175: 238, # 'Џ' + 176: 31, # 'А' + 177: 32, # 'Б' + 178: 35, # 'В' + 179: 43, # 'Г' + 180: 37, # 'Д' + 181: 44, # 'Е' + 182: 55, # 'Ж' + 183: 47, # 'З' + 184: 40, # 'И' + 185: 59, # 'Й' + 186: 33, # 'К' + 187: 46, # 'Л' + 188: 38, # 'М' + 189: 36, # 'Н' + 190: 41, # 'О' + 191: 30, # 'П' + 192: 39, # 'Р' + 193: 28, # 'С' + 194: 34, # 'Т' + 195: 51, # 'У' + 196: 48, # 'Ф' + 197: 49, # 'Х' + 198: 53, # 'Ц' + 199: 50, # 'Ч' + 200: 54, # 'Ш' + 201: 57, # 'Щ' + 202: 61, # 'Ъ' + 203: 239, # 'Ы' + 204: 67, # 'Ь' + 205: 240, # 'Э' + 206: 60, # 'Ю' + 207: 56, # 'Я' + 208: 1, # 'а' + 209: 18, # 'б' + 210: 9, # 'в' + 211: 20, # 'г' + 212: 11, # 'д' + 213: 3, # 'е' + 214: 23, # 'ж' + 215: 15, # 'з' + 216: 2, # 'и' + 217: 26, # 'й' + 218: 12, # 'к' + 219: 10, # 'л' + 220: 14, # 'м' + 221: 6, # 'н' + 222: 4, # 'о' + 223: 13, # 'п' + 224: 7, # 'р' + 225: 8, # 'с' + 226: 5, # 'т' + 227: 19, # 'у' + 228: 29, # 'ф' + 229: 25, # 'х' + 230: 22, # 'ц' + 231: 21, # 'ч' + 232: 27, # 'ш' + 233: 24, # 'щ' + 234: 17, # 'ъ' + 235: 75, # 'ы' + 236: 52, # 'ь' + 237: 241, # 'э' + 238: 42, # 'ю' + 239: 16, # 'я' + 240: 62, # '№' + 241: 242, # 'ё' + 242: 243, # 'ђ' + 243: 244, # 'ѓ' + 244: 58, # 'є' + 245: 245, # 'ѕ' + 246: 98, # 'і' + 247: 246, # 'ї' + 248: 247, # 'ј' + 249: 248, # 'љ' + 250: 249, # 'њ' + 251: 250, # 'ћ' + 252: 251, # 'ќ' + 253: 91, # '§' + 254: 252, # 'ў' + 255: 253, # 'џ' } -ISO_8859_5_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', - language='Bulgarian', - char_to_order_map=ISO_8859_5_BULGARIAN_CHAR_TO_ORDER, - language_model=BULGARIAN_LANG_MODEL, - typical_positive_ratio=0.969392, - keep_ascii_letters=False, - alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') +ISO_8859_5_BULGARIAN_MODEL = SingleByteCharSetModel( + charset_name="ISO-8859-5", + language="Bulgarian", + char_to_order_map=ISO_8859_5_BULGARIAN_CHAR_TO_ORDER, + language_model=BULGARIAN_LANG_MODEL, + typical_positive_ratio=0.969392, + keep_ascii_letters=False, + alphabet="АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя", +) WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 77, # 'A' - 66: 90, # 'B' - 67: 99, # 'C' - 68: 100, # 'D' - 69: 72, # 'E' - 70: 109, # 'F' - 71: 107, # 'G' - 72: 101, # 'H' - 73: 79, # 'I' - 74: 185, # 'J' - 75: 81, # 'K' - 76: 102, # 'L' - 77: 76, # 'M' - 78: 94, # 'N' - 79: 82, # 'O' - 80: 110, # 'P' - 81: 186, # 'Q' - 82: 108, # 'R' - 83: 91, # 'S' - 84: 74, # 'T' - 85: 119, # 'U' - 86: 84, # 'V' - 87: 96, # 'W' - 88: 111, # 'X' - 89: 187, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 65, # 'a' - 98: 69, # 'b' - 99: 70, # 'c' - 100: 66, # 'd' - 101: 63, # 'e' - 102: 68, # 'f' - 103: 112, # 'g' - 104: 103, # 'h' - 105: 92, # 'i' - 106: 194, # 'j' - 107: 104, # 'k' - 108: 95, # 'l' - 109: 86, # 'm' - 110: 87, # 'n' - 111: 71, # 'o' - 112: 116, # 'p' - 113: 195, # 'q' - 114: 85, # 'r' - 115: 93, # 's' - 116: 97, # 't' - 117: 113, # 'u' - 118: 196, # 'v' - 119: 197, # 'w' - 120: 198, # 'x' - 121: 199, # 'y' - 122: 200, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 206, # 'Ђ' - 129: 207, # 'Ѓ' - 130: 208, # '‚' - 131: 209, # 'ѓ' - 132: 210, # '„' - 133: 211, # '…' - 134: 212, # '†' - 135: 213, # '‡' - 136: 120, # '€' - 137: 214, # '‰' - 138: 215, # 'Љ' - 139: 216, # '‹' - 140: 217, # 'Њ' - 141: 218, # 'Ќ' - 142: 219, # 'Ћ' - 143: 220, # 'Џ' - 144: 221, # 'ђ' - 145: 78, # '‘' - 146: 64, # '’' - 147: 83, # '“' - 148: 121, # '”' - 149: 98, # '•' - 150: 117, # '–' - 151: 105, # '—' - 152: 222, # None - 153: 223, # '™' - 154: 224, # 'љ' - 155: 225, # '›' - 156: 226, # 'њ' - 157: 227, # 'ќ' - 158: 228, # 'ћ' - 159: 229, # 'џ' - 160: 88, # '\xa0' - 161: 230, # 'Ў' - 162: 231, # 'ў' - 163: 232, # 'Ј' - 164: 233, # '¤' - 165: 122, # 'Ґ' - 166: 89, # '¦' - 167: 106, # '§' - 168: 234, # 'Ё' - 169: 235, # '©' - 170: 236, # 'Є' - 171: 237, # '«' - 172: 238, # '¬' - 173: 45, # '\xad' - 174: 239, # '®' - 175: 240, # 'Ї' - 176: 73, # '°' - 177: 80, # '±' - 178: 118, # 'І' - 179: 114, # 'і' - 180: 241, # 'ґ' - 181: 242, # 'µ' - 182: 243, # '¶' - 183: 244, # '·' - 184: 245, # 'ё' - 185: 62, # '№' - 186: 58, # 'є' - 187: 246, # '»' - 188: 247, # 'ј' - 189: 248, # 'Ѕ' - 190: 249, # 'ѕ' - 191: 250, # 'ї' - 192: 31, # 'А' - 193: 32, # 'Б' - 194: 35, # 'В' - 195: 43, # 'Г' - 196: 37, # 'Д' - 197: 44, # 'Е' - 198: 55, # 'Ж' - 199: 47, # 'З' - 200: 40, # 'И' - 201: 59, # 'Й' - 202: 33, # 'К' - 203: 46, # 'Л' - 204: 38, # 'М' - 205: 36, # 'Н' - 206: 41, # 'О' - 207: 30, # 'П' - 208: 39, # 'Р' - 209: 28, # 'С' - 210: 34, # 'Т' - 211: 51, # 'У' - 212: 48, # 'Ф' - 213: 49, # 'Х' - 214: 53, # 'Ц' - 215: 50, # 'Ч' - 216: 54, # 'Ш' - 217: 57, # 'Щ' - 218: 61, # 'Ъ' - 219: 251, # 'Ы' - 220: 67, # 'Ь' - 221: 252, # 'Э' - 222: 60, # 'Ю' - 223: 56, # 'Я' - 224: 1, # 'а' - 225: 18, # 'б' - 226: 9, # 'в' - 227: 20, # 'г' - 228: 11, # 'д' - 229: 3, # 'е' - 230: 23, # 'ж' - 231: 15, # 'з' - 232: 2, # 'и' - 233: 26, # 'й' - 234: 12, # 'к' - 235: 10, # 'л' - 236: 14, # 'м' - 237: 6, # 'н' - 238: 4, # 'о' - 239: 13, # 'п' - 240: 7, # 'р' - 241: 8, # 'с' - 242: 5, # 'т' - 243: 19, # 'у' - 244: 29, # 'ф' - 245: 25, # 'х' - 246: 22, # 'ц' - 247: 21, # 'ч' - 248: 27, # 'ш' - 249: 24, # 'щ' - 250: 17, # 'ъ' - 251: 75, # 'ы' - 252: 52, # 'ь' - 253: 253, # 'э' - 254: 42, # 'ю' - 255: 16, # 'я' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 77, # 'A' + 66: 90, # 'B' + 67: 99, # 'C' + 68: 100, # 'D' + 69: 72, # 'E' + 70: 109, # 'F' + 71: 107, # 'G' + 72: 101, # 'H' + 73: 79, # 'I' + 74: 185, # 'J' + 75: 81, # 'K' + 76: 102, # 'L' + 77: 76, # 'M' + 78: 94, # 'N' + 79: 82, # 'O' + 80: 110, # 'P' + 81: 186, # 'Q' + 82: 108, # 'R' + 83: 91, # 'S' + 84: 74, # 'T' + 85: 119, # 'U' + 86: 84, # 'V' + 87: 96, # 'W' + 88: 111, # 'X' + 89: 187, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 65, # 'a' + 98: 69, # 'b' + 99: 70, # 'c' + 100: 66, # 'd' + 101: 63, # 'e' + 102: 68, # 'f' + 103: 112, # 'g' + 104: 103, # 'h' + 105: 92, # 'i' + 106: 194, # 'j' + 107: 104, # 'k' + 108: 95, # 'l' + 109: 86, # 'm' + 110: 87, # 'n' + 111: 71, # 'o' + 112: 116, # 'p' + 113: 195, # 'q' + 114: 85, # 'r' + 115: 93, # 's' + 116: 97, # 't' + 117: 113, # 'u' + 118: 196, # 'v' + 119: 197, # 'w' + 120: 198, # 'x' + 121: 199, # 'y' + 122: 200, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 206, # 'Ђ' + 129: 207, # 'Ѓ' + 130: 208, # '‚' + 131: 209, # 'ѓ' + 132: 210, # '„' + 133: 211, # '…' + 134: 212, # '†' + 135: 213, # '‡' + 136: 120, # '€' + 137: 214, # '‰' + 138: 215, # 'Љ' + 139: 216, # '‹' + 140: 217, # 'Њ' + 141: 218, # 'Ќ' + 142: 219, # 'Ћ' + 143: 220, # 'Џ' + 144: 221, # 'ђ' + 145: 78, # '‘' + 146: 64, # '’' + 147: 83, # '“' + 148: 121, # '”' + 149: 98, # '•' + 150: 117, # '–' + 151: 105, # '—' + 152: 222, # None + 153: 223, # '™' + 154: 224, # 'љ' + 155: 225, # '›' + 156: 226, # 'њ' + 157: 227, # 'ќ' + 158: 228, # 'ћ' + 159: 229, # 'џ' + 160: 88, # '\xa0' + 161: 230, # 'Ў' + 162: 231, # 'ў' + 163: 232, # 'Ј' + 164: 233, # '¤' + 165: 122, # 'Ґ' + 166: 89, # '¦' + 167: 106, # '§' + 168: 234, # 'Ё' + 169: 235, # '©' + 170: 236, # 'Є' + 171: 237, # '«' + 172: 238, # '¬' + 173: 45, # '\xad' + 174: 239, # '®' + 175: 240, # 'Ї' + 176: 73, # '°' + 177: 80, # '±' + 178: 118, # 'І' + 179: 114, # 'і' + 180: 241, # 'ґ' + 181: 242, # 'µ' + 182: 243, # '¶' + 183: 244, # '·' + 184: 245, # 'ё' + 185: 62, # '№' + 186: 58, # 'є' + 187: 246, # '»' + 188: 247, # 'ј' + 189: 248, # 'Ѕ' + 190: 249, # 'ѕ' + 191: 250, # 'ї' + 192: 31, # 'А' + 193: 32, # 'Б' + 194: 35, # 'В' + 195: 43, # 'Г' + 196: 37, # 'Д' + 197: 44, # 'Е' + 198: 55, # 'Ж' + 199: 47, # 'З' + 200: 40, # 'И' + 201: 59, # 'Й' + 202: 33, # 'К' + 203: 46, # 'Л' + 204: 38, # 'М' + 205: 36, # 'Н' + 206: 41, # 'О' + 207: 30, # 'П' + 208: 39, # 'Р' + 209: 28, # 'С' + 210: 34, # 'Т' + 211: 51, # 'У' + 212: 48, # 'Ф' + 213: 49, # 'Х' + 214: 53, # 'Ц' + 215: 50, # 'Ч' + 216: 54, # 'Ш' + 217: 57, # 'Щ' + 218: 61, # 'Ъ' + 219: 251, # 'Ы' + 220: 67, # 'Ь' + 221: 252, # 'Э' + 222: 60, # 'Ю' + 223: 56, # 'Я' + 224: 1, # 'а' + 225: 18, # 'б' + 226: 9, # 'в' + 227: 20, # 'г' + 228: 11, # 'д' + 229: 3, # 'е' + 230: 23, # 'ж' + 231: 15, # 'з' + 232: 2, # 'и' + 233: 26, # 'й' + 234: 12, # 'к' + 235: 10, # 'л' + 236: 14, # 'м' + 237: 6, # 'н' + 238: 4, # 'о' + 239: 13, # 'п' + 240: 7, # 'р' + 241: 8, # 'с' + 242: 5, # 'т' + 243: 19, # 'у' + 244: 29, # 'ф' + 245: 25, # 'х' + 246: 22, # 'ц' + 247: 21, # 'ч' + 248: 27, # 'ш' + 249: 24, # 'щ' + 250: 17, # 'ъ' + 251: 75, # 'ы' + 252: 52, # 'ь' + 253: 253, # 'э' + 254: 42, # 'ю' + 255: 16, # 'я' } -WINDOWS_1251_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', - language='Bulgarian', - char_to_order_map=WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER, - language_model=BULGARIAN_LANG_MODEL, - typical_positive_ratio=0.969392, - keep_ascii_letters=False, - alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') - +WINDOWS_1251_BULGARIAN_MODEL = SingleByteCharSetModel( + charset_name="windows-1251", + language="Bulgarian", + char_to_order_map=WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER, + language_model=BULGARIAN_LANG_MODEL, + typical_positive_ratio=0.969392, + keep_ascii_letters=False, + alphabet="АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя", +) diff --git a/script.module.chardet/lib/chardet/langgreekmodel.py b/script.module.chardet/lib/chardet/langgreekmodel.py index 02b94de65..0471d8bb1 100644 --- a/script.module.chardet/lib/chardet/langgreekmodel.py +++ b/script.module.chardet/lib/chardet/langgreekmodel.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - from chardet.sbcharsetprober import SingleByteCharSetModel - # 3: Positive # 2: Likely # 1: Unlikely @@ -3863,536 +3859,539 @@ # Character Mapping Table(s): WINDOWS_1253_GREEK_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 82, # 'A' - 66: 100, # 'B' - 67: 104, # 'C' - 68: 94, # 'D' - 69: 98, # 'E' - 70: 101, # 'F' - 71: 116, # 'G' - 72: 102, # 'H' - 73: 111, # 'I' - 74: 187, # 'J' - 75: 117, # 'K' - 76: 92, # 'L' - 77: 88, # 'M' - 78: 113, # 'N' - 79: 85, # 'O' - 80: 79, # 'P' - 81: 118, # 'Q' - 82: 105, # 'R' - 83: 83, # 'S' - 84: 67, # 'T' - 85: 114, # 'U' - 86: 119, # 'V' - 87: 95, # 'W' - 88: 99, # 'X' - 89: 109, # 'Y' - 90: 188, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 72, # 'a' - 98: 70, # 'b' - 99: 80, # 'c' - 100: 81, # 'd' - 101: 60, # 'e' - 102: 96, # 'f' - 103: 93, # 'g' - 104: 89, # 'h' - 105: 68, # 'i' - 106: 120, # 'j' - 107: 97, # 'k' - 108: 77, # 'l' - 109: 86, # 'm' - 110: 69, # 'n' - 111: 55, # 'o' - 112: 78, # 'p' - 113: 115, # 'q' - 114: 65, # 'r' - 115: 66, # 's' - 116: 58, # 't' - 117: 76, # 'u' - 118: 106, # 'v' - 119: 103, # 'w' - 120: 87, # 'x' - 121: 107, # 'y' - 122: 112, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 255, # '€' - 129: 255, # None - 130: 255, # '‚' - 131: 255, # 'ƒ' - 132: 255, # '„' - 133: 255, # '…' - 134: 255, # '†' - 135: 255, # '‡' - 136: 255, # None - 137: 255, # '‰' - 138: 255, # None - 139: 255, # '‹' - 140: 255, # None - 141: 255, # None - 142: 255, # None - 143: 255, # None - 144: 255, # None - 145: 255, # '‘' - 146: 255, # '’' - 147: 255, # '“' - 148: 255, # '”' - 149: 255, # '•' - 150: 255, # '–' - 151: 255, # '—' - 152: 255, # None - 153: 255, # '™' - 154: 255, # None - 155: 255, # '›' - 156: 255, # None - 157: 255, # None - 158: 255, # None - 159: 255, # None - 160: 253, # '\xa0' - 161: 233, # '΅' - 162: 61, # 'Ά' - 163: 253, # '£' - 164: 253, # '¤' - 165: 253, # '¥' - 166: 253, # '¦' - 167: 253, # '§' - 168: 253, # '¨' - 169: 253, # '©' - 170: 253, # None - 171: 253, # '«' - 172: 253, # '¬' - 173: 74, # '\xad' - 174: 253, # '®' - 175: 253, # '―' - 176: 253, # '°' - 177: 253, # '±' - 178: 253, # '²' - 179: 253, # '³' - 180: 247, # '΄' - 181: 253, # 'µ' - 182: 253, # '¶' - 183: 36, # '·' - 184: 46, # 'Έ' - 185: 71, # 'Ή' - 186: 73, # 'Ί' - 187: 253, # '»' - 188: 54, # 'Ό' - 189: 253, # '½' - 190: 108, # 'Ύ' - 191: 123, # 'Ώ' - 192: 110, # 'ΐ' - 193: 31, # 'Α' - 194: 51, # 'Β' - 195: 43, # 'Γ' - 196: 41, # 'Δ' - 197: 34, # 'Ε' - 198: 91, # 'Ζ' - 199: 40, # 'Η' - 200: 52, # 'Θ' - 201: 47, # 'Ι' - 202: 44, # 'Κ' - 203: 53, # 'Λ' - 204: 38, # 'Μ' - 205: 49, # 'Ν' - 206: 59, # 'Ξ' - 207: 39, # 'Ο' - 208: 35, # 'Π' - 209: 48, # 'Ρ' - 210: 250, # None - 211: 37, # 'Σ' - 212: 33, # 'Τ' - 213: 45, # 'Υ' - 214: 56, # 'Φ' - 215: 50, # 'Χ' - 216: 84, # 'Ψ' - 217: 57, # 'Ω' - 218: 120, # 'Ϊ' - 219: 121, # 'Ϋ' - 220: 17, # 'ά' - 221: 18, # 'έ' - 222: 22, # 'ή' - 223: 15, # 'ί' - 224: 124, # 'ΰ' - 225: 1, # 'α' - 226: 29, # 'β' - 227: 20, # 'γ' - 228: 21, # 'δ' - 229: 3, # 'ε' - 230: 32, # 'ζ' - 231: 13, # 'η' - 232: 25, # 'θ' - 233: 5, # 'ι' - 234: 11, # 'κ' - 235: 16, # 'λ' - 236: 10, # 'μ' - 237: 6, # 'ν' - 238: 30, # 'ξ' - 239: 4, # 'ο' - 240: 9, # 'π' - 241: 8, # 'ρ' - 242: 14, # 'ς' - 243: 7, # 'σ' - 244: 2, # 'τ' - 245: 12, # 'υ' - 246: 28, # 'φ' - 247: 23, # 'χ' - 248: 42, # 'ψ' - 249: 24, # 'ω' - 250: 64, # 'ϊ' - 251: 75, # 'ϋ' - 252: 19, # 'ό' - 253: 26, # 'ύ' - 254: 27, # 'ώ' - 255: 253, # None + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 82, # 'A' + 66: 100, # 'B' + 67: 104, # 'C' + 68: 94, # 'D' + 69: 98, # 'E' + 70: 101, # 'F' + 71: 116, # 'G' + 72: 102, # 'H' + 73: 111, # 'I' + 74: 187, # 'J' + 75: 117, # 'K' + 76: 92, # 'L' + 77: 88, # 'M' + 78: 113, # 'N' + 79: 85, # 'O' + 80: 79, # 'P' + 81: 118, # 'Q' + 82: 105, # 'R' + 83: 83, # 'S' + 84: 67, # 'T' + 85: 114, # 'U' + 86: 119, # 'V' + 87: 95, # 'W' + 88: 99, # 'X' + 89: 109, # 'Y' + 90: 188, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 72, # 'a' + 98: 70, # 'b' + 99: 80, # 'c' + 100: 81, # 'd' + 101: 60, # 'e' + 102: 96, # 'f' + 103: 93, # 'g' + 104: 89, # 'h' + 105: 68, # 'i' + 106: 120, # 'j' + 107: 97, # 'k' + 108: 77, # 'l' + 109: 86, # 'm' + 110: 69, # 'n' + 111: 55, # 'o' + 112: 78, # 'p' + 113: 115, # 'q' + 114: 65, # 'r' + 115: 66, # 's' + 116: 58, # 't' + 117: 76, # 'u' + 118: 106, # 'v' + 119: 103, # 'w' + 120: 87, # 'x' + 121: 107, # 'y' + 122: 112, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 255, # '€' + 129: 255, # None + 130: 255, # '‚' + 131: 255, # 'ƒ' + 132: 255, # '„' + 133: 255, # '…' + 134: 255, # '†' + 135: 255, # '‡' + 136: 255, # None + 137: 255, # '‰' + 138: 255, # None + 139: 255, # '‹' + 140: 255, # None + 141: 255, # None + 142: 255, # None + 143: 255, # None + 144: 255, # None + 145: 255, # '‘' + 146: 255, # '’' + 147: 255, # '“' + 148: 255, # '”' + 149: 255, # '•' + 150: 255, # '–' + 151: 255, # '—' + 152: 255, # None + 153: 255, # '™' + 154: 255, # None + 155: 255, # '›' + 156: 255, # None + 157: 255, # None + 158: 255, # None + 159: 255, # None + 160: 253, # '\xa0' + 161: 233, # '΅' + 162: 61, # 'Ά' + 163: 253, # '£' + 164: 253, # '¤' + 165: 253, # '¥' + 166: 253, # '¦' + 167: 253, # '§' + 168: 253, # '¨' + 169: 253, # '©' + 170: 253, # None + 171: 253, # '«' + 172: 253, # '¬' + 173: 74, # '\xad' + 174: 253, # '®' + 175: 253, # '―' + 176: 253, # '°' + 177: 253, # '±' + 178: 253, # '²' + 179: 253, # '³' + 180: 247, # '΄' + 181: 253, # 'µ' + 182: 253, # '¶' + 183: 36, # '·' + 184: 46, # 'Έ' + 185: 71, # 'Ή' + 186: 73, # 'Ί' + 187: 253, # '»' + 188: 54, # 'Ό' + 189: 253, # '½' + 190: 108, # 'Ύ' + 191: 123, # 'Ώ' + 192: 110, # 'ΐ' + 193: 31, # 'Α' + 194: 51, # 'Β' + 195: 43, # 'Γ' + 196: 41, # 'Δ' + 197: 34, # 'Ε' + 198: 91, # 'Ζ' + 199: 40, # 'Η' + 200: 52, # 'Θ' + 201: 47, # 'Ι' + 202: 44, # 'Κ' + 203: 53, # 'Λ' + 204: 38, # 'Μ' + 205: 49, # 'Ν' + 206: 59, # 'Ξ' + 207: 39, # 'Ο' + 208: 35, # 'Π' + 209: 48, # 'Ρ' + 210: 250, # None + 211: 37, # 'Σ' + 212: 33, # 'Τ' + 213: 45, # 'Υ' + 214: 56, # 'Φ' + 215: 50, # 'Χ' + 216: 84, # 'Ψ' + 217: 57, # 'Ω' + 218: 120, # 'Ϊ' + 219: 121, # 'Ϋ' + 220: 17, # 'ά' + 221: 18, # 'έ' + 222: 22, # 'ή' + 223: 15, # 'ί' + 224: 124, # 'ΰ' + 225: 1, # 'α' + 226: 29, # 'β' + 227: 20, # 'γ' + 228: 21, # 'δ' + 229: 3, # 'ε' + 230: 32, # 'ζ' + 231: 13, # 'η' + 232: 25, # 'θ' + 233: 5, # 'ι' + 234: 11, # 'κ' + 235: 16, # 'λ' + 236: 10, # 'μ' + 237: 6, # 'ν' + 238: 30, # 'ξ' + 239: 4, # 'ο' + 240: 9, # 'π' + 241: 8, # 'ρ' + 242: 14, # 'ς' + 243: 7, # 'σ' + 244: 2, # 'τ' + 245: 12, # 'υ' + 246: 28, # 'φ' + 247: 23, # 'χ' + 248: 42, # 'ψ' + 249: 24, # 'ω' + 250: 64, # 'ϊ' + 251: 75, # 'ϋ' + 252: 19, # 'ό' + 253: 26, # 'ύ' + 254: 27, # 'ώ' + 255: 253, # None } -WINDOWS_1253_GREEK_MODEL = SingleByteCharSetModel(charset_name='windows-1253', - language='Greek', - char_to_order_map=WINDOWS_1253_GREEK_CHAR_TO_ORDER, - language_model=GREEK_LANG_MODEL, - typical_positive_ratio=0.982851, - keep_ascii_letters=False, - alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') +WINDOWS_1253_GREEK_MODEL = SingleByteCharSetModel( + charset_name="windows-1253", + language="Greek", + char_to_order_map=WINDOWS_1253_GREEK_CHAR_TO_ORDER, + language_model=GREEK_LANG_MODEL, + typical_positive_ratio=0.982851, + keep_ascii_letters=False, + alphabet="ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ", +) ISO_8859_7_GREEK_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 82, # 'A' - 66: 100, # 'B' - 67: 104, # 'C' - 68: 94, # 'D' - 69: 98, # 'E' - 70: 101, # 'F' - 71: 116, # 'G' - 72: 102, # 'H' - 73: 111, # 'I' - 74: 187, # 'J' - 75: 117, # 'K' - 76: 92, # 'L' - 77: 88, # 'M' - 78: 113, # 'N' - 79: 85, # 'O' - 80: 79, # 'P' - 81: 118, # 'Q' - 82: 105, # 'R' - 83: 83, # 'S' - 84: 67, # 'T' - 85: 114, # 'U' - 86: 119, # 'V' - 87: 95, # 'W' - 88: 99, # 'X' - 89: 109, # 'Y' - 90: 188, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 72, # 'a' - 98: 70, # 'b' - 99: 80, # 'c' - 100: 81, # 'd' - 101: 60, # 'e' - 102: 96, # 'f' - 103: 93, # 'g' - 104: 89, # 'h' - 105: 68, # 'i' - 106: 120, # 'j' - 107: 97, # 'k' - 108: 77, # 'l' - 109: 86, # 'm' - 110: 69, # 'n' - 111: 55, # 'o' - 112: 78, # 'p' - 113: 115, # 'q' - 114: 65, # 'r' - 115: 66, # 's' - 116: 58, # 't' - 117: 76, # 'u' - 118: 106, # 'v' - 119: 103, # 'w' - 120: 87, # 'x' - 121: 107, # 'y' - 122: 112, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 255, # '\x80' - 129: 255, # '\x81' - 130: 255, # '\x82' - 131: 255, # '\x83' - 132: 255, # '\x84' - 133: 255, # '\x85' - 134: 255, # '\x86' - 135: 255, # '\x87' - 136: 255, # '\x88' - 137: 255, # '\x89' - 138: 255, # '\x8a' - 139: 255, # '\x8b' - 140: 255, # '\x8c' - 141: 255, # '\x8d' - 142: 255, # '\x8e' - 143: 255, # '\x8f' - 144: 255, # '\x90' - 145: 255, # '\x91' - 146: 255, # '\x92' - 147: 255, # '\x93' - 148: 255, # '\x94' - 149: 255, # '\x95' - 150: 255, # '\x96' - 151: 255, # '\x97' - 152: 255, # '\x98' - 153: 255, # '\x99' - 154: 255, # '\x9a' - 155: 255, # '\x9b' - 156: 255, # '\x9c' - 157: 255, # '\x9d' - 158: 255, # '\x9e' - 159: 255, # '\x9f' - 160: 253, # '\xa0' - 161: 233, # '‘' - 162: 90, # '’' - 163: 253, # '£' - 164: 253, # '€' - 165: 253, # '₯' - 166: 253, # '¦' - 167: 253, # '§' - 168: 253, # '¨' - 169: 253, # '©' - 170: 253, # 'ͺ' - 171: 253, # '«' - 172: 253, # '¬' - 173: 74, # '\xad' - 174: 253, # None - 175: 253, # '―' - 176: 253, # '°' - 177: 253, # '±' - 178: 253, # '²' - 179: 253, # '³' - 180: 247, # '΄' - 181: 248, # '΅' - 182: 61, # 'Ά' - 183: 36, # '·' - 184: 46, # 'Έ' - 185: 71, # 'Ή' - 186: 73, # 'Ί' - 187: 253, # '»' - 188: 54, # 'Ό' - 189: 253, # '½' - 190: 108, # 'Ύ' - 191: 123, # 'Ώ' - 192: 110, # 'ΐ' - 193: 31, # 'Α' - 194: 51, # 'Β' - 195: 43, # 'Γ' - 196: 41, # 'Δ' - 197: 34, # 'Ε' - 198: 91, # 'Ζ' - 199: 40, # 'Η' - 200: 52, # 'Θ' - 201: 47, # 'Ι' - 202: 44, # 'Κ' - 203: 53, # 'Λ' - 204: 38, # 'Μ' - 205: 49, # 'Ν' - 206: 59, # 'Ξ' - 207: 39, # 'Ο' - 208: 35, # 'Π' - 209: 48, # 'Ρ' - 210: 250, # None - 211: 37, # 'Σ' - 212: 33, # 'Τ' - 213: 45, # 'Υ' - 214: 56, # 'Φ' - 215: 50, # 'Χ' - 216: 84, # 'Ψ' - 217: 57, # 'Ω' - 218: 120, # 'Ϊ' - 219: 121, # 'Ϋ' - 220: 17, # 'ά' - 221: 18, # 'έ' - 222: 22, # 'ή' - 223: 15, # 'ί' - 224: 124, # 'ΰ' - 225: 1, # 'α' - 226: 29, # 'β' - 227: 20, # 'γ' - 228: 21, # 'δ' - 229: 3, # 'ε' - 230: 32, # 'ζ' - 231: 13, # 'η' - 232: 25, # 'θ' - 233: 5, # 'ι' - 234: 11, # 'κ' - 235: 16, # 'λ' - 236: 10, # 'μ' - 237: 6, # 'ν' - 238: 30, # 'ξ' - 239: 4, # 'ο' - 240: 9, # 'π' - 241: 8, # 'ρ' - 242: 14, # 'ς' - 243: 7, # 'σ' - 244: 2, # 'τ' - 245: 12, # 'υ' - 246: 28, # 'φ' - 247: 23, # 'χ' - 248: 42, # 'ψ' - 249: 24, # 'ω' - 250: 64, # 'ϊ' - 251: 75, # 'ϋ' - 252: 19, # 'ό' - 253: 26, # 'ύ' - 254: 27, # 'ώ' - 255: 253, # None + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 82, # 'A' + 66: 100, # 'B' + 67: 104, # 'C' + 68: 94, # 'D' + 69: 98, # 'E' + 70: 101, # 'F' + 71: 116, # 'G' + 72: 102, # 'H' + 73: 111, # 'I' + 74: 187, # 'J' + 75: 117, # 'K' + 76: 92, # 'L' + 77: 88, # 'M' + 78: 113, # 'N' + 79: 85, # 'O' + 80: 79, # 'P' + 81: 118, # 'Q' + 82: 105, # 'R' + 83: 83, # 'S' + 84: 67, # 'T' + 85: 114, # 'U' + 86: 119, # 'V' + 87: 95, # 'W' + 88: 99, # 'X' + 89: 109, # 'Y' + 90: 188, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 72, # 'a' + 98: 70, # 'b' + 99: 80, # 'c' + 100: 81, # 'd' + 101: 60, # 'e' + 102: 96, # 'f' + 103: 93, # 'g' + 104: 89, # 'h' + 105: 68, # 'i' + 106: 120, # 'j' + 107: 97, # 'k' + 108: 77, # 'l' + 109: 86, # 'm' + 110: 69, # 'n' + 111: 55, # 'o' + 112: 78, # 'p' + 113: 115, # 'q' + 114: 65, # 'r' + 115: 66, # 's' + 116: 58, # 't' + 117: 76, # 'u' + 118: 106, # 'v' + 119: 103, # 'w' + 120: 87, # 'x' + 121: 107, # 'y' + 122: 112, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 255, # '\x80' + 129: 255, # '\x81' + 130: 255, # '\x82' + 131: 255, # '\x83' + 132: 255, # '\x84' + 133: 255, # '\x85' + 134: 255, # '\x86' + 135: 255, # '\x87' + 136: 255, # '\x88' + 137: 255, # '\x89' + 138: 255, # '\x8a' + 139: 255, # '\x8b' + 140: 255, # '\x8c' + 141: 255, # '\x8d' + 142: 255, # '\x8e' + 143: 255, # '\x8f' + 144: 255, # '\x90' + 145: 255, # '\x91' + 146: 255, # '\x92' + 147: 255, # '\x93' + 148: 255, # '\x94' + 149: 255, # '\x95' + 150: 255, # '\x96' + 151: 255, # '\x97' + 152: 255, # '\x98' + 153: 255, # '\x99' + 154: 255, # '\x9a' + 155: 255, # '\x9b' + 156: 255, # '\x9c' + 157: 255, # '\x9d' + 158: 255, # '\x9e' + 159: 255, # '\x9f' + 160: 253, # '\xa0' + 161: 233, # '‘' + 162: 90, # '’' + 163: 253, # '£' + 164: 253, # '€' + 165: 253, # '₯' + 166: 253, # '¦' + 167: 253, # '§' + 168: 253, # '¨' + 169: 253, # '©' + 170: 253, # 'ͺ' + 171: 253, # '«' + 172: 253, # '¬' + 173: 74, # '\xad' + 174: 253, # None + 175: 253, # '―' + 176: 253, # '°' + 177: 253, # '±' + 178: 253, # '²' + 179: 253, # '³' + 180: 247, # '΄' + 181: 248, # '΅' + 182: 61, # 'Ά' + 183: 36, # '·' + 184: 46, # 'Έ' + 185: 71, # 'Ή' + 186: 73, # 'Ί' + 187: 253, # '»' + 188: 54, # 'Ό' + 189: 253, # '½' + 190: 108, # 'Ύ' + 191: 123, # 'Ώ' + 192: 110, # 'ΐ' + 193: 31, # 'Α' + 194: 51, # 'Β' + 195: 43, # 'Γ' + 196: 41, # 'Δ' + 197: 34, # 'Ε' + 198: 91, # 'Ζ' + 199: 40, # 'Η' + 200: 52, # 'Θ' + 201: 47, # 'Ι' + 202: 44, # 'Κ' + 203: 53, # 'Λ' + 204: 38, # 'Μ' + 205: 49, # 'Ν' + 206: 59, # 'Ξ' + 207: 39, # 'Ο' + 208: 35, # 'Π' + 209: 48, # 'Ρ' + 210: 250, # None + 211: 37, # 'Σ' + 212: 33, # 'Τ' + 213: 45, # 'Υ' + 214: 56, # 'Φ' + 215: 50, # 'Χ' + 216: 84, # 'Ψ' + 217: 57, # 'Ω' + 218: 120, # 'Ϊ' + 219: 121, # 'Ϋ' + 220: 17, # 'ά' + 221: 18, # 'έ' + 222: 22, # 'ή' + 223: 15, # 'ί' + 224: 124, # 'ΰ' + 225: 1, # 'α' + 226: 29, # 'β' + 227: 20, # 'γ' + 228: 21, # 'δ' + 229: 3, # 'ε' + 230: 32, # 'ζ' + 231: 13, # 'η' + 232: 25, # 'θ' + 233: 5, # 'ι' + 234: 11, # 'κ' + 235: 16, # 'λ' + 236: 10, # 'μ' + 237: 6, # 'ν' + 238: 30, # 'ξ' + 239: 4, # 'ο' + 240: 9, # 'π' + 241: 8, # 'ρ' + 242: 14, # 'ς' + 243: 7, # 'σ' + 244: 2, # 'τ' + 245: 12, # 'υ' + 246: 28, # 'φ' + 247: 23, # 'χ' + 248: 42, # 'ψ' + 249: 24, # 'ω' + 250: 64, # 'ϊ' + 251: 75, # 'ϋ' + 252: 19, # 'ό' + 253: 26, # 'ύ' + 254: 27, # 'ώ' + 255: 253, # None } -ISO_8859_7_GREEK_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-7', - language='Greek', - char_to_order_map=ISO_8859_7_GREEK_CHAR_TO_ORDER, - language_model=GREEK_LANG_MODEL, - typical_positive_ratio=0.982851, - keep_ascii_letters=False, - alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') - +ISO_8859_7_GREEK_MODEL = SingleByteCharSetModel( + charset_name="ISO-8859-7", + language="Greek", + char_to_order_map=ISO_8859_7_GREEK_CHAR_TO_ORDER, + language_model=GREEK_LANG_MODEL, + typical_positive_ratio=0.982851, + keep_ascii_letters=False, + alphabet="ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ", +) diff --git a/script.module.chardet/lib/chardet/langhebrewmodel.py b/script.module.chardet/lib/chardet/langhebrewmodel.py index 40fd674c4..86b3c5e64 100644 --- a/script.module.chardet/lib/chardet/langhebrewmodel.py +++ b/script.module.chardet/lib/chardet/langhebrewmodel.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - from chardet.sbcharsetprober import SingleByteCharSetModel - # 3: Positive # 2: Likely # 1: Unlikely @@ -4115,269 +4111,270 @@ # Character Mapping Table(s): WINDOWS_1255_HEBREW_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 69, # 'A' - 66: 91, # 'B' - 67: 79, # 'C' - 68: 80, # 'D' - 69: 92, # 'E' - 70: 89, # 'F' - 71: 97, # 'G' - 72: 90, # 'H' - 73: 68, # 'I' - 74: 111, # 'J' - 75: 112, # 'K' - 76: 82, # 'L' - 77: 73, # 'M' - 78: 95, # 'N' - 79: 85, # 'O' - 80: 78, # 'P' - 81: 121, # 'Q' - 82: 86, # 'R' - 83: 71, # 'S' - 84: 67, # 'T' - 85: 102, # 'U' - 86: 107, # 'V' - 87: 84, # 'W' - 88: 114, # 'X' - 89: 103, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 50, # 'a' - 98: 74, # 'b' - 99: 60, # 'c' - 100: 61, # 'd' - 101: 42, # 'e' - 102: 76, # 'f' - 103: 70, # 'g' - 104: 64, # 'h' - 105: 53, # 'i' - 106: 105, # 'j' - 107: 93, # 'k' - 108: 56, # 'l' - 109: 65, # 'm' - 110: 54, # 'n' - 111: 49, # 'o' - 112: 66, # 'p' - 113: 110, # 'q' - 114: 51, # 'r' - 115: 43, # 's' - 116: 44, # 't' - 117: 63, # 'u' - 118: 81, # 'v' - 119: 77, # 'w' - 120: 98, # 'x' - 121: 75, # 'y' - 122: 108, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 124, # '€' - 129: 202, # None - 130: 203, # '‚' - 131: 204, # 'ƒ' - 132: 205, # '„' - 133: 40, # '…' - 134: 58, # '†' - 135: 206, # '‡' - 136: 207, # 'ˆ' - 137: 208, # '‰' - 138: 209, # None - 139: 210, # '‹' - 140: 211, # None - 141: 212, # None - 142: 213, # None - 143: 214, # None - 144: 215, # None - 145: 83, # '‘' - 146: 52, # '’' - 147: 47, # '“' - 148: 46, # '”' - 149: 72, # '•' - 150: 32, # '–' - 151: 94, # '—' - 152: 216, # '˜' - 153: 113, # '™' - 154: 217, # None - 155: 109, # '›' - 156: 218, # None - 157: 219, # None - 158: 220, # None - 159: 221, # None - 160: 34, # '\xa0' - 161: 116, # '¡' - 162: 222, # '¢' - 163: 118, # '£' - 164: 100, # '₪' - 165: 223, # '¥' - 166: 224, # '¦' - 167: 117, # '§' - 168: 119, # '¨' - 169: 104, # '©' - 170: 125, # '×' - 171: 225, # '«' - 172: 226, # '¬' - 173: 87, # '\xad' - 174: 99, # '®' - 175: 227, # '¯' - 176: 106, # '°' - 177: 122, # '±' - 178: 123, # '²' - 179: 228, # '³' - 180: 55, # '´' - 181: 229, # 'µ' - 182: 230, # '¶' - 183: 101, # '·' - 184: 231, # '¸' - 185: 232, # '¹' - 186: 120, # '÷' - 187: 233, # '»' - 188: 48, # '¼' - 189: 39, # '½' - 190: 57, # '¾' - 191: 234, # '¿' - 192: 30, # 'ְ' - 193: 59, # 'ֱ' - 194: 41, # 'ֲ' - 195: 88, # 'ֳ' - 196: 33, # 'ִ' - 197: 37, # 'ֵ' - 198: 36, # 'ֶ' - 199: 31, # 'ַ' - 200: 29, # 'ָ' - 201: 35, # 'ֹ' - 202: 235, # None - 203: 62, # 'ֻ' - 204: 28, # 'ּ' - 205: 236, # 'ֽ' - 206: 126, # '־' - 207: 237, # 'ֿ' - 208: 238, # '׀' - 209: 38, # 'ׁ' - 210: 45, # 'ׂ' - 211: 239, # '׃' - 212: 240, # 'װ' - 213: 241, # 'ױ' - 214: 242, # 'ײ' - 215: 243, # '׳' - 216: 127, # '״' - 217: 244, # None - 218: 245, # None - 219: 246, # None - 220: 247, # None - 221: 248, # None - 222: 249, # None - 223: 250, # None - 224: 9, # 'א' - 225: 8, # 'ב' - 226: 20, # 'ג' - 227: 16, # 'ד' - 228: 3, # 'ה' - 229: 2, # 'ו' - 230: 24, # 'ז' - 231: 14, # 'ח' - 232: 22, # 'ט' - 233: 1, # 'י' - 234: 25, # 'ך' - 235: 15, # 'כ' - 236: 4, # 'ל' - 237: 11, # 'ם' - 238: 6, # 'מ' - 239: 23, # 'ן' - 240: 12, # 'נ' - 241: 19, # 'ס' - 242: 13, # 'ע' - 243: 26, # 'ף' - 244: 18, # 'פ' - 245: 27, # 'ץ' - 246: 21, # 'צ' - 247: 17, # 'ק' - 248: 7, # 'ר' - 249: 10, # 'ש' - 250: 5, # 'ת' - 251: 251, # None - 252: 252, # None - 253: 128, # '\u200e' - 254: 96, # '\u200f' - 255: 253, # None + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 69, # 'A' + 66: 91, # 'B' + 67: 79, # 'C' + 68: 80, # 'D' + 69: 92, # 'E' + 70: 89, # 'F' + 71: 97, # 'G' + 72: 90, # 'H' + 73: 68, # 'I' + 74: 111, # 'J' + 75: 112, # 'K' + 76: 82, # 'L' + 77: 73, # 'M' + 78: 95, # 'N' + 79: 85, # 'O' + 80: 78, # 'P' + 81: 121, # 'Q' + 82: 86, # 'R' + 83: 71, # 'S' + 84: 67, # 'T' + 85: 102, # 'U' + 86: 107, # 'V' + 87: 84, # 'W' + 88: 114, # 'X' + 89: 103, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 50, # 'a' + 98: 74, # 'b' + 99: 60, # 'c' + 100: 61, # 'd' + 101: 42, # 'e' + 102: 76, # 'f' + 103: 70, # 'g' + 104: 64, # 'h' + 105: 53, # 'i' + 106: 105, # 'j' + 107: 93, # 'k' + 108: 56, # 'l' + 109: 65, # 'm' + 110: 54, # 'n' + 111: 49, # 'o' + 112: 66, # 'p' + 113: 110, # 'q' + 114: 51, # 'r' + 115: 43, # 's' + 116: 44, # 't' + 117: 63, # 'u' + 118: 81, # 'v' + 119: 77, # 'w' + 120: 98, # 'x' + 121: 75, # 'y' + 122: 108, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 124, # '€' + 129: 202, # None + 130: 203, # '‚' + 131: 204, # 'ƒ' + 132: 205, # '„' + 133: 40, # '…' + 134: 58, # '†' + 135: 206, # '‡' + 136: 207, # 'ˆ' + 137: 208, # '‰' + 138: 209, # None + 139: 210, # '‹' + 140: 211, # None + 141: 212, # None + 142: 213, # None + 143: 214, # None + 144: 215, # None + 145: 83, # '‘' + 146: 52, # '’' + 147: 47, # '“' + 148: 46, # '”' + 149: 72, # '•' + 150: 32, # '–' + 151: 94, # '—' + 152: 216, # '˜' + 153: 113, # '™' + 154: 217, # None + 155: 109, # '›' + 156: 218, # None + 157: 219, # None + 158: 220, # None + 159: 221, # None + 160: 34, # '\xa0' + 161: 116, # '¡' + 162: 222, # '¢' + 163: 118, # '£' + 164: 100, # '₪' + 165: 223, # '¥' + 166: 224, # '¦' + 167: 117, # '§' + 168: 119, # '¨' + 169: 104, # '©' + 170: 125, # '×' + 171: 225, # '«' + 172: 226, # '¬' + 173: 87, # '\xad' + 174: 99, # '®' + 175: 227, # '¯' + 176: 106, # '°' + 177: 122, # '±' + 178: 123, # '²' + 179: 228, # '³' + 180: 55, # '´' + 181: 229, # 'µ' + 182: 230, # '¶' + 183: 101, # '·' + 184: 231, # '¸' + 185: 232, # '¹' + 186: 120, # '÷' + 187: 233, # '»' + 188: 48, # '¼' + 189: 39, # '½' + 190: 57, # '¾' + 191: 234, # '¿' + 192: 30, # 'ְ' + 193: 59, # 'ֱ' + 194: 41, # 'ֲ' + 195: 88, # 'ֳ' + 196: 33, # 'ִ' + 197: 37, # 'ֵ' + 198: 36, # 'ֶ' + 199: 31, # 'ַ' + 200: 29, # 'ָ' + 201: 35, # 'ֹ' + 202: 235, # None + 203: 62, # 'ֻ' + 204: 28, # 'ּ' + 205: 236, # 'ֽ' + 206: 126, # '־' + 207: 237, # 'ֿ' + 208: 238, # '׀' + 209: 38, # 'ׁ' + 210: 45, # 'ׂ' + 211: 239, # '׃' + 212: 240, # 'װ' + 213: 241, # 'ױ' + 214: 242, # 'ײ' + 215: 243, # '׳' + 216: 127, # '״' + 217: 244, # None + 218: 245, # None + 219: 246, # None + 220: 247, # None + 221: 248, # None + 222: 249, # None + 223: 250, # None + 224: 9, # 'א' + 225: 8, # 'ב' + 226: 20, # 'ג' + 227: 16, # 'ד' + 228: 3, # 'ה' + 229: 2, # 'ו' + 230: 24, # 'ז' + 231: 14, # 'ח' + 232: 22, # 'ט' + 233: 1, # 'י' + 234: 25, # 'ך' + 235: 15, # 'כ' + 236: 4, # 'ל' + 237: 11, # 'ם' + 238: 6, # 'מ' + 239: 23, # 'ן' + 240: 12, # 'נ' + 241: 19, # 'ס' + 242: 13, # 'ע' + 243: 26, # 'ף' + 244: 18, # 'פ' + 245: 27, # 'ץ' + 246: 21, # 'צ' + 247: 17, # 'ק' + 248: 7, # 'ר' + 249: 10, # 'ש' + 250: 5, # 'ת' + 251: 251, # None + 252: 252, # None + 253: 128, # '\u200e' + 254: 96, # '\u200f' + 255: 253, # None } -WINDOWS_1255_HEBREW_MODEL = SingleByteCharSetModel(charset_name='windows-1255', - language='Hebrew', - char_to_order_map=WINDOWS_1255_HEBREW_CHAR_TO_ORDER, - language_model=HEBREW_LANG_MODEL, - typical_positive_ratio=0.984004, - keep_ascii_letters=False, - alphabet='אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ') - +WINDOWS_1255_HEBREW_MODEL = SingleByteCharSetModel( + charset_name="windows-1255", + language="Hebrew", + char_to_order_map=WINDOWS_1255_HEBREW_CHAR_TO_ORDER, + language_model=HEBREW_LANG_MODEL, + typical_positive_ratio=0.984004, + keep_ascii_letters=False, + alphabet="אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ", +) diff --git a/script.module.chardet/lib/chardet/langhungarianmodel.py b/script.module.chardet/lib/chardet/langhungarianmodel.py index 24a097f52..bd6630a05 100644 --- a/script.module.chardet/lib/chardet/langhungarianmodel.py +++ b/script.module.chardet/lib/chardet/langhungarianmodel.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - from chardet.sbcharsetprober import SingleByteCharSetModel - # 3: Positive # 2: Likely # 1: Unlikely @@ -4115,536 +4111,539 @@ # Character Mapping Table(s): WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 28, # 'A' - 66: 40, # 'B' - 67: 54, # 'C' - 68: 45, # 'D' - 69: 32, # 'E' - 70: 50, # 'F' - 71: 49, # 'G' - 72: 38, # 'H' - 73: 39, # 'I' - 74: 53, # 'J' - 75: 36, # 'K' - 76: 41, # 'L' - 77: 34, # 'M' - 78: 35, # 'N' - 79: 47, # 'O' - 80: 46, # 'P' - 81: 72, # 'Q' - 82: 43, # 'R' - 83: 33, # 'S' - 84: 37, # 'T' - 85: 57, # 'U' - 86: 48, # 'V' - 87: 64, # 'W' - 88: 68, # 'X' - 89: 55, # 'Y' - 90: 52, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 2, # 'a' - 98: 18, # 'b' - 99: 26, # 'c' - 100: 17, # 'd' - 101: 1, # 'e' - 102: 27, # 'f' - 103: 12, # 'g' - 104: 20, # 'h' - 105: 9, # 'i' - 106: 22, # 'j' - 107: 7, # 'k' - 108: 6, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 8, # 'o' - 112: 23, # 'p' - 113: 67, # 'q' - 114: 10, # 'r' - 115: 5, # 's' - 116: 3, # 't' - 117: 21, # 'u' - 118: 19, # 'v' - 119: 65, # 'w' - 120: 62, # 'x' - 121: 16, # 'y' - 122: 11, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 161, # '€' - 129: 162, # None - 130: 163, # '‚' - 131: 164, # None - 132: 165, # '„' - 133: 166, # '…' - 134: 167, # '†' - 135: 168, # '‡' - 136: 169, # None - 137: 170, # '‰' - 138: 171, # 'Š' - 139: 172, # '‹' - 140: 173, # 'Ś' - 141: 174, # 'Ť' - 142: 175, # 'Ž' - 143: 176, # 'Ź' - 144: 177, # None - 145: 178, # '‘' - 146: 179, # '’' - 147: 180, # '“' - 148: 78, # '”' - 149: 181, # '•' - 150: 69, # '–' - 151: 182, # '—' - 152: 183, # None - 153: 184, # '™' - 154: 185, # 'š' - 155: 186, # '›' - 156: 187, # 'ś' - 157: 188, # 'ť' - 158: 189, # 'ž' - 159: 190, # 'ź' - 160: 191, # '\xa0' - 161: 192, # 'ˇ' - 162: 193, # '˘' - 163: 194, # 'Ł' - 164: 195, # '¤' - 165: 196, # 'Ą' - 166: 197, # '¦' - 167: 76, # '§' - 168: 198, # '¨' - 169: 199, # '©' - 170: 200, # 'Ş' - 171: 201, # '«' - 172: 202, # '¬' - 173: 203, # '\xad' - 174: 204, # '®' - 175: 205, # 'Ż' - 176: 81, # '°' - 177: 206, # '±' - 178: 207, # '˛' - 179: 208, # 'ł' - 180: 209, # '´' - 181: 210, # 'µ' - 182: 211, # '¶' - 183: 212, # '·' - 184: 213, # '¸' - 185: 214, # 'ą' - 186: 215, # 'ş' - 187: 216, # '»' - 188: 217, # 'Ľ' - 189: 218, # '˝' - 190: 219, # 'ľ' - 191: 220, # 'ż' - 192: 221, # 'Ŕ' - 193: 51, # 'Á' - 194: 83, # 'Â' - 195: 222, # 'Ă' - 196: 80, # 'Ä' - 197: 223, # 'Ĺ' - 198: 224, # 'Ć' - 199: 225, # 'Ç' - 200: 226, # 'Č' - 201: 44, # 'É' - 202: 227, # 'Ę' - 203: 228, # 'Ë' - 204: 229, # 'Ě' - 205: 61, # 'Í' - 206: 230, # 'Î' - 207: 231, # 'Ď' - 208: 232, # 'Đ' - 209: 233, # 'Ń' - 210: 234, # 'Ň' - 211: 58, # 'Ó' - 212: 235, # 'Ô' - 213: 66, # 'Ő' - 214: 59, # 'Ö' - 215: 236, # '×' - 216: 237, # 'Ř' - 217: 238, # 'Ů' - 218: 60, # 'Ú' - 219: 70, # 'Ű' - 220: 63, # 'Ü' - 221: 239, # 'Ý' - 222: 240, # 'Ţ' - 223: 241, # 'ß' - 224: 84, # 'ŕ' - 225: 14, # 'á' - 226: 75, # 'â' - 227: 242, # 'ă' - 228: 71, # 'ä' - 229: 82, # 'ĺ' - 230: 243, # 'ć' - 231: 73, # 'ç' - 232: 244, # 'č' - 233: 15, # 'é' - 234: 85, # 'ę' - 235: 79, # 'ë' - 236: 86, # 'ě' - 237: 30, # 'í' - 238: 77, # 'î' - 239: 87, # 'ď' - 240: 245, # 'đ' - 241: 246, # 'ń' - 242: 247, # 'ň' - 243: 25, # 'ó' - 244: 74, # 'ô' - 245: 42, # 'ő' - 246: 24, # 'ö' - 247: 248, # '÷' - 248: 249, # 'ř' - 249: 250, # 'ů' - 250: 31, # 'ú' - 251: 56, # 'ű' - 252: 29, # 'ü' - 253: 251, # 'ý' - 254: 252, # 'ţ' - 255: 253, # '˙' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 28, # 'A' + 66: 40, # 'B' + 67: 54, # 'C' + 68: 45, # 'D' + 69: 32, # 'E' + 70: 50, # 'F' + 71: 49, # 'G' + 72: 38, # 'H' + 73: 39, # 'I' + 74: 53, # 'J' + 75: 36, # 'K' + 76: 41, # 'L' + 77: 34, # 'M' + 78: 35, # 'N' + 79: 47, # 'O' + 80: 46, # 'P' + 81: 72, # 'Q' + 82: 43, # 'R' + 83: 33, # 'S' + 84: 37, # 'T' + 85: 57, # 'U' + 86: 48, # 'V' + 87: 64, # 'W' + 88: 68, # 'X' + 89: 55, # 'Y' + 90: 52, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 2, # 'a' + 98: 18, # 'b' + 99: 26, # 'c' + 100: 17, # 'd' + 101: 1, # 'e' + 102: 27, # 'f' + 103: 12, # 'g' + 104: 20, # 'h' + 105: 9, # 'i' + 106: 22, # 'j' + 107: 7, # 'k' + 108: 6, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 8, # 'o' + 112: 23, # 'p' + 113: 67, # 'q' + 114: 10, # 'r' + 115: 5, # 's' + 116: 3, # 't' + 117: 21, # 'u' + 118: 19, # 'v' + 119: 65, # 'w' + 120: 62, # 'x' + 121: 16, # 'y' + 122: 11, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 161, # '€' + 129: 162, # None + 130: 163, # '‚' + 131: 164, # None + 132: 165, # '„' + 133: 166, # '…' + 134: 167, # '†' + 135: 168, # '‡' + 136: 169, # None + 137: 170, # '‰' + 138: 171, # 'Š' + 139: 172, # '‹' + 140: 173, # 'Ś' + 141: 174, # 'Ť' + 142: 175, # 'Ž' + 143: 176, # 'Ź' + 144: 177, # None + 145: 178, # '‘' + 146: 179, # '’' + 147: 180, # '“' + 148: 78, # '”' + 149: 181, # '•' + 150: 69, # '–' + 151: 182, # '—' + 152: 183, # None + 153: 184, # '™' + 154: 185, # 'š' + 155: 186, # '›' + 156: 187, # 'ś' + 157: 188, # 'ť' + 158: 189, # 'ž' + 159: 190, # 'ź' + 160: 191, # '\xa0' + 161: 192, # 'ˇ' + 162: 193, # '˘' + 163: 194, # 'Ł' + 164: 195, # '¤' + 165: 196, # 'Ą' + 166: 197, # '¦' + 167: 76, # '§' + 168: 198, # '¨' + 169: 199, # '©' + 170: 200, # 'Ş' + 171: 201, # '«' + 172: 202, # '¬' + 173: 203, # '\xad' + 174: 204, # '®' + 175: 205, # 'Ż' + 176: 81, # '°' + 177: 206, # '±' + 178: 207, # '˛' + 179: 208, # 'ł' + 180: 209, # '´' + 181: 210, # 'µ' + 182: 211, # '¶' + 183: 212, # '·' + 184: 213, # '¸' + 185: 214, # 'ą' + 186: 215, # 'ş' + 187: 216, # '»' + 188: 217, # 'Ľ' + 189: 218, # '˝' + 190: 219, # 'ľ' + 191: 220, # 'ż' + 192: 221, # 'Ŕ' + 193: 51, # 'Á' + 194: 83, # 'Â' + 195: 222, # 'Ă' + 196: 80, # 'Ä' + 197: 223, # 'Ĺ' + 198: 224, # 'Ć' + 199: 225, # 'Ç' + 200: 226, # 'Č' + 201: 44, # 'É' + 202: 227, # 'Ę' + 203: 228, # 'Ë' + 204: 229, # 'Ě' + 205: 61, # 'Í' + 206: 230, # 'Î' + 207: 231, # 'Ď' + 208: 232, # 'Đ' + 209: 233, # 'Ń' + 210: 234, # 'Ň' + 211: 58, # 'Ó' + 212: 235, # 'Ô' + 213: 66, # 'Ő' + 214: 59, # 'Ö' + 215: 236, # '×' + 216: 237, # 'Ř' + 217: 238, # 'Ů' + 218: 60, # 'Ú' + 219: 70, # 'Ű' + 220: 63, # 'Ü' + 221: 239, # 'Ý' + 222: 240, # 'Ţ' + 223: 241, # 'ß' + 224: 84, # 'ŕ' + 225: 14, # 'á' + 226: 75, # 'â' + 227: 242, # 'ă' + 228: 71, # 'ä' + 229: 82, # 'ĺ' + 230: 243, # 'ć' + 231: 73, # 'ç' + 232: 244, # 'č' + 233: 15, # 'é' + 234: 85, # 'ę' + 235: 79, # 'ë' + 236: 86, # 'ě' + 237: 30, # 'í' + 238: 77, # 'î' + 239: 87, # 'ď' + 240: 245, # 'đ' + 241: 246, # 'ń' + 242: 247, # 'ň' + 243: 25, # 'ó' + 244: 74, # 'ô' + 245: 42, # 'ő' + 246: 24, # 'ö' + 247: 248, # '÷' + 248: 249, # 'ř' + 249: 250, # 'ů' + 250: 31, # 'ú' + 251: 56, # 'ű' + 252: 29, # 'ü' + 253: 251, # 'ý' + 254: 252, # 'ţ' + 255: 253, # '˙' } -WINDOWS_1250_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1250', - language='Hungarian', - char_to_order_map=WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER, - language_model=HUNGARIAN_LANG_MODEL, - typical_positive_ratio=0.947368, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') +WINDOWS_1250_HUNGARIAN_MODEL = SingleByteCharSetModel( + charset_name="windows-1250", + language="Hungarian", + char_to_order_map=WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER, + language_model=HUNGARIAN_LANG_MODEL, + typical_positive_ratio=0.947368, + keep_ascii_letters=True, + alphabet="ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű", +) ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 28, # 'A' - 66: 40, # 'B' - 67: 54, # 'C' - 68: 45, # 'D' - 69: 32, # 'E' - 70: 50, # 'F' - 71: 49, # 'G' - 72: 38, # 'H' - 73: 39, # 'I' - 74: 53, # 'J' - 75: 36, # 'K' - 76: 41, # 'L' - 77: 34, # 'M' - 78: 35, # 'N' - 79: 47, # 'O' - 80: 46, # 'P' - 81: 71, # 'Q' - 82: 43, # 'R' - 83: 33, # 'S' - 84: 37, # 'T' - 85: 57, # 'U' - 86: 48, # 'V' - 87: 64, # 'W' - 88: 68, # 'X' - 89: 55, # 'Y' - 90: 52, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 2, # 'a' - 98: 18, # 'b' - 99: 26, # 'c' - 100: 17, # 'd' - 101: 1, # 'e' - 102: 27, # 'f' - 103: 12, # 'g' - 104: 20, # 'h' - 105: 9, # 'i' - 106: 22, # 'j' - 107: 7, # 'k' - 108: 6, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 8, # 'o' - 112: 23, # 'p' - 113: 67, # 'q' - 114: 10, # 'r' - 115: 5, # 's' - 116: 3, # 't' - 117: 21, # 'u' - 118: 19, # 'v' - 119: 65, # 'w' - 120: 62, # 'x' - 121: 16, # 'y' - 122: 11, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 159, # '\x80' - 129: 160, # '\x81' - 130: 161, # '\x82' - 131: 162, # '\x83' - 132: 163, # '\x84' - 133: 164, # '\x85' - 134: 165, # '\x86' - 135: 166, # '\x87' - 136: 167, # '\x88' - 137: 168, # '\x89' - 138: 169, # '\x8a' - 139: 170, # '\x8b' - 140: 171, # '\x8c' - 141: 172, # '\x8d' - 142: 173, # '\x8e' - 143: 174, # '\x8f' - 144: 175, # '\x90' - 145: 176, # '\x91' - 146: 177, # '\x92' - 147: 178, # '\x93' - 148: 179, # '\x94' - 149: 180, # '\x95' - 150: 181, # '\x96' - 151: 182, # '\x97' - 152: 183, # '\x98' - 153: 184, # '\x99' - 154: 185, # '\x9a' - 155: 186, # '\x9b' - 156: 187, # '\x9c' - 157: 188, # '\x9d' - 158: 189, # '\x9e' - 159: 190, # '\x9f' - 160: 191, # '\xa0' - 161: 192, # 'Ą' - 162: 193, # '˘' - 163: 194, # 'Ł' - 164: 195, # '¤' - 165: 196, # 'Ľ' - 166: 197, # 'Ś' - 167: 75, # '§' - 168: 198, # '¨' - 169: 199, # 'Š' - 170: 200, # 'Ş' - 171: 201, # 'Ť' - 172: 202, # 'Ź' - 173: 203, # '\xad' - 174: 204, # 'Ž' - 175: 205, # 'Ż' - 176: 79, # '°' - 177: 206, # 'ą' - 178: 207, # '˛' - 179: 208, # 'ł' - 180: 209, # '´' - 181: 210, # 'ľ' - 182: 211, # 'ś' - 183: 212, # 'ˇ' - 184: 213, # '¸' - 185: 214, # 'š' - 186: 215, # 'ş' - 187: 216, # 'ť' - 188: 217, # 'ź' - 189: 218, # '˝' - 190: 219, # 'ž' - 191: 220, # 'ż' - 192: 221, # 'Ŕ' - 193: 51, # 'Á' - 194: 81, # 'Â' - 195: 222, # 'Ă' - 196: 78, # 'Ä' - 197: 223, # 'Ĺ' - 198: 224, # 'Ć' - 199: 225, # 'Ç' - 200: 226, # 'Č' - 201: 44, # 'É' - 202: 227, # 'Ę' - 203: 228, # 'Ë' - 204: 229, # 'Ě' - 205: 61, # 'Í' - 206: 230, # 'Î' - 207: 231, # 'Ď' - 208: 232, # 'Đ' - 209: 233, # 'Ń' - 210: 234, # 'Ň' - 211: 58, # 'Ó' - 212: 235, # 'Ô' - 213: 66, # 'Ő' - 214: 59, # 'Ö' - 215: 236, # '×' - 216: 237, # 'Ř' - 217: 238, # 'Ů' - 218: 60, # 'Ú' - 219: 69, # 'Ű' - 220: 63, # 'Ü' - 221: 239, # 'Ý' - 222: 240, # 'Ţ' - 223: 241, # 'ß' - 224: 82, # 'ŕ' - 225: 14, # 'á' - 226: 74, # 'â' - 227: 242, # 'ă' - 228: 70, # 'ä' - 229: 80, # 'ĺ' - 230: 243, # 'ć' - 231: 72, # 'ç' - 232: 244, # 'č' - 233: 15, # 'é' - 234: 83, # 'ę' - 235: 77, # 'ë' - 236: 84, # 'ě' - 237: 30, # 'í' - 238: 76, # 'î' - 239: 85, # 'ď' - 240: 245, # 'đ' - 241: 246, # 'ń' - 242: 247, # 'ň' - 243: 25, # 'ó' - 244: 73, # 'ô' - 245: 42, # 'ő' - 246: 24, # 'ö' - 247: 248, # '÷' - 248: 249, # 'ř' - 249: 250, # 'ů' - 250: 31, # 'ú' - 251: 56, # 'ű' - 252: 29, # 'ü' - 253: 251, # 'ý' - 254: 252, # 'ţ' - 255: 253, # '˙' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 28, # 'A' + 66: 40, # 'B' + 67: 54, # 'C' + 68: 45, # 'D' + 69: 32, # 'E' + 70: 50, # 'F' + 71: 49, # 'G' + 72: 38, # 'H' + 73: 39, # 'I' + 74: 53, # 'J' + 75: 36, # 'K' + 76: 41, # 'L' + 77: 34, # 'M' + 78: 35, # 'N' + 79: 47, # 'O' + 80: 46, # 'P' + 81: 71, # 'Q' + 82: 43, # 'R' + 83: 33, # 'S' + 84: 37, # 'T' + 85: 57, # 'U' + 86: 48, # 'V' + 87: 64, # 'W' + 88: 68, # 'X' + 89: 55, # 'Y' + 90: 52, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 2, # 'a' + 98: 18, # 'b' + 99: 26, # 'c' + 100: 17, # 'd' + 101: 1, # 'e' + 102: 27, # 'f' + 103: 12, # 'g' + 104: 20, # 'h' + 105: 9, # 'i' + 106: 22, # 'j' + 107: 7, # 'k' + 108: 6, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 8, # 'o' + 112: 23, # 'p' + 113: 67, # 'q' + 114: 10, # 'r' + 115: 5, # 's' + 116: 3, # 't' + 117: 21, # 'u' + 118: 19, # 'v' + 119: 65, # 'w' + 120: 62, # 'x' + 121: 16, # 'y' + 122: 11, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 159, # '\x80' + 129: 160, # '\x81' + 130: 161, # '\x82' + 131: 162, # '\x83' + 132: 163, # '\x84' + 133: 164, # '\x85' + 134: 165, # '\x86' + 135: 166, # '\x87' + 136: 167, # '\x88' + 137: 168, # '\x89' + 138: 169, # '\x8a' + 139: 170, # '\x8b' + 140: 171, # '\x8c' + 141: 172, # '\x8d' + 142: 173, # '\x8e' + 143: 174, # '\x8f' + 144: 175, # '\x90' + 145: 176, # '\x91' + 146: 177, # '\x92' + 147: 178, # '\x93' + 148: 179, # '\x94' + 149: 180, # '\x95' + 150: 181, # '\x96' + 151: 182, # '\x97' + 152: 183, # '\x98' + 153: 184, # '\x99' + 154: 185, # '\x9a' + 155: 186, # '\x9b' + 156: 187, # '\x9c' + 157: 188, # '\x9d' + 158: 189, # '\x9e' + 159: 190, # '\x9f' + 160: 191, # '\xa0' + 161: 192, # 'Ą' + 162: 193, # '˘' + 163: 194, # 'Ł' + 164: 195, # '¤' + 165: 196, # 'Ľ' + 166: 197, # 'Ś' + 167: 75, # '§' + 168: 198, # '¨' + 169: 199, # 'Š' + 170: 200, # 'Ş' + 171: 201, # 'Ť' + 172: 202, # 'Ź' + 173: 203, # '\xad' + 174: 204, # 'Ž' + 175: 205, # 'Ż' + 176: 79, # '°' + 177: 206, # 'ą' + 178: 207, # '˛' + 179: 208, # 'ł' + 180: 209, # '´' + 181: 210, # 'ľ' + 182: 211, # 'ś' + 183: 212, # 'ˇ' + 184: 213, # '¸' + 185: 214, # 'š' + 186: 215, # 'ş' + 187: 216, # 'ť' + 188: 217, # 'ź' + 189: 218, # '˝' + 190: 219, # 'ž' + 191: 220, # 'ż' + 192: 221, # 'Ŕ' + 193: 51, # 'Á' + 194: 81, # 'Â' + 195: 222, # 'Ă' + 196: 78, # 'Ä' + 197: 223, # 'Ĺ' + 198: 224, # 'Ć' + 199: 225, # 'Ç' + 200: 226, # 'Č' + 201: 44, # 'É' + 202: 227, # 'Ę' + 203: 228, # 'Ë' + 204: 229, # 'Ě' + 205: 61, # 'Í' + 206: 230, # 'Î' + 207: 231, # 'Ď' + 208: 232, # 'Đ' + 209: 233, # 'Ń' + 210: 234, # 'Ň' + 211: 58, # 'Ó' + 212: 235, # 'Ô' + 213: 66, # 'Ő' + 214: 59, # 'Ö' + 215: 236, # '×' + 216: 237, # 'Ř' + 217: 238, # 'Ů' + 218: 60, # 'Ú' + 219: 69, # 'Ű' + 220: 63, # 'Ü' + 221: 239, # 'Ý' + 222: 240, # 'Ţ' + 223: 241, # 'ß' + 224: 82, # 'ŕ' + 225: 14, # 'á' + 226: 74, # 'â' + 227: 242, # 'ă' + 228: 70, # 'ä' + 229: 80, # 'ĺ' + 230: 243, # 'ć' + 231: 72, # 'ç' + 232: 244, # 'č' + 233: 15, # 'é' + 234: 83, # 'ę' + 235: 77, # 'ë' + 236: 84, # 'ě' + 237: 30, # 'í' + 238: 76, # 'î' + 239: 85, # 'ď' + 240: 245, # 'đ' + 241: 246, # 'ń' + 242: 247, # 'ň' + 243: 25, # 'ó' + 244: 73, # 'ô' + 245: 42, # 'ő' + 246: 24, # 'ö' + 247: 248, # '÷' + 248: 249, # 'ř' + 249: 250, # 'ů' + 250: 31, # 'ú' + 251: 56, # 'ű' + 252: 29, # 'ü' + 253: 251, # 'ý' + 254: 252, # 'ţ' + 255: 253, # '˙' } -ISO_8859_2_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-2', - language='Hungarian', - char_to_order_map=ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER, - language_model=HUNGARIAN_LANG_MODEL, - typical_positive_ratio=0.947368, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') - +ISO_8859_2_HUNGARIAN_MODEL = SingleByteCharSetModel( + charset_name="ISO-8859-2", + language="Hungarian", + char_to_order_map=ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER, + language_model=HUNGARIAN_LANG_MODEL, + typical_positive_ratio=0.947368, + keep_ascii_letters=True, + alphabet="ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű", +) diff --git a/script.module.chardet/lib/chardet/langrussianmodel.py b/script.module.chardet/lib/chardet/langrussianmodel.py index 569689d0f..0d5b17844 100644 --- a/script.module.chardet/lib/chardet/langrussianmodel.py +++ b/script.module.chardet/lib/chardet/langrussianmodel.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - from chardet.sbcharsetprober import SingleByteCharSetModel - # 3: Positive # 2: Likely # 1: Unlikely @@ -4115,1604 +4111,1615 @@ # Character Mapping Table(s): IBM866_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 37, # 'А' - 129: 44, # 'Б' - 130: 33, # 'В' - 131: 46, # 'Г' - 132: 41, # 'Д' - 133: 48, # 'Е' - 134: 56, # 'Ж' - 135: 51, # 'З' - 136: 42, # 'И' - 137: 60, # 'Й' - 138: 36, # 'К' - 139: 49, # 'Л' - 140: 38, # 'М' - 141: 31, # 'Н' - 142: 34, # 'О' - 143: 35, # 'П' - 144: 45, # 'Р' - 145: 32, # 'С' - 146: 40, # 'Т' - 147: 52, # 'У' - 148: 53, # 'Ф' - 149: 55, # 'Х' - 150: 58, # 'Ц' - 151: 50, # 'Ч' - 152: 57, # 'Ш' - 153: 63, # 'Щ' - 154: 70, # 'Ъ' - 155: 62, # 'Ы' - 156: 61, # 'Ь' - 157: 47, # 'Э' - 158: 59, # 'Ю' - 159: 43, # 'Я' - 160: 3, # 'а' - 161: 21, # 'б' - 162: 10, # 'в' - 163: 19, # 'г' - 164: 13, # 'д' - 165: 2, # 'е' - 166: 24, # 'ж' - 167: 20, # 'з' - 168: 4, # 'и' - 169: 23, # 'й' - 170: 11, # 'к' - 171: 8, # 'л' - 172: 12, # 'м' - 173: 5, # 'н' - 174: 1, # 'о' - 175: 15, # 'п' - 176: 191, # '░' - 177: 192, # '▒' - 178: 193, # '▓' - 179: 194, # '│' - 180: 195, # '┤' - 181: 196, # '╡' - 182: 197, # '╢' - 183: 198, # '╖' - 184: 199, # '╕' - 185: 200, # '╣' - 186: 201, # '║' - 187: 202, # '╗' - 188: 203, # '╝' - 189: 204, # '╜' - 190: 205, # '╛' - 191: 206, # '┐' - 192: 207, # '└' - 193: 208, # '┴' - 194: 209, # '┬' - 195: 210, # '├' - 196: 211, # '─' - 197: 212, # '┼' - 198: 213, # '╞' - 199: 214, # '╟' - 200: 215, # '╚' - 201: 216, # '╔' - 202: 217, # '╩' - 203: 218, # '╦' - 204: 219, # '╠' - 205: 220, # '═' - 206: 221, # '╬' - 207: 222, # '╧' - 208: 223, # '╨' - 209: 224, # '╤' - 210: 225, # '╥' - 211: 226, # '╙' - 212: 227, # '╘' - 213: 228, # '╒' - 214: 229, # '╓' - 215: 230, # '╫' - 216: 231, # '╪' - 217: 232, # '┘' - 218: 233, # '┌' - 219: 234, # '█' - 220: 235, # '▄' - 221: 236, # '▌' - 222: 237, # '▐' - 223: 238, # '▀' - 224: 9, # 'р' - 225: 7, # 'с' - 226: 6, # 'т' - 227: 14, # 'у' - 228: 39, # 'ф' - 229: 26, # 'х' - 230: 28, # 'ц' - 231: 22, # 'ч' - 232: 25, # 'ш' - 233: 29, # 'щ' - 234: 54, # 'ъ' - 235: 18, # 'ы' - 236: 17, # 'ь' - 237: 30, # 'э' - 238: 27, # 'ю' - 239: 16, # 'я' - 240: 239, # 'Ё' - 241: 68, # 'ё' - 242: 240, # 'Є' - 243: 241, # 'є' - 244: 242, # 'Ї' - 245: 243, # 'ї' - 246: 244, # 'Ў' - 247: 245, # 'ў' - 248: 246, # '°' - 249: 247, # '∙' - 250: 248, # '·' - 251: 249, # '√' - 252: 250, # '№' - 253: 251, # '¤' - 254: 252, # '■' - 255: 255, # '\xa0' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 3, # 'а' + 161: 21, # 'б' + 162: 10, # 'в' + 163: 19, # 'г' + 164: 13, # 'д' + 165: 2, # 'е' + 166: 24, # 'ж' + 167: 20, # 'з' + 168: 4, # 'и' + 169: 23, # 'й' + 170: 11, # 'к' + 171: 8, # 'л' + 172: 12, # 'м' + 173: 5, # 'н' + 174: 1, # 'о' + 175: 15, # 'п' + 176: 191, # '░' + 177: 192, # '▒' + 178: 193, # '▓' + 179: 194, # '│' + 180: 195, # '┤' + 181: 196, # '╡' + 182: 197, # '╢' + 183: 198, # '╖' + 184: 199, # '╕' + 185: 200, # '╣' + 186: 201, # '║' + 187: 202, # '╗' + 188: 203, # '╝' + 189: 204, # '╜' + 190: 205, # '╛' + 191: 206, # '┐' + 192: 207, # '└' + 193: 208, # '┴' + 194: 209, # '┬' + 195: 210, # '├' + 196: 211, # '─' + 197: 212, # '┼' + 198: 213, # '╞' + 199: 214, # '╟' + 200: 215, # '╚' + 201: 216, # '╔' + 202: 217, # '╩' + 203: 218, # '╦' + 204: 219, # '╠' + 205: 220, # '═' + 206: 221, # '╬' + 207: 222, # '╧' + 208: 223, # '╨' + 209: 224, # '╤' + 210: 225, # '╥' + 211: 226, # '╙' + 212: 227, # '╘' + 213: 228, # '╒' + 214: 229, # '╓' + 215: 230, # '╫' + 216: 231, # '╪' + 217: 232, # '┘' + 218: 233, # '┌' + 219: 234, # '█' + 220: 235, # '▄' + 221: 236, # '▌' + 222: 237, # '▐' + 223: 238, # '▀' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # 'Ё' + 241: 68, # 'ё' + 242: 240, # 'Є' + 243: 241, # 'є' + 244: 242, # 'Ї' + 245: 243, # 'ї' + 246: 244, # 'Ў' + 247: 245, # 'ў' + 248: 246, # '°' + 249: 247, # '∙' + 250: 248, # '·' + 251: 249, # '√' + 252: 250, # '№' + 253: 251, # '¤' + 254: 252, # '■' + 255: 255, # '\xa0' } -IBM866_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM866', - language='Russian', - char_to_order_map=IBM866_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') +IBM866_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="IBM866", + language="Russian", + char_to_order_map=IBM866_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # 'Ђ' - 129: 192, # 'Ѓ' - 130: 193, # '‚' - 131: 194, # 'ѓ' - 132: 195, # '„' - 133: 196, # '…' - 134: 197, # '†' - 135: 198, # '‡' - 136: 199, # '€' - 137: 200, # '‰' - 138: 201, # 'Љ' - 139: 202, # '‹' - 140: 203, # 'Њ' - 141: 204, # 'Ќ' - 142: 205, # 'Ћ' - 143: 206, # 'Џ' - 144: 207, # 'ђ' - 145: 208, # '‘' - 146: 209, # '’' - 147: 210, # '“' - 148: 211, # '”' - 149: 212, # '•' - 150: 213, # '–' - 151: 214, # '—' - 152: 215, # None - 153: 216, # '™' - 154: 217, # 'љ' - 155: 218, # '›' - 156: 219, # 'њ' - 157: 220, # 'ќ' - 158: 221, # 'ћ' - 159: 222, # 'џ' - 160: 223, # '\xa0' - 161: 224, # 'Ў' - 162: 225, # 'ў' - 163: 226, # 'Ј' - 164: 227, # '¤' - 165: 228, # 'Ґ' - 166: 229, # '¦' - 167: 230, # '§' - 168: 231, # 'Ё' - 169: 232, # '©' - 170: 233, # 'Є' - 171: 234, # '«' - 172: 235, # '¬' - 173: 236, # '\xad' - 174: 237, # '®' - 175: 238, # 'Ї' - 176: 239, # '°' - 177: 240, # '±' - 178: 241, # 'І' - 179: 242, # 'і' - 180: 243, # 'ґ' - 181: 244, # 'µ' - 182: 245, # '¶' - 183: 246, # '·' - 184: 68, # 'ё' - 185: 247, # '№' - 186: 248, # 'є' - 187: 249, # '»' - 188: 250, # 'ј' - 189: 251, # 'Ѕ' - 190: 252, # 'ѕ' - 191: 253, # 'ї' - 192: 37, # 'А' - 193: 44, # 'Б' - 194: 33, # 'В' - 195: 46, # 'Г' - 196: 41, # 'Д' - 197: 48, # 'Е' - 198: 56, # 'Ж' - 199: 51, # 'З' - 200: 42, # 'И' - 201: 60, # 'Й' - 202: 36, # 'К' - 203: 49, # 'Л' - 204: 38, # 'М' - 205: 31, # 'Н' - 206: 34, # 'О' - 207: 35, # 'П' - 208: 45, # 'Р' - 209: 32, # 'С' - 210: 40, # 'Т' - 211: 52, # 'У' - 212: 53, # 'Ф' - 213: 55, # 'Х' - 214: 58, # 'Ц' - 215: 50, # 'Ч' - 216: 57, # 'Ш' - 217: 63, # 'Щ' - 218: 70, # 'Ъ' - 219: 62, # 'Ы' - 220: 61, # 'Ь' - 221: 47, # 'Э' - 222: 59, # 'Ю' - 223: 43, # 'Я' - 224: 3, # 'а' - 225: 21, # 'б' - 226: 10, # 'в' - 227: 19, # 'г' - 228: 13, # 'д' - 229: 2, # 'е' - 230: 24, # 'ж' - 231: 20, # 'з' - 232: 4, # 'и' - 233: 23, # 'й' - 234: 11, # 'к' - 235: 8, # 'л' - 236: 12, # 'м' - 237: 5, # 'н' - 238: 1, # 'о' - 239: 15, # 'п' - 240: 9, # 'р' - 241: 7, # 'с' - 242: 6, # 'т' - 243: 14, # 'у' - 244: 39, # 'ф' - 245: 26, # 'х' - 246: 28, # 'ц' - 247: 22, # 'ч' - 248: 25, # 'ш' - 249: 29, # 'щ' - 250: 54, # 'ъ' - 251: 18, # 'ы' - 252: 17, # 'ь' - 253: 30, # 'э' - 254: 27, # 'ю' - 255: 16, # 'я' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'Ђ' + 129: 192, # 'Ѓ' + 130: 193, # '‚' + 131: 194, # 'ѓ' + 132: 195, # '„' + 133: 196, # '…' + 134: 197, # '†' + 135: 198, # '‡' + 136: 199, # '€' + 137: 200, # '‰' + 138: 201, # 'Љ' + 139: 202, # '‹' + 140: 203, # 'Њ' + 141: 204, # 'Ќ' + 142: 205, # 'Ћ' + 143: 206, # 'Џ' + 144: 207, # 'ђ' + 145: 208, # '‘' + 146: 209, # '’' + 147: 210, # '“' + 148: 211, # '”' + 149: 212, # '•' + 150: 213, # '–' + 151: 214, # '—' + 152: 215, # None + 153: 216, # '™' + 154: 217, # 'љ' + 155: 218, # '›' + 156: 219, # 'њ' + 157: 220, # 'ќ' + 158: 221, # 'ћ' + 159: 222, # 'џ' + 160: 223, # '\xa0' + 161: 224, # 'Ў' + 162: 225, # 'ў' + 163: 226, # 'Ј' + 164: 227, # '¤' + 165: 228, # 'Ґ' + 166: 229, # '¦' + 167: 230, # '§' + 168: 231, # 'Ё' + 169: 232, # '©' + 170: 233, # 'Є' + 171: 234, # '«' + 172: 235, # '¬' + 173: 236, # '\xad' + 174: 237, # '®' + 175: 238, # 'Ї' + 176: 239, # '°' + 177: 240, # '±' + 178: 241, # 'І' + 179: 242, # 'і' + 180: 243, # 'ґ' + 181: 244, # 'µ' + 182: 245, # '¶' + 183: 246, # '·' + 184: 68, # 'ё' + 185: 247, # '№' + 186: 248, # 'є' + 187: 249, # '»' + 188: 250, # 'ј' + 189: 251, # 'Ѕ' + 190: 252, # 'ѕ' + 191: 253, # 'ї' + 192: 37, # 'А' + 193: 44, # 'Б' + 194: 33, # 'В' + 195: 46, # 'Г' + 196: 41, # 'Д' + 197: 48, # 'Е' + 198: 56, # 'Ж' + 199: 51, # 'З' + 200: 42, # 'И' + 201: 60, # 'Й' + 202: 36, # 'К' + 203: 49, # 'Л' + 204: 38, # 'М' + 205: 31, # 'Н' + 206: 34, # 'О' + 207: 35, # 'П' + 208: 45, # 'Р' + 209: 32, # 'С' + 210: 40, # 'Т' + 211: 52, # 'У' + 212: 53, # 'Ф' + 213: 55, # 'Х' + 214: 58, # 'Ц' + 215: 50, # 'Ч' + 216: 57, # 'Ш' + 217: 63, # 'Щ' + 218: 70, # 'Ъ' + 219: 62, # 'Ы' + 220: 61, # 'Ь' + 221: 47, # 'Э' + 222: 59, # 'Ю' + 223: 43, # 'Я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 16, # 'я' } -WINDOWS_1251_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', - language='Russian', - char_to_order_map=WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') +WINDOWS_1251_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="windows-1251", + language="Russian", + char_to_order_map=WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) IBM855_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # 'ђ' - 129: 192, # 'Ђ' - 130: 193, # 'ѓ' - 131: 194, # 'Ѓ' - 132: 68, # 'ё' - 133: 195, # 'Ё' - 134: 196, # 'є' - 135: 197, # 'Є' - 136: 198, # 'ѕ' - 137: 199, # 'Ѕ' - 138: 200, # 'і' - 139: 201, # 'І' - 140: 202, # 'ї' - 141: 203, # 'Ї' - 142: 204, # 'ј' - 143: 205, # 'Ј' - 144: 206, # 'љ' - 145: 207, # 'Љ' - 146: 208, # 'њ' - 147: 209, # 'Њ' - 148: 210, # 'ћ' - 149: 211, # 'Ћ' - 150: 212, # 'ќ' - 151: 213, # 'Ќ' - 152: 214, # 'ў' - 153: 215, # 'Ў' - 154: 216, # 'џ' - 155: 217, # 'Џ' - 156: 27, # 'ю' - 157: 59, # 'Ю' - 158: 54, # 'ъ' - 159: 70, # 'Ъ' - 160: 3, # 'а' - 161: 37, # 'А' - 162: 21, # 'б' - 163: 44, # 'Б' - 164: 28, # 'ц' - 165: 58, # 'Ц' - 166: 13, # 'д' - 167: 41, # 'Д' - 168: 2, # 'е' - 169: 48, # 'Е' - 170: 39, # 'ф' - 171: 53, # 'Ф' - 172: 19, # 'г' - 173: 46, # 'Г' - 174: 218, # '«' - 175: 219, # '»' - 176: 220, # '░' - 177: 221, # '▒' - 178: 222, # '▓' - 179: 223, # '│' - 180: 224, # '┤' - 181: 26, # 'х' - 182: 55, # 'Х' - 183: 4, # 'и' - 184: 42, # 'И' - 185: 225, # '╣' - 186: 226, # '║' - 187: 227, # '╗' - 188: 228, # '╝' - 189: 23, # 'й' - 190: 60, # 'Й' - 191: 229, # '┐' - 192: 230, # '└' - 193: 231, # '┴' - 194: 232, # '┬' - 195: 233, # '├' - 196: 234, # '─' - 197: 235, # '┼' - 198: 11, # 'к' - 199: 36, # 'К' - 200: 236, # '╚' - 201: 237, # '╔' - 202: 238, # '╩' - 203: 239, # '╦' - 204: 240, # '╠' - 205: 241, # '═' - 206: 242, # '╬' - 207: 243, # '¤' - 208: 8, # 'л' - 209: 49, # 'Л' - 210: 12, # 'м' - 211: 38, # 'М' - 212: 5, # 'н' - 213: 31, # 'Н' - 214: 1, # 'о' - 215: 34, # 'О' - 216: 15, # 'п' - 217: 244, # '┘' - 218: 245, # '┌' - 219: 246, # '█' - 220: 247, # '▄' - 221: 35, # 'П' - 222: 16, # 'я' - 223: 248, # '▀' - 224: 43, # 'Я' - 225: 9, # 'р' - 226: 45, # 'Р' - 227: 7, # 'с' - 228: 32, # 'С' - 229: 6, # 'т' - 230: 40, # 'Т' - 231: 14, # 'у' - 232: 52, # 'У' - 233: 24, # 'ж' - 234: 56, # 'Ж' - 235: 10, # 'в' - 236: 33, # 'В' - 237: 17, # 'ь' - 238: 61, # 'Ь' - 239: 249, # '№' - 240: 250, # '\xad' - 241: 18, # 'ы' - 242: 62, # 'Ы' - 243: 20, # 'з' - 244: 51, # 'З' - 245: 25, # 'ш' - 246: 57, # 'Ш' - 247: 30, # 'э' - 248: 47, # 'Э' - 249: 29, # 'щ' - 250: 63, # 'Щ' - 251: 22, # 'ч' - 252: 50, # 'Ч' - 253: 251, # '§' - 254: 252, # '■' - 255: 255, # '\xa0' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'ђ' + 129: 192, # 'Ђ' + 130: 193, # 'ѓ' + 131: 194, # 'Ѓ' + 132: 68, # 'ё' + 133: 195, # 'Ё' + 134: 196, # 'є' + 135: 197, # 'Є' + 136: 198, # 'ѕ' + 137: 199, # 'Ѕ' + 138: 200, # 'і' + 139: 201, # 'І' + 140: 202, # 'ї' + 141: 203, # 'Ї' + 142: 204, # 'ј' + 143: 205, # 'Ј' + 144: 206, # 'љ' + 145: 207, # 'Љ' + 146: 208, # 'њ' + 147: 209, # 'Њ' + 148: 210, # 'ћ' + 149: 211, # 'Ћ' + 150: 212, # 'ќ' + 151: 213, # 'Ќ' + 152: 214, # 'ў' + 153: 215, # 'Ў' + 154: 216, # 'џ' + 155: 217, # 'Џ' + 156: 27, # 'ю' + 157: 59, # 'Ю' + 158: 54, # 'ъ' + 159: 70, # 'Ъ' + 160: 3, # 'а' + 161: 37, # 'А' + 162: 21, # 'б' + 163: 44, # 'Б' + 164: 28, # 'ц' + 165: 58, # 'Ц' + 166: 13, # 'д' + 167: 41, # 'Д' + 168: 2, # 'е' + 169: 48, # 'Е' + 170: 39, # 'ф' + 171: 53, # 'Ф' + 172: 19, # 'г' + 173: 46, # 'Г' + 174: 218, # '«' + 175: 219, # '»' + 176: 220, # '░' + 177: 221, # '▒' + 178: 222, # '▓' + 179: 223, # '│' + 180: 224, # '┤' + 181: 26, # 'х' + 182: 55, # 'Х' + 183: 4, # 'и' + 184: 42, # 'И' + 185: 225, # '╣' + 186: 226, # '║' + 187: 227, # '╗' + 188: 228, # '╝' + 189: 23, # 'й' + 190: 60, # 'Й' + 191: 229, # '┐' + 192: 230, # '└' + 193: 231, # '┴' + 194: 232, # '┬' + 195: 233, # '├' + 196: 234, # '─' + 197: 235, # '┼' + 198: 11, # 'к' + 199: 36, # 'К' + 200: 236, # '╚' + 201: 237, # '╔' + 202: 238, # '╩' + 203: 239, # '╦' + 204: 240, # '╠' + 205: 241, # '═' + 206: 242, # '╬' + 207: 243, # '¤' + 208: 8, # 'л' + 209: 49, # 'Л' + 210: 12, # 'м' + 211: 38, # 'М' + 212: 5, # 'н' + 213: 31, # 'Н' + 214: 1, # 'о' + 215: 34, # 'О' + 216: 15, # 'п' + 217: 244, # '┘' + 218: 245, # '┌' + 219: 246, # '█' + 220: 247, # '▄' + 221: 35, # 'П' + 222: 16, # 'я' + 223: 248, # '▀' + 224: 43, # 'Я' + 225: 9, # 'р' + 226: 45, # 'Р' + 227: 7, # 'с' + 228: 32, # 'С' + 229: 6, # 'т' + 230: 40, # 'Т' + 231: 14, # 'у' + 232: 52, # 'У' + 233: 24, # 'ж' + 234: 56, # 'Ж' + 235: 10, # 'в' + 236: 33, # 'В' + 237: 17, # 'ь' + 238: 61, # 'Ь' + 239: 249, # '№' + 240: 250, # '\xad' + 241: 18, # 'ы' + 242: 62, # 'Ы' + 243: 20, # 'з' + 244: 51, # 'З' + 245: 25, # 'ш' + 246: 57, # 'Ш' + 247: 30, # 'э' + 248: 47, # 'Э' + 249: 29, # 'щ' + 250: 63, # 'Щ' + 251: 22, # 'ч' + 252: 50, # 'Ч' + 253: 251, # '§' + 254: 252, # '■' + 255: 255, # '\xa0' } -IBM855_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM855', - language='Russian', - char_to_order_map=IBM855_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') +IBM855_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="IBM855", + language="Russian", + char_to_order_map=IBM855_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) KOI8_R_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # '─' - 129: 192, # '│' - 130: 193, # '┌' - 131: 194, # '┐' - 132: 195, # '└' - 133: 196, # '┘' - 134: 197, # '├' - 135: 198, # '┤' - 136: 199, # '┬' - 137: 200, # '┴' - 138: 201, # '┼' - 139: 202, # '▀' - 140: 203, # '▄' - 141: 204, # '█' - 142: 205, # '▌' - 143: 206, # '▐' - 144: 207, # '░' - 145: 208, # '▒' - 146: 209, # '▓' - 147: 210, # '⌠' - 148: 211, # '■' - 149: 212, # '∙' - 150: 213, # '√' - 151: 214, # '≈' - 152: 215, # '≤' - 153: 216, # '≥' - 154: 217, # '\xa0' - 155: 218, # '⌡' - 156: 219, # '°' - 157: 220, # '²' - 158: 221, # '·' - 159: 222, # '÷' - 160: 223, # '═' - 161: 224, # '║' - 162: 225, # '╒' - 163: 68, # 'ё' - 164: 226, # '╓' - 165: 227, # '╔' - 166: 228, # '╕' - 167: 229, # '╖' - 168: 230, # '╗' - 169: 231, # '╘' - 170: 232, # '╙' - 171: 233, # '╚' - 172: 234, # '╛' - 173: 235, # '╜' - 174: 236, # '╝' - 175: 237, # '╞' - 176: 238, # '╟' - 177: 239, # '╠' - 178: 240, # '╡' - 179: 241, # 'Ё' - 180: 242, # '╢' - 181: 243, # '╣' - 182: 244, # '╤' - 183: 245, # '╥' - 184: 246, # '╦' - 185: 247, # '╧' - 186: 248, # '╨' - 187: 249, # '╩' - 188: 250, # '╪' - 189: 251, # '╫' - 190: 252, # '╬' - 191: 253, # '©' - 192: 27, # 'ю' - 193: 3, # 'а' - 194: 21, # 'б' - 195: 28, # 'ц' - 196: 13, # 'д' - 197: 2, # 'е' - 198: 39, # 'ф' - 199: 19, # 'г' - 200: 26, # 'х' - 201: 4, # 'и' - 202: 23, # 'й' - 203: 11, # 'к' - 204: 8, # 'л' - 205: 12, # 'м' - 206: 5, # 'н' - 207: 1, # 'о' - 208: 15, # 'п' - 209: 16, # 'я' - 210: 9, # 'р' - 211: 7, # 'с' - 212: 6, # 'т' - 213: 14, # 'у' - 214: 24, # 'ж' - 215: 10, # 'в' - 216: 17, # 'ь' - 217: 18, # 'ы' - 218: 20, # 'з' - 219: 25, # 'ш' - 220: 30, # 'э' - 221: 29, # 'щ' - 222: 22, # 'ч' - 223: 54, # 'ъ' - 224: 59, # 'Ю' - 225: 37, # 'А' - 226: 44, # 'Б' - 227: 58, # 'Ц' - 228: 41, # 'Д' - 229: 48, # 'Е' - 230: 53, # 'Ф' - 231: 46, # 'Г' - 232: 55, # 'Х' - 233: 42, # 'И' - 234: 60, # 'Й' - 235: 36, # 'К' - 236: 49, # 'Л' - 237: 38, # 'М' - 238: 31, # 'Н' - 239: 34, # 'О' - 240: 35, # 'П' - 241: 43, # 'Я' - 242: 45, # 'Р' - 243: 32, # 'С' - 244: 40, # 'Т' - 245: 52, # 'У' - 246: 56, # 'Ж' - 247: 33, # 'В' - 248: 61, # 'Ь' - 249: 62, # 'Ы' - 250: 51, # 'З' - 251: 57, # 'Ш' - 252: 47, # 'Э' - 253: 63, # 'Щ' - 254: 50, # 'Ч' - 255: 70, # 'Ъ' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '─' + 129: 192, # '│' + 130: 193, # '┌' + 131: 194, # '┐' + 132: 195, # '└' + 133: 196, # '┘' + 134: 197, # '├' + 135: 198, # '┤' + 136: 199, # '┬' + 137: 200, # '┴' + 138: 201, # '┼' + 139: 202, # '▀' + 140: 203, # '▄' + 141: 204, # '█' + 142: 205, # '▌' + 143: 206, # '▐' + 144: 207, # '░' + 145: 208, # '▒' + 146: 209, # '▓' + 147: 210, # '⌠' + 148: 211, # '■' + 149: 212, # '∙' + 150: 213, # '√' + 151: 214, # '≈' + 152: 215, # '≤' + 153: 216, # '≥' + 154: 217, # '\xa0' + 155: 218, # '⌡' + 156: 219, # '°' + 157: 220, # '²' + 158: 221, # '·' + 159: 222, # '÷' + 160: 223, # '═' + 161: 224, # '║' + 162: 225, # '╒' + 163: 68, # 'ё' + 164: 226, # '╓' + 165: 227, # '╔' + 166: 228, # '╕' + 167: 229, # '╖' + 168: 230, # '╗' + 169: 231, # '╘' + 170: 232, # '╙' + 171: 233, # '╚' + 172: 234, # '╛' + 173: 235, # '╜' + 174: 236, # '╝' + 175: 237, # '╞' + 176: 238, # '╟' + 177: 239, # '╠' + 178: 240, # '╡' + 179: 241, # 'Ё' + 180: 242, # '╢' + 181: 243, # '╣' + 182: 244, # '╤' + 183: 245, # '╥' + 184: 246, # '╦' + 185: 247, # '╧' + 186: 248, # '╨' + 187: 249, # '╩' + 188: 250, # '╪' + 189: 251, # '╫' + 190: 252, # '╬' + 191: 253, # '©' + 192: 27, # 'ю' + 193: 3, # 'а' + 194: 21, # 'б' + 195: 28, # 'ц' + 196: 13, # 'д' + 197: 2, # 'е' + 198: 39, # 'ф' + 199: 19, # 'г' + 200: 26, # 'х' + 201: 4, # 'и' + 202: 23, # 'й' + 203: 11, # 'к' + 204: 8, # 'л' + 205: 12, # 'м' + 206: 5, # 'н' + 207: 1, # 'о' + 208: 15, # 'п' + 209: 16, # 'я' + 210: 9, # 'р' + 211: 7, # 'с' + 212: 6, # 'т' + 213: 14, # 'у' + 214: 24, # 'ж' + 215: 10, # 'в' + 216: 17, # 'ь' + 217: 18, # 'ы' + 218: 20, # 'з' + 219: 25, # 'ш' + 220: 30, # 'э' + 221: 29, # 'щ' + 222: 22, # 'ч' + 223: 54, # 'ъ' + 224: 59, # 'Ю' + 225: 37, # 'А' + 226: 44, # 'Б' + 227: 58, # 'Ц' + 228: 41, # 'Д' + 229: 48, # 'Е' + 230: 53, # 'Ф' + 231: 46, # 'Г' + 232: 55, # 'Х' + 233: 42, # 'И' + 234: 60, # 'Й' + 235: 36, # 'К' + 236: 49, # 'Л' + 237: 38, # 'М' + 238: 31, # 'Н' + 239: 34, # 'О' + 240: 35, # 'П' + 241: 43, # 'Я' + 242: 45, # 'Р' + 243: 32, # 'С' + 244: 40, # 'Т' + 245: 52, # 'У' + 246: 56, # 'Ж' + 247: 33, # 'В' + 248: 61, # 'Ь' + 249: 62, # 'Ы' + 250: 51, # 'З' + 251: 57, # 'Ш' + 252: 47, # 'Э' + 253: 63, # 'Щ' + 254: 50, # 'Ч' + 255: 70, # 'Ъ' } -KOI8_R_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='KOI8-R', - language='Russian', - char_to_order_map=KOI8_R_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') +KOI8_R_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="KOI8-R", + language="Russian", + char_to_order_map=KOI8_R_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 37, # 'А' - 129: 44, # 'Б' - 130: 33, # 'В' - 131: 46, # 'Г' - 132: 41, # 'Д' - 133: 48, # 'Е' - 134: 56, # 'Ж' - 135: 51, # 'З' - 136: 42, # 'И' - 137: 60, # 'Й' - 138: 36, # 'К' - 139: 49, # 'Л' - 140: 38, # 'М' - 141: 31, # 'Н' - 142: 34, # 'О' - 143: 35, # 'П' - 144: 45, # 'Р' - 145: 32, # 'С' - 146: 40, # 'Т' - 147: 52, # 'У' - 148: 53, # 'Ф' - 149: 55, # 'Х' - 150: 58, # 'Ц' - 151: 50, # 'Ч' - 152: 57, # 'Ш' - 153: 63, # 'Щ' - 154: 70, # 'Ъ' - 155: 62, # 'Ы' - 156: 61, # 'Ь' - 157: 47, # 'Э' - 158: 59, # 'Ю' - 159: 43, # 'Я' - 160: 191, # '†' - 161: 192, # '°' - 162: 193, # 'Ґ' - 163: 194, # '£' - 164: 195, # '§' - 165: 196, # '•' - 166: 197, # '¶' - 167: 198, # 'І' - 168: 199, # '®' - 169: 200, # '©' - 170: 201, # '™' - 171: 202, # 'Ђ' - 172: 203, # 'ђ' - 173: 204, # '≠' - 174: 205, # 'Ѓ' - 175: 206, # 'ѓ' - 176: 207, # '∞' - 177: 208, # '±' - 178: 209, # '≤' - 179: 210, # '≥' - 180: 211, # 'і' - 181: 212, # 'µ' - 182: 213, # 'ґ' - 183: 214, # 'Ј' - 184: 215, # 'Є' - 185: 216, # 'є' - 186: 217, # 'Ї' - 187: 218, # 'ї' - 188: 219, # 'Љ' - 189: 220, # 'љ' - 190: 221, # 'Њ' - 191: 222, # 'њ' - 192: 223, # 'ј' - 193: 224, # 'Ѕ' - 194: 225, # '¬' - 195: 226, # '√' - 196: 227, # 'ƒ' - 197: 228, # '≈' - 198: 229, # '∆' - 199: 230, # '«' - 200: 231, # '»' - 201: 232, # '…' - 202: 233, # '\xa0' - 203: 234, # 'Ћ' - 204: 235, # 'ћ' - 205: 236, # 'Ќ' - 206: 237, # 'ќ' - 207: 238, # 'ѕ' - 208: 239, # '–' - 209: 240, # '—' - 210: 241, # '“' - 211: 242, # '”' - 212: 243, # '‘' - 213: 244, # '’' - 214: 245, # '÷' - 215: 246, # '„' - 216: 247, # 'Ў' - 217: 248, # 'ў' - 218: 249, # 'Џ' - 219: 250, # 'џ' - 220: 251, # '№' - 221: 252, # 'Ё' - 222: 68, # 'ё' - 223: 16, # 'я' - 224: 3, # 'а' - 225: 21, # 'б' - 226: 10, # 'в' - 227: 19, # 'г' - 228: 13, # 'д' - 229: 2, # 'е' - 230: 24, # 'ж' - 231: 20, # 'з' - 232: 4, # 'и' - 233: 23, # 'й' - 234: 11, # 'к' - 235: 8, # 'л' - 236: 12, # 'м' - 237: 5, # 'н' - 238: 1, # 'о' - 239: 15, # 'п' - 240: 9, # 'р' - 241: 7, # 'с' - 242: 6, # 'т' - 243: 14, # 'у' - 244: 39, # 'ф' - 245: 26, # 'х' - 246: 28, # 'ц' - 247: 22, # 'ч' - 248: 25, # 'ш' - 249: 29, # 'щ' - 250: 54, # 'ъ' - 251: 18, # 'ы' - 252: 17, # 'ь' - 253: 30, # 'э' - 254: 27, # 'ю' - 255: 255, # '€' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 191, # '†' + 161: 192, # '°' + 162: 193, # 'Ґ' + 163: 194, # '£' + 164: 195, # '§' + 165: 196, # '•' + 166: 197, # '¶' + 167: 198, # 'І' + 168: 199, # '®' + 169: 200, # '©' + 170: 201, # '™' + 171: 202, # 'Ђ' + 172: 203, # 'ђ' + 173: 204, # '≠' + 174: 205, # 'Ѓ' + 175: 206, # 'ѓ' + 176: 207, # '∞' + 177: 208, # '±' + 178: 209, # '≤' + 179: 210, # '≥' + 180: 211, # 'і' + 181: 212, # 'µ' + 182: 213, # 'ґ' + 183: 214, # 'Ј' + 184: 215, # 'Є' + 185: 216, # 'є' + 186: 217, # 'Ї' + 187: 218, # 'ї' + 188: 219, # 'Љ' + 189: 220, # 'љ' + 190: 221, # 'Њ' + 191: 222, # 'њ' + 192: 223, # 'ј' + 193: 224, # 'Ѕ' + 194: 225, # '¬' + 195: 226, # '√' + 196: 227, # 'ƒ' + 197: 228, # '≈' + 198: 229, # '∆' + 199: 230, # '«' + 200: 231, # '»' + 201: 232, # '…' + 202: 233, # '\xa0' + 203: 234, # 'Ћ' + 204: 235, # 'ћ' + 205: 236, # 'Ќ' + 206: 237, # 'ќ' + 207: 238, # 'ѕ' + 208: 239, # '–' + 209: 240, # '—' + 210: 241, # '“' + 211: 242, # '”' + 212: 243, # '‘' + 213: 244, # '’' + 214: 245, # '÷' + 215: 246, # '„' + 216: 247, # 'Ў' + 217: 248, # 'ў' + 218: 249, # 'Џ' + 219: 250, # 'џ' + 220: 251, # '№' + 221: 252, # 'Ё' + 222: 68, # 'ё' + 223: 16, # 'я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 255, # '€' } -MACCYRILLIC_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='MacCyrillic', - language='Russian', - char_to_order_map=MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') +MACCYRILLIC_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="MacCyrillic", + language="Russian", + char_to_order_map=MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) ISO_8859_5_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # '\x80' - 129: 192, # '\x81' - 130: 193, # '\x82' - 131: 194, # '\x83' - 132: 195, # '\x84' - 133: 196, # '\x85' - 134: 197, # '\x86' - 135: 198, # '\x87' - 136: 199, # '\x88' - 137: 200, # '\x89' - 138: 201, # '\x8a' - 139: 202, # '\x8b' - 140: 203, # '\x8c' - 141: 204, # '\x8d' - 142: 205, # '\x8e' - 143: 206, # '\x8f' - 144: 207, # '\x90' - 145: 208, # '\x91' - 146: 209, # '\x92' - 147: 210, # '\x93' - 148: 211, # '\x94' - 149: 212, # '\x95' - 150: 213, # '\x96' - 151: 214, # '\x97' - 152: 215, # '\x98' - 153: 216, # '\x99' - 154: 217, # '\x9a' - 155: 218, # '\x9b' - 156: 219, # '\x9c' - 157: 220, # '\x9d' - 158: 221, # '\x9e' - 159: 222, # '\x9f' - 160: 223, # '\xa0' - 161: 224, # 'Ё' - 162: 225, # 'Ђ' - 163: 226, # 'Ѓ' - 164: 227, # 'Є' - 165: 228, # 'Ѕ' - 166: 229, # 'І' - 167: 230, # 'Ї' - 168: 231, # 'Ј' - 169: 232, # 'Љ' - 170: 233, # 'Њ' - 171: 234, # 'Ћ' - 172: 235, # 'Ќ' - 173: 236, # '\xad' - 174: 237, # 'Ў' - 175: 238, # 'Џ' - 176: 37, # 'А' - 177: 44, # 'Б' - 178: 33, # 'В' - 179: 46, # 'Г' - 180: 41, # 'Д' - 181: 48, # 'Е' - 182: 56, # 'Ж' - 183: 51, # 'З' - 184: 42, # 'И' - 185: 60, # 'Й' - 186: 36, # 'К' - 187: 49, # 'Л' - 188: 38, # 'М' - 189: 31, # 'Н' - 190: 34, # 'О' - 191: 35, # 'П' - 192: 45, # 'Р' - 193: 32, # 'С' - 194: 40, # 'Т' - 195: 52, # 'У' - 196: 53, # 'Ф' - 197: 55, # 'Х' - 198: 58, # 'Ц' - 199: 50, # 'Ч' - 200: 57, # 'Ш' - 201: 63, # 'Щ' - 202: 70, # 'Ъ' - 203: 62, # 'Ы' - 204: 61, # 'Ь' - 205: 47, # 'Э' - 206: 59, # 'Ю' - 207: 43, # 'Я' - 208: 3, # 'а' - 209: 21, # 'б' - 210: 10, # 'в' - 211: 19, # 'г' - 212: 13, # 'д' - 213: 2, # 'е' - 214: 24, # 'ж' - 215: 20, # 'з' - 216: 4, # 'и' - 217: 23, # 'й' - 218: 11, # 'к' - 219: 8, # 'л' - 220: 12, # 'м' - 221: 5, # 'н' - 222: 1, # 'о' - 223: 15, # 'п' - 224: 9, # 'р' - 225: 7, # 'с' - 226: 6, # 'т' - 227: 14, # 'у' - 228: 39, # 'ф' - 229: 26, # 'х' - 230: 28, # 'ц' - 231: 22, # 'ч' - 232: 25, # 'ш' - 233: 29, # 'щ' - 234: 54, # 'ъ' - 235: 18, # 'ы' - 236: 17, # 'ь' - 237: 30, # 'э' - 238: 27, # 'ю' - 239: 16, # 'я' - 240: 239, # '№' - 241: 68, # 'ё' - 242: 240, # 'ђ' - 243: 241, # 'ѓ' - 244: 242, # 'є' - 245: 243, # 'ѕ' - 246: 244, # 'і' - 247: 245, # 'ї' - 248: 246, # 'ј' - 249: 247, # 'љ' - 250: 248, # 'њ' - 251: 249, # 'ћ' - 252: 250, # 'ќ' - 253: 251, # '§' - 254: 252, # 'ў' - 255: 255, # 'џ' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '\x80' + 129: 192, # '\x81' + 130: 193, # '\x82' + 131: 194, # '\x83' + 132: 195, # '\x84' + 133: 196, # '\x85' + 134: 197, # '\x86' + 135: 198, # '\x87' + 136: 199, # '\x88' + 137: 200, # '\x89' + 138: 201, # '\x8a' + 139: 202, # '\x8b' + 140: 203, # '\x8c' + 141: 204, # '\x8d' + 142: 205, # '\x8e' + 143: 206, # '\x8f' + 144: 207, # '\x90' + 145: 208, # '\x91' + 146: 209, # '\x92' + 147: 210, # '\x93' + 148: 211, # '\x94' + 149: 212, # '\x95' + 150: 213, # '\x96' + 151: 214, # '\x97' + 152: 215, # '\x98' + 153: 216, # '\x99' + 154: 217, # '\x9a' + 155: 218, # '\x9b' + 156: 219, # '\x9c' + 157: 220, # '\x9d' + 158: 221, # '\x9e' + 159: 222, # '\x9f' + 160: 223, # '\xa0' + 161: 224, # 'Ё' + 162: 225, # 'Ђ' + 163: 226, # 'Ѓ' + 164: 227, # 'Є' + 165: 228, # 'Ѕ' + 166: 229, # 'І' + 167: 230, # 'Ї' + 168: 231, # 'Ј' + 169: 232, # 'Љ' + 170: 233, # 'Њ' + 171: 234, # 'Ћ' + 172: 235, # 'Ќ' + 173: 236, # '\xad' + 174: 237, # 'Ў' + 175: 238, # 'Џ' + 176: 37, # 'А' + 177: 44, # 'Б' + 178: 33, # 'В' + 179: 46, # 'Г' + 180: 41, # 'Д' + 181: 48, # 'Е' + 182: 56, # 'Ж' + 183: 51, # 'З' + 184: 42, # 'И' + 185: 60, # 'Й' + 186: 36, # 'К' + 187: 49, # 'Л' + 188: 38, # 'М' + 189: 31, # 'Н' + 190: 34, # 'О' + 191: 35, # 'П' + 192: 45, # 'Р' + 193: 32, # 'С' + 194: 40, # 'Т' + 195: 52, # 'У' + 196: 53, # 'Ф' + 197: 55, # 'Х' + 198: 58, # 'Ц' + 199: 50, # 'Ч' + 200: 57, # 'Ш' + 201: 63, # 'Щ' + 202: 70, # 'Ъ' + 203: 62, # 'Ы' + 204: 61, # 'Ь' + 205: 47, # 'Э' + 206: 59, # 'Ю' + 207: 43, # 'Я' + 208: 3, # 'а' + 209: 21, # 'б' + 210: 10, # 'в' + 211: 19, # 'г' + 212: 13, # 'д' + 213: 2, # 'е' + 214: 24, # 'ж' + 215: 20, # 'з' + 216: 4, # 'и' + 217: 23, # 'й' + 218: 11, # 'к' + 219: 8, # 'л' + 220: 12, # 'м' + 221: 5, # 'н' + 222: 1, # 'о' + 223: 15, # 'п' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # '№' + 241: 68, # 'ё' + 242: 240, # 'ђ' + 243: 241, # 'ѓ' + 244: 242, # 'є' + 245: 243, # 'ѕ' + 246: 244, # 'і' + 247: 245, # 'ї' + 248: 246, # 'ј' + 249: 247, # 'љ' + 250: 248, # 'њ' + 251: 249, # 'ћ' + 252: 250, # 'ќ' + 253: 251, # '§' + 254: 252, # 'ў' + 255: 255, # 'џ' } -ISO_8859_5_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', - language='Russian', - char_to_order_map=ISO_8859_5_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - +ISO_8859_5_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="ISO-8859-5", + language="Russian", + char_to_order_map=ISO_8859_5_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) diff --git a/script.module.chardet/lib/chardet/langthaimodel.py b/script.module.chardet/lib/chardet/langthaimodel.py index d0191f241..883fdb1ea 100644 --- a/script.module.chardet/lib/chardet/langthaimodel.py +++ b/script.module.chardet/lib/chardet/langthaimodel.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - from chardet.sbcharsetprober import SingleByteCharSetModel - # 3: Positive # 2: Likely # 1: Unlikely @@ -4115,269 +4111,270 @@ # Character Mapping Table(s): TIS_620_THAI_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 182, # 'A' - 66: 106, # 'B' - 67: 107, # 'C' - 68: 100, # 'D' - 69: 183, # 'E' - 70: 184, # 'F' - 71: 185, # 'G' - 72: 101, # 'H' - 73: 94, # 'I' - 74: 186, # 'J' - 75: 187, # 'K' - 76: 108, # 'L' - 77: 109, # 'M' - 78: 110, # 'N' - 79: 111, # 'O' - 80: 188, # 'P' - 81: 189, # 'Q' - 82: 190, # 'R' - 83: 89, # 'S' - 84: 95, # 'T' - 85: 112, # 'U' - 86: 113, # 'V' - 87: 191, # 'W' - 88: 192, # 'X' - 89: 193, # 'Y' - 90: 194, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 64, # 'a' - 98: 72, # 'b' - 99: 73, # 'c' - 100: 114, # 'd' - 101: 74, # 'e' - 102: 115, # 'f' - 103: 116, # 'g' - 104: 102, # 'h' - 105: 81, # 'i' - 106: 201, # 'j' - 107: 117, # 'k' - 108: 90, # 'l' - 109: 103, # 'm' - 110: 78, # 'n' - 111: 82, # 'o' - 112: 96, # 'p' - 113: 202, # 'q' - 114: 91, # 'r' - 115: 79, # 's' - 116: 84, # 't' - 117: 104, # 'u' - 118: 105, # 'v' - 119: 97, # 'w' - 120: 98, # 'x' - 121: 92, # 'y' - 122: 203, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 209, # '\x80' - 129: 210, # '\x81' - 130: 211, # '\x82' - 131: 212, # '\x83' - 132: 213, # '\x84' - 133: 88, # '\x85' - 134: 214, # '\x86' - 135: 215, # '\x87' - 136: 216, # '\x88' - 137: 217, # '\x89' - 138: 218, # '\x8a' - 139: 219, # '\x8b' - 140: 220, # '\x8c' - 141: 118, # '\x8d' - 142: 221, # '\x8e' - 143: 222, # '\x8f' - 144: 223, # '\x90' - 145: 224, # '\x91' - 146: 99, # '\x92' - 147: 85, # '\x93' - 148: 83, # '\x94' - 149: 225, # '\x95' - 150: 226, # '\x96' - 151: 227, # '\x97' - 152: 228, # '\x98' - 153: 229, # '\x99' - 154: 230, # '\x9a' - 155: 231, # '\x9b' - 156: 232, # '\x9c' - 157: 233, # '\x9d' - 158: 234, # '\x9e' - 159: 235, # '\x9f' - 160: 236, # None - 161: 5, # 'ก' - 162: 30, # 'ข' - 163: 237, # 'ฃ' - 164: 24, # 'ค' - 165: 238, # 'ฅ' - 166: 75, # 'ฆ' - 167: 8, # 'ง' - 168: 26, # 'จ' - 169: 52, # 'ฉ' - 170: 34, # 'ช' - 171: 51, # 'ซ' - 172: 119, # 'ฌ' - 173: 47, # 'ญ' - 174: 58, # 'ฎ' - 175: 57, # 'ฏ' - 176: 49, # 'ฐ' - 177: 53, # 'ฑ' - 178: 55, # 'ฒ' - 179: 43, # 'ณ' - 180: 20, # 'ด' - 181: 19, # 'ต' - 182: 44, # 'ถ' - 183: 14, # 'ท' - 184: 48, # 'ธ' - 185: 3, # 'น' - 186: 17, # 'บ' - 187: 25, # 'ป' - 188: 39, # 'ผ' - 189: 62, # 'ฝ' - 190: 31, # 'พ' - 191: 54, # 'ฟ' - 192: 45, # 'ภ' - 193: 9, # 'ม' - 194: 16, # 'ย' - 195: 2, # 'ร' - 196: 61, # 'ฤ' - 197: 15, # 'ล' - 198: 239, # 'ฦ' - 199: 12, # 'ว' - 200: 42, # 'ศ' - 201: 46, # 'ษ' - 202: 18, # 'ส' - 203: 21, # 'ห' - 204: 76, # 'ฬ' - 205: 4, # 'อ' - 206: 66, # 'ฮ' - 207: 63, # 'ฯ' - 208: 22, # 'ะ' - 209: 10, # 'ั' - 210: 1, # 'า' - 211: 36, # 'ำ' - 212: 23, # 'ิ' - 213: 13, # 'ี' - 214: 40, # 'ึ' - 215: 27, # 'ื' - 216: 32, # 'ุ' - 217: 35, # 'ู' - 218: 86, # 'ฺ' - 219: 240, # None - 220: 241, # None - 221: 242, # None - 222: 243, # None - 223: 244, # '฿' - 224: 11, # 'เ' - 225: 28, # 'แ' - 226: 41, # 'โ' - 227: 29, # 'ใ' - 228: 33, # 'ไ' - 229: 245, # 'ๅ' - 230: 50, # 'ๆ' - 231: 37, # '็' - 232: 6, # '่' - 233: 7, # '้' - 234: 67, # '๊' - 235: 77, # '๋' - 236: 38, # '์' - 237: 93, # 'ํ' - 238: 246, # '๎' - 239: 247, # '๏' - 240: 68, # '๐' - 241: 56, # '๑' - 242: 59, # '๒' - 243: 65, # '๓' - 244: 69, # '๔' - 245: 60, # '๕' - 246: 70, # '๖' - 247: 80, # '๗' - 248: 71, # '๘' - 249: 87, # '๙' - 250: 248, # '๚' - 251: 249, # '๛' - 252: 250, # None - 253: 251, # None - 254: 252, # None - 255: 253, # None + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 182, # 'A' + 66: 106, # 'B' + 67: 107, # 'C' + 68: 100, # 'D' + 69: 183, # 'E' + 70: 184, # 'F' + 71: 185, # 'G' + 72: 101, # 'H' + 73: 94, # 'I' + 74: 186, # 'J' + 75: 187, # 'K' + 76: 108, # 'L' + 77: 109, # 'M' + 78: 110, # 'N' + 79: 111, # 'O' + 80: 188, # 'P' + 81: 189, # 'Q' + 82: 190, # 'R' + 83: 89, # 'S' + 84: 95, # 'T' + 85: 112, # 'U' + 86: 113, # 'V' + 87: 191, # 'W' + 88: 192, # 'X' + 89: 193, # 'Y' + 90: 194, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 64, # 'a' + 98: 72, # 'b' + 99: 73, # 'c' + 100: 114, # 'd' + 101: 74, # 'e' + 102: 115, # 'f' + 103: 116, # 'g' + 104: 102, # 'h' + 105: 81, # 'i' + 106: 201, # 'j' + 107: 117, # 'k' + 108: 90, # 'l' + 109: 103, # 'm' + 110: 78, # 'n' + 111: 82, # 'o' + 112: 96, # 'p' + 113: 202, # 'q' + 114: 91, # 'r' + 115: 79, # 's' + 116: 84, # 't' + 117: 104, # 'u' + 118: 105, # 'v' + 119: 97, # 'w' + 120: 98, # 'x' + 121: 92, # 'y' + 122: 203, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 209, # '\x80' + 129: 210, # '\x81' + 130: 211, # '\x82' + 131: 212, # '\x83' + 132: 213, # '\x84' + 133: 88, # '\x85' + 134: 214, # '\x86' + 135: 215, # '\x87' + 136: 216, # '\x88' + 137: 217, # '\x89' + 138: 218, # '\x8a' + 139: 219, # '\x8b' + 140: 220, # '\x8c' + 141: 118, # '\x8d' + 142: 221, # '\x8e' + 143: 222, # '\x8f' + 144: 223, # '\x90' + 145: 224, # '\x91' + 146: 99, # '\x92' + 147: 85, # '\x93' + 148: 83, # '\x94' + 149: 225, # '\x95' + 150: 226, # '\x96' + 151: 227, # '\x97' + 152: 228, # '\x98' + 153: 229, # '\x99' + 154: 230, # '\x9a' + 155: 231, # '\x9b' + 156: 232, # '\x9c' + 157: 233, # '\x9d' + 158: 234, # '\x9e' + 159: 235, # '\x9f' + 160: 236, # None + 161: 5, # 'ก' + 162: 30, # 'ข' + 163: 237, # 'ฃ' + 164: 24, # 'ค' + 165: 238, # 'ฅ' + 166: 75, # 'ฆ' + 167: 8, # 'ง' + 168: 26, # 'จ' + 169: 52, # 'ฉ' + 170: 34, # 'ช' + 171: 51, # 'ซ' + 172: 119, # 'ฌ' + 173: 47, # 'ญ' + 174: 58, # 'ฎ' + 175: 57, # 'ฏ' + 176: 49, # 'ฐ' + 177: 53, # 'ฑ' + 178: 55, # 'ฒ' + 179: 43, # 'ณ' + 180: 20, # 'ด' + 181: 19, # 'ต' + 182: 44, # 'ถ' + 183: 14, # 'ท' + 184: 48, # 'ธ' + 185: 3, # 'น' + 186: 17, # 'บ' + 187: 25, # 'ป' + 188: 39, # 'ผ' + 189: 62, # 'ฝ' + 190: 31, # 'พ' + 191: 54, # 'ฟ' + 192: 45, # 'ภ' + 193: 9, # 'ม' + 194: 16, # 'ย' + 195: 2, # 'ร' + 196: 61, # 'ฤ' + 197: 15, # 'ล' + 198: 239, # 'ฦ' + 199: 12, # 'ว' + 200: 42, # 'ศ' + 201: 46, # 'ษ' + 202: 18, # 'ส' + 203: 21, # 'ห' + 204: 76, # 'ฬ' + 205: 4, # 'อ' + 206: 66, # 'ฮ' + 207: 63, # 'ฯ' + 208: 22, # 'ะ' + 209: 10, # 'ั' + 210: 1, # 'า' + 211: 36, # 'ำ' + 212: 23, # 'ิ' + 213: 13, # 'ี' + 214: 40, # 'ึ' + 215: 27, # 'ื' + 216: 32, # 'ุ' + 217: 35, # 'ู' + 218: 86, # 'ฺ' + 219: 240, # None + 220: 241, # None + 221: 242, # None + 222: 243, # None + 223: 244, # '฿' + 224: 11, # 'เ' + 225: 28, # 'แ' + 226: 41, # 'โ' + 227: 29, # 'ใ' + 228: 33, # 'ไ' + 229: 245, # 'ๅ' + 230: 50, # 'ๆ' + 231: 37, # '็' + 232: 6, # '่' + 233: 7, # '้' + 234: 67, # '๊' + 235: 77, # '๋' + 236: 38, # '์' + 237: 93, # 'ํ' + 238: 246, # '๎' + 239: 247, # '๏' + 240: 68, # '๐' + 241: 56, # '๑' + 242: 59, # '๒' + 243: 65, # '๓' + 244: 69, # '๔' + 245: 60, # '๕' + 246: 70, # '๖' + 247: 80, # '๗' + 248: 71, # '๘' + 249: 87, # '๙' + 250: 248, # '๚' + 251: 249, # '๛' + 252: 250, # None + 253: 251, # None + 254: 252, # None + 255: 253, # None } -TIS_620_THAI_MODEL = SingleByteCharSetModel(charset_name='TIS-620', - language='Thai', - char_to_order_map=TIS_620_THAI_CHAR_TO_ORDER, - language_model=THAI_LANG_MODEL, - typical_positive_ratio=0.926386, - keep_ascii_letters=False, - alphabet='กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛') - +TIS_620_THAI_MODEL = SingleByteCharSetModel( + charset_name="TIS-620", + language="Thai", + char_to_order_map=TIS_620_THAI_CHAR_TO_ORDER, + language_model=THAI_LANG_MODEL, + typical_positive_ratio=0.926386, + keep_ascii_letters=False, + alphabet="กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛", +) diff --git a/script.module.chardet/lib/chardet/langturkishmodel.py b/script.module.chardet/lib/chardet/langturkishmodel.py index 8ba93224d..64c94336c 100644 --- a/script.module.chardet/lib/chardet/langturkishmodel.py +++ b/script.module.chardet/lib/chardet/langturkishmodel.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - from chardet.sbcharsetprober import SingleByteCharSetModel - # 3: Positive # 2: Likely # 1: Unlikely @@ -4115,269 +4111,270 @@ # Character Mapping Table(s): ISO_8859_9_TURKISH_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 255, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 255, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 255, # ' ' - 33: 255, # '!' - 34: 255, # '"' - 35: 255, # '#' - 36: 255, # '$' - 37: 255, # '%' - 38: 255, # '&' - 39: 255, # "'" - 40: 255, # '(' - 41: 255, # ')' - 42: 255, # '*' - 43: 255, # '+' - 44: 255, # ',' - 45: 255, # '-' - 46: 255, # '.' - 47: 255, # '/' - 48: 255, # '0' - 49: 255, # '1' - 50: 255, # '2' - 51: 255, # '3' - 52: 255, # '4' - 53: 255, # '5' - 54: 255, # '6' - 55: 255, # '7' - 56: 255, # '8' - 57: 255, # '9' - 58: 255, # ':' - 59: 255, # ';' - 60: 255, # '<' - 61: 255, # '=' - 62: 255, # '>' - 63: 255, # '?' - 64: 255, # '@' - 65: 23, # 'A' - 66: 37, # 'B' - 67: 47, # 'C' - 68: 39, # 'D' - 69: 29, # 'E' - 70: 52, # 'F' - 71: 36, # 'G' - 72: 45, # 'H' - 73: 53, # 'I' - 74: 60, # 'J' - 75: 16, # 'K' - 76: 49, # 'L' - 77: 20, # 'M' - 78: 46, # 'N' - 79: 42, # 'O' - 80: 48, # 'P' - 81: 69, # 'Q' - 82: 44, # 'R' - 83: 35, # 'S' - 84: 31, # 'T' - 85: 51, # 'U' - 86: 38, # 'V' - 87: 62, # 'W' - 88: 65, # 'X' - 89: 43, # 'Y' - 90: 56, # 'Z' - 91: 255, # '[' - 92: 255, # '\\' - 93: 255, # ']' - 94: 255, # '^' - 95: 255, # '_' - 96: 255, # '`' - 97: 1, # 'a' - 98: 21, # 'b' - 99: 28, # 'c' - 100: 12, # 'd' - 101: 2, # 'e' - 102: 18, # 'f' - 103: 27, # 'g' - 104: 25, # 'h' - 105: 3, # 'i' - 106: 24, # 'j' - 107: 10, # 'k' - 108: 5, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 15, # 'o' - 112: 26, # 'p' - 113: 64, # 'q' - 114: 7, # 'r' - 115: 8, # 's' - 116: 9, # 't' - 117: 14, # 'u' - 118: 32, # 'v' - 119: 57, # 'w' - 120: 58, # 'x' - 121: 11, # 'y' - 122: 22, # 'z' - 123: 255, # '{' - 124: 255, # '|' - 125: 255, # '}' - 126: 255, # '~' - 127: 255, # '\x7f' - 128: 180, # '\x80' - 129: 179, # '\x81' - 130: 178, # '\x82' - 131: 177, # '\x83' - 132: 176, # '\x84' - 133: 175, # '\x85' - 134: 174, # '\x86' - 135: 173, # '\x87' - 136: 172, # '\x88' - 137: 171, # '\x89' - 138: 170, # '\x8a' - 139: 169, # '\x8b' - 140: 168, # '\x8c' - 141: 167, # '\x8d' - 142: 166, # '\x8e' - 143: 165, # '\x8f' - 144: 164, # '\x90' - 145: 163, # '\x91' - 146: 162, # '\x92' - 147: 161, # '\x93' - 148: 160, # '\x94' - 149: 159, # '\x95' - 150: 101, # '\x96' - 151: 158, # '\x97' - 152: 157, # '\x98' - 153: 156, # '\x99' - 154: 155, # '\x9a' - 155: 154, # '\x9b' - 156: 153, # '\x9c' - 157: 152, # '\x9d' - 158: 151, # '\x9e' - 159: 106, # '\x9f' - 160: 150, # '\xa0' - 161: 149, # '¡' - 162: 148, # '¢' - 163: 147, # '£' - 164: 146, # '¤' - 165: 145, # '¥' - 166: 144, # '¦' - 167: 100, # '§' - 168: 143, # '¨' - 169: 142, # '©' - 170: 141, # 'ª' - 171: 140, # '«' - 172: 139, # '¬' - 173: 138, # '\xad' - 174: 137, # '®' - 175: 136, # '¯' - 176: 94, # '°' - 177: 80, # '±' - 178: 93, # '²' - 179: 135, # '³' - 180: 105, # '´' - 181: 134, # 'µ' - 182: 133, # '¶' - 183: 63, # '·' - 184: 132, # '¸' - 185: 131, # '¹' - 186: 130, # 'º' - 187: 129, # '»' - 188: 128, # '¼' - 189: 127, # '½' - 190: 126, # '¾' - 191: 125, # '¿' - 192: 124, # 'À' - 193: 104, # 'Á' - 194: 73, # 'Â' - 195: 99, # 'Ã' - 196: 79, # 'Ä' - 197: 85, # 'Å' - 198: 123, # 'Æ' - 199: 54, # 'Ç' - 200: 122, # 'È' - 201: 98, # 'É' - 202: 92, # 'Ê' - 203: 121, # 'Ë' - 204: 120, # 'Ì' - 205: 91, # 'Í' - 206: 103, # 'Î' - 207: 119, # 'Ï' - 208: 68, # 'Ğ' - 209: 118, # 'Ñ' - 210: 117, # 'Ò' - 211: 97, # 'Ó' - 212: 116, # 'Ô' - 213: 115, # 'Õ' - 214: 50, # 'Ö' - 215: 90, # '×' - 216: 114, # 'Ø' - 217: 113, # 'Ù' - 218: 112, # 'Ú' - 219: 111, # 'Û' - 220: 55, # 'Ü' - 221: 41, # 'İ' - 222: 40, # 'Ş' - 223: 86, # 'ß' - 224: 89, # 'à' - 225: 70, # 'á' - 226: 59, # 'â' - 227: 78, # 'ã' - 228: 71, # 'ä' - 229: 82, # 'å' - 230: 88, # 'æ' - 231: 33, # 'ç' - 232: 77, # 'è' - 233: 66, # 'é' - 234: 84, # 'ê' - 235: 83, # 'ë' - 236: 110, # 'ì' - 237: 75, # 'í' - 238: 61, # 'î' - 239: 96, # 'ï' - 240: 30, # 'ğ' - 241: 67, # 'ñ' - 242: 109, # 'ò' - 243: 74, # 'ó' - 244: 87, # 'ô' - 245: 102, # 'õ' - 246: 34, # 'ö' - 247: 95, # '÷' - 248: 81, # 'ø' - 249: 108, # 'ù' - 250: 76, # 'ú' - 251: 72, # 'û' - 252: 17, # 'ü' - 253: 6, # 'ı' - 254: 19, # 'ş' - 255: 107, # 'ÿ' + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 255, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 255, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 255, # ' ' + 33: 255, # '!' + 34: 255, # '"' + 35: 255, # '#' + 36: 255, # '$' + 37: 255, # '%' + 38: 255, # '&' + 39: 255, # "'" + 40: 255, # '(' + 41: 255, # ')' + 42: 255, # '*' + 43: 255, # '+' + 44: 255, # ',' + 45: 255, # '-' + 46: 255, # '.' + 47: 255, # '/' + 48: 255, # '0' + 49: 255, # '1' + 50: 255, # '2' + 51: 255, # '3' + 52: 255, # '4' + 53: 255, # '5' + 54: 255, # '6' + 55: 255, # '7' + 56: 255, # '8' + 57: 255, # '9' + 58: 255, # ':' + 59: 255, # ';' + 60: 255, # '<' + 61: 255, # '=' + 62: 255, # '>' + 63: 255, # '?' + 64: 255, # '@' + 65: 23, # 'A' + 66: 37, # 'B' + 67: 47, # 'C' + 68: 39, # 'D' + 69: 29, # 'E' + 70: 52, # 'F' + 71: 36, # 'G' + 72: 45, # 'H' + 73: 53, # 'I' + 74: 60, # 'J' + 75: 16, # 'K' + 76: 49, # 'L' + 77: 20, # 'M' + 78: 46, # 'N' + 79: 42, # 'O' + 80: 48, # 'P' + 81: 69, # 'Q' + 82: 44, # 'R' + 83: 35, # 'S' + 84: 31, # 'T' + 85: 51, # 'U' + 86: 38, # 'V' + 87: 62, # 'W' + 88: 65, # 'X' + 89: 43, # 'Y' + 90: 56, # 'Z' + 91: 255, # '[' + 92: 255, # '\\' + 93: 255, # ']' + 94: 255, # '^' + 95: 255, # '_' + 96: 255, # '`' + 97: 1, # 'a' + 98: 21, # 'b' + 99: 28, # 'c' + 100: 12, # 'd' + 101: 2, # 'e' + 102: 18, # 'f' + 103: 27, # 'g' + 104: 25, # 'h' + 105: 3, # 'i' + 106: 24, # 'j' + 107: 10, # 'k' + 108: 5, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 15, # 'o' + 112: 26, # 'p' + 113: 64, # 'q' + 114: 7, # 'r' + 115: 8, # 's' + 116: 9, # 't' + 117: 14, # 'u' + 118: 32, # 'v' + 119: 57, # 'w' + 120: 58, # 'x' + 121: 11, # 'y' + 122: 22, # 'z' + 123: 255, # '{' + 124: 255, # '|' + 125: 255, # '}' + 126: 255, # '~' + 127: 255, # '\x7f' + 128: 180, # '\x80' + 129: 179, # '\x81' + 130: 178, # '\x82' + 131: 177, # '\x83' + 132: 176, # '\x84' + 133: 175, # '\x85' + 134: 174, # '\x86' + 135: 173, # '\x87' + 136: 172, # '\x88' + 137: 171, # '\x89' + 138: 170, # '\x8a' + 139: 169, # '\x8b' + 140: 168, # '\x8c' + 141: 167, # '\x8d' + 142: 166, # '\x8e' + 143: 165, # '\x8f' + 144: 164, # '\x90' + 145: 163, # '\x91' + 146: 162, # '\x92' + 147: 161, # '\x93' + 148: 160, # '\x94' + 149: 159, # '\x95' + 150: 101, # '\x96' + 151: 158, # '\x97' + 152: 157, # '\x98' + 153: 156, # '\x99' + 154: 155, # '\x9a' + 155: 154, # '\x9b' + 156: 153, # '\x9c' + 157: 152, # '\x9d' + 158: 151, # '\x9e' + 159: 106, # '\x9f' + 160: 150, # '\xa0' + 161: 149, # '¡' + 162: 148, # '¢' + 163: 147, # '£' + 164: 146, # '¤' + 165: 145, # '¥' + 166: 144, # '¦' + 167: 100, # '§' + 168: 143, # '¨' + 169: 142, # '©' + 170: 141, # 'ª' + 171: 140, # '«' + 172: 139, # '¬' + 173: 138, # '\xad' + 174: 137, # '®' + 175: 136, # '¯' + 176: 94, # '°' + 177: 80, # '±' + 178: 93, # '²' + 179: 135, # '³' + 180: 105, # '´' + 181: 134, # 'µ' + 182: 133, # '¶' + 183: 63, # '·' + 184: 132, # '¸' + 185: 131, # '¹' + 186: 130, # 'º' + 187: 129, # '»' + 188: 128, # '¼' + 189: 127, # '½' + 190: 126, # '¾' + 191: 125, # '¿' + 192: 124, # 'À' + 193: 104, # 'Á' + 194: 73, # 'Â' + 195: 99, # 'Ã' + 196: 79, # 'Ä' + 197: 85, # 'Å' + 198: 123, # 'Æ' + 199: 54, # 'Ç' + 200: 122, # 'È' + 201: 98, # 'É' + 202: 92, # 'Ê' + 203: 121, # 'Ë' + 204: 120, # 'Ì' + 205: 91, # 'Í' + 206: 103, # 'Î' + 207: 119, # 'Ï' + 208: 68, # 'Ğ' + 209: 118, # 'Ñ' + 210: 117, # 'Ò' + 211: 97, # 'Ó' + 212: 116, # 'Ô' + 213: 115, # 'Õ' + 214: 50, # 'Ö' + 215: 90, # '×' + 216: 114, # 'Ø' + 217: 113, # 'Ù' + 218: 112, # 'Ú' + 219: 111, # 'Û' + 220: 55, # 'Ü' + 221: 41, # 'İ' + 222: 40, # 'Ş' + 223: 86, # 'ß' + 224: 89, # 'à' + 225: 70, # 'á' + 226: 59, # 'â' + 227: 78, # 'ã' + 228: 71, # 'ä' + 229: 82, # 'å' + 230: 88, # 'æ' + 231: 33, # 'ç' + 232: 77, # 'è' + 233: 66, # 'é' + 234: 84, # 'ê' + 235: 83, # 'ë' + 236: 110, # 'ì' + 237: 75, # 'í' + 238: 61, # 'î' + 239: 96, # 'ï' + 240: 30, # 'ğ' + 241: 67, # 'ñ' + 242: 109, # 'ò' + 243: 74, # 'ó' + 244: 87, # 'ô' + 245: 102, # 'õ' + 246: 34, # 'ö' + 247: 95, # '÷' + 248: 81, # 'ø' + 249: 108, # 'ù' + 250: 76, # 'ú' + 251: 72, # 'û' + 252: 17, # 'ü' + 253: 6, # 'ı' + 254: 19, # 'ş' + 255: 107, # 'ÿ' } -ISO_8859_9_TURKISH_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-9', - language='Turkish', - char_to_order_map=ISO_8859_9_TURKISH_CHAR_TO_ORDER, - language_model=TURKISH_LANG_MODEL, - typical_positive_ratio=0.97029, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVYZabcdefghijklmnoprstuvyzÂÇÎÖÛÜâçîöûüĞğİıŞş') - +ISO_8859_9_TURKISH_MODEL = SingleByteCharSetModel( + charset_name="ISO-8859-9", + language="Turkish", + char_to_order_map=ISO_8859_9_TURKISH_CHAR_TO_ORDER, + language_model=TURKISH_LANG_MODEL, + typical_positive_ratio=0.97029, + keep_ascii_letters=True, + alphabet="ABCDEFGHIJKLMNOPRSTUVYZabcdefghijklmnoprstuvyzÂÇÎÖÛÜâçîöûüĞğİıŞş", +) diff --git a/script.module.chardet/lib/chardet/latin1prober.py b/script.module.chardet/lib/chardet/latin1prober.py index 7d1e8c20f..59a01d91b 100644 --- a/script.module.chardet/lib/chardet/latin1prober.py +++ b/script.module.chardet/lib/chardet/latin1prober.py @@ -26,6 +26,8 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from typing import List, Union + from .charsetprober import CharSetProber from .enums import ProbingState @@ -41,6 +43,7 @@ ASO = 7 # accent small other CLASS_NUM = 8 # total classes +# fmt: off Latin1_CharToClass = ( OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F @@ -91,34 +94,34 @@ 0, 3, 1, 3, 1, 1, 1, 3, # ASV 0, 3, 1, 3, 1, 1, 3, 3, # ASO ) +# fmt: on class Latin1Prober(CharSetProber): - def __init__(self): - super(Latin1Prober, self).__init__() - self._last_char_class = None - self._freq_counter = None + def __init__(self) -> None: + super().__init__() + self._last_char_class = OTH + self._freq_counter: List[int] = [] self.reset() - def reset(self): + def reset(self) -> None: self._last_char_class = OTH self._freq_counter = [0] * FREQ_CAT_NUM - CharSetProber.reset(self) + super().reset() @property - def charset_name(self): + def charset_name(self) -> str: return "ISO-8859-1" @property - def language(self): + def language(self) -> str: return "" - def feed(self, byte_str): - byte_str = self.filter_with_english_letters(byte_str) + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: + byte_str = self.remove_xml_tags(byte_str) for c in byte_str: char_class = Latin1_CharToClass[c] - freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) - + char_class] + freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) + char_class] if freq == 0: self._state = ProbingState.NOT_ME break @@ -127,19 +130,18 @@ def feed(self, byte_str): return self.state - def get_confidence(self): + def get_confidence(self) -> float: if self.state == ProbingState.NOT_ME: return 0.01 total = sum(self._freq_counter) - if total < 0.01: - confidence = 0.0 - else: - confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) - / total) - if confidence < 0.0: - confidence = 0.0 + confidence = ( + 0.0 + if total < 0.01 + else (self._freq_counter[3] - self._freq_counter[1] * 20.0) / total + ) + confidence = max(confidence, 0.0) # lower the confidence of latin1 so that other more accurate # detector can take priority. - confidence = confidence * 0.73 + confidence *= 0.73 return confidence diff --git a/script.module.chardet/lib/chardet/macromanprober.py b/script.module.chardet/lib/chardet/macromanprober.py new file mode 100644 index 000000000..1425d10ec --- /dev/null +++ b/script.module.chardet/lib/chardet/macromanprober.py @@ -0,0 +1,162 @@ +######################## BEGIN LICENSE BLOCK ######################## +# This code was modified from latin1prober.py by Rob Speer . +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Rob Speer - adapt to MacRoman encoding +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from typing import List, Union + +from .charsetprober import CharSetProber +from .enums import ProbingState + +FREQ_CAT_NUM = 4 + +UDF = 0 # undefined +OTH = 1 # other +ASC = 2 # ascii capital letter +ASS = 3 # ascii small letter +ACV = 4 # accent capital vowel +ACO = 5 # accent capital other +ASV = 6 # accent small vowel +ASO = 7 # accent small other +ODD = 8 # character that is unlikely to appear +CLASS_NUM = 9 # total classes + +# The change from Latin1 is that we explicitly look for extended characters +# that are infrequently-occurring symbols, and consider them to always be +# improbable. This should let MacRoman get out of the way of more likely +# encodings in most situations. + +# fmt: off +MacRoman_CharToClass = ( + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F + ACV, ACV, ACO, ACV, ACO, ACV, ACV, ASV, # 80 - 87 + ASV, ASV, ASV, ASV, ASV, ASO, ASV, ASV, # 88 - 8F + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASV, # 90 - 97 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, ASO, # A0 - A7 + OTH, OTH, ODD, ODD, OTH, OTH, ACV, ACV, # A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, ASV, ASV, # B8 - BF + OTH, OTH, ODD, OTH, ODD, OTH, OTH, OTH, # C0 - C7 + OTH, OTH, OTH, ACV, ACV, ACV, ACV, ASV, # C8 - CF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, ODD, # D0 - D7 + ASV, ACV, ODD, OTH, OTH, OTH, OTH, OTH, # D8 - DF + OTH, OTH, OTH, OTH, OTH, ACV, ACV, ACV, # E0 - E7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # E8 - EF + ODD, ACV, ACV, ACV, ACV, ASV, ODD, ODD, # F0 - F7 + ODD, ODD, ODD, ODD, ODD, ODD, ODD, ODD, # F8 - FF +) + +# 0 : illegal +# 1 : very unlikely +# 2 : normal +# 3 : very likely +MacRomanClassModel = ( +# UDF OTH ASC ASS ACV ACO ASV ASO ODD + 0, 0, 0, 0, 0, 0, 0, 0, 0, # UDF + 0, 3, 3, 3, 3, 3, 3, 3, 1, # OTH + 0, 3, 3, 3, 3, 3, 3, 3, 1, # ASC + 0, 3, 3, 3, 1, 1, 3, 3, 1, # ASS + 0, 3, 3, 3, 1, 2, 1, 2, 1, # ACV + 0, 3, 3, 3, 3, 3, 3, 3, 1, # ACO + 0, 3, 1, 3, 1, 1, 1, 3, 1, # ASV + 0, 3, 1, 3, 1, 1, 3, 3, 1, # ASO + 0, 1, 1, 1, 1, 1, 1, 1, 1, # ODD +) +# fmt: on + + +class MacRomanProber(CharSetProber): + def __init__(self) -> None: + super().__init__() + self._last_char_class = OTH + self._freq_counter: List[int] = [] + self.reset() + + def reset(self) -> None: + self._last_char_class = OTH + self._freq_counter = [0] * FREQ_CAT_NUM + + # express the prior that MacRoman is a somewhat rare encoding; + # this can be done by starting out in a slightly improbable state + # that must be overcome + self._freq_counter[2] = 10 + + super().reset() + + @property + def charset_name(self) -> str: + return "MacRoman" + + @property + def language(self) -> str: + return "" + + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: + byte_str = self.remove_xml_tags(byte_str) + for c in byte_str: + char_class = MacRoman_CharToClass[c] + freq = MacRomanClassModel[(self._last_char_class * CLASS_NUM) + char_class] + if freq == 0: + self._state = ProbingState.NOT_ME + break + self._freq_counter[freq] += 1 + self._last_char_class = char_class + + return self.state + + def get_confidence(self) -> float: + if self.state == ProbingState.NOT_ME: + return 0.01 + + total = sum(self._freq_counter) + confidence = ( + 0.0 + if total < 0.01 + else (self._freq_counter[3] - self._freq_counter[1] * 20.0) / total + ) + confidence = max(confidence, 0.0) + # lower the confidence of MacRoman so that other more accurate + # detector can take priority. + confidence *= 0.73 + return confidence diff --git a/script.module.chardet/lib/chardet/mbcharsetprober.py b/script.module.chardet/lib/chardet/mbcharsetprober.py index 6256ecfd1..666307e8f 100644 --- a/script.module.chardet/lib/chardet/mbcharsetprober.py +++ b/script.module.chardet/lib/chardet/mbcharsetprober.py @@ -27,8 +27,12 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from typing import Optional, Union + +from .chardistribution import CharDistributionAnalysis from .charsetprober import CharSetProber -from .enums import ProbingState, MachineState +from .codingstatemachine import CodingStateMachine +from .enums import LanguageFilter, MachineState, ProbingState class MultiByteCharSetProber(CharSetProber): @@ -36,56 +40,56 @@ class MultiByteCharSetProber(CharSetProber): MultiByteCharSetProber """ - def __init__(self, lang_filter=None): - super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) - self.distribution_analyzer = None - self.coding_sm = None - self._last_char = [0, 0] + def __init__(self, lang_filter: LanguageFilter = LanguageFilter.NONE) -> None: + super().__init__(lang_filter=lang_filter) + self.distribution_analyzer: Optional[CharDistributionAnalysis] = None + self.coding_sm: Optional[CodingStateMachine] = None + self._last_char = bytearray(b"\0\0") - def reset(self): - super(MultiByteCharSetProber, self).reset() + def reset(self) -> None: + super().reset() if self.coding_sm: self.coding_sm.reset() if self.distribution_analyzer: self.distribution_analyzer.reset() - self._last_char = [0, 0] - - @property - def charset_name(self): - raise NotImplementedError + self._last_char = bytearray(b"\0\0") - @property - def language(self): - raise NotImplementedError + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: + assert self.coding_sm is not None + assert self.distribution_analyzer is not None - def feed(self, byte_str): - for i in range(len(byte_str)): - coding_state = self.coding_sm.next_state(byte_str[i]) + for i, byte in enumerate(byte_str): + coding_state = self.coding_sm.next_state(byte) if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) + self.logger.debug( + "%s %s prober hit error at byte %s", + self.charset_name, + self.language, + i, + ) self._state = ProbingState.NOT_ME break - elif coding_state == MachineState.ITS_ME: + if coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break - elif coding_state == MachineState.START: + if coding_state == MachineState.START: char_len = self.coding_sm.get_current_charlen() if i == 0: - self._last_char[1] = byte_str[0] + self._last_char[1] = byte self.distribution_analyzer.feed(self._last_char, char_len) else: - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) + self.distribution_analyzer.feed(byte_str[i - 1 : i + 1], char_len) self._last_char[0] = byte_str[-1] if self.state == ProbingState.DETECTING: - if (self.distribution_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + if self.distribution_analyzer.got_enough_data() and ( + self.get_confidence() > self.SHORTCUT_THRESHOLD + ): self._state = ProbingState.FOUND_IT return self.state - def get_confidence(self): + def get_confidence(self) -> float: + assert self.distribution_analyzer is not None return self.distribution_analyzer.get_confidence() diff --git a/script.module.chardet/lib/chardet/mbcsgroupprober.py b/script.module.chardet/lib/chardet/mbcsgroupprober.py index 530abe75e..6cb9cc7b3 100644 --- a/script.module.chardet/lib/chardet/mbcsgroupprober.py +++ b/script.module.chardet/lib/chardet/mbcsgroupprober.py @@ -27,20 +27,22 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from .big5prober import Big5Prober from .charsetgroupprober import CharSetGroupProber -from .utf8prober import UTF8Prober -from .sjisprober import SJISProber +from .cp949prober import CP949Prober +from .enums import LanguageFilter from .eucjpprober import EUCJPProber -from .gb2312prober import GB2312Prober from .euckrprober import EUCKRProber -from .cp949prober import CP949Prober -from .big5prober import Big5Prober from .euctwprober import EUCTWProber +from .gb2312prober import GB2312Prober +from .johabprober import JOHABProber +from .sjisprober import SJISProber +from .utf8prober import UTF8Prober class MBCSGroupProber(CharSetGroupProber): - def __init__(self, lang_filter=None): - super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) + def __init__(self, lang_filter: LanguageFilter = LanguageFilter.NONE) -> None: + super().__init__(lang_filter=lang_filter) self.probers = [ UTF8Prober(), SJISProber(), @@ -49,6 +51,7 @@ def __init__(self, lang_filter=None): EUCKRProber(), CP949Prober(), Big5Prober(), - EUCTWProber() + EUCTWProber(), + JOHABProber(), ] self.reset() diff --git a/script.module.chardet/lib/chardet/mbcssm.py b/script.module.chardet/lib/chardet/mbcssm.py index 8360d0f28..7bbe97e66 100644 --- a/script.module.chardet/lib/chardet/mbcssm.py +++ b/script.module.chardet/lib/chardet/mbcssm.py @@ -25,43 +25,45 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from .codingstatemachinedict import CodingStateMachineDict from .enums import MachineState # BIG5 +# fmt: off BIG5_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,1, # 78 - 7f - 4,4,4,4,4,4,4,4, # 80 - 87 - 4,4,4,4,4,4,4,4, # 88 - 8f - 4,4,4,4,4,4,4,4, # 90 - 97 - 4,4,4,4,4,4,4,4, # 98 - 9f - 4,3,3,3,3,3,3,3, # a0 - a7 - 3,3,3,3,3,3,3,3, # a8 - af - 3,3,3,3,3,3,3,3, # b0 - b7 - 3,3,3,3,3,3,3,3, # b8 - bf - 3,3,3,3,3,3,3,3, # c0 - c7 - 3,3,3,3,3,3,3,3, # c8 - cf - 3,3,3,3,3,3,3,3, # d0 - d7 - 3,3,3,3,3,3,3,3, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,3,3,3, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,3,3,0 # f8 - ff + 1, 1, 1, 1, 1, 1, 1, 1, # 00 - 07 #allow 0x00 as legal value + 1, 1, 1, 1, 1, 1, 0, 0, # 08 - 0f + 1, 1, 1, 1, 1, 1, 1, 1, # 10 - 17 + 1, 1, 1, 0, 1, 1, 1, 1, # 18 - 1f + 1, 1, 1, 1, 1, 1, 1, 1, # 20 - 27 + 1, 1, 1, 1, 1, 1, 1, 1, # 28 - 2f + 1, 1, 1, 1, 1, 1, 1, 1, # 30 - 37 + 1, 1, 1, 1, 1, 1, 1, 1, # 38 - 3f + 2, 2, 2, 2, 2, 2, 2, 2, # 40 - 47 + 2, 2, 2, 2, 2, 2, 2, 2, # 48 - 4f + 2, 2, 2, 2, 2, 2, 2, 2, # 50 - 57 + 2, 2, 2, 2, 2, 2, 2, 2, # 58 - 5f + 2, 2, 2, 2, 2, 2, 2, 2, # 60 - 67 + 2, 2, 2, 2, 2, 2, 2, 2, # 68 - 6f + 2, 2, 2, 2, 2, 2, 2, 2, # 70 - 77 + 2, 2, 2, 2, 2, 2, 2, 1, # 78 - 7f + 4, 4, 4, 4, 4, 4, 4, 4, # 80 - 87 + 4, 4, 4, 4, 4, 4, 4, 4, # 88 - 8f + 4, 4, 4, 4, 4, 4, 4, 4, # 90 - 97 + 4, 4, 4, 4, 4, 4, 4, 4, # 98 - 9f + 4, 3, 3, 3, 3, 3, 3, 3, # a0 - a7 + 3, 3, 3, 3, 3, 3, 3, 3, # a8 - af + 3, 3, 3, 3, 3, 3, 3, 3, # b0 - b7 + 3, 3, 3, 3, 3, 3, 3, 3, # b8 - bf + 3, 3, 3, 3, 3, 3, 3, 3, # c0 - c7 + 3, 3, 3, 3, 3, 3, 3, 3, # c8 - cf + 3, 3, 3, 3, 3, 3, 3, 3, # d0 - d7 + 3, 3, 3, 3, 3, 3, 3, 3, # d8 - df + 3, 3, 3, 3, 3, 3, 3, 3, # e0 - e7 + 3, 3, 3, 3, 3, 3, 3, 3, # e8 - ef + 3, 3, 3, 3, 3, 3, 3, 3, # f0 - f7 + 3, 3, 3, 3, 3, 3, 3, 0 # f8 - ff ) BIG5_ST = ( @@ -69,34 +71,37 @@ MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 ) +# fmt: on BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) -BIG5_SM_MODEL = {'class_table': BIG5_CLS, - 'class_factor': 5, - 'state_table': BIG5_ST, - 'char_len_table': BIG5_CHAR_LEN_TABLE, - 'name': 'Big5'} +BIG5_SM_MODEL: CodingStateMachineDict = { + "class_table": BIG5_CLS, + "class_factor": 5, + "state_table": BIG5_ST, + "char_len_table": BIG5_CHAR_LEN_TABLE, + "name": "Big5", +} # CP949 - +# fmt: off CP949_CLS = ( - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f - 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f - 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f - 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f - 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f - 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f - 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f - 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f - 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af - 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf - 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, # 00 - 0f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, # 10 - 1f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 20 - 2f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 30 - 3f + 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, # 40 - 4f + 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, # 50 - 5f + 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, # 60 - 6f + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, # 70 - 7f + 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, # 80 - 8f + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, # 90 - 9f + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, # a0 - af + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, # b0 - bf + 7, 7, 7, 7, 7, 7, 9, 2, 2, 3, 2, 2, 2, 2, 2, 2, # c0 - cf + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, # d0 - df + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, # e0 - ef + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, # f0 - ff ) CP949_ST = ( @@ -109,50 +114,53 @@ MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 ) +# fmt: on CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) -CP949_SM_MODEL = {'class_table': CP949_CLS, - 'class_factor': 10, - 'state_table': CP949_ST, - 'char_len_table': CP949_CHAR_LEN_TABLE, - 'name': 'CP949'} +CP949_SM_MODEL: CodingStateMachineDict = { + "class_table": CP949_CLS, + "class_factor": 10, + "state_table": CP949_ST, + "char_len_table": CP949_CHAR_LEN_TABLE, + "name": "CP949", +} # EUC-JP - +# fmt: off EUCJP_CLS = ( - 4,4,4,4,4,4,4,4, # 00 - 07 - 4,4,4,4,4,4,5,5, # 08 - 0f - 4,4,4,4,4,4,4,4, # 10 - 17 - 4,4,4,5,4,4,4,4, # 18 - 1f - 4,4,4,4,4,4,4,4, # 20 - 27 - 4,4,4,4,4,4,4,4, # 28 - 2f - 4,4,4,4,4,4,4,4, # 30 - 37 - 4,4,4,4,4,4,4,4, # 38 - 3f - 4,4,4,4,4,4,4,4, # 40 - 47 - 4,4,4,4,4,4,4,4, # 48 - 4f - 4,4,4,4,4,4,4,4, # 50 - 57 - 4,4,4,4,4,4,4,4, # 58 - 5f - 4,4,4,4,4,4,4,4, # 60 - 67 - 4,4,4,4,4,4,4,4, # 68 - 6f - 4,4,4,4,4,4,4,4, # 70 - 77 - 4,4,4,4,4,4,4,4, # 78 - 7f - 5,5,5,5,5,5,5,5, # 80 - 87 - 5,5,5,5,5,5,1,3, # 88 - 8f - 5,5,5,5,5,5,5,5, # 90 - 97 - 5,5,5,5,5,5,5,5, # 98 - 9f - 5,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,2,2,2, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,2,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,0,5 # f8 - ff + 4, 4, 4, 4, 4, 4, 4, 4, # 00 - 07 + 4, 4, 4, 4, 4, 4, 5, 5, # 08 - 0f + 4, 4, 4, 4, 4, 4, 4, 4, # 10 - 17 + 4, 4, 4, 5, 4, 4, 4, 4, # 18 - 1f + 4, 4, 4, 4, 4, 4, 4, 4, # 20 - 27 + 4, 4, 4, 4, 4, 4, 4, 4, # 28 - 2f + 4, 4, 4, 4, 4, 4, 4, 4, # 30 - 37 + 4, 4, 4, 4, 4, 4, 4, 4, # 38 - 3f + 4, 4, 4, 4, 4, 4, 4, 4, # 40 - 47 + 4, 4, 4, 4, 4, 4, 4, 4, # 48 - 4f + 4, 4, 4, 4, 4, 4, 4, 4, # 50 - 57 + 4, 4, 4, 4, 4, 4, 4, 4, # 58 - 5f + 4, 4, 4, 4, 4, 4, 4, 4, # 60 - 67 + 4, 4, 4, 4, 4, 4, 4, 4, # 68 - 6f + 4, 4, 4, 4, 4, 4, 4, 4, # 70 - 77 + 4, 4, 4, 4, 4, 4, 4, 4, # 78 - 7f + 5, 5, 5, 5, 5, 5, 5, 5, # 80 - 87 + 5, 5, 5, 5, 5, 5, 1, 3, # 88 - 8f + 5, 5, 5, 5, 5, 5, 5, 5, # 90 - 97 + 5, 5, 5, 5, 5, 5, 5, 5, # 98 - 9f + 5, 2, 2, 2, 2, 2, 2, 2, # a0 - a7 + 2, 2, 2, 2, 2, 2, 2, 2, # a8 - af + 2, 2, 2, 2, 2, 2, 2, 2, # b0 - b7 + 2, 2, 2, 2, 2, 2, 2, 2, # b8 - bf + 2, 2, 2, 2, 2, 2, 2, 2, # c0 - c7 + 2, 2, 2, 2, 2, 2, 2, 2, # c8 - cf + 2, 2, 2, 2, 2, 2, 2, 2, # d0 - d7 + 2, 2, 2, 2, 2, 2, 2, 2, # d8 - df + 0, 0, 0, 0, 0, 0, 0, 0, # e0 - e7 + 0, 0, 0, 0, 0, 0, 0, 0, # e8 - ef + 0, 0, 0, 0, 0, 0, 0, 0, # f0 - f7 + 0, 0, 0, 0, 0, 0, 0, 5 # f8 - ff ) EUCJP_ST = ( @@ -162,100 +170,163 @@ MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 ) +# fmt: on EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) -EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, - 'class_factor': 6, - 'state_table': EUCJP_ST, - 'char_len_table': EUCJP_CHAR_LEN_TABLE, - 'name': 'EUC-JP'} +EUCJP_SM_MODEL: CodingStateMachineDict = { + "class_table": EUCJP_CLS, + "class_factor": 6, + "state_table": EUCJP_ST, + "char_len_table": EUCJP_CHAR_LEN_TABLE, + "name": "EUC-JP", +} # EUC-KR - +# fmt: off EUCKR_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 1,1,1,1,1,1,1,1, # 40 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, # 00 - 07 + 1, 1, 1, 1, 1, 1, 0, 0, # 08 - 0f + 1, 1, 1, 1, 1, 1, 1, 1, # 10 - 17 + 1, 1, 1, 0, 1, 1, 1, 1, # 18 - 1f + 1, 1, 1, 1, 1, 1, 1, 1, # 20 - 27 + 1, 1, 1, 1, 1, 1, 1, 1, # 28 - 2f + 1, 1, 1, 1, 1, 1, 1, 1, # 30 - 37 + 1, 1, 1, 1, 1, 1, 1, 1, # 38 - 3f + 1, 1, 1, 1, 1, 1, 1, 1, # 40 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, # 48 - 4f + 1, 1, 1, 1, 1, 1, 1, 1, # 50 - 57 + 1, 1, 1, 1, 1, 1, 1, 1, # 58 - 5f + 1, 1, 1, 1, 1, 1, 1, 1, # 60 - 67 + 1, 1, 1, 1, 1, 1, 1, 1, # 68 - 6f + 1, 1, 1, 1, 1, 1, 1, 1, # 70 - 77 + 1, 1, 1, 1, 1, 1, 1, 1, # 78 - 7f + 0, 0, 0, 0, 0, 0, 0, 0, # 80 - 87 + 0, 0, 0, 0, 0, 0, 0, 0, # 88 - 8f + 0, 0, 0, 0, 0, 0, 0, 0, # 90 - 97 + 0, 0, 0, 0, 0, 0, 0, 0, # 98 - 9f + 0, 2, 2, 2, 2, 2, 2, 2, # a0 - a7 + 2, 2, 2, 2, 2, 3, 3, 3, # a8 - af + 2, 2, 2, 2, 2, 2, 2, 2, # b0 - b7 + 2, 2, 2, 2, 2, 2, 2, 2, # b8 - bf + 2, 2, 2, 2, 2, 2, 2, 2, # c0 - c7 + 2, 3, 2, 2, 2, 2, 2, 2, # c8 - cf + 2, 2, 2, 2, 2, 2, 2, 2, # d0 - d7 + 2, 2, 2, 2, 2, 2, 2, 2, # d8 - df + 2, 2, 2, 2, 2, 2, 2, 2, # e0 - e7 + 2, 2, 2, 2, 2, 2, 2, 2, # e8 - ef + 2, 2, 2, 2, 2, 2, 2, 2, # f0 - f7 + 2, 2, 2, 2, 2, 2, 2, 0 # f8 - ff +) + +EUCKR_ST = ( + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f +) +# fmt: on + +EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) + +EUCKR_SM_MODEL: CodingStateMachineDict = { + "class_table": EUCKR_CLS, + "class_factor": 4, + "state_table": EUCKR_ST, + "char_len_table": EUCKR_CHAR_LEN_TABLE, + "name": "EUC-KR", +} + +# JOHAB +# fmt: off +JOHAB_CLS = ( + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,0,0, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,0,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,3,3,3,3,3,3,3, # 30 - 37 + 3,3,3,3,3,3,3,3, # 38 - 3f + 3,1,1,1,1,1,1,1, # 40 - 47 1,1,1,1,1,1,1,1, # 48 - 4f 1,1,1,1,1,1,1,1, # 50 - 57 1,1,1,1,1,1,1,1, # 58 - 5f 1,1,1,1,1,1,1,1, # 60 - 67 1,1,1,1,1,1,1,1, # 68 - 6f 1,1,1,1,1,1,1,1, # 70 - 77 - 1,1,1,1,1,1,1,1, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,3,3,3, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,3,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 2,2,2,2,2,2,2,2, # e0 - e7 - 2,2,2,2,2,2,2,2, # e8 - ef - 2,2,2,2,2,2,2,2, # f0 - f7 - 2,2,2,2,2,2,2,0 # f8 - ff + 1,1,1,1,1,1,1,2, # 78 - 7f + 6,6,6,6,8,8,8,8, # 80 - 87 + 8,8,8,8,8,8,8,8, # 88 - 8f + 8,7,7,7,7,7,7,7, # 90 - 97 + 7,7,7,7,7,7,7,7, # 98 - 9f + 7,7,7,7,7,7,7,7, # a0 - a7 + 7,7,7,7,7,7,7,7, # a8 - af + 7,7,7,7,7,7,7,7, # b0 - b7 + 7,7,7,7,7,7,7,7, # b8 - bf + 7,7,7,7,7,7,7,7, # c0 - c7 + 7,7,7,7,7,7,7,7, # c8 - cf + 7,7,7,7,5,5,5,5, # d0 - d7 + 5,9,9,9,9,9,9,5, # d8 - df + 9,9,9,9,9,9,9,9, # e0 - e7 + 9,9,9,9,9,9,9,9, # e8 - ef + 9,9,9,9,9,9,9,9, # f0 - f7 + 9,9,5,5,5,5,5,0 # f8 - ff ) -EUCKR_ST = ( - MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f +JOHAB_ST = ( +# cls = 0 1 2 3 4 5 6 7 8 9 + MachineState.ERROR ,MachineState.START ,MachineState.START ,MachineState.START ,MachineState.START ,MachineState.ERROR ,MachineState.ERROR ,3 ,3 ,4 , # MachineState.START + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME + MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR ,MachineState.ERROR , # MachineState.ERROR + MachineState.ERROR ,MachineState.START ,MachineState.START ,MachineState.ERROR ,MachineState.ERROR ,MachineState.START ,MachineState.START ,MachineState.START ,MachineState.START ,MachineState.START , # 3 + MachineState.ERROR ,MachineState.START ,MachineState.ERROR ,MachineState.START ,MachineState.ERROR ,MachineState.START ,MachineState.ERROR ,MachineState.START ,MachineState.ERROR ,MachineState.START , # 4 ) +# fmt: on -EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) +JOHAB_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 0, 0, 2, 2, 2) -EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, - 'class_factor': 4, - 'state_table': EUCKR_ST, - 'char_len_table': EUCKR_CHAR_LEN_TABLE, - 'name': 'EUC-KR'} +JOHAB_SM_MODEL: CodingStateMachineDict = { + "class_table": JOHAB_CLS, + "class_factor": 10, + "state_table": JOHAB_ST, + "char_len_table": JOHAB_CHAR_LEN_TABLE, + "name": "Johab", +} # EUC-TW - +# fmt: off EUCTW_CLS = ( - 2,2,2,2,2,2,2,2, # 00 - 07 - 2,2,2,2,2,2,0,0, # 08 - 0f - 2,2,2,2,2,2,2,2, # 10 - 17 - 2,2,2,0,2,2,2,2, # 18 - 1f - 2,2,2,2,2,2,2,2, # 20 - 27 - 2,2,2,2,2,2,2,2, # 28 - 2f - 2,2,2,2,2,2,2,2, # 30 - 37 - 2,2,2,2,2,2,2,2, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,2, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,6,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,3,4,4,4,4,4,4, # a0 - a7 - 5,5,1,1,1,1,1,1, # a8 - af - 1,1,1,1,1,1,1,1, # b0 - b7 - 1,1,1,1,1,1,1,1, # b8 - bf - 1,1,3,1,3,3,3,3, # c0 - c7 - 3,3,3,3,3,3,3,3, # c8 - cf - 3,3,3,3,3,3,3,3, # d0 - d7 - 3,3,3,3,3,3,3,3, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,3,3,3, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,3,3,0 # f8 - ff + 2, 2, 2, 2, 2, 2, 2, 2, # 00 - 07 + 2, 2, 2, 2, 2, 2, 0, 0, # 08 - 0f + 2, 2, 2, 2, 2, 2, 2, 2, # 10 - 17 + 2, 2, 2, 0, 2, 2, 2, 2, # 18 - 1f + 2, 2, 2, 2, 2, 2, 2, 2, # 20 - 27 + 2, 2, 2, 2, 2, 2, 2, 2, # 28 - 2f + 2, 2, 2, 2, 2, 2, 2, 2, # 30 - 37 + 2, 2, 2, 2, 2, 2, 2, 2, # 38 - 3f + 2, 2, 2, 2, 2, 2, 2, 2, # 40 - 47 + 2, 2, 2, 2, 2, 2, 2, 2, # 48 - 4f + 2, 2, 2, 2, 2, 2, 2, 2, # 50 - 57 + 2, 2, 2, 2, 2, 2, 2, 2, # 58 - 5f + 2, 2, 2, 2, 2, 2, 2, 2, # 60 - 67 + 2, 2, 2, 2, 2, 2, 2, 2, # 68 - 6f + 2, 2, 2, 2, 2, 2, 2, 2, # 70 - 77 + 2, 2, 2, 2, 2, 2, 2, 2, # 78 - 7f + 0, 0, 0, 0, 0, 0, 0, 0, # 80 - 87 + 0, 0, 0, 0, 0, 0, 6, 0, # 88 - 8f + 0, 0, 0, 0, 0, 0, 0, 0, # 90 - 97 + 0, 0, 0, 0, 0, 0, 0, 0, # 98 - 9f + 0, 3, 4, 4, 4, 4, 4, 4, # a0 - a7 + 5, 5, 1, 1, 1, 1, 1, 1, # a8 - af + 1, 1, 1, 1, 1, 1, 1, 1, # b0 - b7 + 1, 1, 1, 1, 1, 1, 1, 1, # b8 - bf + 1, 1, 3, 1, 3, 3, 3, 3, # c0 - c7 + 3, 3, 3, 3, 3, 3, 3, 3, # c8 - cf + 3, 3, 3, 3, 3, 3, 3, 3, # d0 - d7 + 3, 3, 3, 3, 3, 3, 3, 3, # d8 - df + 3, 3, 3, 3, 3, 3, 3, 3, # e0 - e7 + 3, 3, 3, 3, 3, 3, 3, 3, # e8 - ef + 3, 3, 3, 3, 3, 3, 3, 3, # f0 - f7 + 3, 3, 3, 3, 3, 3, 3, 0 # f8 - ff ) EUCTW_ST = ( @@ -266,50 +337,53 @@ 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f ) +# fmt: on EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) -EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, - 'class_factor': 7, - 'state_table': EUCTW_ST, - 'char_len_table': EUCTW_CHAR_LEN_TABLE, - 'name': 'x-euc-tw'} +EUCTW_SM_MODEL: CodingStateMachineDict = { + "class_table": EUCTW_CLS, + "class_factor": 7, + "state_table": EUCTW_ST, + "char_len_table": EUCTW_CHAR_LEN_TABLE, + "name": "x-euc-tw", +} # GB2312 - +# fmt: off GB2312_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 3,3,3,3,3,3,3,3, # 30 - 37 - 3,3,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,4, # 78 - 7f - 5,6,6,6,6,6,6,6, # 80 - 87 - 6,6,6,6,6,6,6,6, # 88 - 8f - 6,6,6,6,6,6,6,6, # 90 - 97 - 6,6,6,6,6,6,6,6, # 98 - 9f - 6,6,6,6,6,6,6,6, # a0 - a7 - 6,6,6,6,6,6,6,6, # a8 - af - 6,6,6,6,6,6,6,6, # b0 - b7 - 6,6,6,6,6,6,6,6, # b8 - bf - 6,6,6,6,6,6,6,6, # c0 - c7 - 6,6,6,6,6,6,6,6, # c8 - cf - 6,6,6,6,6,6,6,6, # d0 - d7 - 6,6,6,6,6,6,6,6, # d8 - df - 6,6,6,6,6,6,6,6, # e0 - e7 - 6,6,6,6,6,6,6,6, # e8 - ef - 6,6,6,6,6,6,6,6, # f0 - f7 - 6,6,6,6,6,6,6,0 # f8 - ff + 1, 1, 1, 1, 1, 1, 1, 1, # 00 - 07 + 1, 1, 1, 1, 1, 1, 0, 0, # 08 - 0f + 1, 1, 1, 1, 1, 1, 1, 1, # 10 - 17 + 1, 1, 1, 0, 1, 1, 1, 1, # 18 - 1f + 1, 1, 1, 1, 1, 1, 1, 1, # 20 - 27 + 1, 1, 1, 1, 1, 1, 1, 1, # 28 - 2f + 3, 3, 3, 3, 3, 3, 3, 3, # 30 - 37 + 3, 3, 1, 1, 1, 1, 1, 1, # 38 - 3f + 2, 2, 2, 2, 2, 2, 2, 2, # 40 - 47 + 2, 2, 2, 2, 2, 2, 2, 2, # 48 - 4f + 2, 2, 2, 2, 2, 2, 2, 2, # 50 - 57 + 2, 2, 2, 2, 2, 2, 2, 2, # 58 - 5f + 2, 2, 2, 2, 2, 2, 2, 2, # 60 - 67 + 2, 2, 2, 2, 2, 2, 2, 2, # 68 - 6f + 2, 2, 2, 2, 2, 2, 2, 2, # 70 - 77 + 2, 2, 2, 2, 2, 2, 2, 4, # 78 - 7f + 5, 6, 6, 6, 6, 6, 6, 6, # 80 - 87 + 6, 6, 6, 6, 6, 6, 6, 6, # 88 - 8f + 6, 6, 6, 6, 6, 6, 6, 6, # 90 - 97 + 6, 6, 6, 6, 6, 6, 6, 6, # 98 - 9f + 6, 6, 6, 6, 6, 6, 6, 6, # a0 - a7 + 6, 6, 6, 6, 6, 6, 6, 6, # a8 - af + 6, 6, 6, 6, 6, 6, 6, 6, # b0 - b7 + 6, 6, 6, 6, 6, 6, 6, 6, # b8 - bf + 6, 6, 6, 6, 6, 6, 6, 6, # c0 - c7 + 6, 6, 6, 6, 6, 6, 6, 6, # c8 - cf + 6, 6, 6, 6, 6, 6, 6, 6, # d0 - d7 + 6, 6, 6, 6, 6, 6, 6, 6, # d8 - df + 6, 6, 6, 6, 6, 6, 6, 6, # e0 - e7 + 6, 6, 6, 6, 6, 6, 6, 6, # e8 - ef + 6, 6, 6, 6, 6, 6, 6, 6, # f0 - f7 + 6, 6, 6, 6, 6, 6, 6, 0 # f8 - ff ) GB2312_ST = ( @@ -320,6 +394,7 @@ MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f ) +# fmt: on # To be accurate, the length of class 6 can be either 2 or 4. # But it is not necessary to discriminate between the two since @@ -328,100 +403,105 @@ # 2 here. GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) -GB2312_SM_MODEL = {'class_table': GB2312_CLS, - 'class_factor': 7, - 'state_table': GB2312_ST, - 'char_len_table': GB2312_CHAR_LEN_TABLE, - 'name': 'GB2312'} +GB2312_SM_MODEL: CodingStateMachineDict = { + "class_table": GB2312_CLS, + "class_factor": 7, + "state_table": GB2312_ST, + "char_len_table": GB2312_CHAR_LEN_TABLE, + "name": "GB2312", +} # Shift_JIS - +# fmt: off SJIS_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,1, # 78 - 7f - 3,3,3,3,3,2,2,3, # 80 - 87 - 3,3,3,3,3,3,3,3, # 88 - 8f - 3,3,3,3,3,3,3,3, # 90 - 97 - 3,3,3,3,3,3,3,3, # 98 - 9f + 1, 1, 1, 1, 1, 1, 1, 1, # 00 - 07 + 1, 1, 1, 1, 1, 1, 0, 0, # 08 - 0f + 1, 1, 1, 1, 1, 1, 1, 1, # 10 - 17 + 1, 1, 1, 0, 1, 1, 1, 1, # 18 - 1f + 1, 1, 1, 1, 1, 1, 1, 1, # 20 - 27 + 1, 1, 1, 1, 1, 1, 1, 1, # 28 - 2f + 1, 1, 1, 1, 1, 1, 1, 1, # 30 - 37 + 1, 1, 1, 1, 1, 1, 1, 1, # 38 - 3f + 2, 2, 2, 2, 2, 2, 2, 2, # 40 - 47 + 2, 2, 2, 2, 2, 2, 2, 2, # 48 - 4f + 2, 2, 2, 2, 2, 2, 2, 2, # 50 - 57 + 2, 2, 2, 2, 2, 2, 2, 2, # 58 - 5f + 2, 2, 2, 2, 2, 2, 2, 2, # 60 - 67 + 2, 2, 2, 2, 2, 2, 2, 2, # 68 - 6f + 2, 2, 2, 2, 2, 2, 2, 2, # 70 - 77 + 2, 2, 2, 2, 2, 2, 2, 1, # 78 - 7f + 3, 3, 3, 3, 3, 2, 2, 3, # 80 - 87 + 3, 3, 3, 3, 3, 3, 3, 3, # 88 - 8f + 3, 3, 3, 3, 3, 3, 3, 3, # 90 - 97 + 3, 3, 3, 3, 3, 3, 3, 3, # 98 - 9f #0xa0 is illegal in sjis encoding, but some pages does #contain such byte. We need to be more error forgiven. - 2,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,2,2,2, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,2,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,4,4,4, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,0,0,0) # f8 - ff - + 2, 2, 2, 2, 2, 2, 2, 2, # a0 - a7 + 2, 2, 2, 2, 2, 2, 2, 2, # a8 - af + 2, 2, 2, 2, 2, 2, 2, 2, # b0 - b7 + 2, 2, 2, 2, 2, 2, 2, 2, # b8 - bf + 2, 2, 2, 2, 2, 2, 2, 2, # c0 - c7 + 2, 2, 2, 2, 2, 2, 2, 2, # c8 - cf + 2, 2, 2, 2, 2, 2, 2, 2, # d0 - d7 + 2, 2, 2, 2, 2, 2, 2, 2, # d8 - df + 3, 3, 3, 3, 3, 3, 3, 3, # e0 - e7 + 3, 3, 3, 3, 3, 4, 4, 4, # e8 - ef + 3, 3, 3, 3, 3, 3, 3, 3, # f0 - f7 + 3, 3, 3, 3, 3, 0, 0, 0, # f8 - ff +) SJIS_ST = ( MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 ) +# fmt: on SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) -SJIS_SM_MODEL = {'class_table': SJIS_CLS, - 'class_factor': 6, - 'state_table': SJIS_ST, - 'char_len_table': SJIS_CHAR_LEN_TABLE, - 'name': 'Shift_JIS'} +SJIS_SM_MODEL: CodingStateMachineDict = { + "class_table": SJIS_CLS, + "class_factor": 6, + "state_table": SJIS_ST, + "char_len_table": SJIS_CHAR_LEN_TABLE, + "name": "Shift_JIS", +} # UCS2-BE - +# fmt: off UCS2BE_CLS = ( - 0,0,0,0,0,0,0,0, # 00 - 07 - 0,0,1,0,0,2,0,0, # 08 - 0f - 0,0,0,0,0,0,0,0, # 10 - 17 - 0,0,0,3,0,0,0,0, # 18 - 1f - 0,0,0,0,0,0,0,0, # 20 - 27 - 0,3,3,3,3,3,0,0, # 28 - 2f - 0,0,0,0,0,0,0,0, # 30 - 37 - 0,0,0,0,0,0,0,0, # 38 - 3f - 0,0,0,0,0,0,0,0, # 40 - 47 - 0,0,0,0,0,0,0,0, # 48 - 4f - 0,0,0,0,0,0,0,0, # 50 - 57 - 0,0,0,0,0,0,0,0, # 58 - 5f - 0,0,0,0,0,0,0,0, # 60 - 67 - 0,0,0,0,0,0,0,0, # 68 - 6f - 0,0,0,0,0,0,0,0, # 70 - 77 - 0,0,0,0,0,0,0,0, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,0,0,0,0,0,0,0, # a0 - a7 - 0,0,0,0,0,0,0,0, # a8 - af - 0,0,0,0,0,0,0,0, # b0 - b7 - 0,0,0,0,0,0,0,0, # b8 - bf - 0,0,0,0,0,0,0,0, # c0 - c7 - 0,0,0,0,0,0,0,0, # c8 - cf - 0,0,0,0,0,0,0,0, # d0 - d7 - 0,0,0,0,0,0,0,0, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,4,5 # f8 - ff + 0, 0, 0, 0, 0, 0, 0, 0, # 00 - 07 + 0, 0, 1, 0, 0, 2, 0, 0, # 08 - 0f + 0, 0, 0, 0, 0, 0, 0, 0, # 10 - 17 + 0, 0, 0, 3, 0, 0, 0, 0, # 18 - 1f + 0, 0, 0, 0, 0, 0, 0, 0, # 20 - 27 + 0, 3, 3, 3, 3, 3, 0, 0, # 28 - 2f + 0, 0, 0, 0, 0, 0, 0, 0, # 30 - 37 + 0, 0, 0, 0, 0, 0, 0, 0, # 38 - 3f + 0, 0, 0, 0, 0, 0, 0, 0, # 40 - 47 + 0, 0, 0, 0, 0, 0, 0, 0, # 48 - 4f + 0, 0, 0, 0, 0, 0, 0, 0, # 50 - 57 + 0, 0, 0, 0, 0, 0, 0, 0, # 58 - 5f + 0, 0, 0, 0, 0, 0, 0, 0, # 60 - 67 + 0, 0, 0, 0, 0, 0, 0, 0, # 68 - 6f + 0, 0, 0, 0, 0, 0, 0, 0, # 70 - 77 + 0, 0, 0, 0, 0, 0, 0, 0, # 78 - 7f + 0, 0, 0, 0, 0, 0, 0, 0, # 80 - 87 + 0, 0, 0, 0, 0, 0, 0, 0, # 88 - 8f + 0, 0, 0, 0, 0, 0, 0, 0, # 90 - 97 + 0, 0, 0, 0, 0, 0, 0, 0, # 98 - 9f + 0, 0, 0, 0, 0, 0, 0, 0, # a0 - a7 + 0, 0, 0, 0, 0, 0, 0, 0, # a8 - af + 0, 0, 0, 0, 0, 0, 0, 0, # b0 - b7 + 0, 0, 0, 0, 0, 0, 0, 0, # b8 - bf + 0, 0, 0, 0, 0, 0, 0, 0, # c0 - c7 + 0, 0, 0, 0, 0, 0, 0, 0, # c8 - cf + 0, 0, 0, 0, 0, 0, 0, 0, # d0 - d7 + 0, 0, 0, 0, 0, 0, 0, 0, # d8 - df + 0, 0, 0, 0, 0, 0, 0, 0, # e0 - e7 + 0, 0, 0, 0, 0, 0, 0, 0, # e8 - ef + 0, 0, 0, 0, 0, 0, 0, 0, # f0 - f7 + 0, 0, 0, 0, 0, 0, 4, 5 # f8 - ff ) UCS2BE_ST = ( @@ -433,50 +513,53 @@ 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 ) +# fmt: on UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) -UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, - 'class_factor': 6, - 'state_table': UCS2BE_ST, - 'char_len_table': UCS2BE_CHAR_LEN_TABLE, - 'name': 'UTF-16BE'} +UCS2BE_SM_MODEL: CodingStateMachineDict = { + "class_table": UCS2BE_CLS, + "class_factor": 6, + "state_table": UCS2BE_ST, + "char_len_table": UCS2BE_CHAR_LEN_TABLE, + "name": "UTF-16BE", +} # UCS2-LE - +# fmt: off UCS2LE_CLS = ( - 0,0,0,0,0,0,0,0, # 00 - 07 - 0,0,1,0,0,2,0,0, # 08 - 0f - 0,0,0,0,0,0,0,0, # 10 - 17 - 0,0,0,3,0,0,0,0, # 18 - 1f - 0,0,0,0,0,0,0,0, # 20 - 27 - 0,3,3,3,3,3,0,0, # 28 - 2f - 0,0,0,0,0,0,0,0, # 30 - 37 - 0,0,0,0,0,0,0,0, # 38 - 3f - 0,0,0,0,0,0,0,0, # 40 - 47 - 0,0,0,0,0,0,0,0, # 48 - 4f - 0,0,0,0,0,0,0,0, # 50 - 57 - 0,0,0,0,0,0,0,0, # 58 - 5f - 0,0,0,0,0,0,0,0, # 60 - 67 - 0,0,0,0,0,0,0,0, # 68 - 6f - 0,0,0,0,0,0,0,0, # 70 - 77 - 0,0,0,0,0,0,0,0, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,0,0,0,0,0,0,0, # a0 - a7 - 0,0,0,0,0,0,0,0, # a8 - af - 0,0,0,0,0,0,0,0, # b0 - b7 - 0,0,0,0,0,0,0,0, # b8 - bf - 0,0,0,0,0,0,0,0, # c0 - c7 - 0,0,0,0,0,0,0,0, # c8 - cf - 0,0,0,0,0,0,0,0, # d0 - d7 - 0,0,0,0,0,0,0,0, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,4,5 # f8 - ff + 0, 0, 0, 0, 0, 0, 0, 0, # 00 - 07 + 0, 0, 1, 0, 0, 2, 0, 0, # 08 - 0f + 0, 0, 0, 0, 0, 0, 0, 0, # 10 - 17 + 0, 0, 0, 3, 0, 0, 0, 0, # 18 - 1f + 0, 0, 0, 0, 0, 0, 0, 0, # 20 - 27 + 0, 3, 3, 3, 3, 3, 0, 0, # 28 - 2f + 0, 0, 0, 0, 0, 0, 0, 0, # 30 - 37 + 0, 0, 0, 0, 0, 0, 0, 0, # 38 - 3f + 0, 0, 0, 0, 0, 0, 0, 0, # 40 - 47 + 0, 0, 0, 0, 0, 0, 0, 0, # 48 - 4f + 0, 0, 0, 0, 0, 0, 0, 0, # 50 - 57 + 0, 0, 0, 0, 0, 0, 0, 0, # 58 - 5f + 0, 0, 0, 0, 0, 0, 0, 0, # 60 - 67 + 0, 0, 0, 0, 0, 0, 0, 0, # 68 - 6f + 0, 0, 0, 0, 0, 0, 0, 0, # 70 - 77 + 0, 0, 0, 0, 0, 0, 0, 0, # 78 - 7f + 0, 0, 0, 0, 0, 0, 0, 0, # 80 - 87 + 0, 0, 0, 0, 0, 0, 0, 0, # 88 - 8f + 0, 0, 0, 0, 0, 0, 0, 0, # 90 - 97 + 0, 0, 0, 0, 0, 0, 0, 0, # 98 - 9f + 0, 0, 0, 0, 0, 0, 0, 0, # a0 - a7 + 0, 0, 0, 0, 0, 0, 0, 0, # a8 - af + 0, 0, 0, 0, 0, 0, 0, 0, # b0 - b7 + 0, 0, 0, 0, 0, 0, 0, 0, # b8 - bf + 0, 0, 0, 0, 0, 0, 0, 0, # c0 - c7 + 0, 0, 0, 0, 0, 0, 0, 0, # c8 - cf + 0, 0, 0, 0, 0, 0, 0, 0, # d0 - d7 + 0, 0, 0, 0, 0, 0, 0, 0, # d8 - df + 0, 0, 0, 0, 0, 0, 0, 0, # e0 - e7 + 0, 0, 0, 0, 0, 0, 0, 0, # e8 - ef + 0, 0, 0, 0, 0, 0, 0, 0, # f0 - f7 + 0, 0, 0, 0, 0, 0, 4, 5 # f8 - ff ) UCS2LE_ST = ( @@ -488,50 +571,53 @@ 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 ) +# fmt: on UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) -UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, - 'class_factor': 6, - 'state_table': UCS2LE_ST, - 'char_len_table': UCS2LE_CHAR_LEN_TABLE, - 'name': 'UTF-16LE'} +UCS2LE_SM_MODEL: CodingStateMachineDict = { + "class_table": UCS2LE_CLS, + "class_factor": 6, + "state_table": UCS2LE_ST, + "char_len_table": UCS2LE_CHAR_LEN_TABLE, + "name": "UTF-16LE", +} # UTF-8 - +# fmt: off UTF8_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 1,1,1,1,1,1,1,1, # 40 - 47 - 1,1,1,1,1,1,1,1, # 48 - 4f - 1,1,1,1,1,1,1,1, # 50 - 57 - 1,1,1,1,1,1,1,1, # 58 - 5f - 1,1,1,1,1,1,1,1, # 60 - 67 - 1,1,1,1,1,1,1,1, # 68 - 6f - 1,1,1,1,1,1,1,1, # 70 - 77 - 1,1,1,1,1,1,1,1, # 78 - 7f - 2,2,2,2,3,3,3,3, # 80 - 87 - 4,4,4,4,4,4,4,4, # 88 - 8f - 4,4,4,4,4,4,4,4, # 90 - 97 - 4,4,4,4,4,4,4,4, # 98 - 9f - 5,5,5,5,5,5,5,5, # a0 - a7 - 5,5,5,5,5,5,5,5, # a8 - af - 5,5,5,5,5,5,5,5, # b0 - b7 - 5,5,5,5,5,5,5,5, # b8 - bf - 0,0,6,6,6,6,6,6, # c0 - c7 - 6,6,6,6,6,6,6,6, # c8 - cf - 6,6,6,6,6,6,6,6, # d0 - d7 - 6,6,6,6,6,6,6,6, # d8 - df - 7,8,8,8,8,8,8,8, # e0 - e7 - 8,8,8,8,8,9,8,8, # e8 - ef - 10,11,11,11,11,11,11,11, # f0 - f7 - 12,13,13,13,14,15,0,0 # f8 - ff + 1, 1, 1, 1, 1, 1, 1, 1, # 00 - 07 #allow 0x00 as a legal value + 1, 1, 1, 1, 1, 1, 0, 0, # 08 - 0f + 1, 1, 1, 1, 1, 1, 1, 1, # 10 - 17 + 1, 1, 1, 0, 1, 1, 1, 1, # 18 - 1f + 1, 1, 1, 1, 1, 1, 1, 1, # 20 - 27 + 1, 1, 1, 1, 1, 1, 1, 1, # 28 - 2f + 1, 1, 1, 1, 1, 1, 1, 1, # 30 - 37 + 1, 1, 1, 1, 1, 1, 1, 1, # 38 - 3f + 1, 1, 1, 1, 1, 1, 1, 1, # 40 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, # 48 - 4f + 1, 1, 1, 1, 1, 1, 1, 1, # 50 - 57 + 1, 1, 1, 1, 1, 1, 1, 1, # 58 - 5f + 1, 1, 1, 1, 1, 1, 1, 1, # 60 - 67 + 1, 1, 1, 1, 1, 1, 1, 1, # 68 - 6f + 1, 1, 1, 1, 1, 1, 1, 1, # 70 - 77 + 1, 1, 1, 1, 1, 1, 1, 1, # 78 - 7f + 2, 2, 2, 2, 3, 3, 3, 3, # 80 - 87 + 4, 4, 4, 4, 4, 4, 4, 4, # 88 - 8f + 4, 4, 4, 4, 4, 4, 4, 4, # 90 - 97 + 4, 4, 4, 4, 4, 4, 4, 4, # 98 - 9f + 5, 5, 5, 5, 5, 5, 5, 5, # a0 - a7 + 5, 5, 5, 5, 5, 5, 5, 5, # a8 - af + 5, 5, 5, 5, 5, 5, 5, 5, # b0 - b7 + 5, 5, 5, 5, 5, 5, 5, 5, # b8 - bf + 0, 0, 6, 6, 6, 6, 6, 6, # c0 - c7 + 6, 6, 6, 6, 6, 6, 6, 6, # c8 - cf + 6, 6, 6, 6, 6, 6, 6, 6, # d0 - d7 + 6, 6, 6, 6, 6, 6, 6, 6, # d8 - df + 7, 8, 8, 8, 8, 8, 8, 8, # e0 - e7 + 8, 8, 8, 8, 8, 9, 8, 8, # e8 - ef + 10, 11, 11, 11, 11, 11, 11, 11, # f0 - f7 + 12, 13, 13, 13, 14, 15, 0, 0 # f8 - ff ) UTF8_ST = ( @@ -562,11 +648,14 @@ MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf ) +# fmt: on UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) -UTF8_SM_MODEL = {'class_table': UTF8_CLS, - 'class_factor': 16, - 'state_table': UTF8_ST, - 'char_len_table': UTF8_CHAR_LEN_TABLE, - 'name': 'UTF-8'} +UTF8_SM_MODEL: CodingStateMachineDict = { + "class_table": UTF8_CLS, + "class_factor": 16, + "state_table": UTF8_ST, + "char_len_table": UTF8_CHAR_LEN_TABLE, + "name": "UTF-8", +} diff --git a/script.module.chardet/lib/chardet/metadata/languages.py b/script.module.chardet/lib/chardet/metadata/languages.py index 3237d5abf..eb40c5f0c 100644 --- a/script.module.chardet/lib/chardet/metadata/languages.py +++ b/script.module.chardet/lib/chardet/metadata/languages.py @@ -1,19 +1,17 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- """ Metadata about languages used by our model training code for our SingleByteCharSetProbers. Could be used for other things in the future. This code is based on the language metadata from the uchardet project. """ -from __future__ import absolute_import, print_function from string import ascii_letters +from typing import List, Optional +# TODO: Add Ukrainian (KOI8-U) -# TODO: Add Ukranian (KOI8-U) -class Language(object): +class Language: """Metadata about a language useful for training models :ivar name: The human name for the language, in English. @@ -33,9 +31,17 @@ class Language(object): Wikipedia for training data. :type wiki_start_pages: list of str """ - def __init__(self, name=None, iso_code=None, use_ascii=True, charsets=None, - alphabet=None, wiki_start_pages=None): - super(Language, self).__init__() + + def __init__( + self, + name: Optional[str] = None, + iso_code: Optional[str] = None, + use_ascii: bool = True, + charsets: Optional[List[str]] = None, + alphabet: Optional[str] = None, + wiki_start_pages: Optional[List[str]] = None, + ) -> None: + super().__init__() self.name = name self.iso_code = iso_code self.use_ascii = use_ascii @@ -46,265 +52,301 @@ def __init__(self, name=None, iso_code=None, use_ascii=True, charsets=None, else: alphabet = ascii_letters elif not alphabet: - raise ValueError('Must supply alphabet if use_ascii is False') - self.alphabet = ''.join(sorted(set(alphabet))) if alphabet else None + raise ValueError("Must supply alphabet if use_ascii is False") + self.alphabet = "".join(sorted(set(alphabet))) if alphabet else None self.wiki_start_pages = wiki_start_pages - def __repr__(self): - return '{}({})'.format(self.__class__.__name__, - ', '.join('{}={!r}'.format(k, v) - for k, v in self.__dict__.items() - if not k.startswith('_'))) + def __repr__(self) -> str: + param_str = ", ".join( + f"{k}={v!r}" for k, v in self.__dict__.items() if not k.startswith("_") + ) + return f"{self.__class__.__name__}({param_str})" -LANGUAGES = {'Arabic': Language(name='Arabic', - iso_code='ar', - use_ascii=False, - # We only support encodings that use isolated - # forms, because the current recommendation is - # that the rendering system handles presentation - # forms. This means we purposefully skip IBM864. - charsets=['ISO-8859-6', 'WINDOWS-1256', - 'CP720', 'CP864'], - alphabet=u'ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّ', - wiki_start_pages=[u'الصفحة_الرئيسية']), - 'Belarusian': Language(name='Belarusian', - iso_code='be', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'IBM866', 'MacCyrillic'], - alphabet=(u'АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШЫЬЭЮЯ' - u'абвгдеёжзійклмнопрстуўфхцчшыьэюяʼ'), - wiki_start_pages=[u'Галоўная_старонка']), - 'Bulgarian': Language(name='Bulgarian', - iso_code='bg', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'IBM855'], - alphabet=(u'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ' - u'абвгдежзийклмнопрстуфхцчшщъьюя'), - wiki_start_pages=[u'Начална_страница']), - 'Czech': Language(name='Czech', - iso_code='cz', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ', - wiki_start_pages=[u'Hlavní_strana']), - 'Danish': Language(name='Danish', - iso_code='da', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'æøåÆØÅ', - wiki_start_pages=[u'Forside']), - 'German': Language(name='German', - iso_code='de', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - alphabet=u'äöüßÄÖÜ', - wiki_start_pages=[u'Wikipedia:Hauptseite']), - 'Greek': Language(name='Greek', - iso_code='el', - use_ascii=False, - charsets=['ISO-8859-7', 'WINDOWS-1253'], - alphabet=(u'αβγδεζηθικλμνξοπρσςτυφχψωάέήίόύώ' - u'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΣΤΥΦΧΨΩΆΈΉΊΌΎΏ'), - wiki_start_pages=[u'Πύλη:Κύρια']), - 'English': Language(name='English', - iso_code='en', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - wiki_start_pages=[u'Main_Page']), - 'Esperanto': Language(name='Esperanto', - iso_code='eo', - # Q, W, X, and Y not used at all - use_ascii=False, - charsets=['ISO-8859-3'], - alphabet=(u'abcĉdefgĝhĥijĵklmnoprsŝtuŭvz' - u'ABCĈDEFGĜHĤIJĴKLMNOPRSŜTUŬVZ'), - wiki_start_pages=[u'Vikipedio:Ĉefpaĝo']), - 'Spanish': Language(name='Spanish', - iso_code='es', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ñáéíóúüÑÁÉÍÓÚÜ', - wiki_start_pages=[u'Wikipedia:Portada']), - 'Estonian': Language(name='Estonian', - iso_code='et', - use_ascii=False, - charsets=['ISO-8859-4', 'ISO-8859-13', - 'WINDOWS-1257'], - # C, F, Š, Q, W, X, Y, Z, Ž are only for - # loanwords - alphabet=(u'ABDEGHIJKLMNOPRSTUVÕÄÖÜ' - u'abdeghijklmnoprstuvõäöü'), - wiki_start_pages=[u'Esileht']), - 'Finnish': Language(name='Finnish', - iso_code='fi', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÅÄÖŠŽåäöšž', - wiki_start_pages=[u'Wikipedia:Etusivu']), - 'French': Language(name='French', - iso_code='fr', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'œàâçèéîïùûêŒÀÂÇÈÉÎÏÙÛÊ', - wiki_start_pages=[u'Wikipédia:Accueil_principal', - u'Bœuf (animal)']), - 'Hebrew': Language(name='Hebrew', - iso_code='he', - use_ascii=False, - charsets=['ISO-8859-8', 'WINDOWS-1255'], - alphabet=u'אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ', - wiki_start_pages=[u'עמוד_ראשי']), - 'Croatian': Language(name='Croatian', - iso_code='hr', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcčćdđefghijklmnoprsštuvzž' - u'ABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ'), - wiki_start_pages=[u'Glavna_stranica']), - 'Hungarian': Language(name='Hungarian', - iso_code='hu', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcdefghijklmnoprstuvzáéíóöőúüű' - u'ABCDEFGHIJKLMNOPRSTUVZÁÉÍÓÖŐÚÜŰ'), - wiki_start_pages=[u'Kezdőlap']), - 'Italian': Language(name='Italian', - iso_code='it', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÀÈÉÌÒÓÙàèéìòóù', - wiki_start_pages=[u'Pagina_principale']), - 'Lithuanian': Language(name='Lithuanian', - iso_code='lt', - use_ascii=False, - charsets=['ISO-8859-13', 'WINDOWS-1257', - 'ISO-8859-4'], - # Q, W, and X not used at all - alphabet=(u'AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ' - u'aąbcčdeęėfghiįyjklmnoprsštuųūvzž'), - wiki_start_pages=[u'Pagrindinis_puslapis']), - 'Latvian': Language(name='Latvian', - iso_code='lv', - use_ascii=False, - charsets=['ISO-8859-13', 'WINDOWS-1257', - 'ISO-8859-4'], - # Q, W, X, Y are only for loanwords - alphabet=(u'AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ' - u'aābcčdeēfgģhiījkķlļmnņoprsštuūvzž'), - wiki_start_pages=[u'Sākumlapa']), - 'Macedonian': Language(name='Macedonian', - iso_code='mk', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'MacCyrillic', 'IBM855'], - alphabet=(u'АБВГДЃЕЖЗЅИЈКЛЉМНЊОПРСТЌУФХЦЧЏШ' - u'абвгдѓежзѕијклљмнњопрстќуфхцчџш'), - wiki_start_pages=[u'Главна_страница']), - 'Dutch': Language(name='Dutch', - iso_code='nl', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - wiki_start_pages=[u'Hoofdpagina']), - 'Polish': Language(name='Polish', - iso_code='pl', - # Q and X are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻ' - u'aąbcćdeęfghijklłmnńoóprsśtuwyzźż'), - wiki_start_pages=[u'Wikipedia:Strona_główna']), - 'Portuguese': Language(name='Portuguese', - iso_code='pt', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÁÂÃÀÇÉÊÍÓÔÕÚáâãàçéêíóôõú', - wiki_start_pages=[u'Wikipédia:Página_principal']), - 'Romanian': Language(name='Romanian', - iso_code='ro', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'ăâîșțĂÂÎȘȚ', - wiki_start_pages=[u'Pagina_principală']), - 'Russian': Language(name='Russian', - iso_code='ru', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'KOI8-R', 'MacCyrillic', 'IBM866', - 'IBM855'], - alphabet=(u'абвгдеёжзийклмнопрстуфхцчшщъыьэюя' - u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'), - wiki_start_pages=[u'Заглавная_страница']), - 'Slovak': Language(name='Slovak', - iso_code='sk', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ', - wiki_start_pages=[u'Hlavná_stránka']), - 'Slovene': Language(name='Slovene', - iso_code='sl', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcčdefghijklmnoprsštuvzž' - u'ABCČDEFGHIJKLMNOPRSŠTUVZŽ'), - wiki_start_pages=[u'Glavna_stran']), - # Serbian can be written in both Latin and Cyrillic, but there's no - # simple way to get the Latin alphabet pages from Wikipedia through - # the API, so for now we just support Cyrillic. - 'Serbian': Language(name='Serbian', - iso_code='sr', - alphabet=(u'АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ' - u'абвгдђежзијклљмнњопрстћуфхцчџш'), - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'MacCyrillic', 'IBM855'], - wiki_start_pages=[u'Главна_страна']), - 'Thai': Language(name='Thai', - iso_code='th', - use_ascii=False, - charsets=['ISO-8859-11', 'TIS-620', 'CP874'], - alphabet=u'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛', - wiki_start_pages=[u'หน้าหลัก']), - 'Turkish': Language(name='Turkish', - iso_code='tr', - # Q, W, and X are not used by Turkish - use_ascii=False, - charsets=['ISO-8859-3', 'ISO-8859-9', - 'WINDOWS-1254'], - alphabet=(u'abcçdefgğhıijklmnoöprsştuüvyzâîû' - u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZÂÎÛ'), - wiki_start_pages=[u'Ana_Sayfa']), - 'Vietnamese': Language(name='Vietnamese', - iso_code='vi', - use_ascii=False, - # Windows-1258 is the only common 8-bit - # Vietnamese encoding supported by Python. - # From Wikipedia: - # For systems that lack support for Unicode, - # dozens of 8-bit Vietnamese code pages are - # available.[1] The most common are VISCII - # (TCVN 5712:1993), VPS, and Windows-1258.[3] - # Where ASCII is required, such as when - # ensuring readability in plain text e-mail, - # Vietnamese letters are often encoded - # according to Vietnamese Quoted-Readable - # (VIQR) or VSCII Mnemonic (VSCII-MNEM),[4] - # though usage of either variable-width - # scheme has declined dramatically following - # the adoption of Unicode on the World Wide - # Web. - charsets=['WINDOWS-1258'], - alphabet=(u'aăâbcdđeêghiklmnoôơpqrstuưvxy' - u'AĂÂBCDĐEÊGHIKLMNOÔƠPQRSTUƯVXY'), - wiki_start_pages=[u'Chữ_Quốc_ngữ']), - } +LANGUAGES = { + "Arabic": Language( + name="Arabic", + iso_code="ar", + use_ascii=False, + # We only support encodings that use isolated + # forms, because the current recommendation is + # that the rendering system handles presentation + # forms. This means we purposefully skip IBM864. + charsets=["ISO-8859-6", "WINDOWS-1256", "CP720", "CP864"], + alphabet="ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّ", + wiki_start_pages=["الصفحة_الرئيسية"], + ), + "Belarusian": Language( + name="Belarusian", + iso_code="be", + use_ascii=False, + charsets=["ISO-8859-5", "WINDOWS-1251", "IBM866", "MacCyrillic"], + alphabet="АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШЫЬЭЮЯабвгдеёжзійклмнопрстуўфхцчшыьэюяʼ", + wiki_start_pages=["Галоўная_старонка"], + ), + "Bulgarian": Language( + name="Bulgarian", + iso_code="bg", + use_ascii=False, + charsets=["ISO-8859-5", "WINDOWS-1251", "IBM855"], + alphabet="АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя", + wiki_start_pages=["Начална_страница"], + ), + "Czech": Language( + name="Czech", + iso_code="cz", + use_ascii=True, + charsets=["ISO-8859-2", "WINDOWS-1250"], + alphabet="áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ", + wiki_start_pages=["Hlavní_strana"], + ), + "Danish": Language( + name="Danish", + iso_code="da", + use_ascii=True, + charsets=["ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "MacRoman"], + alphabet="æøåÆØÅ", + wiki_start_pages=["Forside"], + ), + "German": Language( + name="German", + iso_code="de", + use_ascii=True, + charsets=["ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "MacRoman"], + alphabet="äöüßẞÄÖÜ", + wiki_start_pages=["Wikipedia:Hauptseite"], + ), + "Greek": Language( + name="Greek", + iso_code="el", + use_ascii=False, + charsets=["ISO-8859-7", "WINDOWS-1253"], + alphabet="αβγδεζηθικλμνξοπρσςτυφχψωάέήίόύώΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΣΤΥΦΧΨΩΆΈΉΊΌΎΏ", + wiki_start_pages=["Πύλη:Κύρια"], + ), + "English": Language( + name="English", + iso_code="en", + use_ascii=True, + charsets=["ISO-8859-1", "WINDOWS-1252", "MacRoman"], + wiki_start_pages=["Main_Page"], + ), + "Esperanto": Language( + name="Esperanto", + iso_code="eo", + # Q, W, X, and Y not used at all + use_ascii=False, + charsets=["ISO-8859-3"], + alphabet="abcĉdefgĝhĥijĵklmnoprsŝtuŭvzABCĈDEFGĜHĤIJĴKLMNOPRSŜTUŬVZ", + wiki_start_pages=["Vikipedio:Ĉefpaĝo"], + ), + "Spanish": Language( + name="Spanish", + iso_code="es", + use_ascii=True, + charsets=["ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "MacRoman"], + alphabet="ñáéíóúüÑÁÉÍÓÚÜ", + wiki_start_pages=["Wikipedia:Portada"], + ), + "Estonian": Language( + name="Estonian", + iso_code="et", + use_ascii=False, + charsets=["ISO-8859-4", "ISO-8859-13", "WINDOWS-1257"], + # C, F, Š, Q, W, X, Y, Z, Ž are only for + # loanwords + alphabet="ABDEGHIJKLMNOPRSTUVÕÄÖÜabdeghijklmnoprstuvõäöü", + wiki_start_pages=["Esileht"], + ), + "Finnish": Language( + name="Finnish", + iso_code="fi", + use_ascii=True, + charsets=["ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "MacRoman"], + alphabet="ÅÄÖŠŽåäöšž", + wiki_start_pages=["Wikipedia:Etusivu"], + ), + "French": Language( + name="French", + iso_code="fr", + use_ascii=True, + charsets=["ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "MacRoman"], + alphabet="œàâçèéîïùûêŒÀÂÇÈÉÎÏÙÛÊ", + wiki_start_pages=["Wikipédia:Accueil_principal", "Bœuf (animal)"], + ), + "Hebrew": Language( + name="Hebrew", + iso_code="he", + use_ascii=False, + charsets=["ISO-8859-8", "WINDOWS-1255"], + alphabet="אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ", + wiki_start_pages=["עמוד_ראשי"], + ), + "Croatian": Language( + name="Croatian", + iso_code="hr", + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=["ISO-8859-2", "WINDOWS-1250"], + alphabet="abcčćdđefghijklmnoprsštuvzžABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ", + wiki_start_pages=["Glavna_stranica"], + ), + "Hungarian": Language( + name="Hungarian", + iso_code="hu", + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=["ISO-8859-2", "WINDOWS-1250"], + alphabet="abcdefghijklmnoprstuvzáéíóöőúüűABCDEFGHIJKLMNOPRSTUVZÁÉÍÓÖŐÚÜŰ", + wiki_start_pages=["Kezdőlap"], + ), + "Italian": Language( + name="Italian", + iso_code="it", + use_ascii=True, + charsets=["ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "MacRoman"], + alphabet="ÀÈÉÌÒÓÙàèéìòóù", + wiki_start_pages=["Pagina_principale"], + ), + "Lithuanian": Language( + name="Lithuanian", + iso_code="lt", + use_ascii=False, + charsets=["ISO-8859-13", "WINDOWS-1257", "ISO-8859-4"], + # Q, W, and X not used at all + alphabet="AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽaąbcčdeęėfghiįyjklmnoprsštuųūvzž", + wiki_start_pages=["Pagrindinis_puslapis"], + ), + "Latvian": Language( + name="Latvian", + iso_code="lv", + use_ascii=False, + charsets=["ISO-8859-13", "WINDOWS-1257", "ISO-8859-4"], + # Q, W, X, Y are only for loanwords + alphabet="AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽaābcčdeēfgģhiījkķlļmnņoprsštuūvzž", + wiki_start_pages=["Sākumlapa"], + ), + "Macedonian": Language( + name="Macedonian", + iso_code="mk", + use_ascii=False, + charsets=["ISO-8859-5", "WINDOWS-1251", "MacCyrillic", "IBM855"], + alphabet="АБВГДЃЕЖЗЅИЈКЛЉМНЊОПРСТЌУФХЦЧЏШабвгдѓежзѕијклљмнњопрстќуфхцчџш", + wiki_start_pages=["Главна_страница"], + ), + "Dutch": Language( + name="Dutch", + iso_code="nl", + use_ascii=True, + charsets=["ISO-8859-1", "WINDOWS-1252", "MacRoman"], + wiki_start_pages=["Hoofdpagina"], + ), + "Polish": Language( + name="Polish", + iso_code="pl", + # Q and X are only used for foreign words. + use_ascii=False, + charsets=["ISO-8859-2", "WINDOWS-1250"], + alphabet="AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻaąbcćdeęfghijklłmnńoóprsśtuwyzźż", + wiki_start_pages=["Wikipedia:Strona_główna"], + ), + "Portuguese": Language( + name="Portuguese", + iso_code="pt", + use_ascii=True, + charsets=["ISO-8859-1", "ISO-8859-15", "WINDOWS-1252", "MacRoman"], + alphabet="ÁÂÃÀÇÉÊÍÓÔÕÚáâãàçéêíóôõú", + wiki_start_pages=["Wikipédia:Página_principal"], + ), + "Romanian": Language( + name="Romanian", + iso_code="ro", + use_ascii=True, + charsets=["ISO-8859-2", "WINDOWS-1250"], + alphabet="ăâîșțĂÂÎȘȚ", + wiki_start_pages=["Pagina_principală"], + ), + "Russian": Language( + name="Russian", + iso_code="ru", + use_ascii=False, + charsets=[ + "ISO-8859-5", + "WINDOWS-1251", + "KOI8-R", + "MacCyrillic", + "IBM866", + "IBM855", + ], + alphabet="абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ", + wiki_start_pages=["Заглавная_страница"], + ), + "Slovak": Language( + name="Slovak", + iso_code="sk", + use_ascii=True, + charsets=["ISO-8859-2", "WINDOWS-1250"], + alphabet="áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ", + wiki_start_pages=["Hlavná_stránka"], + ), + "Slovene": Language( + name="Slovene", + iso_code="sl", + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=["ISO-8859-2", "WINDOWS-1250"], + alphabet="abcčdefghijklmnoprsštuvzžABCČDEFGHIJKLMNOPRSŠTUVZŽ", + wiki_start_pages=["Glavna_stran"], + ), + # Serbian can be written in both Latin and Cyrillic, but there's no + # simple way to get the Latin alphabet pages from Wikipedia through + # the API, so for now we just support Cyrillic. + "Serbian": Language( + name="Serbian", + iso_code="sr", + alphabet="АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШабвгдђежзијклљмнњопрстћуфхцчџш", + charsets=["ISO-8859-5", "WINDOWS-1251", "MacCyrillic", "IBM855"], + wiki_start_pages=["Главна_страна"], + ), + "Thai": Language( + name="Thai", + iso_code="th", + use_ascii=False, + charsets=["ISO-8859-11", "TIS-620", "CP874"], + alphabet="กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛", + wiki_start_pages=["หน้าหลัก"], + ), + "Turkish": Language( + name="Turkish", + iso_code="tr", + # Q, W, and X are not used by Turkish + use_ascii=False, + charsets=["ISO-8859-3", "ISO-8859-9", "WINDOWS-1254"], + alphabet="abcçdefgğhıijklmnoöprsştuüvyzâîûABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZÂÎÛ", + wiki_start_pages=["Ana_Sayfa"], + ), + "Vietnamese": Language( + name="Vietnamese", + iso_code="vi", + use_ascii=False, + # Windows-1258 is the only common 8-bit + # Vietnamese encoding supported by Python. + # From Wikipedia: + # For systems that lack support for Unicode, + # dozens of 8-bit Vietnamese code pages are + # available.[1] The most common are VISCII + # (TCVN 5712:1993), VPS, and Windows-1258.[3] + # Where ASCII is required, such as when + # ensuring readability in plain text e-mail, + # Vietnamese letters are often encoded + # according to Vietnamese Quoted-Readable + # (VIQR) or VSCII Mnemonic (VSCII-MNEM),[4] + # though usage of either variable-width + # scheme has declined dramatically following + # the adoption of Unicode on the World Wide + # Web. + charsets=["WINDOWS-1258"], + alphabet="aăâbcdđeêghiklmnoôơpqrstuưvxyAĂÂBCDĐEÊGHIKLMNOÔƠPQRSTUƯVXY", + wiki_start_pages=["Chữ_Quốc_ngữ"], + ), +} diff --git a/script.module.chardet/lib/chardet/resultdict.py b/script.module.chardet/lib/chardet/resultdict.py new file mode 100644 index 000000000..7d36e64c4 --- /dev/null +++ b/script.module.chardet/lib/chardet/resultdict.py @@ -0,0 +1,16 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + # TypedDict was introduced in Python 3.8. + # + # TODO: Remove the else block and TYPE_CHECKING check when dropping support + # for Python 3.7. + from typing import TypedDict + + class ResultDict(TypedDict): + encoding: Optional[str] + confidence: float + language: Optional[str] + +else: + ResultDict = dict diff --git a/script.module.chardet/lib/chardet/sbcharsetprober.py b/script.module.chardet/lib/chardet/sbcharsetprober.py index 46ba835c6..0ffbcdd2c 100644 --- a/script.module.chardet/lib/chardet/sbcharsetprober.py +++ b/script.module.chardet/lib/chardet/sbcharsetprober.py @@ -26,70 +26,77 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from collections import namedtuple +from typing import Dict, List, NamedTuple, Optional, Union from .charsetprober import CharSetProber from .enums import CharacterCategory, ProbingState, SequenceLikelihood -SingleByteCharSetModel = namedtuple('SingleByteCharSetModel', - ['charset_name', - 'language', - 'char_to_order_map', - 'language_model', - 'typical_positive_ratio', - 'keep_ascii_letters', - 'alphabet']) +class SingleByteCharSetModel(NamedTuple): + charset_name: str + language: str + char_to_order_map: Dict[int, int] + language_model: Dict[int, Dict[int, int]] + typical_positive_ratio: float + keep_ascii_letters: bool + alphabet: str class SingleByteCharSetProber(CharSetProber): SAMPLE_SIZE = 64 - SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 + SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 POSITIVE_SHORTCUT_THRESHOLD = 0.95 NEGATIVE_SHORTCUT_THRESHOLD = 0.05 - def __init__(self, model, reversed=False, name_prober=None): - super(SingleByteCharSetProber, self).__init__() + def __init__( + self, + model: SingleByteCharSetModel, + is_reversed: bool = False, + name_prober: Optional[CharSetProber] = None, + ) -> None: + super().__init__() self._model = model # TRUE if we need to reverse every pair in the model lookup - self._reversed = reversed + self._reversed = is_reversed # Optional auxiliary prober for name decision self._name_prober = name_prober - self._last_order = None - self._seq_counters = None - self._total_seqs = None - self._total_char = None - self._freq_char = None + self._last_order = 255 + self._seq_counters: List[int] = [] + self._total_seqs = 0 + self._total_char = 0 + self._control_char = 0 + self._freq_char = 0 self.reset() - def reset(self): - super(SingleByteCharSetProber, self).reset() + def reset(self) -> None: + super().reset() # char order of last character self._last_order = 255 self._seq_counters = [0] * SequenceLikelihood.get_num_categories() self._total_seqs = 0 self._total_char = 0 + self._control_char = 0 # characters that fall in our sampling range self._freq_char = 0 @property - def charset_name(self): + def charset_name(self) -> Optional[str]: if self._name_prober: return self._name_prober.charset_name - else: - return self._model.charset_name + return self._model.charset_name @property - def language(self): + def language(self) -> Optional[str]: if self._name_prober: return self._name_prober.language - else: - return self._model.language + return self._model.language - def feed(self, byte_str): + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: # TODO: Make filter_international_words keep things in self.alphabet if not self._model.keep_ascii_letters: byte_str = self.filter_international_words(byte_str) + else: + byte_str = self.remove_xml_tags(byte_str) if not byte_str: return self.state char_to_order_map = self._model.char_to_order_map @@ -103,9 +110,6 @@ def feed(self, byte_str): # _total_char purposes. if order < CharacterCategory.CONTROL: self._total_char += 1 - # TODO: Follow uchardet's lead and discount confidence for frequent - # control characters. - # See https://github.com/BYVoid/uchardet/commit/55b4f23971db61 if order < self.SAMPLE_SIZE: self._freq_char += 1 if self._last_order < self.SAMPLE_SIZE: @@ -122,23 +126,36 @@ def feed(self, byte_str): if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: confidence = self.get_confidence() if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: - self.logger.debug('%s confidence = %s, we have a winner', - charset_name, confidence) + self.logger.debug( + "%s confidence = %s, we have a winner", charset_name, confidence + ) self._state = ProbingState.FOUND_IT elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: - self.logger.debug('%s confidence = %s, below negative ' - 'shortcut threshhold %s', charset_name, - confidence, - self.NEGATIVE_SHORTCUT_THRESHOLD) + self.logger.debug( + "%s confidence = %s, below negative shortcut threshold %s", + charset_name, + confidence, + self.NEGATIVE_SHORTCUT_THRESHOLD, + ) self._state = ProbingState.NOT_ME return self.state - def get_confidence(self): + def get_confidence(self) -> float: r = 0.01 if self._total_seqs > 0: - r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / - self._total_seqs / self._model.typical_positive_ratio) + r = ( + ( + self._seq_counters[SequenceLikelihood.POSITIVE] + + 0.25 * self._seq_counters[SequenceLikelihood.LIKELY] + ) + / self._total_seqs + / self._model.typical_positive_ratio + ) + # The more control characters (proportionnaly to the size + # of the text), the less confident we become in the current + # charset. + r = r * (self._total_char - self._control_char) / self._total_char r = r * self._freq_char / self._total_char if r >= 1.0: r = 0.99 diff --git a/script.module.chardet/lib/chardet/sbcsgroupprober.py b/script.module.chardet/lib/chardet/sbcsgroupprober.py index bdeef4e15..890ae8465 100644 --- a/script.module.chardet/lib/chardet/sbcsgroupprober.py +++ b/script.module.chardet/lib/chardet/sbcsgroupprober.py @@ -28,33 +28,38 @@ from .charsetgroupprober import CharSetGroupProber from .hebrewprober import HebrewProber -from .langbulgarianmodel import (ISO_8859_5_BULGARIAN_MODEL, - WINDOWS_1251_BULGARIAN_MODEL) +from .langbulgarianmodel import ISO_8859_5_BULGARIAN_MODEL, WINDOWS_1251_BULGARIAN_MODEL from .langgreekmodel import ISO_8859_7_GREEK_MODEL, WINDOWS_1253_GREEK_MODEL from .langhebrewmodel import WINDOWS_1255_HEBREW_MODEL + # from .langhungarianmodel import (ISO_8859_2_HUNGARIAN_MODEL, # WINDOWS_1250_HUNGARIAN_MODEL) -from .langrussianmodel import (IBM855_RUSSIAN_MODEL, IBM866_RUSSIAN_MODEL, - ISO_8859_5_RUSSIAN_MODEL, KOI8_R_RUSSIAN_MODEL, - MACCYRILLIC_RUSSIAN_MODEL, - WINDOWS_1251_RUSSIAN_MODEL) +from .langrussianmodel import ( + IBM855_RUSSIAN_MODEL, + IBM866_RUSSIAN_MODEL, + ISO_8859_5_RUSSIAN_MODEL, + KOI8_R_RUSSIAN_MODEL, + MACCYRILLIC_RUSSIAN_MODEL, + WINDOWS_1251_RUSSIAN_MODEL, +) from .langthaimodel import TIS_620_THAI_MODEL from .langturkishmodel import ISO_8859_9_TURKISH_MODEL from .sbcharsetprober import SingleByteCharSetProber class SBCSGroupProber(CharSetGroupProber): - def __init__(self): - super(SBCSGroupProber, self).__init__() + def __init__(self) -> None: + super().__init__() hebrew_prober = HebrewProber() - logical_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, - False, hebrew_prober) + logical_hebrew_prober = SingleByteCharSetProber( + WINDOWS_1255_HEBREW_MODEL, is_reversed=False, name_prober=hebrew_prober + ) # TODO: See if using ISO-8859-8 Hebrew model works better here, since # it's actually the visual one - visual_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, - True, hebrew_prober) - hebrew_prober.set_model_probers(logical_hebrew_prober, - visual_hebrew_prober) + visual_hebrew_prober = SingleByteCharSetProber( + WINDOWS_1255_HEBREW_MODEL, is_reversed=True, name_prober=hebrew_prober + ) + hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) # TODO: ORDER MATTERS HERE. I changed the order vs what was in master # and several tests failed that did not before. Some thought # should be put into the ordering, and we should consider making diff --git a/script.module.chardet/lib/chardet/sjisprober.py b/script.module.chardet/lib/chardet/sjisprober.py index 9e29623bd..91df07796 100644 --- a/script.module.chardet/lib/chardet/sjisprober.py +++ b/script.module.chardet/lib/chardet/sjisprober.py @@ -25,68 +25,81 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine +from typing import Union + from .chardistribution import SJISDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .enums import MachineState, ProbingState from .jpcntx import SJISContextAnalysis +from .mbcharsetprober import MultiByteCharSetProber from .mbcssm import SJIS_SM_MODEL -from .enums import ProbingState, MachineState class SJISProber(MultiByteCharSetProber): - def __init__(self): - super(SJISProber, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) self.distribution_analyzer = SJISDistributionAnalysis() self.context_analyzer = SJISContextAnalysis() self.reset() - def reset(self): - super(SJISProber, self).reset() + def reset(self) -> None: + super().reset() self.context_analyzer.reset() @property - def charset_name(self): + def charset_name(self) -> str: return self.context_analyzer.charset_name @property - def language(self): + def language(self) -> str: return "Japanese" - def feed(self, byte_str): - for i in range(len(byte_str)): - coding_state = self.coding_sm.next_state(byte_str[i]) + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: + assert self.coding_sm is not None + assert self.distribution_analyzer is not None + + for i, byte in enumerate(byte_str): + coding_state = self.coding_sm.next_state(byte) if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) + self.logger.debug( + "%s %s prober hit error at byte %s", + self.charset_name, + self.language, + i, + ) self._state = ProbingState.NOT_ME break - elif coding_state == MachineState.ITS_ME: + if coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break - elif coding_state == MachineState.START: + if coding_state == MachineState.START: char_len = self.coding_sm.get_current_charlen() if i == 0: - self._last_char[1] = byte_str[0] - self.context_analyzer.feed(self._last_char[2 - char_len:], - char_len) + self._last_char[1] = byte + self.context_analyzer.feed( + self._last_char[2 - char_len :], char_len + ) self.distribution_analyzer.feed(self._last_char, char_len) else: - self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 - - char_len], char_len) - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) + self.context_analyzer.feed( + byte_str[i + 1 - char_len : i + 3 - char_len], char_len + ) + self.distribution_analyzer.feed(byte_str[i - 1 : i + 1], char_len) self._last_char[0] = byte_str[-1] if self.state == ProbingState.DETECTING: - if (self.context_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + if self.context_analyzer.got_enough_data() and ( + self.get_confidence() > self.SHORTCUT_THRESHOLD + ): self._state = ProbingState.FOUND_IT return self.state - def get_confidence(self): + def get_confidence(self) -> float: + assert self.distribution_analyzer is not None + context_conf = self.context_analyzer.get_confidence() distrib_conf = self.distribution_analyzer.get_confidence() return max(context_conf, distrib_conf) diff --git a/script.module.chardet/lib/chardet/universaldetector.py b/script.module.chardet/lib/chardet/universaldetector.py index 055a8ac1b..30c441dc2 100644 --- a/script.module.chardet/lib/chardet/universaldetector.py +++ b/script.module.chardet/lib/chardet/universaldetector.py @@ -39,16 +39,21 @@ class a user of ``chardet`` should use. import codecs import logging import re +from typing import List, Optional, Union from .charsetgroupprober import CharSetGroupProber +from .charsetprober import CharSetProber from .enums import InputState, LanguageFilter, ProbingState from .escprober import EscCharSetProber from .latin1prober import Latin1Prober +from .macromanprober import MacRomanProber from .mbcsgroupprober import MBCSGroupProber +from .resultdict import ResultDict from .sbcsgroupprober import SBCSGroupProber +from .utf1632prober import UTF1632Prober -class UniversalDetector(object): +class UniversalDetector: """ The ``UniversalDetector`` class underlies the ``chardet.detect`` function and coordinates all of the different charset probers. @@ -66,49 +71,87 @@ class UniversalDetector(object): """ MINIMUM_THRESHOLD = 0.20 - HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') - ESC_DETECTOR = re.compile(b'(\033|~{)') - WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') - ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', - 'iso-8859-2': 'Windows-1250', - 'iso-8859-5': 'Windows-1251', - 'iso-8859-6': 'Windows-1256', - 'iso-8859-7': 'Windows-1253', - 'iso-8859-8': 'Windows-1255', - 'iso-8859-9': 'Windows-1254', - 'iso-8859-13': 'Windows-1257'} - - def __init__(self, lang_filter=LanguageFilter.ALL): - self._esc_charset_prober = None - self._charset_probers = [] - self.result = None - self.done = None - self._got_data = None - self._input_state = None - self._last_char = None + HIGH_BYTE_DETECTOR = re.compile(b"[\x80-\xFF]") + ESC_DETECTOR = re.compile(b"(\033|~{)") + WIN_BYTE_DETECTOR = re.compile(b"[\x80-\x9F]") + ISO_WIN_MAP = { + "iso-8859-1": "Windows-1252", + "iso-8859-2": "Windows-1250", + "iso-8859-5": "Windows-1251", + "iso-8859-6": "Windows-1256", + "iso-8859-7": "Windows-1253", + "iso-8859-8": "Windows-1255", + "iso-8859-9": "Windows-1254", + "iso-8859-13": "Windows-1257", + } + # Based on https://encoding.spec.whatwg.org/#names-and-labels + # but altered to match Python names for encodings and remove mappings + # that break tests. + LEGACY_MAP = { + "ascii": "Windows-1252", + "iso-8859-1": "Windows-1252", + "tis-620": "ISO-8859-11", + "iso-8859-9": "Windows-1254", + "gb2312": "GB18030", + "euc-kr": "CP949", + "utf-16le": "UTF-16", + } + + def __init__( + self, + lang_filter: LanguageFilter = LanguageFilter.ALL, + should_rename_legacy: bool = False, + ) -> None: + self._esc_charset_prober: Optional[EscCharSetProber] = None + self._utf1632_prober: Optional[UTF1632Prober] = None + self._charset_probers: List[CharSetProber] = [] + self.result: ResultDict = { + "encoding": None, + "confidence": 0.0, + "language": None, + } + self.done = False + self._got_data = False + self._input_state = InputState.PURE_ASCII + self._last_char = b"" self.lang_filter = lang_filter self.logger = logging.getLogger(__name__) - self._has_win_bytes = None + self._has_win_bytes = False + self.should_rename_legacy = should_rename_legacy self.reset() - def reset(self): + @property + def input_state(self) -> int: + return self._input_state + + @property + def has_win_bytes(self) -> bool: + return self._has_win_bytes + + @property + def charset_probers(self) -> List[CharSetProber]: + return self._charset_probers + + def reset(self) -> None: """ Reset the UniversalDetector and all of its probers back to their initial states. This is called by ``__init__``, so you only need to call this directly in between analyses of different documents. """ - self.result = {'encoding': None, 'confidence': 0.0, 'language': None} + self.result = {"encoding": None, "confidence": 0.0, "language": None} self.done = False self._got_data = False self._has_win_bytes = False self._input_state = InputState.PURE_ASCII - self._last_char = b'' + self._last_char = b"" if self._esc_charset_prober: self._esc_charset_prober.reset() + if self._utf1632_prober: + self._utf1632_prober.reset() for prober in self._charset_probers: prober.reset() - def feed(self, byte_str): + def feed(self, byte_str: Union[bytes, bytearray]) -> None: """ Takes a chunk of a document and feeds it through all of the relevant charset probers. @@ -125,7 +168,7 @@ def feed(self, byte_str): if self.done: return - if not len(byte_str): + if not byte_str: return if not isinstance(byte_str, bytearray): @@ -136,35 +179,38 @@ def feed(self, byte_str): # If the data starts with BOM, we know it is UTF if byte_str.startswith(codecs.BOM_UTF8): # EF BB BF UTF-8 with BOM - self.result = {'encoding': "UTF-8-SIG", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith((codecs.BOM_UTF32_LE, - codecs.BOM_UTF32_BE)): + self.result = { + "encoding": "UTF-8-SIG", + "confidence": 1.0, + "language": "", + } + elif byte_str.startswith((codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)): # FF FE 00 00 UTF-32, little-endian BOM # 00 00 FE FF UTF-32, big-endian BOM - self.result = {'encoding': "UTF-32", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith(b'\xFE\xFF\x00\x00'): + self.result = {"encoding": "UTF-32", "confidence": 1.0, "language": ""} + elif byte_str.startswith(b"\xFE\xFF\x00\x00"): # FE FF 00 00 UCS-4, unusual octet order BOM (3412) - self.result = {'encoding': "X-ISO-10646-UCS-4-3412", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith(b'\x00\x00\xFF\xFE'): + self.result = { + # TODO: This encoding is not supported by Python. Should remove? + "encoding": "X-ISO-10646-UCS-4-3412", + "confidence": 1.0, + "language": "", + } + elif byte_str.startswith(b"\x00\x00\xFF\xFE"): # 00 00 FF FE UCS-4, unusual octet order BOM (2143) - self.result = {'encoding': "X-ISO-10646-UCS-4-2143", - 'confidence': 1.0, - 'language': ''} + self.result = { + # TODO: This encoding is not supported by Python. Should remove? + "encoding": "X-ISO-10646-UCS-4-2143", + "confidence": 1.0, + "language": "", + } elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): # FF FE UTF-16, little endian BOM # FE FF UTF-16, big endian BOM - self.result = {'encoding': "UTF-16", - 'confidence': 1.0, - 'language': ''} + self.result = {"encoding": "UTF-16", "confidence": 1.0, "language": ""} self._got_data = True - if self.result['encoding'] is not None: + if self.result["encoding"] is not None: self.done = True return @@ -173,12 +219,29 @@ def feed(self, byte_str): if self._input_state == InputState.PURE_ASCII: if self.HIGH_BYTE_DETECTOR.search(byte_str): self._input_state = InputState.HIGH_BYTE - elif self._input_state == InputState.PURE_ASCII and \ - self.ESC_DETECTOR.search(self._last_char + byte_str): + elif ( + self._input_state == InputState.PURE_ASCII + and self.ESC_DETECTOR.search(self._last_char + byte_str) + ): self._input_state = InputState.ESC_ASCII self._last_char = byte_str[-1:] + # next we will look to see if it is appears to be either a UTF-16 or + # UTF-32 encoding + if not self._utf1632_prober: + self._utf1632_prober = UTF1632Prober() + + if self._utf1632_prober.state == ProbingState.DETECTING: + if self._utf1632_prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = { + "encoding": self._utf1632_prober.charset_name, + "confidence": self._utf1632_prober.get_confidence(), + "language": "", + } + self.done = True + return + # If we've seen escape sequences, use the EscCharSetProber, which # uses a simple state machine to check for known escape sequences in # HZ and ISO-2022 encodings, since those are the only encodings that @@ -187,12 +250,11 @@ def feed(self, byte_str): if not self._esc_charset_prober: self._esc_charset_prober = EscCharSetProber(self.lang_filter) if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: - self.result = {'encoding': - self._esc_charset_prober.charset_name, - 'confidence': - self._esc_charset_prober.get_confidence(), - 'language': - self._esc_charset_prober.language} + self.result = { + "encoding": self._esc_charset_prober.charset_name, + "confidence": self._esc_charset_prober.get_confidence(), + "language": self._esc_charset_prober.language, + } self.done = True # If we've seen high bytes (i.e., those with values greater than 127), # we need to do more complicated checks using all our multi-byte and @@ -207,17 +269,20 @@ def feed(self, byte_str): if self.lang_filter & LanguageFilter.NON_CJK: self._charset_probers.append(SBCSGroupProber()) self._charset_probers.append(Latin1Prober()) + self._charset_probers.append(MacRomanProber()) for prober in self._charset_probers: if prober.feed(byte_str) == ProbingState.FOUND_IT: - self.result = {'encoding': prober.charset_name, - 'confidence': prober.get_confidence(), - 'language': prober.language} + self.result = { + "encoding": prober.charset_name, + "confidence": prober.get_confidence(), + "language": prober.language, + } self.done = True break if self.WIN_BYTE_DETECTOR.search(byte_str): self._has_win_bytes = True - def close(self): + def close(self) -> ResultDict: """ Stop analyzing the current document and come up with a final prediction. @@ -231,13 +296,11 @@ def close(self): self.done = True if not self._got_data: - self.logger.debug('no data received!') + self.logger.debug("no data received!") # Default to ASCII if it is all we've seen so far elif self._input_state == InputState.PURE_ASCII: - self.result = {'encoding': 'ascii', - 'confidence': 1.0, - 'language': ''} + self.result = {"encoding": "ascii", "confidence": 1.0, "language": ""} # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD elif self._input_state == InputState.HIGH_BYTE: @@ -253,34 +316,47 @@ def close(self): max_prober = prober if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): charset_name = max_prober.charset_name - lower_charset_name = max_prober.charset_name.lower() + assert charset_name is not None + lower_charset_name = charset_name.lower() confidence = max_prober.get_confidence() # Use Windows encoding name instead of ISO-8859 if we saw any # extra Windows-specific bytes - if lower_charset_name.startswith('iso-8859'): + if lower_charset_name.startswith("iso-8859"): if self._has_win_bytes: - charset_name = self.ISO_WIN_MAP.get(lower_charset_name, - charset_name) - self.result = {'encoding': charset_name, - 'confidence': confidence, - 'language': max_prober.language} + charset_name = self.ISO_WIN_MAP.get( + lower_charset_name, charset_name + ) + # Rename legacy encodings with superset encodings if asked + if self.should_rename_legacy: + charset_name = self.LEGACY_MAP.get( + (charset_name or "").lower(), charset_name + ) + self.result = { + "encoding": charset_name, + "confidence": confidence, + "language": max_prober.language, + } # Log all prober confidences if none met MINIMUM_THRESHOLD if self.logger.getEffectiveLevel() <= logging.DEBUG: - if self.result['encoding'] is None: - self.logger.debug('no probers hit minimum threshold') + if self.result["encoding"] is None: + self.logger.debug("no probers hit minimum threshold") for group_prober in self._charset_probers: if not group_prober: continue if isinstance(group_prober, CharSetGroupProber): for prober in group_prober.probers: - self.logger.debug('%s %s confidence = %s', - prober.charset_name, - prober.language, - prober.get_confidence()) + self.logger.debug( + "%s %s confidence = %s", + prober.charset_name, + prober.language, + prober.get_confidence(), + ) else: - self.logger.debug('%s %s confidence = %s', - group_prober.charset_name, - group_prober.language, - group_prober.get_confidence()) + self.logger.debug( + "%s %s confidence = %s", + group_prober.charset_name, + group_prober.language, + group_prober.get_confidence(), + ) return self.result diff --git a/script.module.chardet/lib/chardet/utf1632prober.py b/script.module.chardet/lib/chardet/utf1632prober.py new file mode 100644 index 000000000..6bdec63d6 --- /dev/null +++ b/script.module.chardet/lib/chardet/utf1632prober.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# +# Contributor(s): +# Jason Zavaglia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### +from typing import List, Union + +from .charsetprober import CharSetProber +from .enums import ProbingState + + +class UTF1632Prober(CharSetProber): + """ + This class simply looks for occurrences of zero bytes, and infers + whether the file is UTF16 or UTF32 (low-endian or big-endian) + For instance, files looking like ( \0 \0 \0 [nonzero] )+ + have a good probability to be UTF32BE. Files looking like ( \0 [nonzero] )+ + may be guessed to be UTF16BE, and inversely for little-endian varieties. + """ + + # how many logical characters to scan before feeling confident of prediction + MIN_CHARS_FOR_DETECTION = 20 + # a fixed constant ratio of expected zeros or non-zeros in modulo-position. + EXPECTED_RATIO = 0.94 + + def __init__(self) -> None: + super().__init__() + self.position = 0 + self.zeros_at_mod = [0] * 4 + self.nonzeros_at_mod = [0] * 4 + self._state = ProbingState.DETECTING + self.quad = [0, 0, 0, 0] + self.invalid_utf16be = False + self.invalid_utf16le = False + self.invalid_utf32be = False + self.invalid_utf32le = False + self.first_half_surrogate_pair_detected_16be = False + self.first_half_surrogate_pair_detected_16le = False + self.reset() + + def reset(self) -> None: + super().reset() + self.position = 0 + self.zeros_at_mod = [0] * 4 + self.nonzeros_at_mod = [0] * 4 + self._state = ProbingState.DETECTING + self.invalid_utf16be = False + self.invalid_utf16le = False + self.invalid_utf32be = False + self.invalid_utf32le = False + self.first_half_surrogate_pair_detected_16be = False + self.first_half_surrogate_pair_detected_16le = False + self.quad = [0, 0, 0, 0] + + @property + def charset_name(self) -> str: + if self.is_likely_utf32be(): + return "utf-32be" + if self.is_likely_utf32le(): + return "utf-32le" + if self.is_likely_utf16be(): + return "utf-16be" + if self.is_likely_utf16le(): + return "utf-16le" + # default to something valid + return "utf-16" + + @property + def language(self) -> str: + return "" + + def approx_32bit_chars(self) -> float: + return max(1.0, self.position / 4.0) + + def approx_16bit_chars(self) -> float: + return max(1.0, self.position / 2.0) + + def is_likely_utf32be(self) -> bool: + approx_chars = self.approx_32bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + self.zeros_at_mod[0] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[1] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[2] / approx_chars > self.EXPECTED_RATIO + and self.nonzeros_at_mod[3] / approx_chars > self.EXPECTED_RATIO + and not self.invalid_utf32be + ) + + def is_likely_utf32le(self) -> bool: + approx_chars = self.approx_32bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + self.nonzeros_at_mod[0] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[1] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[2] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[3] / approx_chars > self.EXPECTED_RATIO + and not self.invalid_utf32le + ) + + def is_likely_utf16be(self) -> bool: + approx_chars = self.approx_16bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + (self.nonzeros_at_mod[1] + self.nonzeros_at_mod[3]) / approx_chars + > self.EXPECTED_RATIO + and (self.zeros_at_mod[0] + self.zeros_at_mod[2]) / approx_chars + > self.EXPECTED_RATIO + and not self.invalid_utf16be + ) + + def is_likely_utf16le(self) -> bool: + approx_chars = self.approx_16bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + (self.nonzeros_at_mod[0] + self.nonzeros_at_mod[2]) / approx_chars + > self.EXPECTED_RATIO + and (self.zeros_at_mod[1] + self.zeros_at_mod[3]) / approx_chars + > self.EXPECTED_RATIO + and not self.invalid_utf16le + ) + + def validate_utf32_characters(self, quad: List[int]) -> None: + """ + Validate if the quad of bytes is valid UTF-32. + + UTF-32 is valid in the range 0x00000000 - 0x0010FFFF + excluding 0x0000D800 - 0x0000DFFF + + https://en.wikipedia.org/wiki/UTF-32 + """ + if ( + quad[0] != 0 + or quad[1] > 0x10 + or (quad[0] == 0 and quad[1] == 0 and 0xD8 <= quad[2] <= 0xDF) + ): + self.invalid_utf32be = True + if ( + quad[3] != 0 + or quad[2] > 0x10 + or (quad[3] == 0 and quad[2] == 0 and 0xD8 <= quad[1] <= 0xDF) + ): + self.invalid_utf32le = True + + def validate_utf16_characters(self, pair: List[int]) -> None: + """ + Validate if the pair of bytes is valid UTF-16. + + UTF-16 is valid in the range 0x0000 - 0xFFFF excluding 0xD800 - 0xFFFF + with an exception for surrogate pairs, which must be in the range + 0xD800-0xDBFF followed by 0xDC00-0xDFFF + + https://en.wikipedia.org/wiki/UTF-16 + """ + if not self.first_half_surrogate_pair_detected_16be: + if 0xD8 <= pair[0] <= 0xDB: + self.first_half_surrogate_pair_detected_16be = True + elif 0xDC <= pair[0] <= 0xDF: + self.invalid_utf16be = True + else: + if 0xDC <= pair[0] <= 0xDF: + self.first_half_surrogate_pair_detected_16be = False + else: + self.invalid_utf16be = True + + if not self.first_half_surrogate_pair_detected_16le: + if 0xD8 <= pair[1] <= 0xDB: + self.first_half_surrogate_pair_detected_16le = True + elif 0xDC <= pair[1] <= 0xDF: + self.invalid_utf16le = True + else: + if 0xDC <= pair[1] <= 0xDF: + self.first_half_surrogate_pair_detected_16le = False + else: + self.invalid_utf16le = True + + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: + for c in byte_str: + mod4 = self.position % 4 + self.quad[mod4] = c + if mod4 == 3: + self.validate_utf32_characters(self.quad) + self.validate_utf16_characters(self.quad[0:2]) + self.validate_utf16_characters(self.quad[2:4]) + if c == 0: + self.zeros_at_mod[mod4] += 1 + else: + self.nonzeros_at_mod[mod4] += 1 + self.position += 1 + return self.state + + @property + def state(self) -> ProbingState: + if self._state in {ProbingState.NOT_ME, ProbingState.FOUND_IT}: + # terminal, decided states + return self._state + if self.get_confidence() > 0.80: + self._state = ProbingState.FOUND_IT + elif self.position > 4 * 1024: + # if we get to 4kb into the file, and we can't conclude it's UTF, + # let's give up + self._state = ProbingState.NOT_ME + return self._state + + def get_confidence(self) -> float: + return ( + 0.85 + if ( + self.is_likely_utf16le() + or self.is_likely_utf16be() + or self.is_likely_utf32le() + or self.is_likely_utf32be() + ) + else 0.00 + ) diff --git a/script.module.chardet/lib/chardet/utf8prober.py b/script.module.chardet/lib/chardet/utf8prober.py index 6c3196cc2..d96354d97 100644 --- a/script.module.chardet/lib/chardet/utf8prober.py +++ b/script.module.chardet/lib/chardet/utf8prober.py @@ -25,45 +25,46 @@ # 02110-1301 USA ######################### END LICENSE BLOCK ######################### +from typing import Union + from .charsetprober import CharSetProber -from .enums import ProbingState, MachineState from .codingstatemachine import CodingStateMachine +from .enums import MachineState, ProbingState from .mbcssm import UTF8_SM_MODEL - class UTF8Prober(CharSetProber): ONE_CHAR_PROB = 0.5 - def __init__(self): - super(UTF8Prober, self).__init__() + def __init__(self) -> None: + super().__init__() self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) - self._num_mb_chars = None + self._num_mb_chars = 0 self.reset() - def reset(self): - super(UTF8Prober, self).reset() + def reset(self) -> None: + super().reset() self.coding_sm.reset() self._num_mb_chars = 0 @property - def charset_name(self): + def charset_name(self) -> str: return "utf-8" @property - def language(self): + def language(self) -> str: return "" - def feed(self, byte_str): + def feed(self, byte_str: Union[bytes, bytearray]) -> ProbingState: for c in byte_str: coding_state = self.coding_sm.next_state(c) if coding_state == MachineState.ERROR: self._state = ProbingState.NOT_ME break - elif coding_state == MachineState.ITS_ME: + if coding_state == MachineState.ITS_ME: self._state = ProbingState.FOUND_IT break - elif coding_state == MachineState.START: + if coding_state == MachineState.START: if self.coding_sm.get_current_charlen() >= 2: self._num_mb_chars += 1 @@ -73,10 +74,9 @@ def feed(self, byte_str): return self.state - def get_confidence(self): + def get_confidence(self) -> float: unlike = 0.99 if self._num_mb_chars < 6: - unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars + unlike *= self.ONE_CHAR_PROB**self._num_mb_chars return 1.0 - unlike - else: - return unlike + return unlike diff --git a/script.module.chardet/lib/chardet/version.py b/script.module.chardet/lib/chardet/version.py index 70369b9d6..c5e9d85cd 100644 --- a/script.module.chardet/lib/chardet/version.py +++ b/script.module.chardet/lib/chardet/version.py @@ -1,9 +1,9 @@ """ This module exists only to simplify retrieving the version number of chardet -from within setup.py and from chardet subpackages. +from within setuptools and from chardet subpackages. :author: Dan Blanchard (dan.blanchard@gmail.com) """ -__version__ = "4.0.0" -VERSION = __version__.split('.') +__version__ = "5.1.0" +VERSION = __version__.split(".") From a9050db005c6659e60c64a7d75782d32c38d3353 Mon Sep 17 00:00:00 2001 From: L2501 Date: Thu, 6 Jul 2023 00:11:42 +0300 Subject: [PATCH 050/145] [script.module.certifi] 2023.5.7 (#2474) --- .../{LICENSE => LICENSE.txt} | 4 +- script.module.certifi/README.rst | 56 ---- script.module.certifi/addon.xml | 4 +- script.module.certifi/lib/certifi/__init__.py | 2 +- script.module.certifi/lib/certifi/cacert.pem | 243 +++++------------- 5 files changed, 67 insertions(+), 242 deletions(-) rename script.module.certifi/{LICENSE => LICENSE.txt} (85%) delete mode 100644 script.module.certifi/README.rst diff --git a/script.module.certifi/LICENSE b/script.module.certifi/LICENSE.txt similarity index 85% rename from script.module.certifi/LICENSE rename to script.module.certifi/LICENSE.txt index 802b53ff1..0a64774ea 100644 --- a/script.module.certifi/LICENSE +++ b/script.module.certifi/LICENSE.txt @@ -1,4 +1,4 @@ -This packge contains a modified version of ca-bundle.crt: +This package contains a modified version of ca-bundle.crt: ca-bundle.crt -- Bundle of CA Root Certificates @@ -6,7 +6,7 @@ Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# This is a bundle of X.509 certificates of public Certificate Authorities (CA). These were automatically extracted from Mozilla's root certificates file (certdata.txt). This file can be found in the mozilla source tree: -http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# +https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt It contains the certificates in PEM format and therefore can be directly used with curl / libcurl / php_curl, or with an Apache+mod_ssl webserver for SSL client authentication. diff --git a/script.module.certifi/README.rst b/script.module.certifi/README.rst deleted file mode 100644 index 182b5112a..000000000 --- a/script.module.certifi/README.rst +++ /dev/null @@ -1,56 +0,0 @@ -Certifi: Python SSL Certificates -================================ - -`Certifi`_ provides Mozilla's carefully curated collection of Root Certificates for -validating the trustworthiness of SSL certificates while verifying the identity -of TLS hosts. It has been extracted from the `Requests`_ project. - -Installation ------------- - -``certifi`` is available on PyPI. Simply install it with ``pip``:: - - $ pip install certifi - -Usage ------ - -To reference the installed certificate authority (CA) bundle, you can use the -built-in function:: - - >>> import certifi - - >>> certifi.where() - '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' - -Or from the command line:: - - $ python -m certifi - /usr/local/lib/python3.7/site-packages/certifi/cacert.pem - -Enjoy! - -1024-bit Root Certificates -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Browsers and certificate authorities have concluded that 1024-bit keys are -unacceptably weak for certificates, particularly root certificates. For this -reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its -bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) -certificate from the same CA. Because Mozilla removed these certificates from -its bundle, ``certifi`` removed them as well. - -In previous versions, ``certifi`` provided the ``certifi.old_where()`` function -to intentionally re-add the 1024-bit roots back into your bundle. This was not -recommended in production and therefore was removed at the end of 2018. - -.. _`Certifi`: https://certifiio.readthedocs.io/en/latest/ -.. _`Requests`: https://requests.readthedocs.io/en/master/ - -Addition/Removal of Certificates --------------------------------- - -Certifi does not support any addition/removal or other modification of the -CA trust store content. This project is intended to provide a reliable and -highly portable root of trust to python deployments. Look to upstream projects -for methods to use alternate trust. diff --git a/script.module.certifi/addon.xml b/script.module.certifi/addon.xml index a91cf17b3..ece196a28 100644 --- a/script.module.certifi/addon.xml +++ b/script.module.certifi/addon.xml @@ -1,11 +1,11 @@ - + - Python package for providing Mozilla's CA Bundle. + Certifi: Python SSL Certificates Certifi is a carefully curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts. It has been extracted from the Requests project. MPL-2.0 https://github.com/certifi/python-certifi diff --git a/script.module.certifi/lib/certifi/__init__.py b/script.module.certifi/lib/certifi/__init__.py index af4bcc151..705f416d6 100644 --- a/script.module.certifi/lib/certifi/__init__.py +++ b/script.module.certifi/lib/certifi/__init__.py @@ -1,4 +1,4 @@ from .core import contents, where __all__ = ["contents", "where"] -__version__ = "2022.09.24" +__version__ = "2023.05.07" diff --git a/script.module.certifi/lib/certifi/cacert.pem b/script.module.certifi/lib/certifi/cacert.pem index 400515511..5183934bb 100644 --- a/script.module.certifi/lib/certifi/cacert.pem +++ b/script.module.certifi/lib/certifi/cacert.pem @@ -636,37 +636,6 @@ BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- -# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Label: "Network Solutions Certificate Authority" -# Serial: 116697915152937497490437556386812487904 -# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e -# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce -# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi -MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu -MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp -dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV -UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO -ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz -c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP -OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl -mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF -BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 -qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw -gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu -bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp -dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 -6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ -h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH -/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv -wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN -pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey ------END CERTIFICATE----- - # Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited # Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited # Label: "COMODO ECC Certification Authority" @@ -2204,46 +2173,6 @@ KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg xwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- -# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Label: "Staat der Nederlanden EV Root CA" -# Serial: 10000013 -# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba -# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb -# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a ------BEGIN CERTIFICATE----- -MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO -TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh -dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y -MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg -TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS -b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS -M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC -UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d -Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p -rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l -pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb -j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC -KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS -/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X -cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH -1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP -px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 -MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI -eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u -2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS -v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC -wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy -CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e -vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 -Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa -Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL -eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 -FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc -7uzXLg== ------END CERTIFICATE----- - # Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust # Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust # Label: "IdenTrust Commercial Root CA 1" @@ -2851,116 +2780,6 @@ T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== -----END CERTIFICATE----- -# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-1" -# Serial: 15752444095811006489 -# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 -# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a -# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD -VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk -MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U -cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y -IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB -pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h -IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG -A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU -cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid -RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V -seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme -9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV -EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW -hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ -DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD -ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I -/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf -ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ -yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts -L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN -zl/HHk484IkzlQsPpTLWPFp5LBk= ------END CERTIFICATE----- - -# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-2" -# Serial: 2711694510199101698 -# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 -# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 -# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 ------BEGIN CERTIFICATE----- -MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV -BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw -IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy -dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig -Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk -MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg -Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD -VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy -dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ -QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq -1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp -2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK -DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape -az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF -3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 -oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM -g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 -mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh -8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd -BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U -nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw -DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX -dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ -MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL -/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX -CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa -ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW -2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 -N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 -Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB -As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp -5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu -1uwJ ------END CERTIFICATE----- - -# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor ECA-1" -# Serial: 9548242946988625984 -# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c -# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd -# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD -VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk -MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U -cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y -IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV -BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw -IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy -dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig -RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb -3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA -BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 -3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou -owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ -wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF -ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf -BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ -MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv -civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 -AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F -hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 -soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI -WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi -tJ/X5g== ------END CERTIFICATE----- - # Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation # Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation # Label: "SSL.com Root Certification Authority RSA" @@ -4706,3 +4525,65 @@ BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu 9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= -----END CERTIFICATE----- + +# Issuer: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY +# Subject: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY +# Label: "BJCA Global Root CA1" +# Serial: 113562791157148395269083148143378328608 +# MD5 Fingerprint: 42:32:99:76:43:33:36:24:35:07:82:9b:28:f9:d0:90 +# SHA1 Fingerprint: d5:ec:8d:7b:4c:ba:79:f4:e7:e8:cb:9d:6b:ae:77:83:10:03:21:6a +# SHA256 Fingerprint: f3:89:6f:88:fe:7c:0a:88:27:66:a7:fa:6a:d2:74:9f:b5:7a:7f:3e:98:fb:76:9c:1f:a7:b0:9c:2c:44:d5:ae +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU +MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI +T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz +MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF +SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh +bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z +xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ +spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5 +58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR +at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll +5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq +nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK +V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/ +pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO +z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn +jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+ +WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF +7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 +YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli +awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u ++2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88 +X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN +SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo +P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI ++pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz +znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9 +eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2 +YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy +r/6zcCwupvI= +-----END CERTIFICATE----- + +# Issuer: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY +# Subject: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY +# Label: "BJCA Global Root CA2" +# Serial: 58605626836079930195615843123109055211 +# MD5 Fingerprint: 5e:0a:f6:47:5f:a6:14:e8:11:01:95:3f:4d:01:eb:3c +# SHA1 Fingerprint: f4:27:86:eb:6e:b8:6d:88:31:67:02:fb:ba:66:a4:53:00:aa:7a:a6 +# SHA256 Fingerprint: 57:4d:f6:93:1e:27:80:39:66:7b:72:0a:fd:c1:60:0f:c2:7e:b6:6d:d3:09:29:79:fb:73:85:64:87:21:28:82 +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw +CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ +VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy +MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ +TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS +b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B +IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+ ++kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK +sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA +94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B +43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== +-----END CERTIFICATE----- From 43f6cceadb45351a3767f61476f073d4840b38b4 Mon Sep 17 00:00:00 2001 From: L2501 Date: Thu, 6 Jul 2023 00:11:57 +0300 Subject: [PATCH 051/145] [script.module.urllib3] 1.26.16+matrix.1 (#2475) --- script.module.urllib3/README.md | 111 ------------- script.module.urllib3/addon.xml | 4 +- script.module.urllib3/lib/urllib3/_version.py | 2 +- .../lib/urllib3/connection.py | 5 + .../lib/urllib3/connectionpool.py | 40 ++++- .../lib/urllib3/contrib/appengine.py | 2 +- .../lib/urllib3/contrib/ntlmpool.py | 4 +- .../packages/backports/weakref_finalize.py | 155 ++++++++++++++++++ .../lib/urllib3/poolmanager.py | 2 +- script.module.urllib3/lib/urllib3/response.py | 4 +- .../lib/urllib3/util/timeout.py | 9 +- script.module.urllib3/lib/urllib3/util/url.py | 6 +- 12 files changed, 209 insertions(+), 135 deletions(-) delete mode 100644 script.module.urllib3/README.md create mode 100644 script.module.urllib3/lib/urllib3/packages/backports/weakref_finalize.py diff --git a/script.module.urllib3/README.md b/script.module.urllib3/README.md deleted file mode 100644 index 523e6b62d..000000000 --- a/script.module.urllib3/README.md +++ /dev/null @@ -1,111 +0,0 @@ -

- -![urllib3](https://github.com/urllib3/urllib3/raw/main/docs/_static/banner_github.svg) - -

- -

- PyPI Version - Python Versions - Join our Discord - Coverage Status - Build Status on GitHub - Documentation Status -

- -urllib3 is a powerful, *user-friendly* HTTP client for Python. Much of the -Python ecosystem already uses urllib3 and you should too. -urllib3 brings many critical features that are missing from the Python -standard libraries: - -- Thread safety. -- Connection pooling. -- Client-side SSL/TLS verification. -- File uploads with multipart encoding. -- Helpers for retrying requests and dealing with HTTP redirects. -- Support for gzip, deflate, and brotli encoding. -- Proxy support for HTTP and SOCKS. -- 100% test coverage. - -urllib3 is powerful and easy to use: - -```python3 ->>> import urllib3 ->>> http = urllib3.PoolManager() ->>> resp = http.request("GET", "http://httpbin.org/robots.txt") ->>> resp.status -200 ->>> resp.data -b"User-agent: *\nDisallow: /deny\n" -``` - -## Installing - -urllib3 can be installed with [pip](https://pip.pypa.io): - -```bash -$ python -m pip install urllib3 -``` - -Alternatively, you can grab the latest source code from [GitHub](https://github.com/urllib3/urllib3): - -```bash -$ git clone https://github.com/urllib3/urllib3.git -$ cd urllib3 -$ pip install . -``` - - -## Documentation - -urllib3 has usage and reference documentation at [urllib3.readthedocs.io](https://urllib3.readthedocs.io). - - -## Community - -urllib3 has a [community Discord channel](https://discord.gg/urllib3) for asking questions and -collaborating with other contributors. Drop by and say hello 👋 - - -## Contributing - -urllib3 happily accepts contributions. Please see our -[contributing documentation](https://urllib3.readthedocs.io/en/latest/contributing.html) -for some tips on getting started. - - -## Security Disclosures - -To report a security vulnerability, please use the -[Tidelift security contact](https://tidelift.com/security). -Tidelift will coordinate the fix and disclosure with maintainers. - - -## Maintainers - -- [@sethmlarson](https://github.com/sethmlarson) (Seth M. Larson) -- [@pquentin](https://github.com/pquentin) (Quentin Pradet) -- [@theacodes](https://github.com/theacodes) (Thea Flowers) -- [@haikuginger](https://github.com/haikuginger) (Jess Shapiro) -- [@lukasa](https://github.com/lukasa) (Cory Benfield) -- [@sigmavirus24](https://github.com/sigmavirus24) (Ian Stapleton Cordasco) -- [@shazow](https://github.com/shazow) (Andrey Petrov) - -👋 - - -## Sponsorship - -If your company benefits from this library, please consider [sponsoring its -development](https://urllib3.readthedocs.io/en/latest/sponsors.html). - - -## For Enterprise - -Professional support for urllib3 is available as part of the [Tidelift -Subscription][1]. Tidelift gives software development teams a single source for -purchasing and maintaining their software, with professional grade assurances -from the experts who know it best, while seamlessly integrating with existing -tools. - -[1]: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme diff --git a/script.module.urllib3/addon.xml b/script.module.urllib3/addon.xml index 02e299ca4..f0bb80712 100644 --- a/script.module.urllib3/addon.xml +++ b/script.module.urllib3/addon.xml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,7 @@ urllib3 is a powerful, user-friendly HTTP client for Python. Much of the Python ecosystem already uses urllib3 and you should too. urllib3 brings many critical features that are missing from the Python standard libraries MIT all - https://urllib3.readthedocs.io/en/latest/ + https://urllib3.readthedocs.io/ https://github.com/urllib3/urllib3 resources/icon.png diff --git a/script.module.urllib3/lib/urllib3/_version.py b/script.module.urllib3/lib/urllib3/_version.py index 308d7f281..d69ca3145 100644 --- a/script.module.urllib3/lib/urllib3/_version.py +++ b/script.module.urllib3/lib/urllib3/_version.py @@ -1,2 +1,2 @@ # This file is protected via CODEOWNERS -__version__ = "1.26.13" +__version__ = "1.26.16" diff --git a/script.module.urllib3/lib/urllib3/connection.py b/script.module.urllib3/lib/urllib3/connection.py index 10fb36c4e..54b96b191 100644 --- a/script.module.urllib3/lib/urllib3/connection.py +++ b/script.module.urllib3/lib/urllib3/connection.py @@ -229,6 +229,11 @@ def putheader(self, header, *values): ) def request(self, method, url, body=None, headers=None): + # Update the inner socket's timeout value to send the request. + # This only triggers if the connection is re-used. + if getattr(self, "sock", None) is not None: + self.sock.settimeout(self.timeout) + if headers is None: headers = {} else: diff --git a/script.module.urllib3/lib/urllib3/connectionpool.py b/script.module.urllib3/lib/urllib3/connectionpool.py index 708739279..96844d933 100644 --- a/script.module.urllib3/lib/urllib3/connectionpool.py +++ b/script.module.urllib3/lib/urllib3/connectionpool.py @@ -50,6 +50,13 @@ from .util.url import _normalize_host as normalize_host from .util.url import get_host, parse_url +try: # Platform-specific: Python 3 + import weakref + + weakref_finalize = weakref.finalize +except AttributeError: # Platform-specific: Python 2 + from .packages.backports.weakref_finalize import weakref_finalize + xrange = six.moves.xrange log = logging.getLogger(__name__) @@ -220,6 +227,16 @@ def __init__( self.conn_kw["proxy"] = self.proxy self.conn_kw["proxy_config"] = self.proxy_config + # Do not pass 'self' as callback to 'finalize'. + # Then the 'finalize' would keep an endless living (leak) to self. + # By just passing a reference to the pool allows the garbage collector + # to free self if nobody else has a reference to it. + pool = self.pool + + # Close all the HTTPConnections in the pool before the + # HTTPConnectionPool object is garbage collected. + weakref_finalize(self, _close_pool_connections, pool) + def _new_conn(self): """ Return a fresh :class:`HTTPConnection`. @@ -379,7 +396,7 @@ def _make_request( timeout_obj = self._get_timeout(timeout) timeout_obj.start_connect() - conn.timeout = timeout_obj.connect_timeout + conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout) # Trigger any extra validation we need to do. try: @@ -489,14 +506,8 @@ def close(self): # Disable access to the pool old_pool, self.pool = self.pool, None - try: - while True: - conn = old_pool.get(block=False) - if conn: - conn.close() - - except queue.Empty: - pass # Done. + # Close all the HTTPConnections in the pool. + _close_pool_connections(old_pool) def is_same_host(self, url): """ @@ -1108,3 +1119,14 @@ def _normalize_host(host, scheme): if host.startswith("[") and host.endswith("]"): host = host[1:-1] return host + + +def _close_pool_connections(pool): + """Drains a queue of connections and closes each one.""" + try: + while True: + conn = pool.get(block=False) + if conn: + conn.close() + except queue.Empty: + pass # Done. diff --git a/script.module.urllib3/lib/urllib3/contrib/appengine.py b/script.module.urllib3/lib/urllib3/contrib/appengine.py index f91bdd6e7..a5a6d9103 100644 --- a/script.module.urllib3/lib/urllib3/contrib/appengine.py +++ b/script.module.urllib3/lib/urllib3/contrib/appengine.py @@ -224,7 +224,7 @@ def urlopen( ) # Check if we should retry the HTTP response. - has_retry_after = bool(http_response.getheader("Retry-After")) + has_retry_after = bool(http_response.headers.get("Retry-After")) if retries.is_retry(method, http_response.status, has_retry_after): retries = retries.increment(method, url, response=http_response, _pool=self) log.debug("Retry: %s", url) diff --git a/script.module.urllib3/lib/urllib3/contrib/ntlmpool.py b/script.module.urllib3/lib/urllib3/contrib/ntlmpool.py index 41a8fd174..471665754 100644 --- a/script.module.urllib3/lib/urllib3/contrib/ntlmpool.py +++ b/script.module.urllib3/lib/urllib3/contrib/ntlmpool.py @@ -69,7 +69,7 @@ def _new_conn(self): log.debug("Request headers: %s", headers) conn.request("GET", self.authurl, None, headers) res = conn.getresponse() - reshdr = dict(res.getheaders()) + reshdr = dict(res.headers) log.debug("Response status: %s %s", res.status, res.reason) log.debug("Response headers: %s", reshdr) log.debug("Response data: %s [...]", res.read(100)) @@ -101,7 +101,7 @@ def _new_conn(self): conn.request("GET", self.authurl, None, headers) res = conn.getresponse() log.debug("Response status: %s %s", res.status, res.reason) - log.debug("Response headers: %s", dict(res.getheaders())) + log.debug("Response headers: %s", dict(res.headers)) log.debug("Response data: %s [...]", res.read()[:100]) if res.status != 200: if res.status == 401: diff --git a/script.module.urllib3/lib/urllib3/packages/backports/weakref_finalize.py b/script.module.urllib3/lib/urllib3/packages/backports/weakref_finalize.py new file mode 100644 index 000000000..a2f2966e5 --- /dev/null +++ b/script.module.urllib3/lib/urllib3/packages/backports/weakref_finalize.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +""" +backports.weakref_finalize +~~~~~~~~~~~~~~~~~~ + +Backports the Python 3 ``weakref.finalize`` method. +""" +from __future__ import absolute_import + +import itertools +import sys +from weakref import ref + +__all__ = ["weakref_finalize"] + + +class weakref_finalize(object): + """Class for finalization of weakrefable objects + finalize(obj, func, *args, **kwargs) returns a callable finalizer + object which will be called when obj is garbage collected. The + first time the finalizer is called it evaluates func(*arg, **kwargs) + and returns the result. After this the finalizer is dead, and + calling it just returns None. + When the program exits any remaining finalizers for which the + atexit attribute is true will be run in reverse order of creation. + By default atexit is true. + """ + + # Finalizer objects don't have any state of their own. They are + # just used as keys to lookup _Info objects in the registry. This + # ensures that they cannot be part of a ref-cycle. + + __slots__ = () + _registry = {} + _shutdown = False + _index_iter = itertools.count() + _dirty = False + _registered_with_atexit = False + + class _Info(object): + __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") + + def __init__(self, obj, func, *args, **kwargs): + if not self._registered_with_atexit: + # We may register the exit function more than once because + # of a thread race, but that is harmless + import atexit + + atexit.register(self._exitfunc) + weakref_finalize._registered_with_atexit = True + info = self._Info() + info.weakref = ref(obj, self) + info.func = func + info.args = args + info.kwargs = kwargs or None + info.atexit = True + info.index = next(self._index_iter) + self._registry[self] = info + weakref_finalize._dirty = True + + def __call__(self, _=None): + """If alive then mark as dead and return func(*args, **kwargs); + otherwise return None""" + info = self._registry.pop(self, None) + if info and not self._shutdown: + return info.func(*info.args, **(info.kwargs or {})) + + def detach(self): + """If alive then mark as dead and return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None and self._registry.pop(self, None): + return (obj, info.func, info.args, info.kwargs or {}) + + def peek(self): + """If alive then return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None: + return (obj, info.func, info.args, info.kwargs or {}) + + @property + def alive(self): + """Whether finalizer is alive""" + return self in self._registry + + @property + def atexit(self): + """Whether finalizer should be called at exit""" + info = self._registry.get(self) + return bool(info) and info.atexit + + @atexit.setter + def atexit(self, value): + info = self._registry.get(self) + if info: + info.atexit = bool(value) + + def __repr__(self): + info = self._registry.get(self) + obj = info and info.weakref() + if obj is None: + return "<%s object at %#x; dead>" % (type(self).__name__, id(self)) + else: + return "<%s object at %#x; for %r at %#x>" % ( + type(self).__name__, + id(self), + type(obj).__name__, + id(obj), + ) + + @classmethod + def _select_for_exit(cls): + # Return live finalizers marked for exit, oldest first + L = [(f, i) for (f, i) in cls._registry.items() if i.atexit] + L.sort(key=lambda item: item[1].index) + return [f for (f, i) in L] + + @classmethod + def _exitfunc(cls): + # At shutdown invoke finalizers for which atexit is true. + # This is called once all other non-daemonic threads have been + # joined. + reenable_gc = False + try: + if cls._registry: + import gc + + if gc.isenabled(): + reenable_gc = True + gc.disable() + pending = None + while True: + if pending is None or weakref_finalize._dirty: + pending = cls._select_for_exit() + weakref_finalize._dirty = False + if not pending: + break + f = pending.pop() + try: + # gc is disabled, so (assuming no daemonic + # threads) the following is the only line in + # this function which might trigger creation + # of a new finalizer + f() + except Exception: + sys.excepthook(*sys.exc_info()) + assert f not in cls._registry + finally: + # prevent any more finalizers from executing during shutdown + weakref_finalize._shutdown = True + if reenable_gc: + gc.enable() diff --git a/script.module.urllib3/lib/urllib3/poolmanager.py b/script.module.urllib3/lib/urllib3/poolmanager.py index ca4ec3411..14b10daf3 100644 --- a/script.module.urllib3/lib/urllib3/poolmanager.py +++ b/script.module.urllib3/lib/urllib3/poolmanager.py @@ -171,7 +171,7 @@ class PoolManager(RequestMethods): def __init__(self, num_pools=10, headers=None, **connection_pool_kw): RequestMethods.__init__(self, headers) self.connection_pool_kw = connection_pool_kw - self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close()) + self.pools = RecentlyUsedContainer(num_pools) # Locally set the pool classes and keys so other PoolManagers can # override them. diff --git a/script.module.urllib3/lib/urllib3/response.py b/script.module.urllib3/lib/urllib3/response.py index 8f1b4fa88..0bd13d40b 100644 --- a/script.module.urllib3/lib/urllib3/response.py +++ b/script.module.urllib3/lib/urllib3/response.py @@ -666,7 +666,7 @@ def from_httplib(ResponseCls, r, **response_kw): def getheaders(self): warnings.warn( "HTTPResponse.getheaders() is deprecated and will be removed " - "in urllib3 v2.1.0. Instead access HTTResponse.headers directly.", + "in urllib3 v2.1.0. Instead access HTTPResponse.headers directly.", category=DeprecationWarning, stacklevel=2, ) @@ -675,7 +675,7 @@ def getheaders(self): def getheader(self, name, default=None): warnings.warn( "HTTPResponse.getheader() is deprecated and will be removed " - "in urllib3 v2.1.0. Instead use HTTResponse.headers.get(name, default).", + "in urllib3 v2.1.0. Instead use HTTPResponse.headers.get(name, default).", category=DeprecationWarning, stacklevel=2, ) diff --git a/script.module.urllib3/lib/urllib3/util/timeout.py b/script.module.urllib3/lib/urllib3/util/timeout.py index ff69593b0..78e18a627 100644 --- a/script.module.urllib3/lib/urllib3/util/timeout.py +++ b/script.module.urllib3/lib/urllib3/util/timeout.py @@ -2,9 +2,8 @@ import time -# The default socket timeout, used by httplib to indicate that no timeout was -# specified by the user -from socket import _GLOBAL_DEFAULT_TIMEOUT +# The default socket timeout, used by httplib to indicate that no timeout was; specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT, getdefaulttimeout from ..exceptions import TimeoutStateError @@ -116,6 +115,10 @@ def __repr__(self): # __str__ provided for backwards compatibility __str__ = __repr__ + @classmethod + def resolve_default_timeout(cls, timeout): + return getdefaulttimeout() if timeout is cls.DEFAULT_TIMEOUT else timeout + @classmethod def _validate_timeout(cls, value, name): """Check that a timeout attribute is valid. diff --git a/script.module.urllib3/lib/urllib3/util/url.py b/script.module.urllib3/lib/urllib3/util/url.py index 94f1b8d47..e5682d3be 100644 --- a/script.module.urllib3/lib/urllib3/util/url.py +++ b/script.module.urllib3/lib/urllib3/util/url.py @@ -50,7 +50,7 @@ "(?:(?:%(hex)s:){0,6}%(hex)s)?::", ] -UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._!\-~" +UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._\-~" IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")" ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+" IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]" @@ -63,7 +63,7 @@ BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$") ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$") -_HOST_PORT_PAT = ("^(%s|%s|%s)(?::0*([0-9]{0,5}))?$") % ( +_HOST_PORT_PAT = ("^(%s|%s|%s)(?::0*?(|0|[1-9][0-9]{0,4}))?$") % ( REG_NAME_PAT, IPV4_PAT, IPV6_ADDRZ_PAT, @@ -303,7 +303,7 @@ def _normalize_host(host, scheme): def _idna_encode(name): - if name and any([ord(x) > 128 for x in name]): + if name and any(ord(x) >= 128 for x in name): try: import idna except ImportError: From 800b9dae203fe2690363604b442a129e52fdf45e Mon Sep 17 00:00:00 2001 From: L2501 Date: Thu, 6 Jul 2023 17:31:40 +0300 Subject: [PATCH 052/145] [script.module.requests] 2.31.0 (#2476) --- script.module.requests/README.md | 6 - script.module.requests/addon.xml | 10 +- .../lib/requests/__init__.py | 106 +++-- .../lib/requests/__version__.py | 20 +- .../lib/requests/_internal_utils.py | 26 +- .../lib/requests/adapters.py | 264 ++++++------ script.module.requests/lib/requests/api.py | 24 +- script.module.requests/lib/requests/auth.py | 156 +++---- script.module.requests/lib/requests/certs.py | 3 +- script.module.requests/lib/requests/compat.py | 92 ++-- .../lib/requests/cookies.py | 152 +++---- .../lib/requests/exceptions.py | 22 +- script.module.requests/lib/requests/help.py | 101 +++-- script.module.requests/lib/requests/hooks.py | 7 +- script.module.requests/lib/requests/models.py | 347 ++++++++------- .../lib/requests/packages.py | 16 +- .../lib/requests/sessions.py | 278 +++++++----- .../lib/requests/status_codes.py | 169 ++++---- .../lib/requests/structures.py | 12 +- script.module.requests/lib/requests/utils.py | 394 ++++++++++-------- 20 files changed, 1208 insertions(+), 997 deletions(-) delete mode 100644 script.module.requests/README.md diff --git a/script.module.requests/README.md b/script.module.requests/README.md deleted file mode 100644 index 3d38c8c47..000000000 --- a/script.module.requests/README.md +++ /dev/null @@ -1,6 +0,0 @@ -script.module.requests -====================== - -Python requests library packed for KODI. - -See https://github.com/requests/requests diff --git a/script.module.requests/addon.xml b/script.module.requests/addon.xml index ea56040b1..644278b6e 100644 --- a/script.module.requests/addon.xml +++ b/script.module.requests/addon.xml @@ -1,11 +1,11 @@ - + - - - - + + + + diff --git a/script.module.requests/lib/requests/__init__.py b/script.module.requests/lib/requests/__init__.py index 53a5b42af..300a16c57 100644 --- a/script.module.requests/lib/requests/__init__.py +++ b/script.module.requests/lib/requests/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # __ # /__) _ _ _ _ _/ _ # / ( (- (/ (/ (- _) / _) @@ -40,8 +38,10 @@ :license: Apache 2.0, see LICENSE for more details. """ -import urllib3 import warnings + +import urllib3 + from .exceptions import RequestsDependencyWarning try: @@ -54,54 +54,65 @@ except ImportError: chardet_version = None + def check_compatibility(urllib3_version, chardet_version, charset_normalizer_version): - urllib3_version = urllib3_version.split('.') - assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git. + urllib3_version = urllib3_version.split(".") + assert urllib3_version != ["dev"] # Verify urllib3 isn't installed from git. # Sometimes, urllib3 only reports its version as 16.1. if len(urllib3_version) == 2: - urllib3_version.append('0') + urllib3_version.append("0") # Check urllib3 for compatibility. major, minor, patch = urllib3_version # noqa: F811 major, minor, patch = int(major), int(minor), int(patch) - # urllib3 >= 1.21.1, <= 1.26 - assert major == 1 - assert minor >= 21 - assert minor <= 26 + # urllib3 >= 1.21.1 + assert major >= 1 + if major == 1: + assert minor >= 21 # Check charset_normalizer for compatibility. if chardet_version: - major, minor, patch = chardet_version.split('.')[:3] + major, minor, patch = chardet_version.split(".")[:3] major, minor, patch = int(major), int(minor), int(patch) - # chardet_version >= 3.0.2, < 5.0.0 - assert (3, 0, 2) <= (major, minor, patch) < (5, 0, 0) + # chardet_version >= 3.0.2, < 6.0.0 + assert (3, 0, 2) <= (major, minor, patch) < (6, 0, 0) elif charset_normalizer_version: - major, minor, patch = charset_normalizer_version.split('.')[:3] + major, minor, patch = charset_normalizer_version.split(".")[:3] major, minor, patch = int(major), int(minor), int(patch) - # charset_normalizer >= 2.0.0 < 3.0.0 - assert (2, 0, 0) <= (major, minor, patch) < (3, 0, 0) + # charset_normalizer >= 2.0.0 < 4.0.0 + assert (2, 0, 0) <= (major, minor, patch) < (4, 0, 0) else: raise Exception("You need either charset_normalizer or chardet installed") + def _check_cryptography(cryptography_version): # cryptography < 1.3.4 try: - cryptography_version = list(map(int, cryptography_version.split('.'))) + cryptography_version = list(map(int, cryptography_version.split("."))) except ValueError: return if cryptography_version < [1, 3, 4]: - warning = 'Old version of cryptography ({}) may cause slowdown.'.format(cryptography_version) + warning = "Old version of cryptography ({}) may cause slowdown.".format( + cryptography_version + ) warnings.warn(warning, RequestsDependencyWarning) + # Check imported dependencies for compatibility. try: - check_compatibility(urllib3.__version__, chardet_version, charset_normalizer_version) + check_compatibility( + urllib3.__version__, chardet_version, charset_normalizer_version + ) except (AssertionError, ValueError): - warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported " - "version!".format(urllib3.__version__, chardet_version, charset_normalizer_version), - RequestsDependencyWarning) + warnings.warn( + "urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported " + "version!".format( + urllib3.__version__, chardet_version, charset_normalizer_version + ), + RequestsDependencyWarning, + ) # Attempt to enable urllib3's fallback for SNI support # if the standard library doesn't support SNI or the @@ -114,39 +125,56 @@ def _check_cryptography(cryptography_version): if not getattr(ssl, "HAS_SNI", False): from urllib3.contrib import pyopenssl + pyopenssl.inject_into_urllib3() # Check cryptography version from cryptography import __version__ as cryptography_version + _check_cryptography(cryptography_version) except ImportError: pass # urllib3's DependencyWarnings should be silenced. from urllib3.exceptions import DependencyWarning -warnings.simplefilter('ignore', DependencyWarning) -from .__version__ import __title__, __description__, __url__, __version__ -from .__version__ import __build__, __author__, __author_email__, __license__ -from .__version__ import __copyright__, __cake__ - -from . import utils -from . import packages -from .models import Request, Response, PreparedRequest -from .api import request, get, head, post, patch, put, delete, options -from .sessions import session, Session -from .status_codes import codes -from .exceptions import ( - RequestException, Timeout, URLRequired, - TooManyRedirects, HTTPError, ConnectionError, - FileModeWarning, ConnectTimeout, ReadTimeout, JSONDecodeError -) +warnings.simplefilter("ignore", DependencyWarning) # Set default logging handler to avoid "No handler found" warnings. import logging from logging import NullHandler +from . import packages, utils +from .__version__ import ( + __author__, + __author_email__, + __build__, + __cake__, + __copyright__, + __description__, + __license__, + __title__, + __url__, + __version__, +) +from .api import delete, get, head, options, patch, post, put, request +from .exceptions import ( + ConnectionError, + ConnectTimeout, + FileModeWarning, + HTTPError, + JSONDecodeError, + ReadTimeout, + RequestException, + Timeout, + TooManyRedirects, + URLRequired, +) +from .models import PreparedRequest, Request, Response +from .sessions import Session, session +from .status_codes import codes + logging.getLogger(__name__).addHandler(NullHandler()) # FileModeWarnings go off per the default. -warnings.simplefilter('default', FileModeWarning, append=True) +warnings.simplefilter("default", FileModeWarning, append=True) diff --git a/script.module.requests/lib/requests/__version__.py b/script.module.requests/lib/requests/__version__.py index e973b03b5..5063c3f8e 100644 --- a/script.module.requests/lib/requests/__version__.py +++ b/script.module.requests/lib/requests/__version__.py @@ -2,13 +2,13 @@ # |( |- |.| | | |- `-. | `-. # ' ' `-' `-`.`-' `-' `-' ' `-' -__title__ = 'requests' -__description__ = 'Python HTTP for Humans.' -__url__ = 'https://requests.readthedocs.io' -__version__ = '2.27.1' -__build__ = 0x022701 -__author__ = 'Kenneth Reitz' -__author_email__ = 'me@kennethreitz.org' -__license__ = 'Apache 2.0' -__copyright__ = 'Copyright 2022 Kenneth Reitz' -__cake__ = u'\u2728 \U0001f370 \u2728' +__title__ = "requests" +__description__ = "Python HTTP for Humans." +__url__ = "https://requests.readthedocs.io" +__version__ = "2.31.0" +__build__ = 0x023100 +__author__ = "Kenneth Reitz" +__author_email__ = "me@kennethreitz.org" +__license__ = "Apache 2.0" +__copyright__ = "Copyright Kenneth Reitz" +__cake__ = "\u2728 \U0001f370 \u2728" diff --git a/script.module.requests/lib/requests/_internal_utils.py b/script.module.requests/lib/requests/_internal_utils.py index 759d9a56b..f2cf635e2 100644 --- a/script.module.requests/lib/requests/_internal_utils.py +++ b/script.module.requests/lib/requests/_internal_utils.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests._internal_utils ~~~~~~~~~~~~~~ @@ -7,11 +5,24 @@ Provides utility functions that are consumed internally by Requests which depend on extremely few external helpers (such as compat) """ +import re + +from .compat import builtin_str + +_VALID_HEADER_NAME_RE_BYTE = re.compile(rb"^[^:\s][^:\r\n]*$") +_VALID_HEADER_NAME_RE_STR = re.compile(r"^[^:\s][^:\r\n]*$") +_VALID_HEADER_VALUE_RE_BYTE = re.compile(rb"^\S[^\r\n]*$|^$") +_VALID_HEADER_VALUE_RE_STR = re.compile(r"^\S[^\r\n]*$|^$") -from .compat import is_py2, builtin_str, str +_HEADER_VALIDATORS_STR = (_VALID_HEADER_NAME_RE_STR, _VALID_HEADER_VALUE_RE_STR) +_HEADER_VALIDATORS_BYTE = (_VALID_HEADER_NAME_RE_BYTE, _VALID_HEADER_VALUE_RE_BYTE) +HEADER_VALIDATORS = { + bytes: _HEADER_VALIDATORS_BYTE, + str: _HEADER_VALIDATORS_STR, +} -def to_native_string(string, encoding='ascii'): +def to_native_string(string, encoding="ascii"): """Given a string object, regardless of type, returns a representation of that string in the native string type, encoding and decoding where necessary. This assumes ASCII unless told otherwise. @@ -19,10 +30,7 @@ def to_native_string(string, encoding='ascii'): if isinstance(string, builtin_str): out = string else: - if is_py2: - out = string.encode(encoding) - else: - out = string.decode(encoding) + out = string.decode(encoding) return out @@ -36,7 +44,7 @@ def unicode_is_ascii(u_string): """ assert isinstance(u_string, str) try: - u_string.encode('ascii') + u_string.encode("ascii") return True except UnicodeEncodeError: return False diff --git a/script.module.requests/lib/requests/adapters.py b/script.module.requests/lib/requests/adapters.py index fe22ff450..78e3bb6ec 100644 --- a/script.module.requests/lib/requests/adapters.py +++ b/script.module.requests/lib/requests/adapters.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.adapters ~~~~~~~~~~~~~~~~~ @@ -9,58 +7,75 @@ """ import os.path -import socket +import socket # noqa: F401 -from urllib3.poolmanager import PoolManager, proxy_from_url -from urllib3.response import HTTPResponse -from urllib3.util import parse_url -from urllib3.util import Timeout as TimeoutSauce -from urllib3.util.retry import Retry -from urllib3.exceptions import ClosedPoolError -from urllib3.exceptions import ConnectTimeoutError +from urllib3.exceptions import ClosedPoolError, ConnectTimeoutError from urllib3.exceptions import HTTPError as _HTTPError from urllib3.exceptions import InvalidHeader as _InvalidHeader -from urllib3.exceptions import MaxRetryError -from urllib3.exceptions import NewConnectionError +from urllib3.exceptions import ( + LocationValueError, + MaxRetryError, + NewConnectionError, + ProtocolError, +) from urllib3.exceptions import ProxyError as _ProxyError -from urllib3.exceptions import ProtocolError -from urllib3.exceptions import ReadTimeoutError +from urllib3.exceptions import ReadTimeoutError, ResponseError from urllib3.exceptions import SSLError as _SSLError -from urllib3.exceptions import ResponseError -from urllib3.exceptions import LocationValueError +from urllib3.poolmanager import PoolManager, proxy_from_url +from urllib3.util import Timeout as TimeoutSauce +from urllib3.util import parse_url +from urllib3.util.retry import Retry +from .auth import _basic_auth_str +from .compat import basestring, urlparse +from .cookies import extract_cookies_to_jar +from .exceptions import ( + ConnectionError, + ConnectTimeout, + InvalidHeader, + InvalidProxyURL, + InvalidSchema, + InvalidURL, + ProxyError, + ReadTimeout, + RetryError, + SSLError, +) from .models import Response -from .compat import urlparse, basestring -from .utils import (DEFAULT_CA_BUNDLE_PATH, extract_zipped_paths, - get_encoding_from_headers, prepend_scheme_if_needed, - get_auth_from_url, urldefragauth, select_proxy) from .structures import CaseInsensitiveDict -from .cookies import extract_cookies_to_jar -from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError, - ProxyError, RetryError, InvalidSchema, InvalidProxyURL, - InvalidURL, InvalidHeader) -from .auth import _basic_auth_str +from .utils import ( + DEFAULT_CA_BUNDLE_PATH, + extract_zipped_paths, + get_auth_from_url, + get_encoding_from_headers, + prepend_scheme_if_needed, + select_proxy, + urldefragauth, +) try: from urllib3.contrib.socks import SOCKSProxyManager except ImportError: + def SOCKSProxyManager(*args, **kwargs): raise InvalidSchema("Missing dependencies for SOCKS support.") + DEFAULT_POOLBLOCK = False DEFAULT_POOLSIZE = 10 DEFAULT_RETRIES = 0 DEFAULT_POOL_TIMEOUT = None -class BaseAdapter(object): +class BaseAdapter: """The Base Transport Adapter""" def __init__(self): - super(BaseAdapter, self).__init__() + super().__init__() - def send(self, request, stream=False, timeout=None, verify=True, - cert=None, proxies=None): + def send( + self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None + ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest ` being sent. @@ -108,12 +123,22 @@ class HTTPAdapter(BaseAdapter): >>> a = requests.adapters.HTTPAdapter(max_retries=3) >>> s.mount('http://', a) """ - __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', - '_pool_block'] - def __init__(self, pool_connections=DEFAULT_POOLSIZE, - pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES, - pool_block=DEFAULT_POOLBLOCK): + __attrs__ = [ + "max_retries", + "config", + "_pool_connections", + "_pool_maxsize", + "_pool_block", + ] + + def __init__( + self, + pool_connections=DEFAULT_POOLSIZE, + pool_maxsize=DEFAULT_POOLSIZE, + max_retries=DEFAULT_RETRIES, + pool_block=DEFAULT_POOLBLOCK, + ): if max_retries == DEFAULT_RETRIES: self.max_retries = Retry(0, read=False) else: @@ -121,7 +146,7 @@ def __init__(self, pool_connections=DEFAULT_POOLSIZE, self.config = {} self.proxy_manager = {} - super(HTTPAdapter, self).__init__() + super().__init__() self._pool_connections = pool_connections self._pool_maxsize = pool_maxsize @@ -141,10 +166,13 @@ def __setstate__(self, state): for attr, value in state.items(): setattr(self, attr, value) - self.init_poolmanager(self._pool_connections, self._pool_maxsize, - block=self._pool_block) + self.init_poolmanager( + self._pool_connections, self._pool_maxsize, block=self._pool_block + ) - def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs): + def init_poolmanager( + self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs + ): """Initializes a urllib3 PoolManager. This method should not be called from user code, and is only @@ -161,8 +189,12 @@ def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool self._pool_maxsize = maxsize self._pool_block = block - self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize, - block=block, strict=True, **pool_kwargs) + self.poolmanager = PoolManager( + num_pools=connections, + maxsize=maxsize, + block=block, + **pool_kwargs, + ) def proxy_manager_for(self, proxy, **proxy_kwargs): """Return urllib3 ProxyManager for the given proxy. @@ -178,7 +210,7 @@ def proxy_manager_for(self, proxy, **proxy_kwargs): """ if proxy in self.proxy_manager: manager = self.proxy_manager[proxy] - elif proxy.lower().startswith('socks'): + elif proxy.lower().startswith("socks"): username, password = get_auth_from_url(proxy) manager = self.proxy_manager[proxy] = SOCKSProxyManager( proxy, @@ -187,7 +219,7 @@ def proxy_manager_for(self, proxy, **proxy_kwargs): num_pools=self._pool_connections, maxsize=self._pool_maxsize, block=self._pool_block, - **proxy_kwargs + **proxy_kwargs, ) else: proxy_headers = self.proxy_headers(proxy) @@ -197,7 +229,8 @@ def proxy_manager_for(self, proxy, **proxy_kwargs): num_pools=self._pool_connections, maxsize=self._pool_maxsize, block=self._pool_block, - **proxy_kwargs) + **proxy_kwargs, + ) return manager @@ -213,7 +246,7 @@ def cert_verify(self, conn, url, verify, cert): to a CA bundle to use :param cert: The SSL certificate to verify. """ - if url.lower().startswith('https') and verify: + if url.lower().startswith("https") and verify: cert_loc = None @@ -225,17 +258,19 @@ def cert_verify(self, conn, url, verify, cert): cert_loc = extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH) if not cert_loc or not os.path.exists(cert_loc): - raise IOError("Could not find a suitable TLS CA certificate bundle, " - "invalid path: {}".format(cert_loc)) + raise OSError( + f"Could not find a suitable TLS CA certificate bundle, " + f"invalid path: {cert_loc}" + ) - conn.cert_reqs = 'CERT_REQUIRED' + conn.cert_reqs = "CERT_REQUIRED" if not os.path.isdir(cert_loc): conn.ca_certs = cert_loc else: conn.ca_cert_dir = cert_loc else: - conn.cert_reqs = 'CERT_NONE' + conn.cert_reqs = "CERT_NONE" conn.ca_certs = None conn.ca_cert_dir = None @@ -247,11 +282,14 @@ def cert_verify(self, conn, url, verify, cert): conn.cert_file = cert conn.key_file = None if conn.cert_file and not os.path.exists(conn.cert_file): - raise IOError("Could not find the TLS certificate file, " - "invalid path: {}".format(conn.cert_file)) + raise OSError( + f"Could not find the TLS certificate file, " + f"invalid path: {conn.cert_file}" + ) if conn.key_file and not os.path.exists(conn.key_file): - raise IOError("Could not find the TLS key file, " - "invalid path: {}".format(conn.key_file)) + raise OSError( + f"Could not find the TLS key file, invalid path: {conn.key_file}" + ) def build_response(self, req, resp): """Builds a :class:`Response ` object from a urllib3 @@ -266,10 +304,10 @@ def build_response(self, req, resp): response = Response() # Fallback to None if there's no status_code, for whatever reason. - response.status_code = getattr(resp, 'status', None) + response.status_code = getattr(resp, "status", None) # Make headers case-insensitive. - response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {})) + response.headers = CaseInsensitiveDict(getattr(resp, "headers", {})) # Set encoding. response.encoding = get_encoding_from_headers(response.headers) @@ -277,7 +315,7 @@ def build_response(self, req, resp): response.reason = response.raw.reason if isinstance(req.url, bytes): - response.url = req.url.decode('utf-8') + response.url = req.url.decode("utf-8") else: response.url = req.url @@ -302,11 +340,13 @@ def get_connection(self, url, proxies=None): proxy = select_proxy(url, proxies) if proxy: - proxy = prepend_scheme_if_needed(proxy, 'http') + proxy = prepend_scheme_if_needed(proxy, "http") proxy_url = parse_url(proxy) if not proxy_url.host: - raise InvalidProxyURL("Please check proxy URL. It is malformed" - " and could be missing the host.") + raise InvalidProxyURL( + "Please check proxy URL. It is malformed " + "and could be missing the host." + ) proxy_manager = self.proxy_manager_for(proxy) conn = proxy_manager.connection_from_url(url) else: @@ -344,11 +384,11 @@ def request_url(self, request, proxies): proxy = select_proxy(request.url, proxies) scheme = urlparse(request.url).scheme - is_proxied_http_request = (proxy and scheme != 'https') + is_proxied_http_request = proxy and scheme != "https" using_socks_proxy = False if proxy: proxy_scheme = urlparse(proxy).scheme.lower() - using_socks_proxy = proxy_scheme.startswith('socks') + using_socks_proxy = proxy_scheme.startswith("socks") url = request.path_url if is_proxied_http_request and not using_socks_proxy: @@ -387,12 +427,13 @@ def proxy_headers(self, proxy): username, password = get_auth_from_url(proxy) if username: - headers['Proxy-Authorization'] = _basic_auth_str(username, - password) + headers["Proxy-Authorization"] = _basic_auth_str(username, password) return headers - def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): + def send( + self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None + ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest ` being sent. @@ -416,88 +457,47 @@ def send(self, request, stream=False, timeout=None, verify=True, cert=None, prox self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) - self.add_headers(request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies) + self.add_headers( + request, + stream=stream, + timeout=timeout, + verify=verify, + cert=cert, + proxies=proxies, + ) - chunked = not (request.body is None or 'Content-Length' in request.headers) + chunked = not (request.body is None or "Content-Length" in request.headers) if isinstance(timeout, tuple): try: connect, read = timeout timeout = TimeoutSauce(connect=connect, read=read) - except ValueError as e: - # this may raise a string formatting error. - err = ("Invalid timeout {}. Pass a (connect, read) " - "timeout tuple, or a single float to set " - "both timeouts to the same value".format(timeout)) - raise ValueError(err) + except ValueError: + raise ValueError( + f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " + f"or a single float to set both timeouts to the same value." + ) elif isinstance(timeout, TimeoutSauce): pass else: timeout = TimeoutSauce(connect=timeout, read=timeout) try: - if not chunked: - resp = conn.urlopen( - method=request.method, - url=url, - body=request.body, - headers=request.headers, - redirect=False, - assert_same_host=False, - preload_content=False, - decode_content=False, - retries=self.max_retries, - timeout=timeout - ) + resp = conn.urlopen( + method=request.method, + url=url, + body=request.body, + headers=request.headers, + redirect=False, + assert_same_host=False, + preload_content=False, + decode_content=False, + retries=self.max_retries, + timeout=timeout, + chunked=chunked, + ) - # Send the request. - else: - if hasattr(conn, 'proxy_pool'): - conn = conn.proxy_pool - - low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT) - - try: - skip_host = 'Host' in request.headers - low_conn.putrequest(request.method, - url, - skip_accept_encoding=True, - skip_host=skip_host) - - for header, value in request.headers.items(): - low_conn.putheader(header, value) - - low_conn.endheaders() - - for i in request.body: - low_conn.send(hex(len(i))[2:].encode('utf-8')) - low_conn.send(b'\r\n') - low_conn.send(i) - low_conn.send(b'\r\n') - low_conn.send(b'0\r\n\r\n') - - # Receive the response from the server - try: - # For Python 2.7, use buffering of HTTP responses - r = low_conn.getresponse(buffering=True) - except TypeError: - # For compatibility with Python 3.3+ - r = low_conn.getresponse() - - resp = HTTPResponse.from_httplib( - r, - pool=conn, - connection=low_conn, - preload_content=False, - decode_content=False - ) - except: - # If we hit any problems here, clean up the connection. - # Then, reraise so that we can handle the actual exception. - low_conn.close() - raise - - except (ProtocolError, socket.error) as err: + except (ProtocolError, OSError) as err: raise ConnectionError(err, request=request) except MaxRetryError as e: diff --git a/script.module.requests/lib/requests/api.py b/script.module.requests/lib/requests/api.py index 4cba90eef..cd0b3eeac 100644 --- a/script.module.requests/lib/requests/api.py +++ b/script.module.requests/lib/requests/api.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.api ~~~~~~~~~~~~ @@ -72,7 +70,7 @@ def get(url, params=None, **kwargs): :rtype: requests.Response """ - return request('get', url, params=params, **kwargs) + return request("get", url, params=params, **kwargs) def options(url, **kwargs): @@ -84,7 +82,7 @@ def options(url, **kwargs): :rtype: requests.Response """ - return request('options', url, **kwargs) + return request("options", url, **kwargs) def head(url, **kwargs): @@ -98,8 +96,8 @@ def head(url, **kwargs): :rtype: requests.Response """ - kwargs.setdefault('allow_redirects', False) - return request('head', url, **kwargs) + kwargs.setdefault("allow_redirects", False) + return request("head", url, **kwargs) def post(url, data=None, json=None, **kwargs): @@ -108,13 +106,13 @@ def post(url, data=None, json=None, **kwargs): :param url: URL for the new :class:`Request` object. :param data: (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the :class:`Request`. - :param json: (optional) json data to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. :param \*\*kwargs: Optional arguments that ``request`` takes. :return: :class:`Response ` object :rtype: requests.Response """ - return request('post', url, data=data, json=json, **kwargs) + return request("post", url, data=data, json=json, **kwargs) def put(url, data=None, **kwargs): @@ -123,13 +121,13 @@ def put(url, data=None, **kwargs): :param url: URL for the new :class:`Request` object. :param data: (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the :class:`Request`. - :param json: (optional) json data to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. :param \*\*kwargs: Optional arguments that ``request`` takes. :return: :class:`Response ` object :rtype: requests.Response """ - return request('put', url, data=data, **kwargs) + return request("put", url, data=data, **kwargs) def patch(url, data=None, **kwargs): @@ -138,13 +136,13 @@ def patch(url, data=None, **kwargs): :param url: URL for the new :class:`Request` object. :param data: (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the :class:`Request`. - :param json: (optional) json data to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. :param \*\*kwargs: Optional arguments that ``request`` takes. :return: :class:`Response ` object :rtype: requests.Response """ - return request('patch', url, data=data, **kwargs) + return request("patch", url, data=data, **kwargs) def delete(url, **kwargs): @@ -156,4 +154,4 @@ def delete(url, **kwargs): :rtype: requests.Response """ - return request('delete', url, **kwargs) + return request("delete", url, **kwargs) diff --git a/script.module.requests/lib/requests/auth.py b/script.module.requests/lib/requests/auth.py index eeface39a..9733686dd 100644 --- a/script.module.requests/lib/requests/auth.py +++ b/script.module.requests/lib/requests/auth.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.auth ~~~~~~~~~~~~~ @@ -7,22 +5,21 @@ This module contains the authentication handlers for Requests. """ +import hashlib import os import re -import time -import hashlib import threading +import time import warnings - from base64 import b64encode -from .compat import urlparse, str, basestring -from .cookies import extract_cookies_to_jar from ._internal_utils import to_native_string +from .compat import basestring, str, urlparse +from .cookies import extract_cookies_to_jar from .utils import parse_dict_header -CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' -CONTENT_TYPE_MULTI_PART = 'multipart/form-data' +CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded" +CONTENT_TYPE_MULTI_PART = "multipart/form-data" def _basic_auth_str(username, password): @@ -57,23 +54,23 @@ def _basic_auth_str(username, password): # -- End Removal -- if isinstance(username, str): - username = username.encode('latin1') + username = username.encode("latin1") if isinstance(password, str): - password = password.encode('latin1') + password = password.encode("latin1") - authstr = 'Basic ' + to_native_string( - b64encode(b':'.join((username, password))).strip() + authstr = "Basic " + to_native_string( + b64encode(b":".join((username, password))).strip() ) return authstr -class AuthBase(object): +class AuthBase: """Base class that all auth implementations derive from""" def __call__(self, r): - raise NotImplementedError('Auth hooks must be callable.') + raise NotImplementedError("Auth hooks must be callable.") class HTTPBasicAuth(AuthBase): @@ -84,16 +81,18 @@ def __init__(self, username, password): self.password = password def __eq__(self, other): - return all([ - self.username == getattr(other, 'username', None), - self.password == getattr(other, 'password', None) - ]) + return all( + [ + self.username == getattr(other, "username", None), + self.password == getattr(other, "password", None), + ] + ) def __ne__(self, other): return not self == other def __call__(self, r): - r.headers['Authorization'] = _basic_auth_str(self.username, self.password) + r.headers["Authorization"] = _basic_auth_str(self.username, self.password) return r @@ -101,7 +100,7 @@ class HTTPProxyAuth(HTTPBasicAuth): """Attaches HTTP Proxy Authentication to a given Request object.""" def __call__(self, r): - r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password) + r.headers["Proxy-Authorization"] = _basic_auth_str(self.username, self.password) return r @@ -116,9 +115,9 @@ def __init__(self, username, password): def init_per_thread_state(self): # Ensure state is initialized just once per-thread - if not hasattr(self._thread_local, 'init'): + if not hasattr(self._thread_local, "init"): self._thread_local.init = True - self._thread_local.last_nonce = '' + self._thread_local.last_nonce = "" self._thread_local.nonce_count = 0 self._thread_local.chal = {} self._thread_local.pos = None @@ -129,44 +128,52 @@ def build_digest_header(self, method, url): :rtype: str """ - realm = self._thread_local.chal['realm'] - nonce = self._thread_local.chal['nonce'] - qop = self._thread_local.chal.get('qop') - algorithm = self._thread_local.chal.get('algorithm') - opaque = self._thread_local.chal.get('opaque') + realm = self._thread_local.chal["realm"] + nonce = self._thread_local.chal["nonce"] + qop = self._thread_local.chal.get("qop") + algorithm = self._thread_local.chal.get("algorithm") + opaque = self._thread_local.chal.get("opaque") hash_utf8 = None if algorithm is None: - _algorithm = 'MD5' + _algorithm = "MD5" else: _algorithm = algorithm.upper() # lambdas assume digest modules are imported at the top level - if _algorithm == 'MD5' or _algorithm == 'MD5-SESS': + if _algorithm == "MD5" or _algorithm == "MD5-SESS": + def md5_utf8(x): if isinstance(x, str): - x = x.encode('utf-8') + x = x.encode("utf-8") return hashlib.md5(x).hexdigest() + hash_utf8 = md5_utf8 - elif _algorithm == 'SHA': + elif _algorithm == "SHA": + def sha_utf8(x): if isinstance(x, str): - x = x.encode('utf-8') + x = x.encode("utf-8") return hashlib.sha1(x).hexdigest() + hash_utf8 = sha_utf8 - elif _algorithm == 'SHA-256': + elif _algorithm == "SHA-256": + def sha256_utf8(x): if isinstance(x, str): - x = x.encode('utf-8') + x = x.encode("utf-8") return hashlib.sha256(x).hexdigest() + hash_utf8 = sha256_utf8 - elif _algorithm == 'SHA-512': + elif _algorithm == "SHA-512": + def sha512_utf8(x): if isinstance(x, str): - x = x.encode('utf-8') + x = x.encode("utf-8") return hashlib.sha512(x).hexdigest() + hash_utf8 = sha512_utf8 - KD = lambda s, d: hash_utf8("%s:%s" % (s, d)) + KD = lambda s, d: hash_utf8(f"{s}:{d}") # noqa:E731 if hash_utf8 is None: return None @@ -177,10 +184,10 @@ def sha512_utf8(x): #: path is request-uri defined in RFC 2616 which should not be empty path = p_parsed.path or "/" if p_parsed.query: - path += '?' + p_parsed.query + path += f"?{p_parsed.query}" - A1 = '%s:%s:%s' % (self.username, realm, self.password) - A2 = '%s:%s' % (method, path) + A1 = f"{self.username}:{realm}:{self.password}" + A2 = f"{method}:{path}" HA1 = hash_utf8(A1) HA2 = hash_utf8(A2) @@ -189,22 +196,20 @@ def sha512_utf8(x): self._thread_local.nonce_count += 1 else: self._thread_local.nonce_count = 1 - ncvalue = '%08x' % self._thread_local.nonce_count - s = str(self._thread_local.nonce_count).encode('utf-8') - s += nonce.encode('utf-8') - s += time.ctime().encode('utf-8') + ncvalue = f"{self._thread_local.nonce_count:08x}" + s = str(self._thread_local.nonce_count).encode("utf-8") + s += nonce.encode("utf-8") + s += time.ctime().encode("utf-8") s += os.urandom(8) - cnonce = (hashlib.sha1(s).hexdigest()[:16]) - if _algorithm == 'MD5-SESS': - HA1 = hash_utf8('%s:%s:%s' % (HA1, nonce, cnonce)) + cnonce = hashlib.sha1(s).hexdigest()[:16] + if _algorithm == "MD5-SESS": + HA1 = hash_utf8(f"{HA1}:{nonce}:{cnonce}") if not qop: - respdig = KD(HA1, "%s:%s" % (nonce, HA2)) - elif qop == 'auth' or 'auth' in qop.split(','): - noncebit = "%s:%s:%s:%s:%s" % ( - nonce, ncvalue, cnonce, 'auth', HA2 - ) + respdig = KD(HA1, f"{nonce}:{HA2}") + elif qop == "auth" or "auth" in qop.split(","): + noncebit = f"{nonce}:{ncvalue}:{cnonce}:auth:{HA2}" respdig = KD(HA1, noncebit) else: # XXX handle auth-int. @@ -213,18 +218,20 @@ def sha512_utf8(x): self._thread_local.last_nonce = nonce # XXX should the partial digests be encoded too? - base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \ - 'response="%s"' % (self.username, realm, nonce, path, respdig) + base = ( + f'username="{self.username}", realm="{realm}", nonce="{nonce}", ' + f'uri="{path}", response="{respdig}"' + ) if opaque: - base += ', opaque="%s"' % opaque + base += f', opaque="{opaque}"' if algorithm: - base += ', algorithm="%s"' % algorithm + base += f', algorithm="{algorithm}"' if entdig: - base += ', digest="%s"' % entdig + base += f', digest="{entdig}"' if qop: - base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce) + base += f', qop="auth", nc={ncvalue}, cnonce="{cnonce}"' - return 'Digest %s' % (base) + return f"Digest {base}" def handle_redirect(self, r, **kwargs): """Reset num_401_calls counter on redirects.""" @@ -248,13 +255,13 @@ def handle_401(self, r, **kwargs): # Rewind the file position indicator of the body to where # it was to resend the request. r.request.body.seek(self._thread_local.pos) - s_auth = r.headers.get('www-authenticate', '') + s_auth = r.headers.get("www-authenticate", "") - if 'digest' in s_auth.lower() and self._thread_local.num_401_calls < 2: + if "digest" in s_auth.lower() and self._thread_local.num_401_calls < 2: self._thread_local.num_401_calls += 1 - pat = re.compile(r'digest ', flags=re.IGNORECASE) - self._thread_local.chal = parse_dict_header(pat.sub('', s_auth, count=1)) + pat = re.compile(r"digest ", flags=re.IGNORECASE) + self._thread_local.chal = parse_dict_header(pat.sub("", s_auth, count=1)) # Consume content and release the original connection # to allow our new request to reuse the same one. @@ -264,8 +271,9 @@ def handle_401(self, r, **kwargs): extract_cookies_to_jar(prep._cookies, r.request, r.raw) prep.prepare_cookies(prep._cookies) - prep.headers['Authorization'] = self.build_digest_header( - prep.method, prep.url) + prep.headers["Authorization"] = self.build_digest_header( + prep.method, prep.url + ) _r = r.connection.send(prep, **kwargs) _r.history.append(r) _r.request = prep @@ -280,7 +288,7 @@ def __call__(self, r): self.init_per_thread_state() # If we have a saved nonce, skip the 401 if self._thread_local.last_nonce: - r.headers['Authorization'] = self.build_digest_header(r.method, r.url) + r.headers["Authorization"] = self.build_digest_header(r.method, r.url) try: self._thread_local.pos = r.body.tell() except AttributeError: @@ -289,17 +297,19 @@ def __call__(self, r): # file position of the previous body. Ensure it's set to # None. self._thread_local.pos = None - r.register_hook('response', self.handle_401) - r.register_hook('response', self.handle_redirect) + r.register_hook("response", self.handle_401) + r.register_hook("response", self.handle_redirect) self._thread_local.num_401_calls = 1 return r def __eq__(self, other): - return all([ - self.username == getattr(other, 'username', None), - self.password == getattr(other, 'password', None) - ]) + return all( + [ + self.username == getattr(other, "username", None), + self.password == getattr(other, "password", None), + ] + ) def __ne__(self, other): return not self == other diff --git a/script.module.requests/lib/requests/certs.py b/script.module.requests/lib/requests/certs.py index d1a378d78..be422c3e9 100644 --- a/script.module.requests/lib/requests/certs.py +++ b/script.module.requests/lib/requests/certs.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ requests.certs @@ -14,5 +13,5 @@ """ from certifi import where -if __name__ == '__main__': +if __name__ == "__main__": print(where()) diff --git a/script.module.requests/lib/requests/compat.py b/script.module.requests/lib/requests/compat.py index 029ae62ac..6776163c9 100644 --- a/script.module.requests/lib/requests/compat.py +++ b/script.module.requests/lib/requests/compat.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- - """ requests.compat ~~~~~~~~~~~~~~~ -This module handles import compatibility issues between Python 2 and -Python 3. +This module previously handled import compatibility issues +between Python 2 and Python 3. It remains for backwards +compatibility until the next major version. """ try: @@ -23,59 +22,58 @@ _ver = sys.version_info #: Python 2.x? -is_py2 = (_ver[0] == 2) +is_py2 = _ver[0] == 2 #: Python 3.x? -is_py3 = (_ver[0] == 3) +is_py3 = _ver[0] == 3 +# json/simplejson module import resolution has_simplejson = False try: import simplejson as json + has_simplejson = True except ImportError: import json -# --------- -# Specifics -# --------- - -if is_py2: - from urllib import ( - quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, - proxy_bypass, proxy_bypass_environment, getproxies_environment) - from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag - from urllib2 import parse_http_list - import cookielib - from Cookie import Morsel - from StringIO import StringIO - # Keep OrderedDict for backwards compatibility. - from collections import Callable, Mapping, MutableMapping, OrderedDict +if has_simplejson: + from simplejson import JSONDecodeError +else: + from json import JSONDecodeError - builtin_str = str - bytes = str - str = unicode - basestring = basestring - numeric_types = (int, long, float) - integer_types = (int, long) - JSONDecodeError = ValueError +# Keep OrderedDict for backwards compatibility. +from collections import OrderedDict +from collections.abc import Callable, Mapping, MutableMapping +from http import cookiejar as cookielib +from http.cookies import Morsel +from io import StringIO -elif is_py3: - from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag - from urllib.request import parse_http_list, getproxies, proxy_bypass, proxy_bypass_environment, getproxies_environment - from http import cookiejar as cookielib - from http.cookies import Morsel - from io import StringIO - # Keep OrderedDict for backwards compatibility. - from collections import OrderedDict - from collections.abc import Callable, Mapping, MutableMapping - if has_simplejson: - from simplejson import JSONDecodeError - else: - from json import JSONDecodeError +# -------------- +# Legacy Imports +# -------------- +from urllib.parse import ( + quote, + quote_plus, + unquote, + unquote_plus, + urldefrag, + urlencode, + urljoin, + urlparse, + urlsplit, + urlunparse, +) +from urllib.request import ( + getproxies, + getproxies_environment, + parse_http_list, + proxy_bypass, + proxy_bypass_environment, +) - builtin_str = str - str = str - bytes = bytes - basestring = (str, bytes) - numeric_types = (int, float) - integer_types = (int,) +builtin_str = str +str = str +bytes = bytes +basestring = (str, bytes) +numeric_types = (int, float) +integer_types = (int,) diff --git a/script.module.requests/lib/requests/cookies.py b/script.module.requests/lib/requests/cookies.py index 56fccd9c2..bf54ab237 100644 --- a/script.module.requests/lib/requests/cookies.py +++ b/script.module.requests/lib/requests/cookies.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.cookies ~~~~~~~~~~~~~~~~ @@ -9,12 +7,12 @@ requests.utils imports from here, so be careful with imports. """ +import calendar import copy import time -import calendar from ._internal_utils import to_native_string -from .compat import cookielib, urlparse, urlunparse, Morsel, MutableMapping +from .compat import Morsel, MutableMapping, cookielib, urlparse, urlunparse try: import threading @@ -22,7 +20,7 @@ import dummy_threading as threading -class MockRequest(object): +class MockRequest: """Wraps a `requests.Request` to mimic a `urllib2.Request`. The code in `cookielib.CookieJar` expects this interface in order to correctly @@ -51,16 +49,22 @@ def get_origin_req_host(self): def get_full_url(self): # Only return the response's URL if the user hadn't set the Host # header - if not self._r.headers.get('Host'): + if not self._r.headers.get("Host"): return self._r.url # If they did set it, retrieve it and reconstruct the expected domain - host = to_native_string(self._r.headers['Host'], encoding='utf-8') + host = to_native_string(self._r.headers["Host"], encoding="utf-8") parsed = urlparse(self._r.url) # Reconstruct the URL as we expect it - return urlunparse([ - parsed.scheme, host, parsed.path, parsed.params, parsed.query, - parsed.fragment - ]) + return urlunparse( + [ + parsed.scheme, + host, + parsed.path, + parsed.params, + parsed.query, + parsed.fragment, + ] + ) def is_unverifiable(self): return True @@ -73,7 +77,9 @@ def get_header(self, name, default=None): def add_header(self, key, val): """cookielib has no legitimate use for this method; add it back if you find one.""" - raise NotImplementedError("Cookie headers should be added with add_unredirected_header()") + raise NotImplementedError( + "Cookie headers should be added with add_unredirected_header()" + ) def add_unredirected_header(self, name, value): self._new_headers[name] = value @@ -94,7 +100,7 @@ def host(self): return self.get_host() -class MockResponse(object): +class MockResponse: """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. ...what? Basically, expose the parsed HTTP headers from the server response @@ -122,8 +128,7 @@ def extract_cookies_to_jar(jar, request, response): :param request: our own requests.Request object :param response: urllib3.HTTPResponse object """ - if not (hasattr(response, '_original_response') and - response._original_response): + if not (hasattr(response, "_original_response") and response._original_response): return # the _original_response field is the wrapped httplib.HTTPResponse object, req = MockRequest(request) @@ -140,7 +145,7 @@ def get_cookie_header(jar, request): """ r = MockRequest(request) jar.add_cookie_header(r) - return r.get_new_headers().get('Cookie') + return r.get_new_headers().get("Cookie") def remove_cookie_by_name(cookiejar, name, domain=None, path=None): @@ -205,7 +210,9 @@ def set(self, name, value, **kwargs): """ # support client code that unsets cookies by assignment of a None value: if value is None: - remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path=kwargs.get('path')) + remove_cookie_by_name( + self, name, domain=kwargs.get("domain"), path=kwargs.get("path") + ) return if isinstance(value, Morsel): @@ -305,16 +312,15 @@ def get_dict(self, domain=None, path=None): """ dictionary = {} for cookie in iter(self): - if ( - (domain is None or cookie.domain == domain) and - (path is None or cookie.path == path) + if (domain is None or cookie.domain == domain) and ( + path is None or cookie.path == path ): dictionary[cookie.name] = cookie.value return dictionary def __contains__(self, name): try: - return super(RequestsCookieJar, self).__contains__(name) + return super().__contains__(name) except CookieConflictError: return True @@ -341,9 +347,13 @@ def __delitem__(self, name): remove_cookie_by_name(self, name) def set_cookie(self, cookie, *args, **kwargs): - if hasattr(cookie.value, 'startswith') and cookie.value.startswith('"') and cookie.value.endswith('"'): - cookie.value = cookie.value.replace('\\"', '') - return super(RequestsCookieJar, self).set_cookie(cookie, *args, **kwargs) + if ( + hasattr(cookie.value, "startswith") + and cookie.value.startswith('"') + and cookie.value.endswith('"') + ): + cookie.value = cookie.value.replace('\\"', "") + return super().set_cookie(cookie, *args, **kwargs) def update(self, other): """Updates this jar with cookies from another CookieJar or dict-like""" @@ -351,7 +361,7 @@ def update(self, other): for cookie in other: self.set_cookie(copy.copy(cookie)) else: - super(RequestsCookieJar, self).update(other) + super().update(other) def _find(self, name, domain=None, path=None): """Requests uses this method internally to get cookie values. @@ -371,7 +381,7 @@ def _find(self, name, domain=None, path=None): if path is None or cookie.path == path: return cookie.value - raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}") def _find_no_duplicates(self, name, domain=None, path=None): """Both ``__get_item__`` and ``get`` call this function: it's never @@ -390,25 +400,29 @@ def _find_no_duplicates(self, name, domain=None, path=None): if cookie.name == name: if domain is None or cookie.domain == domain: if path is None or cookie.path == path: - if toReturn is not None: # if there are multiple cookies that meet passed in criteria - raise CookieConflictError('There are multiple cookies with name, %r' % (name)) - toReturn = cookie.value # we will eventually return this as long as no cookie conflict + if toReturn is not None: + # if there are multiple cookies that meet passed in criteria + raise CookieConflictError( + f"There are multiple cookies with name, {name!r}" + ) + # we will eventually return this as long as no cookie conflict + toReturn = cookie.value if toReturn: return toReturn - raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}") def __getstate__(self): """Unlike a normal CookieJar, this class is pickleable.""" state = self.__dict__.copy() # remove the unpickleable RLock object - state.pop('_cookies_lock') + state.pop("_cookies_lock") return state def __setstate__(self, state): """Unlike a normal CookieJar, this class is pickleable.""" self.__dict__.update(state) - if '_cookies_lock' not in self.__dict__: + if "_cookies_lock" not in self.__dict__: self._cookies_lock = threading.RLock() def copy(self): @@ -427,7 +441,7 @@ def _copy_cookie_jar(jar): if jar is None: return None - if hasattr(jar, 'copy'): + if hasattr(jar, "copy"): # We're dealing with an instance of RequestsCookieJar return jar.copy() # We're dealing with a generic CookieJar instance @@ -445,31 +459,32 @@ def create_cookie(name, value, **kwargs): and sent on every request (this is sometimes called a "supercookie"). """ result = { - 'version': 0, - 'name': name, - 'value': value, - 'port': None, - 'domain': '', - 'path': '/', - 'secure': False, - 'expires': None, - 'discard': True, - 'comment': None, - 'comment_url': None, - 'rest': {'HttpOnly': None}, - 'rfc2109': False, + "version": 0, + "name": name, + "value": value, + "port": None, + "domain": "", + "path": "/", + "secure": False, + "expires": None, + "discard": True, + "comment": None, + "comment_url": None, + "rest": {"HttpOnly": None}, + "rfc2109": False, } badargs = set(kwargs) - set(result) if badargs: - err = 'create_cookie() got unexpected keyword arguments: %s' - raise TypeError(err % list(badargs)) + raise TypeError( + f"create_cookie() got unexpected keyword arguments: {list(badargs)}" + ) result.update(kwargs) - result['port_specified'] = bool(result['port']) - result['domain_specified'] = bool(result['domain']) - result['domain_initial_dot'] = result['domain'].startswith('.') - result['path_specified'] = bool(result['path']) + result["port_specified"] = bool(result["port"]) + result["domain_specified"] = bool(result["domain"]) + result["domain_initial_dot"] = result["domain"].startswith(".") + result["path_specified"] = bool(result["path"]) return cookielib.Cookie(**result) @@ -478,30 +493,28 @@ def morsel_to_cookie(morsel): """Convert a Morsel object into a Cookie containing the one k/v pair.""" expires = None - if morsel['max-age']: + if morsel["max-age"]: try: - expires = int(time.time() + int(morsel['max-age'])) + expires = int(time.time() + int(morsel["max-age"])) except ValueError: - raise TypeError('max-age: %s must be integer' % morsel['max-age']) - elif morsel['expires']: - time_template = '%a, %d-%b-%Y %H:%M:%S GMT' - expires = calendar.timegm( - time.strptime(morsel['expires'], time_template) - ) + raise TypeError(f"max-age: {morsel['max-age']} must be integer") + elif morsel["expires"]: + time_template = "%a, %d-%b-%Y %H:%M:%S GMT" + expires = calendar.timegm(time.strptime(morsel["expires"], time_template)) return create_cookie( - comment=morsel['comment'], - comment_url=bool(morsel['comment']), + comment=morsel["comment"], + comment_url=bool(morsel["comment"]), discard=False, - domain=morsel['domain'], + domain=morsel["domain"], expires=expires, name=morsel.key, - path=morsel['path'], + path=morsel["path"], port=None, - rest={'HttpOnly': morsel['httponly']}, + rest={"HttpOnly": morsel["httponly"]}, rfc2109=False, - secure=bool(morsel['secure']), + secure=bool(morsel["secure"]), value=morsel.value, - version=morsel['version'] or 0, + version=morsel["version"] or 0, ) @@ -534,11 +547,10 @@ def merge_cookies(cookiejar, cookies): :rtype: CookieJar """ if not isinstance(cookiejar, cookielib.CookieJar): - raise ValueError('You can only merge into CookieJar') + raise ValueError("You can only merge into CookieJar") if isinstance(cookies, dict): - cookiejar = cookiejar_from_dict( - cookies, cookiejar=cookiejar, overwrite=False) + cookiejar = cookiejar_from_dict(cookies, cookiejar=cookiejar, overwrite=False) elif isinstance(cookies, cookielib.CookieJar): try: cookiejar.update(cookies) diff --git a/script.module.requests/lib/requests/exceptions.py b/script.module.requests/lib/requests/exceptions.py index 79697635a..e1cedf883 100644 --- a/script.module.requests/lib/requests/exceptions.py +++ b/script.module.requests/lib/requests/exceptions.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.exceptions ~~~~~~~~~~~~~~~~~~~ @@ -18,13 +16,12 @@ class RequestException(IOError): def __init__(self, *args, **kwargs): """Initialize RequestException with `request` and `response` objects.""" - response = kwargs.pop('response', None) + response = kwargs.pop("response", None) self.response = response - self.request = kwargs.pop('request', None) - if (response is not None and not self.request and - hasattr(response, 'request')): + self.request = kwargs.pop("request", None) + if response is not None and not self.request and hasattr(response, "request"): self.request = self.response.request - super(RequestException, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class InvalidJSONError(RequestException): @@ -34,6 +31,16 @@ class InvalidJSONError(RequestException): class JSONDecodeError(InvalidJSONError, CompatJSONDecodeError): """Couldn't decode the text into json""" + def __init__(self, *args, **kwargs): + """ + Construct the JSONDecodeError instance first with all + args. Then use it's args to construct the IOError so that + the json specific args aren't used as IOError specific args + and the error message from JSONDecodeError is preserved. + """ + CompatJSONDecodeError.__init__(self, *args) + InvalidJSONError.__init__(self, *self.args, **kwargs) + class HTTPError(RequestException): """An HTTP error occurred.""" @@ -118,6 +125,7 @@ class RetryError(RequestException): class UnrewindableBodyError(RequestException): """Requests encountered an error when trying to rewind a body.""" + # Warnings diff --git a/script.module.requests/lib/requests/help.py b/script.module.requests/lib/requests/help.py index 4cd6389f5..8fbcd6560 100644 --- a/script.module.requests/lib/requests/help.py +++ b/script.module.requests/lib/requests/help.py @@ -1,10 +1,9 @@ """Module containing bug report helper(s).""" -from __future__ import print_function import json import platform -import sys import ssl +import sys import idna import urllib3 @@ -28,16 +27,16 @@ OpenSSL = None cryptography = None else: - import OpenSSL import cryptography + import OpenSSL def _implementation(): """Return a dict with the Python implementation and version. Provide both the name and the version of the Python implementation - currently running. For example, on CPython 2.7.5 it will return - {'name': 'CPython', 'version': '2.7.5'}. + currently running. For example, on CPython 3.10.3 it will return + {'name': 'CPython', 'version': '3.10.3'}. This function works best on CPython and PyPy: in particular, it probably doesn't work for Jython or IronPython. Future investigation should be done @@ -45,83 +44,83 @@ def _implementation(): """ implementation = platform.python_implementation() - if implementation == 'CPython': + if implementation == "CPython": implementation_version = platform.python_version() - elif implementation == 'PyPy': - implementation_version = '%s.%s.%s' % (sys.pypy_version_info.major, - sys.pypy_version_info.minor, - sys.pypy_version_info.micro) - if sys.pypy_version_info.releaselevel != 'final': - implementation_version = ''.join([ - implementation_version, sys.pypy_version_info.releaselevel - ]) - elif implementation == 'Jython': + elif implementation == "PyPy": + implementation_version = "{}.{}.{}".format( + sys.pypy_version_info.major, + sys.pypy_version_info.minor, + sys.pypy_version_info.micro, + ) + if sys.pypy_version_info.releaselevel != "final": + implementation_version = "".join( + [implementation_version, sys.pypy_version_info.releaselevel] + ) + elif implementation == "Jython": implementation_version = platform.python_version() # Complete Guess - elif implementation == 'IronPython': + elif implementation == "IronPython": implementation_version = platform.python_version() # Complete Guess else: - implementation_version = 'Unknown' + implementation_version = "Unknown" - return {'name': implementation, 'version': implementation_version} + return {"name": implementation, "version": implementation_version} def info(): """Generate information for a bug report.""" try: platform_info = { - 'system': platform.system(), - 'release': platform.release(), + "system": platform.system(), + "release": platform.release(), } - except IOError: + except OSError: platform_info = { - 'system': 'Unknown', - 'release': 'Unknown', + "system": "Unknown", + "release": "Unknown", } implementation_info = _implementation() - urllib3_info = {'version': urllib3.__version__} - charset_normalizer_info = {'version': None} - chardet_info = {'version': None} + urllib3_info = {"version": urllib3.__version__} + charset_normalizer_info = {"version": None} + chardet_info = {"version": None} if charset_normalizer: - charset_normalizer_info = {'version': charset_normalizer.__version__} + charset_normalizer_info = {"version": charset_normalizer.__version__} if chardet: - chardet_info = {'version': chardet.__version__} + chardet_info = {"version": chardet.__version__} pyopenssl_info = { - 'version': None, - 'openssl_version': '', + "version": None, + "openssl_version": "", } if OpenSSL: pyopenssl_info = { - 'version': OpenSSL.__version__, - 'openssl_version': '%x' % OpenSSL.SSL.OPENSSL_VERSION_NUMBER, + "version": OpenSSL.__version__, + "openssl_version": f"{OpenSSL.SSL.OPENSSL_VERSION_NUMBER:x}", } cryptography_info = { - 'version': getattr(cryptography, '__version__', ''), + "version": getattr(cryptography, "__version__", ""), } idna_info = { - 'version': getattr(idna, '__version__', ''), + "version": getattr(idna, "__version__", ""), } system_ssl = ssl.OPENSSL_VERSION_NUMBER - system_ssl_info = { - 'version': '%x' % system_ssl if system_ssl is not None else '' - } + system_ssl_info = {"version": f"{system_ssl:x}" if system_ssl is not None else ""} return { - 'platform': platform_info, - 'implementation': implementation_info, - 'system_ssl': system_ssl_info, - 'using_pyopenssl': pyopenssl is not None, - 'using_charset_normalizer': chardet is None, - 'pyOpenSSL': pyopenssl_info, - 'urllib3': urllib3_info, - 'chardet': chardet_info, - 'charset_normalizer': charset_normalizer_info, - 'cryptography': cryptography_info, - 'idna': idna_info, - 'requests': { - 'version': requests_version, + "platform": platform_info, + "implementation": implementation_info, + "system_ssl": system_ssl_info, + "using_pyopenssl": pyopenssl is not None, + "using_charset_normalizer": chardet is None, + "pyOpenSSL": pyopenssl_info, + "urllib3": urllib3_info, + "chardet": chardet_info, + "charset_normalizer": charset_normalizer_info, + "cryptography": cryptography_info, + "idna": idna_info, + "requests": { + "version": requests_version, }, } @@ -131,5 +130,5 @@ def main(): print(json.dumps(info(), sort_keys=True, indent=2)) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/script.module.requests/lib/requests/hooks.py b/script.module.requests/lib/requests/hooks.py index 7a51f212c..d181ba2ec 100644 --- a/script.module.requests/lib/requests/hooks.py +++ b/script.module.requests/lib/requests/hooks.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.hooks ~~~~~~~~~~~~~~ @@ -11,12 +9,13 @@ ``response``: The response generated from a Request. """ -HOOKS = ['response'] +HOOKS = ["response"] def default_hooks(): return {event: [] for event in HOOKS} + # TODO: response is the only one @@ -25,7 +24,7 @@ def dispatch_hook(key, hooks, hook_data, **kwargs): hooks = hooks or {} hooks = hooks.get(key) if hooks: - if hasattr(hooks, '__call__'): + if hasattr(hooks, "__call__"): hooks = [hooks] for hook in hooks: _hook_data = hook(hook_data, **kwargs) diff --git a/script.module.requests/lib/requests/models.py b/script.module.requests/lib/requests/models.py index dfbea854f..617a4134e 100644 --- a/script.module.requests/lib/requests/models.py +++ b/script.module.requests/lib/requests/models.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.models ~~~~~~~~~~~~~~~ @@ -8,48 +6,72 @@ """ import datetime -import sys # Import encoding now, to avoid implicit import later. # Implicit import within threads may cause LookupError when standard library is in a ZIP, # such as in Embedded Python. See https://github.com/psf/requests/issues/3578. -import encodings.idna +import encodings.idna # noqa: F401 +from io import UnsupportedOperation +from urllib3.exceptions import ( + DecodeError, + LocationParseError, + ProtocolError, + ReadTimeoutError, + SSLError, +) from urllib3.fields import RequestField from urllib3.filepost import encode_multipart_formdata from urllib3.util import parse_url -from urllib3.exceptions import ( - DecodeError, ReadTimeoutError, ProtocolError, LocationParseError) - -from io import UnsupportedOperation -from .hooks import default_hooks -from .structures import CaseInsensitiveDict -from .auth import HTTPBasicAuth -from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar -from .exceptions import ( - HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError, - ContentDecodingError, ConnectionError, StreamConsumedError, - InvalidJSONError) -from .exceptions import JSONDecodeError as RequestsJSONDecodeError from ._internal_utils import to_native_string, unicode_is_ascii -from .utils import ( - guess_filename, get_auth_from_url, requote_uri, - stream_decode_response_unicode, to_key_val_list, parse_header_links, - iter_slices, guess_json_utf, super_len, check_header_validity) +from .auth import HTTPBasicAuth from .compat import ( - Callable, Mapping, - cookielib, urlunparse, urlsplit, urlencode, str, bytes, - is_py2, chardet, builtin_str, basestring, JSONDecodeError) + Callable, + JSONDecodeError, + Mapping, + basestring, + builtin_str, + chardet, + cookielib, +) from .compat import json as complexjson +from .compat import urlencode, urlsplit, urlunparse +from .cookies import _copy_cookie_jar, cookiejar_from_dict, get_cookie_header +from .exceptions import ( + ChunkedEncodingError, + ConnectionError, + ContentDecodingError, + HTTPError, + InvalidJSONError, + InvalidURL, +) +from .exceptions import JSONDecodeError as RequestsJSONDecodeError +from .exceptions import MissingSchema +from .exceptions import SSLError as RequestsSSLError +from .exceptions import StreamConsumedError +from .hooks import default_hooks from .status_codes import codes +from .structures import CaseInsensitiveDict +from .utils import ( + check_header_validity, + get_auth_from_url, + guess_filename, + guess_json_utf, + iter_slices, + parse_header_links, + requote_uri, + stream_decode_response_unicode, + super_len, + to_key_val_list, +) #: The set of HTTP status codes that indicate an automatically #: processable redirect. REDIRECT_STATI = ( - codes.moved, # 301 - codes.found, # 302 - codes.other, # 303 + codes.moved, # 301 + codes.found, # 302 + codes.other, # 303 codes.temporary_redirect, # 307 codes.permanent_redirect, # 308 ) @@ -59,7 +81,7 @@ ITER_CHUNK_SIZE = 512 -class RequestEncodingMixin(object): +class RequestEncodingMixin: @property def path_url(self): """Build the path URL to use.""" @@ -70,16 +92,16 @@ def path_url(self): path = p.path if not path: - path = '/' + path = "/" url.append(path) query = p.query if query: - url.append('?') + url.append("?") url.append(query) - return ''.join(url) + return "".join(url) @staticmethod def _encode_params(data): @@ -92,18 +114,21 @@ def _encode_params(data): if isinstance(data, (str, bytes)): return data - elif hasattr(data, 'read'): + elif hasattr(data, "read"): return data - elif hasattr(data, '__iter__'): + elif hasattr(data, "__iter__"): result = [] for k, vs in to_key_val_list(data): - if isinstance(vs, basestring) or not hasattr(vs, '__iter__'): + if isinstance(vs, basestring) or not hasattr(vs, "__iter__"): vs = [vs] for v in vs: if v is not None: result.append( - (k.encode('utf-8') if isinstance(k, str) else k, - v.encode('utf-8') if isinstance(v, str) else v)) + ( + k.encode("utf-8") if isinstance(k, str) else k, + v.encode("utf-8") if isinstance(v, str) else v, + ) + ) return urlencode(result, doseq=True) else: return data @@ -118,7 +143,7 @@ def _encode_files(files, data): The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype) or 4-tuples (filename, fileobj, contentype, custom_headers). """ - if (not files): + if not files: raise ValueError("Files must be provided.") elif isinstance(data, basestring): raise ValueError("Data must not be a string.") @@ -128,7 +153,7 @@ def _encode_files(files, data): files = to_key_val_list(files or {}) for field, val in fields: - if isinstance(val, basestring) or not hasattr(val, '__iter__'): + if isinstance(val, basestring) or not hasattr(val, "__iter__"): val = [val] for v in val: if v is not None: @@ -137,8 +162,13 @@ def _encode_files(files, data): v = str(v) new_fields.append( - (field.decode('utf-8') if isinstance(field, bytes) else field, - v.encode('utf-8') if isinstance(v, str) else v)) + ( + field.decode("utf-8") + if isinstance(field, bytes) + else field, + v.encode("utf-8") if isinstance(v, str) else v, + ) + ) for (k, v) in files: # support for explicit filename @@ -157,7 +187,7 @@ def _encode_files(files, data): if isinstance(fp, (str, bytes, bytearray)): fdata = fp - elif hasattr(fp, 'read'): + elif hasattr(fp, "read"): fdata = fp.read() elif fp is None: continue @@ -173,16 +203,16 @@ def _encode_files(files, data): return body, content_type -class RequestHooksMixin(object): +class RequestHooksMixin: def register_hook(self, event, hook): """Properly register a hook.""" if event not in self.hooks: - raise ValueError('Unsupported event specified, with event name "%s"' % (event)) + raise ValueError(f'Unsupported event specified, with event name "{event}"') if isinstance(hook, Callable): self.hooks[event].append(hook) - elif hasattr(hook, '__iter__'): + elif hasattr(hook, "__iter__"): self.hooks[event].extend(h for h in hook if isinstance(h, Callable)) def deregister_hook(self, event, hook): @@ -225,9 +255,19 @@ class Request(RequestHooksMixin): """ - def __init__(self, - method=None, url=None, headers=None, files=None, data=None, - params=None, auth=None, cookies=None, hooks=None, json=None): + def __init__( + self, + method=None, + url=None, + headers=None, + files=None, + data=None, + params=None, + auth=None, + cookies=None, + hooks=None, + json=None, + ): # Default empty dicts for dict params. data = [] if data is None else data @@ -251,7 +291,7 @@ def __init__(self, self.cookies = cookies def __repr__(self): - return '' % (self.method) + return f"" def prepare(self): """Constructs a :class:`PreparedRequest ` for transmission and returns it.""" @@ -309,9 +349,19 @@ def __init__(self): #: integer denoting starting position of a readable file-like body. self._body_position = None - def prepare(self, - method=None, url=None, headers=None, files=None, data=None, - params=None, auth=None, cookies=None, hooks=None, json=None): + def prepare( + self, + method=None, + url=None, + headers=None, + files=None, + data=None, + params=None, + auth=None, + cookies=None, + hooks=None, + json=None, + ): """Prepares the entire request with the given parameters.""" self.prepare_method(method) @@ -328,7 +378,7 @@ def prepare(self, self.prepare_hooks(hooks) def __repr__(self): - return '' % (self.method) + return f"" def copy(self): p = PreparedRequest() @@ -352,7 +402,7 @@ def _get_idna_encoded_host(host): import idna try: - host = idna.encode(host, uts46=True).decode('utf-8') + host = idna.encode(host, uts46=True).decode("utf-8") except idna.IDNAError: raise UnicodeError return host @@ -365,9 +415,9 @@ def prepare_url(self, url, params): #: on python 3.x. #: https://github.com/psf/requests/pull/2238 if isinstance(url, bytes): - url = url.decode('utf8') + url = url.decode("utf8") else: - url = unicode(url) if is_py2 else str(url) + url = str(url) # Remove leading whitespaces from url url = url.lstrip() @@ -375,7 +425,7 @@ def prepare_url(self, url, params): # Don't do any URL preparation for non-HTTP schemes like `mailto`, # `data` etc to work around exceptions from `url_parse`, which # handles RFC 3986 only. - if ':' in url and not url.lower().startswith('http'): + if ":" in url and not url.lower().startswith("http"): self.url = url return @@ -386,13 +436,13 @@ def prepare_url(self, url, params): raise InvalidURL(*e.args) if not scheme: - error = ("Invalid URL {0!r}: No scheme supplied. Perhaps you meant http://{0}?") - error = error.format(to_native_string(url, 'utf8')) - - raise MissingSchema(error) + raise MissingSchema( + f"Invalid URL {url!r}: No scheme supplied. " + f"Perhaps you meant https://{url}?" + ) if not host: - raise InvalidURL("Invalid URL %r: No host supplied" % url) + raise InvalidURL(f"Invalid URL {url!r}: No host supplied") # In general, we want to try IDNA encoding the hostname if the string contains # non-ASCII characters. This allows users to automatically get the correct IDNA @@ -402,33 +452,21 @@ def prepare_url(self, url, params): try: host = self._get_idna_encoded_host(host) except UnicodeError: - raise InvalidURL('URL has an invalid label.') - elif host.startswith((u'*', u'.')): - raise InvalidURL('URL has an invalid label.') + raise InvalidURL("URL has an invalid label.") + elif host.startswith(("*", ".")): + raise InvalidURL("URL has an invalid label.") # Carefully reconstruct the network location - netloc = auth or '' + netloc = auth or "" if netloc: - netloc += '@' + netloc += "@" netloc += host if port: - netloc += ':' + str(port) + netloc += f":{port}" # Bare domains aren't valid URLs. if not path: - path = '/' - - if is_py2: - if isinstance(scheme, str): - scheme = scheme.encode('utf-8') - if isinstance(netloc, str): - netloc = netloc.encode('utf-8') - if isinstance(path, str): - path = path.encode('utf-8') - if isinstance(query, str): - query = query.encode('utf-8') - if isinstance(fragment, str): - fragment = fragment.encode('utf-8') + path = "/" if isinstance(params, (str, bytes)): params = to_native_string(params) @@ -436,7 +474,7 @@ def prepare_url(self, url, params): enc_params = self._encode_params(params) if enc_params: if query: - query = '%s&%s' % (query, enc_params) + query = f"{query}&{enc_params}" else: query = enc_params @@ -467,7 +505,7 @@ def prepare_body(self, data, files, json=None): if not data and json is not None: # urllib3 requires a bytes-like body. Python 2's json.dumps # provides this natively, but Python 3 gives a Unicode string. - content_type = 'application/json' + content_type = "application/json" try: body = complexjson.dumps(json, allow_nan=False) @@ -475,12 +513,14 @@ def prepare_body(self, data, files, json=None): raise InvalidJSONError(ve, request=self) if not isinstance(body, bytes): - body = body.encode('utf-8') + body = body.encode("utf-8") - is_stream = all([ - hasattr(data, '__iter__'), - not isinstance(data, (basestring, list, tuple, Mapping)) - ]) + is_stream = all( + [ + hasattr(data, "__iter__"), + not isinstance(data, (basestring, list, tuple, Mapping)), + ] + ) if is_stream: try: @@ -490,24 +530,26 @@ def prepare_body(self, data, files, json=None): body = data - if getattr(body, 'tell', None) is not None: + if getattr(body, "tell", None) is not None: # Record the current file position before reading. # This will allow us to rewind a file in the event # of a redirect. try: self._body_position = body.tell() - except (IOError, OSError): + except OSError: # This differentiates from None, allowing us to catch # a failed `tell()` later when trying to rewind the body self._body_position = object() if files: - raise NotImplementedError('Streamed bodies and files are mutually exclusive.') + raise NotImplementedError( + "Streamed bodies and files are mutually exclusive." + ) if length: - self.headers['Content-Length'] = builtin_str(length) + self.headers["Content-Length"] = builtin_str(length) else: - self.headers['Transfer-Encoding'] = 'chunked' + self.headers["Transfer-Encoding"] = "chunked" else: # Multi-part file uploads. if files: @@ -515,16 +557,16 @@ def prepare_body(self, data, files, json=None): else: if data: body = self._encode_params(data) - if isinstance(data, basestring) or hasattr(data, 'read'): + if isinstance(data, basestring) or hasattr(data, "read"): content_type = None else: - content_type = 'application/x-www-form-urlencoded' + content_type = "application/x-www-form-urlencoded" self.prepare_content_length(body) # Add content-type if it wasn't explicitly provided. - if content_type and ('content-type' not in self.headers): - self.headers['Content-Type'] = content_type + if content_type and ("content-type" not in self.headers): + self.headers["Content-Type"] = content_type self.body = body @@ -535,13 +577,16 @@ def prepare_content_length(self, body): if length: # If length exists, set it. Otherwise, we fallback # to Transfer-Encoding: chunked. - self.headers['Content-Length'] = builtin_str(length) - elif self.method not in ('GET', 'HEAD') and self.headers.get('Content-Length') is None: + self.headers["Content-Length"] = builtin_str(length) + elif ( + self.method not in ("GET", "HEAD") + and self.headers.get("Content-Length") is None + ): # Set Content-Length to 0 for methods that can have a body # but don't provide one. (i.e. not GET or HEAD) - self.headers['Content-Length'] = '0' + self.headers["Content-Length"] = "0" - def prepare_auth(self, auth, url=''): + def prepare_auth(self, auth, url=""): """Prepares the given HTTP auth data.""" # If no Auth is explicitly provided, extract it from the URL first. @@ -581,7 +626,7 @@ def prepare_cookies(self, cookies): cookie_header = get_cookie_header(self._cookies, self) if cookie_header is not None: - self.headers['Cookie'] = cookie_header + self.headers["Cookie"] = cookie_header def prepare_hooks(self, hooks): """Prepares the given hooks.""" @@ -593,14 +638,22 @@ def prepare_hooks(self, hooks): self.register_hook(event, hooks[event]) -class Response(object): +class Response: """The :class:`Response ` object, which contains a server's response to an HTTP request. """ __attrs__ = [ - '_content', 'status_code', 'headers', 'url', 'history', - 'encoding', 'reason', 'cookies', 'elapsed', 'request' + "_content", + "status_code", + "headers", + "url", + "history", + "encoding", + "reason", + "cookies", + "elapsed", + "request", ] def __init__(self): @@ -669,11 +722,11 @@ def __setstate__(self, state): setattr(self, name, value) # pickled objects do not have .raw - setattr(self, '_content_consumed', True) - setattr(self, 'raw', None) + setattr(self, "_content_consumed", True) + setattr(self, "raw", None) def __repr__(self): - return '' % (self.status_code) + return f"" def __bool__(self): """Returns True if :attr:`status_code` is less than 400. @@ -719,12 +772,15 @@ def is_redirect(self): """True if this Response is a well-formed HTTP redirect that could have been processed automatically (by :meth:`Session.resolve_redirects`). """ - return ('location' in self.headers and self.status_code in REDIRECT_STATI) + return "location" in self.headers and self.status_code in REDIRECT_STATI @property def is_permanent_redirect(self): """True if this Response one of the permanent versions of redirect.""" - return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect)) + return "location" in self.headers and self.status_code in ( + codes.moved_permanently, + codes.permanent_redirect, + ) @property def next(self): @@ -734,7 +790,7 @@ def next(self): @property def apparent_encoding(self): """The apparent encoding, provided by the charset_normalizer or chardet libraries.""" - return chardet.detect(self.content)['encoding'] + return chardet.detect(self.content)["encoding"] def iter_content(self, chunk_size=1, decode_unicode=False): """Iterates over the response data. When stream=True is set on the @@ -755,16 +811,17 @@ def iter_content(self, chunk_size=1, decode_unicode=False): def generate(): # Special case for urllib3. - if hasattr(self.raw, 'stream'): + if hasattr(self.raw, "stream"): try: - for chunk in self.raw.stream(chunk_size, decode_content=True): - yield chunk + yield from self.raw.stream(chunk_size, decode_content=True) except ProtocolError as e: raise ChunkedEncodingError(e) except DecodeError as e: raise ContentDecodingError(e) except ReadTimeoutError as e: raise ConnectionError(e) + except SSLError as e: + raise RequestsSSLError(e) else: # Standard file-like object. while True: @@ -778,7 +835,9 @@ def generate(): if self._content_consumed and isinstance(self._content, bool): raise StreamConsumedError() elif chunk_size is not None and not isinstance(chunk_size, int): - raise TypeError("chunk_size must be an int, it is instead a %s." % type(chunk_size)) + raise TypeError( + f"chunk_size must be an int, it is instead a {type(chunk_size)}." + ) # simulate reading small chunks of the content reused_chunks = iter_slices(self._content, chunk_size) @@ -791,7 +850,9 @@ def generate(): return chunks - def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None): + def iter_lines( + self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None + ): """Iterates over the response data, one line at a time. When stream=True is set on the request, this avoids reading the content at once into memory for large responses. @@ -801,7 +862,9 @@ def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter pending = None - for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode): + for chunk in self.iter_content( + chunk_size=chunk_size, decode_unicode=decode_unicode + ): if pending is not None: chunk = pending + chunk @@ -816,8 +879,7 @@ def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter else: pending = None - for line in lines: - yield line + yield from lines if pending is not None: yield pending @@ -829,13 +891,12 @@ def content(self): if self._content is False: # Read the contents. if self._content_consumed: - raise RuntimeError( - 'The content for this response was already consumed') + raise RuntimeError("The content for this response was already consumed") if self.status_code == 0 or self.raw is None: self._content = None else: - self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b'' + self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b"" self._content_consumed = True # don't need to release the connection; that's been handled by urllib3 @@ -860,7 +921,7 @@ def text(self): encoding = self.encoding if not self.content: - return str('') + return "" # Fallback to auto-detected encoding. if self.encoding is None: @@ -868,7 +929,7 @@ def text(self): # Decode unicode from given encoding. try: - content = str(self.content, encoding, errors='replace') + content = str(self.content, encoding, errors="replace") except (LookupError, TypeError): # A LookupError is raised if the encoding was not found which could # indicate a misspelling or similar mistake. @@ -876,7 +937,7 @@ def text(self): # A TypeError can be raised if encoding is None # # So we try blindly encoding. - content = str(self.content, errors='replace') + content = str(self.content, errors="replace") return content @@ -896,65 +957,65 @@ def json(self, **kwargs): encoding = guess_json_utf(self.content) if encoding is not None: try: - return complexjson.loads( - self.content.decode(encoding), **kwargs - ) + return complexjson.loads(self.content.decode(encoding), **kwargs) except UnicodeDecodeError: # Wrong UTF codec detected; usually because it's not UTF-8 # but some other 8-bit codec. This is an RFC violation, # and the server didn't bother to tell us what codec *was* # used. pass + except JSONDecodeError as e: + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) try: return complexjson.loads(self.text, **kwargs) except JSONDecodeError as e: # Catch JSON-related errors and raise as requests.JSONDecodeError # This aliases json.JSONDecodeError and simplejson.JSONDecodeError - if is_py2: # e is a ValueError - raise RequestsJSONDecodeError(e.message) - else: - raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) @property def links(self): """Returns the parsed header links of the response, if any.""" - header = self.headers.get('link') + header = self.headers.get("link") - # l = MultiDict() - l = {} + resolved_links = {} if header: links = parse_header_links(header) for link in links: - key = link.get('rel') or link.get('url') - l[key] = link + key = link.get("rel") or link.get("url") + resolved_links[key] = link - return l + return resolved_links def raise_for_status(self): """Raises :class:`HTTPError`, if one occurred.""" - http_error_msg = '' + http_error_msg = "" if isinstance(self.reason, bytes): # We attempt to decode utf-8 first because some servers # choose to localize their reason strings. If the string # isn't utf-8, we fall back to iso-8859-1 for all other # encodings. (See PR #3538) try: - reason = self.reason.decode('utf-8') + reason = self.reason.decode("utf-8") except UnicodeDecodeError: - reason = self.reason.decode('iso-8859-1') + reason = self.reason.decode("iso-8859-1") else: reason = self.reason if 400 <= self.status_code < 500: - http_error_msg = u'%s Client Error: %s for url: %s' % (self.status_code, reason, self.url) + http_error_msg = ( + f"{self.status_code} Client Error: {reason} for url: {self.url}" + ) elif 500 <= self.status_code < 600: - http_error_msg = u'%s Server Error: %s for url: %s' % (self.status_code, reason, self.url) + http_error_msg = ( + f"{self.status_code} Server Error: {reason} for url: {self.url}" + ) if http_error_msg: raise HTTPError(http_error_msg, response=self) @@ -968,6 +1029,6 @@ def close(self): if not self._content_consumed: self.raw.close() - release_conn = getattr(self.raw, 'release_conn', None) + release_conn = getattr(self.raw, "release_conn", None) if release_conn is not None: release_conn() diff --git a/script.module.requests/lib/requests/packages.py b/script.module.requests/lib/requests/packages.py index 00196bff2..77c45c9e9 100644 --- a/script.module.requests/lib/requests/packages.py +++ b/script.module.requests/lib/requests/packages.py @@ -3,24 +3,26 @@ try: import chardet except ImportError: - import charset_normalizer as chardet import warnings - warnings.filterwarnings('ignore', 'Trying to detect', module='charset_normalizer') + import charset_normalizer as chardet + + warnings.filterwarnings("ignore", "Trying to detect", module="charset_normalizer") # This code exists for backwards compatibility reasons. # I don't like it either. Just look the other way. :) -for package in ('urllib3', 'idna'): +for package in ("urllib3", "idna"): locals()[package] = __import__(package) # This traversal is apparently necessary such that the identities are # preserved (requests.packages.urllib3.* is urllib3.*) for mod in list(sys.modules): - if mod == package or mod.startswith(package + '.'): - sys.modules['requests.packages.' + mod] = sys.modules[mod] + if mod == package or mod.startswith(f"{package}."): + sys.modules[f"requests.packages.{mod}"] = sys.modules[mod] target = chardet.__name__ for mod in list(sys.modules): - if mod == target or mod.startswith(target + '.'): - sys.modules['requests.packages.' + target.replace(target, 'chardet')] = sys.modules[mod] + if mod == target or mod.startswith(f"{target}."): + target = target.replace(target, "chardet") + sys.modules[f"requests.packages.{target}"] = sys.modules[mod] # Kinda cool, though, right? diff --git a/script.module.requests/lib/requests/sessions.py b/script.module.requests/lib/requests/sessions.py index 3f59cab92..dbcf2a7b0 100644 --- a/script.module.requests/lib/requests/sessions.py +++ b/script.module.requests/lib/requests/sessions.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.sessions ~~~~~~~~~~~~~~~~~ @@ -10,39 +8,52 @@ import os import sys import time -from datetime import timedelta from collections import OrderedDict +from datetime import timedelta +from ._internal_utils import to_native_string +from .adapters import HTTPAdapter from .auth import _basic_auth_str -from .compat import cookielib, is_py3, urljoin, urlparse, Mapping +from .compat import Mapping, cookielib, urljoin, urlparse from .cookies import ( - cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) -from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT -from .hooks import default_hooks, dispatch_hook -from ._internal_utils import to_native_string -from .utils import to_key_val_list, default_headers, DEFAULT_PORTS + RequestsCookieJar, + cookiejar_from_dict, + extract_cookies_to_jar, + merge_cookies, +) from .exceptions import ( - TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError) - -from .structures import CaseInsensitiveDict -from .adapters import HTTPAdapter - -from .utils import ( - requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies, - get_auth_from_url, rewind_body, resolve_proxies + ChunkedEncodingError, + ContentDecodingError, + InvalidSchema, + TooManyRedirects, ) - -from .status_codes import codes +from .hooks import default_hooks, dispatch_hook # formerly defined here, reexposed here for backward compatibility -from .models import REDIRECT_STATI +from .models import ( # noqa: F401 + DEFAULT_REDIRECT_LIMIT, + REDIRECT_STATI, + PreparedRequest, + Request, +) +from .status_codes import codes +from .structures import CaseInsensitiveDict +from .utils import ( # noqa: F401 + DEFAULT_PORTS, + default_headers, + get_auth_from_url, + get_environ_proxies, + get_netrc_auth, + requote_uri, + resolve_proxies, + rewind_body, + should_bypass_proxies, + to_key_val_list, +) # Preferred clock, based on which one is more accurate on a given system. -if sys.platform == 'win32': - try: # Python 3.4+ - preferred_clock = time.perf_counter - except AttributeError: # Earlier than Python 3. - preferred_clock = time.clock +if sys.platform == "win32": + preferred_clock = time.perf_counter else: preferred_clock = time.time @@ -61,8 +72,7 @@ def merge_setting(request_setting, session_setting, dict_class=OrderedDict): # Bypass if not a dictionary (e.g. verify) if not ( - isinstance(session_setting, Mapping) and - isinstance(request_setting, Mapping) + isinstance(session_setting, Mapping) and isinstance(request_setting, Mapping) ): return request_setting @@ -84,17 +94,16 @@ def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict): This is necessary because when request_hooks == {'response': []}, the merge breaks Session hooks entirely. """ - if session_hooks is None or session_hooks.get('response') == []: + if session_hooks is None or session_hooks.get("response") == []: return request_hooks - if request_hooks is None or request_hooks.get('response') == []: + if request_hooks is None or request_hooks.get("response") == []: return session_hooks return merge_setting(request_hooks, session_hooks, dict_class) -class SessionRedirectMixin(object): - +class SessionRedirectMixin: def get_redirect_target(self, resp): """Receives a Response. Returns a redirect URI or ``None``""" # Due to the nature of how requests processes redirects this method will @@ -104,16 +113,15 @@ def get_redirect_target(self, resp): # to cache the redirect location onto the response object as a private # attribute. if resp.is_redirect: - location = resp.headers['location'] + location = resp.headers["location"] # Currently the underlying http module on py3 decode headers # in latin1, but empirical evidence suggests that latin1 is very # rarely used with non-ASCII characters in HTTP headers. # It is more likely to get UTF8 header rather than latin1. # This causes incorrect handling of UTF8 encoded location headers. # To solve this, we re-encode the location in latin1. - if is_py3: - location = location.encode('latin1') - return to_native_string(location, 'utf8') + location = location.encode("latin1") + return to_native_string(location, "utf8") return None def should_strip_auth(self, old_url, new_url): @@ -126,23 +134,40 @@ def should_strip_auth(self, old_url, new_url): # ports. This isn't specified by RFC 7235, but is kept to avoid # breaking backwards compatibility with older versions of requests # that allowed any redirects on the same host. - if (old_parsed.scheme == 'http' and old_parsed.port in (80, None) - and new_parsed.scheme == 'https' and new_parsed.port in (443, None)): + if ( + old_parsed.scheme == "http" + and old_parsed.port in (80, None) + and new_parsed.scheme == "https" + and new_parsed.port in (443, None) + ): return False # Handle default port usage corresponding to scheme. changed_port = old_parsed.port != new_parsed.port changed_scheme = old_parsed.scheme != new_parsed.scheme default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None) - if (not changed_scheme and old_parsed.port in default_port - and new_parsed.port in default_port): + if ( + not changed_scheme + and old_parsed.port in default_port + and new_parsed.port in default_port + ): return False # Standard case: root URI must match return changed_port or changed_scheme - def resolve_redirects(self, resp, req, stream=False, timeout=None, - verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs): + def resolve_redirects( + self, + resp, + req, + stream=False, + timeout=None, + verify=True, + cert=None, + proxies=None, + yield_requests=False, + **adapter_kwargs, + ): """Receives a Response. Returns a generator of Responses or Requests.""" hist = [] # keep track of history @@ -163,19 +188,21 @@ def resolve_redirects(self, resp, req, stream=False, timeout=None, resp.raw.read(decode_content=False) if len(resp.history) >= self.max_redirects: - raise TooManyRedirects('Exceeded {} redirects.'.format(self.max_redirects), response=resp) + raise TooManyRedirects( + f"Exceeded {self.max_redirects} redirects.", response=resp + ) # Release the connection back into the pool. resp.close() # Handle redirection without scheme (see: RFC 1808 Section 4) - if url.startswith('//'): + if url.startswith("//"): parsed_rurl = urlparse(resp.url) - url = ':'.join([to_native_string(parsed_rurl.scheme), url]) + url = ":".join([to_native_string(parsed_rurl.scheme), url]) # Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2) parsed = urlparse(url) - if parsed.fragment == '' and previous_fragment: + if parsed.fragment == "" and previous_fragment: parsed = parsed._replace(fragment=previous_fragment) elif parsed.fragment: previous_fragment = parsed.fragment @@ -194,15 +221,18 @@ def resolve_redirects(self, resp, req, stream=False, timeout=None, self.rebuild_method(prepared_request, resp) # https://github.com/psf/requests/issues/1084 - if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect): + if resp.status_code not in ( + codes.temporary_redirect, + codes.permanent_redirect, + ): # https://github.com/psf/requests/issues/3490 - purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding') + purged_headers = ("Content-Length", "Content-Type", "Transfer-Encoding") for header in purged_headers: prepared_request.headers.pop(header, None) prepared_request.body = None headers = prepared_request.headers - headers.pop('Cookie', None) + headers.pop("Cookie", None) # Extract any cookies sent on the response to the cookiejar # in the new request. Because we've mutated our copied prepared @@ -218,9 +248,8 @@ def resolve_redirects(self, resp, req, stream=False, timeout=None, # A failed tell() sets `_body_position` to `object()`. This non-None # value ensures `rewindable` will be True, allowing us to raise an # UnrewindableBodyError, instead of hanging the connection. - rewindable = ( - prepared_request._body_position is not None and - ('Content-Length' in headers or 'Transfer-Encoding' in headers) + rewindable = prepared_request._body_position is not None and ( + "Content-Length" in headers or "Transfer-Encoding" in headers ) # Attempt to rewind consumed file-like object. @@ -242,7 +271,7 @@ def resolve_redirects(self, resp, req, stream=False, timeout=None, cert=cert, proxies=proxies, allow_redirects=False, - **adapter_kwargs + **adapter_kwargs, ) extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) @@ -259,10 +288,12 @@ def rebuild_auth(self, prepared_request, response): headers = prepared_request.headers url = prepared_request.url - if 'Authorization' in headers and self.should_strip_auth(response.request.url, url): + if "Authorization" in headers and self.should_strip_auth( + response.request.url, url + ): # If we get redirected to a new host, we should strip out any # authentication headers. - del headers['Authorization'] + del headers["Authorization"] # .netrc might have more auth for us on our new host. new_auth = get_netrc_auth(url) if self.trust_env else None @@ -285,16 +316,18 @@ def rebuild_proxies(self, prepared_request, proxies): scheme = urlparse(prepared_request.url).scheme new_proxies = resolve_proxies(prepared_request, proxies, self.trust_env) - if 'Proxy-Authorization' in headers: - del headers['Proxy-Authorization'] + if "Proxy-Authorization" in headers: + del headers["Proxy-Authorization"] try: username, password = get_auth_from_url(new_proxies[scheme]) except KeyError: username, password = None, None - if username and password: - headers['Proxy-Authorization'] = _basic_auth_str(username, password) + # urllib3 handles proxy authorization for us in the standard adapter. + # Avoid appending this to TLS tunneled requests where it may be leaked. + if not scheme.startswith('https') and username and password: + headers["Proxy-Authorization"] = _basic_auth_str(username, password) return new_proxies @@ -305,18 +338,18 @@ def rebuild_method(self, prepared_request, response): method = prepared_request.method # https://tools.ietf.org/html/rfc7231#section-6.4.4 - if response.status_code == codes.see_other and method != 'HEAD': - method = 'GET' + if response.status_code == codes.see_other and method != "HEAD": + method = "GET" # Do what the browsers do, despite standards... # First, turn 302s into GETs. - if response.status_code == codes.found and method != 'HEAD': - method = 'GET' + if response.status_code == codes.found and method != "HEAD": + method = "GET" # Second, if a POST is responded to with a 301, turn it into a GET. # This bizarre behaviour is explained in Issue 1704. - if response.status_code == codes.moved and method == 'POST': - method = 'GET' + if response.status_code == codes.moved and method == "POST": + method = "GET" prepared_request.method = method @@ -341,9 +374,18 @@ class Session(SessionRedirectMixin): """ __attrs__ = [ - 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify', - 'cert', 'adapters', 'stream', 'trust_env', - 'max_redirects', + "headers", + "cookies", + "auth", + "proxies", + "hooks", + "params", + "verify", + "cert", + "adapters", + "stream", + "trust_env", + "max_redirects", ] def __init__(self): @@ -405,8 +447,8 @@ def __init__(self): # Default connection adapters. self.adapters = OrderedDict() - self.mount('https://', HTTPAdapter()) - self.mount('http://', HTTPAdapter()) + self.mount("https://", HTTPAdapter()) + self.mount("http://", HTTPAdapter()) def __enter__(self): return self @@ -432,7 +474,8 @@ def prepare_request(self, request): # Merge with session cookies merged_cookies = merge_cookies( - merge_cookies(RequestsCookieJar(), self.cookies), cookies) + merge_cookies(RequestsCookieJar(), self.cookies), cookies + ) # Set environment's basic authentication if not explicitly set. auth = request.auth @@ -446,7 +489,9 @@ def prepare_request(self, request): files=request.files, data=request.data, json=request.json, - headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict), + headers=merge_setting( + request.headers, self.headers, dict_class=CaseInsensitiveDict + ), params=merge_setting(request.params, self.params), auth=merge_setting(auth, self.auth), cookies=merged_cookies, @@ -454,10 +499,25 @@ def prepare_request(self, request): ) return p - def request(self, method, url, - params=None, data=None, headers=None, cookies=None, files=None, - auth=None, timeout=None, allow_redirects=True, proxies=None, - hooks=None, stream=None, verify=None, cert=None, json=None): + def request( + self, + method, + url, + params=None, + data=None, + headers=None, + cookies=None, + files=None, + auth=None, + timeout=None, + allow_redirects=True, + proxies=None, + hooks=None, + stream=None, + verify=None, + cert=None, + json=None, + ): """Constructs a :class:`Request `, prepares it and sends it. Returns :class:`Response ` object. @@ -493,7 +553,7 @@ def request(self, method, url, ``False``, requests will accept any TLS certificate presented by the server, and will ignore hostname mismatches and/or expired certificates, which will make your application vulnerable to - man-in-the-middle (MitM) attacks. Setting verify to ``False`` + man-in-the-middle (MitM) attacks. Setting verify to ``False`` may be useful during local development or testing. :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. @@ -522,8 +582,8 @@ def request(self, method, url, # Send the request. send_kwargs = { - 'timeout': timeout, - 'allow_redirects': allow_redirects, + "timeout": timeout, + "allow_redirects": allow_redirects, } send_kwargs.update(settings) resp = self.send(prep, **send_kwargs) @@ -538,8 +598,8 @@ def get(self, url, **kwargs): :rtype: requests.Response """ - kwargs.setdefault('allow_redirects', True) - return self.request('GET', url, **kwargs) + kwargs.setdefault("allow_redirects", True) + return self.request("GET", url, **kwargs) def options(self, url, **kwargs): r"""Sends a OPTIONS request. Returns :class:`Response` object. @@ -549,8 +609,8 @@ def options(self, url, **kwargs): :rtype: requests.Response """ - kwargs.setdefault('allow_redirects', True) - return self.request('OPTIONS', url, **kwargs) + kwargs.setdefault("allow_redirects", True) + return self.request("OPTIONS", url, **kwargs) def head(self, url, **kwargs): r"""Sends a HEAD request. Returns :class:`Response` object. @@ -560,8 +620,8 @@ def head(self, url, **kwargs): :rtype: requests.Response """ - kwargs.setdefault('allow_redirects', False) - return self.request('HEAD', url, **kwargs) + kwargs.setdefault("allow_redirects", False) + return self.request("HEAD", url, **kwargs) def post(self, url, data=None, json=None, **kwargs): r"""Sends a POST request. Returns :class:`Response` object. @@ -574,7 +634,7 @@ def post(self, url, data=None, json=None, **kwargs): :rtype: requests.Response """ - return self.request('POST', url, data=data, json=json, **kwargs) + return self.request("POST", url, data=data, json=json, **kwargs) def put(self, url, data=None, **kwargs): r"""Sends a PUT request. Returns :class:`Response` object. @@ -586,7 +646,7 @@ def put(self, url, data=None, **kwargs): :rtype: requests.Response """ - return self.request('PUT', url, data=data, **kwargs) + return self.request("PUT", url, data=data, **kwargs) def patch(self, url, data=None, **kwargs): r"""Sends a PATCH request. Returns :class:`Response` object. @@ -598,7 +658,7 @@ def patch(self, url, data=None, **kwargs): :rtype: requests.Response """ - return self.request('PATCH', url, data=data, **kwargs) + return self.request("PATCH", url, data=data, **kwargs) def delete(self, url, **kwargs): r"""Sends a DELETE request. Returns :class:`Response` object. @@ -608,7 +668,7 @@ def delete(self, url, **kwargs): :rtype: requests.Response """ - return self.request('DELETE', url, **kwargs) + return self.request("DELETE", url, **kwargs) def send(self, request, **kwargs): """Send a given PreparedRequest. @@ -617,22 +677,20 @@ def send(self, request, **kwargs): """ # Set defaults that the hooks can utilize to ensure they always have # the correct parameters to reproduce the previous request. - kwargs.setdefault('stream', self.stream) - kwargs.setdefault('verify', self.verify) - kwargs.setdefault('cert', self.cert) - if 'proxies' not in kwargs: - kwargs['proxies'] = resolve_proxies( - request, self.proxies, self.trust_env - ) + kwargs.setdefault("stream", self.stream) + kwargs.setdefault("verify", self.verify) + kwargs.setdefault("cert", self.cert) + if "proxies" not in kwargs: + kwargs["proxies"] = resolve_proxies(request, self.proxies, self.trust_env) # It's possible that users might accidentally send a Request object. # Guard against that specific failure case. if isinstance(request, Request): - raise ValueError('You can only send PreparedRequests.') + raise ValueError("You can only send PreparedRequests.") # Set up variables needed for resolve_redirects and dispatching of hooks - allow_redirects = kwargs.pop('allow_redirects', True) - stream = kwargs.get('stream') + allow_redirects = kwargs.pop("allow_redirects", True) + stream = kwargs.get("stream") hooks = request.hooks # Get the appropriate adapter to use @@ -649,7 +707,7 @@ def send(self, request, **kwargs): r.elapsed = timedelta(seconds=elapsed) # Response manipulation hooks - r = dispatch_hook('response', hooks, r, **kwargs) + r = dispatch_hook("response", hooks, r, **kwargs) # Persist cookies if r.history: @@ -679,7 +737,9 @@ def send(self, request, **kwargs): # If redirects aren't being followed, store the response on the Request for Response.next(). if not allow_redirects: try: - r._next = next(self.resolve_redirects(r, request, yield_requests=True, **kwargs)) + r._next = next( + self.resolve_redirects(r, request, yield_requests=True, **kwargs) + ) except StopIteration: pass @@ -697,16 +757,19 @@ def merge_environment_settings(self, url, proxies, stream, verify, cert): # Gather clues from the surrounding environment. if self.trust_env: # Set environment's proxies. - no_proxy = proxies.get('no_proxy') if proxies is not None else None + no_proxy = proxies.get("no_proxy") if proxies is not None else None env_proxies = get_environ_proxies(url, no_proxy=no_proxy) for (k, v) in env_proxies.items(): proxies.setdefault(k, v) - # Look for requests environment configuration and be compatible - # with cURL. + # Look for requests environment configuration + # and be compatible with cURL. if verify is True or verify is None: - verify = (os.environ.get('REQUESTS_CA_BUNDLE') or - os.environ.get('CURL_CA_BUNDLE')) + verify = ( + os.environ.get("REQUESTS_CA_BUNDLE") + or os.environ.get("CURL_CA_BUNDLE") + or verify + ) # Merge all the kwargs. proxies = merge_setting(proxies, self.proxies) @@ -714,8 +777,7 @@ def merge_environment_settings(self, url, proxies, stream, verify, cert): verify = merge_setting(verify, self.verify) cert = merge_setting(cert, self.cert) - return {'verify': verify, 'proxies': proxies, 'stream': stream, - 'cert': cert} + return {"proxies": proxies, "stream": stream, "verify": verify, "cert": cert} def get_adapter(self, url): """ @@ -729,7 +791,7 @@ def get_adapter(self, url): return adapter # Nothing matches :-/ - raise InvalidSchema("No connection adapters were found for {!r}".format(url)) + raise InvalidSchema(f"No connection adapters were found for {url!r}") def close(self): """Closes all adapters and as such the session""" diff --git a/script.module.requests/lib/requests/status_codes.py b/script.module.requests/lib/requests/status_codes.py index d80a7cd4d..4bd072be9 100644 --- a/script.module.requests/lib/requests/status_codes.py +++ b/script.module.requests/lib/requests/status_codes.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - r""" The ``codes`` object defines a mapping from common names for HTTP statuses to their numerical codes, accessible either as attributes or as dictionary @@ -23,101 +21,108 @@ from .structures import LookupDict _codes = { - # Informational. - 100: ('continue',), - 101: ('switching_protocols',), - 102: ('processing',), - 103: ('checkpoint',), - 122: ('uri_too_long', 'request_uri_too_long'), - 200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'), - 201: ('created',), - 202: ('accepted',), - 203: ('non_authoritative_info', 'non_authoritative_information'), - 204: ('no_content',), - 205: ('reset_content', 'reset'), - 206: ('partial_content', 'partial'), - 207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'), - 208: ('already_reported',), - 226: ('im_used',), - + 100: ("continue",), + 101: ("switching_protocols",), + 102: ("processing",), + 103: ("checkpoint",), + 122: ("uri_too_long", "request_uri_too_long"), + 200: ("ok", "okay", "all_ok", "all_okay", "all_good", "\\o/", "✓"), + 201: ("created",), + 202: ("accepted",), + 203: ("non_authoritative_info", "non_authoritative_information"), + 204: ("no_content",), + 205: ("reset_content", "reset"), + 206: ("partial_content", "partial"), + 207: ("multi_status", "multiple_status", "multi_stati", "multiple_stati"), + 208: ("already_reported",), + 226: ("im_used",), # Redirection. - 300: ('multiple_choices',), - 301: ('moved_permanently', 'moved', '\\o-'), - 302: ('found',), - 303: ('see_other', 'other'), - 304: ('not_modified',), - 305: ('use_proxy',), - 306: ('switch_proxy',), - 307: ('temporary_redirect', 'temporary_moved', 'temporary'), - 308: ('permanent_redirect', - 'resume_incomplete', 'resume',), # These 2 to be removed in 3.0 - + 300: ("multiple_choices",), + 301: ("moved_permanently", "moved", "\\o-"), + 302: ("found",), + 303: ("see_other", "other"), + 304: ("not_modified",), + 305: ("use_proxy",), + 306: ("switch_proxy",), + 307: ("temporary_redirect", "temporary_moved", "temporary"), + 308: ( + "permanent_redirect", + "resume_incomplete", + "resume", + ), # "resume" and "resume_incomplete" to be removed in 3.0 # Client Error. - 400: ('bad_request', 'bad'), - 401: ('unauthorized',), - 402: ('payment_required', 'payment'), - 403: ('forbidden',), - 404: ('not_found', '-o-'), - 405: ('method_not_allowed', 'not_allowed'), - 406: ('not_acceptable',), - 407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'), - 408: ('request_timeout', 'timeout'), - 409: ('conflict',), - 410: ('gone',), - 411: ('length_required',), - 412: ('precondition_failed', 'precondition'), - 413: ('request_entity_too_large',), - 414: ('request_uri_too_large',), - 415: ('unsupported_media_type', 'unsupported_media', 'media_type'), - 416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'), - 417: ('expectation_failed',), - 418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'), - 421: ('misdirected_request',), - 422: ('unprocessable_entity', 'unprocessable'), - 423: ('locked',), - 424: ('failed_dependency', 'dependency'), - 425: ('unordered_collection', 'unordered'), - 426: ('upgrade_required', 'upgrade'), - 428: ('precondition_required', 'precondition'), - 429: ('too_many_requests', 'too_many'), - 431: ('header_fields_too_large', 'fields_too_large'), - 444: ('no_response', 'none'), - 449: ('retry_with', 'retry'), - 450: ('blocked_by_windows_parental_controls', 'parental_controls'), - 451: ('unavailable_for_legal_reasons', 'legal_reasons'), - 499: ('client_closed_request',), - + 400: ("bad_request", "bad"), + 401: ("unauthorized",), + 402: ("payment_required", "payment"), + 403: ("forbidden",), + 404: ("not_found", "-o-"), + 405: ("method_not_allowed", "not_allowed"), + 406: ("not_acceptable",), + 407: ("proxy_authentication_required", "proxy_auth", "proxy_authentication"), + 408: ("request_timeout", "timeout"), + 409: ("conflict",), + 410: ("gone",), + 411: ("length_required",), + 412: ("precondition_failed", "precondition"), + 413: ("request_entity_too_large",), + 414: ("request_uri_too_large",), + 415: ("unsupported_media_type", "unsupported_media", "media_type"), + 416: ( + "requested_range_not_satisfiable", + "requested_range", + "range_not_satisfiable", + ), + 417: ("expectation_failed",), + 418: ("im_a_teapot", "teapot", "i_am_a_teapot"), + 421: ("misdirected_request",), + 422: ("unprocessable_entity", "unprocessable"), + 423: ("locked",), + 424: ("failed_dependency", "dependency"), + 425: ("unordered_collection", "unordered"), + 426: ("upgrade_required", "upgrade"), + 428: ("precondition_required", "precondition"), + 429: ("too_many_requests", "too_many"), + 431: ("header_fields_too_large", "fields_too_large"), + 444: ("no_response", "none"), + 449: ("retry_with", "retry"), + 450: ("blocked_by_windows_parental_controls", "parental_controls"), + 451: ("unavailable_for_legal_reasons", "legal_reasons"), + 499: ("client_closed_request",), # Server Error. - 500: ('internal_server_error', 'server_error', '/o\\', '✗'), - 501: ('not_implemented',), - 502: ('bad_gateway',), - 503: ('service_unavailable', 'unavailable'), - 504: ('gateway_timeout',), - 505: ('http_version_not_supported', 'http_version'), - 506: ('variant_also_negotiates',), - 507: ('insufficient_storage',), - 509: ('bandwidth_limit_exceeded', 'bandwidth'), - 510: ('not_extended',), - 511: ('network_authentication_required', 'network_auth', 'network_authentication'), + 500: ("internal_server_error", "server_error", "/o\\", "✗"), + 501: ("not_implemented",), + 502: ("bad_gateway",), + 503: ("service_unavailable", "unavailable"), + 504: ("gateway_timeout",), + 505: ("http_version_not_supported", "http_version"), + 506: ("variant_also_negotiates",), + 507: ("insufficient_storage",), + 509: ("bandwidth_limit_exceeded", "bandwidth"), + 510: ("not_extended",), + 511: ("network_authentication_required", "network_auth", "network_authentication"), } -codes = LookupDict(name='status_codes') +codes = LookupDict(name="status_codes") + def _init(): for code, titles in _codes.items(): for title in titles: setattr(codes, title, code) - if not title.startswith(('\\', '/')): + if not title.startswith(("\\", "/")): setattr(codes, title.upper(), code) def doc(code): - names = ', '.join('``%s``' % n for n in _codes[code]) - return '* %d: %s' % (code, names) + names = ", ".join(f"``{n}``" for n in _codes[code]) + return "* %d: %s" % (code, names) global __doc__ - __doc__ = (__doc__ + '\n' + - '\n'.join(doc(code) for code in sorted(_codes)) - if __doc__ is not None else None) + __doc__ = ( + __doc__ + "\n" + "\n".join(doc(code) for code in sorted(_codes)) + if __doc__ is not None + else None + ) + _init() diff --git a/script.module.requests/lib/requests/structures.py b/script.module.requests/lib/requests/structures.py index 8ee0ba7a0..188e13e48 100644 --- a/script.module.requests/lib/requests/structures.py +++ b/script.module.requests/lib/requests/structures.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.structures ~~~~~~~~~~~~~~~~~~~ @@ -64,11 +62,7 @@ def __len__(self): def lower_items(self): """Like iteritems(), but with all lowercase keys.""" - return ( - (lowerkey, keyval[1]) - for (lowerkey, keyval) - in self._store.items() - ) + return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()) def __eq__(self, other): if isinstance(other, Mapping): @@ -91,10 +85,10 @@ class LookupDict(dict): def __init__(self, name=None): self.name = name - super(LookupDict, self).__init__() + super().__init__() def __repr__(self): - return '' % (self.name) + return f"" def __getitem__(self, key): # We allow fall-through here, so values default to None diff --git a/script.module.requests/lib/requests/utils.py b/script.module.requests/lib/requests/utils.py index 153776c7f..a367417f8 100644 --- a/script.module.requests/lib/requests/utils.py +++ b/script.module.requests/lib/requests/utils.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ requests.utils ~~~~~~~~~~~~~~ @@ -20,28 +18,51 @@ import warnings import zipfile from collections import OrderedDict -from urllib3.util import make_headers -from urllib3.util import parse_url -from .__version__ import __version__ +from urllib3.util import make_headers, parse_url + from . import certs +from .__version__ import __version__ + # to_native_string is unused here, but imported here for backwards compatibility -from ._internal_utils import to_native_string +from ._internal_utils import ( # noqa: F401 + _HEADER_VALIDATORS_BYTE, + _HEADER_VALIDATORS_STR, + HEADER_VALIDATORS, + to_native_string, +) +from .compat import ( + Mapping, + basestring, + bytes, + getproxies, + getproxies_environment, + integer_types, +) from .compat import parse_http_list as _parse_list_header from .compat import ( - quote, urlparse, bytes, str, unquote, getproxies, - proxy_bypass, urlunparse, basestring, integer_types, is_py3, - proxy_bypass_environment, getproxies_environment, Mapping) + proxy_bypass, + proxy_bypass_environment, + quote, + str, + unquote, + urlparse, + urlunparse, +) from .cookies import cookiejar_from_dict -from .structures import CaseInsensitiveDict from .exceptions import ( - InvalidURL, InvalidHeader, FileModeWarning, UnrewindableBodyError) + FileModeWarning, + InvalidHeader, + InvalidURL, + UnrewindableBodyError, +) +from .structures import CaseInsensitiveDict -NETRC_FILES = ('.netrc', '_netrc') +NETRC_FILES = (".netrc", "_netrc") DEFAULT_CA_BUNDLE_PATH = certs.where() -DEFAULT_PORTS = {'http': 80, 'https': 443} +DEFAULT_PORTS = {"http": 80, "https": 443} # Ensure that ', ' is used to preserve previous delimiter behavior. DEFAULT_ACCEPT_ENCODING = ", ".join( @@ -49,28 +70,25 @@ ) -if sys.platform == 'win32': +if sys.platform == "win32": # provide a proxy_bypass version on Windows without DNS lookups def proxy_bypass_registry(host): try: - if is_py3: - import winreg - else: - import _winreg as winreg + import winreg except ImportError: return False try: - internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER, - r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') + internetSettings = winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", + ) # ProxyEnable could be REG_SZ or REG_DWORD, normalizing it - proxyEnable = int(winreg.QueryValueEx(internetSettings, - 'ProxyEnable')[0]) + proxyEnable = int(winreg.QueryValueEx(internetSettings, "ProxyEnable")[0]) # ProxyOverride is almost always a string - proxyOverride = winreg.QueryValueEx(internetSettings, - 'ProxyOverride')[0] - except OSError: + proxyOverride = winreg.QueryValueEx(internetSettings, "ProxyOverride")[0] + except (OSError, ValueError): return False if not proxyEnable or not proxyOverride: return False @@ -78,15 +96,15 @@ def proxy_bypass_registry(host): # make a check value list from the registry entry: replace the # '' string by the localhost entry and the corresponding # canonical entry. - proxyOverride = proxyOverride.split(';') + proxyOverride = proxyOverride.split(";") # now check if we match one of the registry values. for test in proxyOverride: - if test == '': - if '.' not in host: + if test == "": + if "." not in host: return True - test = test.replace(".", r"\.") # mask dots - test = test.replace("*", r".*") # change glob sequence - test = test.replace("?", r".") # change glob char + test = test.replace(".", r"\.") # mask dots + test = test.replace("*", r".*") # change glob sequence + test = test.replace("?", r".") # change glob char if re.match(test, host, re.I): return True return False @@ -106,7 +124,7 @@ def proxy_bypass(host): # noqa def dict_to_sequence(d): """Returns an internal sequence dictionary update.""" - if hasattr(d, 'items'): + if hasattr(d, "items"): d = d.items() return d @@ -116,13 +134,13 @@ def super_len(o): total_length = None current_position = 0 - if hasattr(o, '__len__'): + if hasattr(o, "__len__"): total_length = len(o) - elif hasattr(o, 'len'): + elif hasattr(o, "len"): total_length = o.len - elif hasattr(o, 'fileno'): + elif hasattr(o, "fileno"): try: fileno = o.fileno() except (io.UnsupportedOperation, AttributeError): @@ -135,21 +153,23 @@ def super_len(o): # Having used fstat to determine the file length, we need to # confirm that this file was opened up in binary mode. - if 'b' not in o.mode: - warnings.warn(( - "Requests has determined the content-length for this " - "request using the binary size of the file: however, the " - "file has been opened in text mode (i.e. without the 'b' " - "flag in the mode). This may lead to an incorrect " - "content-length. In Requests 3.0, support will be removed " - "for files in text mode."), - FileModeWarning + if "b" not in o.mode: + warnings.warn( + ( + "Requests has determined the content-length for this " + "request using the binary size of the file: however, the " + "file has been opened in text mode (i.e. without the 'b' " + "flag in the mode). This may lead to an incorrect " + "content-length. In Requests 3.0, support will be removed " + "for files in text mode." + ), + FileModeWarning, ) - if hasattr(o, 'tell'): + if hasattr(o, "tell"): try: current_position = o.tell() - except (OSError, IOError): + except OSError: # This can happen in some weird situations, such as when the file # is actually a special file descriptor like stdin. In this # instance, we don't know what the length is, so set it to zero and @@ -157,7 +177,7 @@ def super_len(o): if total_length is not None: current_position = total_length else: - if hasattr(o, 'seek') and total_length is None: + if hasattr(o, "seek") and total_length is None: # StringIO and BytesIO have seek but no usable fileno try: # seek to end of file @@ -167,7 +187,7 @@ def super_len(o): # seek back to current position to support # partially read file-like objects o.seek(current_position or 0) - except (OSError, IOError): + except OSError: total_length = 0 if total_length is None: @@ -179,14 +199,14 @@ def super_len(o): def get_netrc_auth(url, raise_errors=False): """Returns the Requests tuple auth for a given url from netrc.""" - netrc_file = os.environ.get('NETRC') + netrc_file = os.environ.get("NETRC") if netrc_file is not None: netrc_locations = (netrc_file,) else: - netrc_locations = ('~/{}'.format(f) for f in NETRC_FILES) + netrc_locations = (f"~/{f}" for f in NETRC_FILES) try: - from netrc import netrc, NetrcParseError + from netrc import NetrcParseError, netrc netrc_path = None @@ -211,18 +231,18 @@ def get_netrc_auth(url, raise_errors=False): # Strip port numbers from netloc. This weird `if...encode`` dance is # used for Python 3.2, which doesn't support unicode literals. - splitstr = b':' + splitstr = b":" if isinstance(url, str): - splitstr = splitstr.decode('ascii') + splitstr = splitstr.decode("ascii") host = ri.netloc.split(splitstr)[0] try: _netrc = netrc(netrc_path).authenticators(host) if _netrc: # Return with login / password - login_i = (0 if _netrc[0] else 1) + login_i = 0 if _netrc[0] else 1 return (_netrc[login_i], _netrc[2]) - except (NetrcParseError, IOError): + except (NetrcParseError, OSError): # If there was a parsing error or a permissions issue reading the file, # we'll just skip netrc auth unless explicitly asked to raise errors. if raise_errors: @@ -235,9 +255,8 @@ def get_netrc_auth(url, raise_errors=False): def guess_filename(obj): """Tries to guess the filename of the given object.""" - name = getattr(obj, 'name', None) - if (name and isinstance(name, basestring) and name[0] != '<' and - name[-1] != '>'): + name = getattr(obj, "name", None) + if name and isinstance(name, basestring) and name[0] != "<" and name[-1] != ">": return os.path.basename(name) @@ -259,7 +278,7 @@ def extract_zipped_paths(path): # If we don't check for an empty prefix after the split (in other words, archive remains unchanged after the split), # we _can_ end up in an infinite loop on a rare corner case affecting a small number of users break - member = '/'.join([prefix, member]) + member = "/".join([prefix, member]) if not zipfile.is_zipfile(archive): return path @@ -270,7 +289,7 @@ def extract_zipped_paths(path): # we have a valid zip archive and a valid member of that archive tmp = tempfile.gettempdir() - extracted_path = os.path.join(tmp, member.split('/')[-1]) + extracted_path = os.path.join(tmp, member.split("/")[-1]) if not os.path.exists(extracted_path): # use read + write to avoid the creating nested folders, we only want the file, avoids mkdir racing condition with atomic_open(extracted_path) as file_handler: @@ -281,12 +300,11 @@ def extract_zipped_paths(path): @contextlib.contextmanager def atomic_open(filename): """Write a file to the disk in an atomic fashion""" - replacer = os.rename if sys.version_info[0] == 2 else os.replace tmp_descriptor, tmp_name = tempfile.mkstemp(dir=os.path.dirname(filename)) try: - with os.fdopen(tmp_descriptor, 'wb') as tmp_handler: + with os.fdopen(tmp_descriptor, "wb") as tmp_handler: yield tmp_handler - replacer(tmp_name, filename) + os.replace(tmp_name, filename) except BaseException: os.remove(tmp_name) raise @@ -314,7 +332,7 @@ def from_key_val_list(value): return None if isinstance(value, (str, bytes, bool, int)): - raise ValueError('cannot encode objects that are not 2-tuples') + raise ValueError("cannot encode objects that are not 2-tuples") return OrderedDict(value) @@ -340,7 +358,7 @@ def to_key_val_list(value): return None if isinstance(value, (str, bytes, bool, int)): - raise ValueError('cannot encode objects that are not 2-tuples') + raise ValueError("cannot encode objects that are not 2-tuples") if isinstance(value, Mapping): value = value.items() @@ -405,10 +423,10 @@ def parse_dict_header(value): """ result = {} for item in _parse_list_header(value): - if '=' not in item: + if "=" not in item: result[item] = None continue - name, value = item.split('=', 1) + name, value = item.split("=", 1) if value[:1] == value[-1:] == '"': value = unquote_header_value(value[1:-1]) result[name] = value @@ -436,8 +454,8 @@ def unquote_header_value(value, is_filename=False): # replace sequence below on a UNC path has the effect of turning # the leading double slash into a single slash and then # _fix_ie_filename() doesn't work correctly. See #458. - if not is_filename or value[:2] != '\\\\': - return value.replace('\\\\', '\\').replace('\\"', '"') + if not is_filename or value[:2] != "\\\\": + return value.replace("\\\\", "\\").replace('\\"', '"') return value @@ -472,19 +490,24 @@ def get_encodings_from_content(content): :param content: bytestring to extract encodings from. """ - warnings.warn(( - 'In requests 3.0, get_encodings_from_content will be removed. For ' - 'more information, please see the discussion on issue #2266. (This' - ' warning should only appear once.)'), - DeprecationWarning) + warnings.warn( + ( + "In requests 3.0, get_encodings_from_content will be removed. For " + "more information, please see the discussion on issue #2266. (This" + " warning should only appear once.)" + ), + DeprecationWarning, + ) charset_re = re.compile(r']', flags=re.I) pragma_re = re.compile(r']', flags=re.I) xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') - return (charset_re.findall(content) + - pragma_re.findall(content) + - xml_re.findall(content)) + return ( + charset_re.findall(content) + + pragma_re.findall(content) + + xml_re.findall(content) + ) def _parse_content_type_header(header): @@ -495,7 +518,7 @@ def _parse_content_type_header(header): parameters """ - tokens = header.split(';') + tokens = header.split(";") content_type, params = tokens[0].strip(), tokens[1:] params_dict = {} items_to_strip = "\"' " @@ -507,7 +530,7 @@ def _parse_content_type_header(header): index_of_equals = param.find("=") if index_of_equals != -1: key = param[:index_of_equals].strip(items_to_strip) - value = param[index_of_equals + 1:].strip(items_to_strip) + value = param[index_of_equals + 1 :].strip(items_to_strip) params_dict[key.lower()] = value return content_type, params_dict @@ -519,38 +542,37 @@ def get_encoding_from_headers(headers): :rtype: str """ - content_type = headers.get('content-type') + content_type = headers.get("content-type") if not content_type: return None content_type, params = _parse_content_type_header(content_type) - if 'charset' in params: - return params['charset'].strip("'\"") + if "charset" in params: + return params["charset"].strip("'\"") - if 'text' in content_type: - return 'ISO-8859-1' + if "text" in content_type: + return "ISO-8859-1" - if 'application/json' in content_type: + if "application/json" in content_type: # Assume UTF-8 based on RFC 4627: https://www.ietf.org/rfc/rfc4627.txt since the charset was unset - return 'utf-8' + return "utf-8" def stream_decode_response_unicode(iterator, r): - """Stream decodes a iterator.""" + """Stream decodes an iterator.""" if r.encoding is None: - for item in iterator: - yield item + yield from iterator return - decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace') + decoder = codecs.getincrementaldecoder(r.encoding)(errors="replace") for chunk in iterator: rv = decoder.decode(chunk) if rv: yield rv - rv = decoder.decode(b'', final=True) + rv = decoder.decode(b"", final=True) if rv: yield rv @@ -561,7 +583,7 @@ def iter_slices(string, slice_length): if slice_length is None or slice_length <= 0: slice_length = len(string) while pos < len(string): - yield string[pos:pos + slice_length] + yield string[pos : pos + slice_length] pos += slice_length @@ -577,11 +599,14 @@ def get_unicode_from_response(r): :rtype: str """ - warnings.warn(( - 'In requests 3.0, get_unicode_from_response will be removed. For ' - 'more information, please see the discussion on issue #2266. (This' - ' warning should only appear once.)'), - DeprecationWarning) + warnings.warn( + ( + "In requests 3.0, get_unicode_from_response will be removed. For " + "more information, please see the discussion on issue #2266. (This" + " warning should only appear once.)" + ), + DeprecationWarning, + ) tried_encodings = [] @@ -596,14 +621,15 @@ def get_unicode_from_response(r): # Fall back: try: - return str(r.content, encoding, errors='replace') + return str(r.content, encoding, errors="replace") except TypeError: return r.content # The unreserved URI characters (RFC 3986) UNRESERVED_SET = frozenset( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~") + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~" +) def unquote_unreserved(uri): @@ -612,22 +638,22 @@ def unquote_unreserved(uri): :rtype: str """ - parts = uri.split('%') + parts = uri.split("%") for i in range(1, len(parts)): h = parts[i][0:2] if len(h) == 2 and h.isalnum(): try: c = chr(int(h, 16)) except ValueError: - raise InvalidURL("Invalid percent-escape sequence: '%s'" % h) + raise InvalidURL(f"Invalid percent-escape sequence: '{h}'") if c in UNRESERVED_SET: parts[i] = c + parts[i][2:] else: - parts[i] = '%' + parts[i] + parts[i] = f"%{parts[i]}" else: - parts[i] = '%' + parts[i] - return ''.join(parts) + parts[i] = f"%{parts[i]}" + return "".join(parts) def requote_uri(uri): @@ -660,10 +686,10 @@ def address_in_network(ip, net): :rtype: bool """ - ipaddr = struct.unpack('=L', socket.inet_aton(ip))[0] - netaddr, bits = net.split('/') - netmask = struct.unpack('=L', socket.inet_aton(dotted_netmask(int(bits))))[0] - network = struct.unpack('=L', socket.inet_aton(netaddr))[0] & netmask + ipaddr = struct.unpack("=L", socket.inet_aton(ip))[0] + netaddr, bits = net.split("/") + netmask = struct.unpack("=L", socket.inet_aton(dotted_netmask(int(bits))))[0] + network = struct.unpack("=L", socket.inet_aton(netaddr))[0] & netmask return (ipaddr & netmask) == (network & netmask) @@ -674,8 +700,8 @@ def dotted_netmask(mask): :rtype: str """ - bits = 0xffffffff ^ (1 << 32 - mask) - 1 - return socket.inet_ntoa(struct.pack('>I', bits)) + bits = 0xFFFFFFFF ^ (1 << 32 - mask) - 1 + return socket.inet_ntoa(struct.pack(">I", bits)) def is_ipv4_address(string_ip): @@ -684,7 +710,7 @@ def is_ipv4_address(string_ip): """ try: socket.inet_aton(string_ip) - except socket.error: + except OSError: return False return True @@ -695,9 +721,9 @@ def is_valid_cidr(string_network): :rtype: bool """ - if string_network.count('/') == 1: + if string_network.count("/") == 1: try: - mask = int(string_network.split('/')[1]) + mask = int(string_network.split("/")[1]) except ValueError: return False @@ -705,8 +731,8 @@ def is_valid_cidr(string_network): return False try: - socket.inet_aton(string_network.split('/')[0]) - except socket.error: + socket.inet_aton(string_network.split("/")[0]) + except OSError: return False else: return False @@ -743,13 +769,14 @@ def should_bypass_proxies(url, no_proxy): """ # Prioritize lowercase environment variables over uppercase # to keep a consistent behaviour with other http projects (curl, wget). - get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper()) + def get_proxy(key): + return os.environ.get(key) or os.environ.get(key.upper()) # First check whether no_proxy is defined. If it is, check that the URL # we're getting isn't in the no_proxy list. no_proxy_arg = no_proxy if no_proxy is None: - no_proxy = get_proxy('no_proxy') + no_proxy = get_proxy("no_proxy") parsed = urlparse(url) if parsed.hostname is None: @@ -759,9 +786,7 @@ def should_bypass_proxies(url, no_proxy): if no_proxy: # We need to check whether we match here. We need to see if we match # the end of the hostname, both with and without the port. - no_proxy = ( - host for host in no_proxy.replace(' ', '').split(',') if host - ) + no_proxy = (host for host in no_proxy.replace(" ", "").split(",") if host) if is_ipv4_address(parsed.hostname): for proxy_ip in no_proxy: @@ -775,7 +800,7 @@ def should_bypass_proxies(url, no_proxy): else: host_with_port = parsed.hostname if parsed.port: - host_with_port += ':{}'.format(parsed.port) + host_with_port += f":{parsed.port}" for host in no_proxy: if parsed.hostname.endswith(host) or host_with_port.endswith(host): @@ -783,7 +808,7 @@ def should_bypass_proxies(url, no_proxy): # to apply the proxies on this URL. return True - with set_environ('no_proxy', no_proxy_arg): + with set_environ("no_proxy", no_proxy_arg): # parsed.hostname can be `None` in cases such as a file URI. try: bypass = proxy_bypass(parsed.hostname) @@ -817,13 +842,13 @@ def select_proxy(url, proxies): proxies = proxies or {} urlparts = urlparse(url) if urlparts.hostname is None: - return proxies.get(urlparts.scheme, proxies.get('all')) + return proxies.get(urlparts.scheme, proxies.get("all")) proxy_keys = [ - urlparts.scheme + '://' + urlparts.hostname, + urlparts.scheme + "://" + urlparts.hostname, urlparts.scheme, - 'all://' + urlparts.hostname, - 'all', + "all://" + urlparts.hostname, + "all", ] proxy = None for proxy_key in proxy_keys: @@ -848,13 +873,13 @@ def resolve_proxies(request, proxies, trust_env=True): proxies = proxies if proxies is not None else {} url = request.url scheme = urlparse(url).scheme - no_proxy = proxies.get('no_proxy') + no_proxy = proxies.get("no_proxy") new_proxies = proxies.copy() if trust_env and not should_bypass_proxies(url, no_proxy=no_proxy): environ_proxies = get_environ_proxies(url, no_proxy=no_proxy) - proxy = environ_proxies.get(scheme, environ_proxies.get('all')) + proxy = environ_proxies.get(scheme, environ_proxies.get("all")) if proxy: new_proxies.setdefault(scheme, proxy) @@ -867,19 +892,21 @@ def default_user_agent(name="python-requests"): :rtype: str """ - return '%s/%s' % (name, __version__) + return f"{name}/{__version__}" def default_headers(): """ :rtype: requests.structures.CaseInsensitiveDict """ - return CaseInsensitiveDict({ - 'User-Agent': default_user_agent(), - 'Accept-Encoding': DEFAULT_ACCEPT_ENCODING, - 'Accept': '*/*', - 'Connection': 'keep-alive', - }) + return CaseInsensitiveDict( + { + "User-Agent": default_user_agent(), + "Accept-Encoding": DEFAULT_ACCEPT_ENCODING, + "Accept": "*/*", + "Connection": "keep-alive", + } + ) def parse_header_links(value): @@ -892,23 +919,23 @@ def parse_header_links(value): links = [] - replace_chars = ' \'"' + replace_chars = " '\"" value = value.strip(replace_chars) if not value: return links - for val in re.split(', *<', value): + for val in re.split(", *<", value): try: - url, params = val.split(';', 1) + url, params = val.split(";", 1) except ValueError: - url, params = val, '' + url, params = val, "" - link = {'url': url.strip('<> \'"')} + link = {"url": url.strip("<> '\"")} - for param in params.split(';'): + for param in params.split(";"): try: - key, value = param.split('=') + key, value = param.split("=") except ValueError: break @@ -920,7 +947,7 @@ def parse_header_links(value): # Null bytes; no need to recreate these on each call to guess_json_utf -_null = '\x00'.encode('ascii') # encoding to ASCII for Python 3 +_null = "\x00".encode("ascii") # encoding to ASCII for Python 3 _null2 = _null * 2 _null3 = _null * 3 @@ -934,25 +961,25 @@ def guess_json_utf(data): # determine the encoding. Also detect a BOM, if present. sample = data[:4] if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE): - return 'utf-32' # BOM included + return "utf-32" # BOM included if sample[:3] == codecs.BOM_UTF8: - return 'utf-8-sig' # BOM included, MS style (discouraged) + return "utf-8-sig" # BOM included, MS style (discouraged) if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): - return 'utf-16' # BOM included + return "utf-16" # BOM included nullcount = sample.count(_null) if nullcount == 0: - return 'utf-8' + return "utf-8" if nullcount == 2: - if sample[::2] == _null2: # 1st and 3rd are null - return 'utf-16-be' + if sample[::2] == _null2: # 1st and 3rd are null + return "utf-16-be" if sample[1::2] == _null2: # 2nd and 4th are null - return 'utf-16-le' + return "utf-16-le" # Did not detect 2 valid UTF-16 ascii-range characters if nullcount == 3: if sample[:3] == _null3: - return 'utf-32-be' + return "utf-32-be" if sample[1:] == _null3: - return 'utf-32-le' + return "utf-32-le" # Did not detect a valid UTF-32 ascii-range character return None @@ -977,13 +1004,13 @@ def prepend_scheme_if_needed(url, new_scheme): if auth: # parse_url doesn't provide the netloc with auth # so we'll add it ourselves. - netloc = '@'.join([auth, netloc]) + netloc = "@".join([auth, netloc]) if scheme is None: scheme = new_scheme if path is None: - path = '' + path = "" - return urlunparse((scheme, netloc, path, '', query, fragment)) + return urlunparse((scheme, netloc, path, "", query, fragment)) def get_auth_from_url(url): @@ -997,35 +1024,39 @@ def get_auth_from_url(url): try: auth = (unquote(parsed.username), unquote(parsed.password)) except (AttributeError, TypeError): - auth = ('', '') + auth = ("", "") return auth -# Moved outside of function to avoid recompile every call -_CLEAN_HEADER_REGEX_BYTE = re.compile(b'^\\S[^\\r\\n]*$|^$') -_CLEAN_HEADER_REGEX_STR = re.compile(r'^\S[^\r\n]*$|^$') - - def check_header_validity(header): - """Verifies that header value is a string which doesn't contain - leading whitespace or return characters. This prevents unintended - header injection. + """Verifies that header parts don't contain leading whitespace + reserved characters, or return characters. :param header: tuple, in the format (name, value). """ name, value = header + _validate_header_part(header, name, 0) + _validate_header_part(header, value, 1) + - if isinstance(value, bytes): - pat = _CLEAN_HEADER_REGEX_BYTE +def _validate_header_part(header, header_part, header_validator_index): + if isinstance(header_part, str): + validator = _HEADER_VALIDATORS_STR[header_validator_index] + elif isinstance(header_part, bytes): + validator = _HEADER_VALIDATORS_BYTE[header_validator_index] else: - pat = _CLEAN_HEADER_REGEX_STR - try: - if not pat.match(value): - raise InvalidHeader("Invalid return character or leading space in header: %s" % name) - except TypeError: - raise InvalidHeader("Value for header {%s: %s} must be of type str or " - "bytes, not %s" % (name, value, type(value))) + raise InvalidHeader( + f"Header part ({header_part!r}) from {header} " + f"must be of type str or bytes, not {type(header_part)}" + ) + + if not validator.match(header_part): + header_kind = "name" if header_validator_index == 0 else "value" + raise InvalidHeader( + f"Invalid leading whitespace, reserved character(s), or return" + f"character(s) in header {header_kind}: {header_part!r}" + ) def urldefragauth(url): @@ -1040,21 +1071,24 @@ def urldefragauth(url): if not netloc: netloc, path = path, netloc - netloc = netloc.rsplit('@', 1)[-1] + netloc = netloc.rsplit("@", 1)[-1] - return urlunparse((scheme, netloc, path, params, query, '')) + return urlunparse((scheme, netloc, path, params, query, "")) def rewind_body(prepared_request): """Move file pointer back to its recorded starting position so it can be read again on redirect. """ - body_seek = getattr(prepared_request.body, 'seek', None) - if body_seek is not None and isinstance(prepared_request._body_position, integer_types): + body_seek = getattr(prepared_request.body, "seek", None) + if body_seek is not None and isinstance( + prepared_request._body_position, integer_types + ): try: body_seek(prepared_request._body_position) - except (IOError, OSError): - raise UnrewindableBodyError("An error occurred when rewinding request " - "body for redirect.") + except OSError: + raise UnrewindableBodyError( + "An error occurred when rewinding request body for redirect." + ) else: raise UnrewindableBodyError("Unable to rewind request body for redirect.") From 1ccfa9c0876a013761d99f40693f51d2e9b666c7 Mon Sep 17 00:00:00 2001 From: romanvm Date: Sat, 8 Jul 2023 11:14:06 +0000 Subject: [PATCH 053/145] [script.module.web-pdb] 1.6.2 --- script.module.web-pdb/addon.xml | 7 +- .../libs/web_pdb/__init__.py | 48 +- .../asyncore_wsgi/SimpleWebSocketServer.py | 40 +- .../libs/web_pdb/asyncore_wsgi/__init__.py | 4 +- .../libs/web_pdb/asyncore_wsgi/asyncore.py | 644 ++++++++++++++++++ script.module.web-pdb/libs/web_pdb/logging.py | 26 +- script.module.web-pdb/libs/web_pdb/pdb_py2.py | 56 -- .../libs/web_pdb/web_console.py | 21 +- .../libs/web_pdb/wsgi_app.py | 15 +- script.module.web-pdb/main.py | 1 - 10 files changed, 699 insertions(+), 163 deletions(-) create mode 100644 script.module.web-pdb/libs/web_pdb/asyncore_wsgi/asyncore.py delete mode 100644 script.module.web-pdb/libs/web_pdb/pdb_py2.py diff --git a/script.module.web-pdb/addon.xml b/script.module.web-pdb/addon.xml index bc3ab42e9..97726dade 100644 --- a/script.module.web-pdb/addon.xml +++ b/script.module.web-pdb/addon.xml @@ -1,11 +1,11 @@ - + executable @@ -22,6 +22,7 @@ icon.png resources/screenshot.jpg - - 1.5.6: Fixed not being able to assign a local variable via the debugger console. + - 1.6.2: Various internal changes. +- 1.6.0: Dropped Python 2 compatibility.
diff --git a/script.module.web-pdb/libs/web_pdb/__init__.py b/script.module.web-pdb/libs/web_pdb/__init__.py index 8aa807db2..8088bfea4 100644 --- a/script.module.web-pdb/libs/web_pdb/__init__.py +++ b/script.module.web-pdb/libs/web_pdb/__init__.py @@ -1,6 +1,5 @@ -# coding: utf-8 # Author: Roman Miroshnychenko aka Roman V.M. -# E-mail: romanvm@yandex.ua +# E-mail: roman1972@gmail.com # # Copyright (c) 2016 Roman Miroshnychenko # @@ -25,20 +24,18 @@ A web-interface for Python's built-in PDB debugger """ -from __future__ import absolute_import, unicode_literals import inspect import os +import random import sys import traceback -import random from contextlib import contextmanager +from pdb import Pdb from pprint import pformat -if sys.version_info[0] == 2: - from .pdb_py2 import PdbPy2 as Pdb -else: - from pdb import Pdb + import xbmc from xbmcgui import Dialog + from .web_console import WebConsole __all__ = ['WebPdb', 'set_trace', 'post_mortem', 'catch_post_mortem'] @@ -68,7 +65,7 @@ def __init__(self, host='', port=5555): random.seed() port = random.randint(32768, 65536) self.console = WebConsole(host, port, self) - Pdb.__init__(self, stdin=self.console, stdout=self.console) + super().__init__(stdin=self.console, stdout=self.console) WebPdb.active_instance = self def do_quit(self, arg): @@ -80,7 +77,7 @@ def do_quit(self, arg): self.console.flush() self.console.close() WebPdb.active_instance = None - return Pdb.do_quit(self, arg) + return super().do_quit(arg) do_q = do_exit = do_quit @@ -96,18 +93,13 @@ def do_inspect(self, arg): else: obj = WebPdb.null if obj is not WebPdb.null: - self.console.writeline( - '{0} = {1}:\n'.format(arg, type(obj)) - ) + self.console.writeline(f'{arg} = {type(obj)}:\n') for name, value in inspect.getmembers(obj): if not (name.startswith('__') and (name.endswith('__'))): - self.console.writeline(' {0}: {1}\n'.format( - name, self._get_repr(value, pretty=True, indent=8) - )) + repr_value = self._get_repr(value, pretty=True, indent=8) + self.console.writeline(f' {name}: {repr_value}\n') else: - self.console.writeline( - 'NameError: name "{0}" is not defined\n'.format(arg) - ) + self.console.writeline(f'NameError: name "{arg}" is not defined\n') self.console.flush() do_i = do_inspect @@ -130,12 +122,6 @@ def _get_repr(obj, pretty=False, indent=1): repr_value = pformat(obj, indent) else: repr_value = repr(obj) - if sys.version_info[0] == 2: - # Try to convert Unicode string to human-readable form - try: - repr_value = repr_value.decode('raw_unicode_escape') - except UnicodeError: - repr_value = repr_value.decode('utf-8', 'replace') return repr_value def set_continue(self): @@ -144,7 +130,7 @@ def set_continue(self): def dispatch_return(self, frame, arg): # The parent's method needs to be called first. - ret = Pdb.dispatch_return(self, frame, arg) + ret = super().dispatch_return(frame, arg) if frame.f_back is None: self.console.writeline('*** Thread finished ***\n') if not self.console.closed: @@ -164,8 +150,6 @@ def get_current_frame_data(self): """ filename = self.curframe.f_code.co_filename lines, start_line = inspect.findsource(self.curframe) - if sys.version_info[0] == 2: - lines = [line.decode('utf-8') for line in lines] return { 'dirname': os.path.dirname(os.path.abspath(filename)) + os.path.sep, 'filename': os.path.basename(filename), @@ -187,7 +171,7 @@ def _format_variables(self, raw_vars): for var, value in raw_vars.items(): if not (var.startswith('__') and var.endswith('__')): repr_value = self._get_repr(value) - f_vars.append('{0} = {1}'.format(var, repr_value)) + f_vars.append(f'{var} = {repr_value}') return '\n'.join(sorted(f_vars)) def get_globals(self): @@ -328,9 +312,9 @@ def catch_post_mortem(host='', port=5555): try: yield except Exception: - xbmc.log('Web-PDB: unhandled exception detected:\n{0}'.format( - traceback.format_exc()), xbmc.LOGERROR - ) + stack_trace = traceback.format_exc() + xbmc.log(f'Web-PDB: unhandled exception detected:\n{stack_trace}', + xbmc.LOGERROR) xbmc.log('Web-PDB: starting post-mortem debugging...', xbmc.LOGERROR) Dialog().notification('Web-PDB', 'Addon error! Starting post-mortem debugging.', diff --git a/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/SimpleWebSocketServer.py b/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/SimpleWebSocketServer.py index 041e17101..3970e0f20 100644 --- a/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/SimpleWebSocketServer.py +++ b/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/SimpleWebSocketServer.py @@ -10,24 +10,17 @@ Asynchronous WebSocket handler """ -from __future__ import absolute_import -import sys -VER = sys.version_info[0] -if VER >= 3: - from http.server import BaseHTTPRequestHandler - from io import StringIO, BytesIO -else: - from BaseHTTPServer import BaseHTTPRequestHandler - from StringIO import StringIO - -import asyncore -import hashlib import base64 +import codecs +import errno +import hashlib import socket import struct -import errno -import codecs from collections import deque +from http.server import BaseHTTPRequestHandler +from io import BytesIO + +from . import asyncore from .. import logging __all__ = ['WebSocket', 'AsyncWebSocketHandler'] @@ -36,10 +29,7 @@ def _check_unicode(val): - if VER >= 3: - return isinstance(val, str) - else: - return isinstance(val, unicode) + return isinstance(val, str) class WebSocketError(Exception): @@ -47,11 +37,9 @@ class WebSocketError(Exception): class HTTPRequest(BaseHTTPRequestHandler): + def __init__(self, request_text): - if VER >= 3: - self.rfile = BytesIO(request_text) - else: - self.rfile = StringIO(request_text) + self.rfile = BytesIO(request_text) self.raw_requestline = self.rfile.readline() self.error_code = self.error_message = None self.parse_request() @@ -290,12 +278,8 @@ def _handleData(self): if not data: raise WebSocketError("remote socket closed") - if VER >= 3: - for d in data: - self._parseMessage(d) - else: - for d in data: - self._parseMessage(ord(d)) + for d in data: + self._parseMessage(d) def close(self, status=1000, reason=u''): """ diff --git a/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/__init__.py b/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/__init__.py index 7710c9cdd..5a406645a 100644 --- a/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/__init__.py +++ b/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/__init__.py @@ -31,8 +31,6 @@ def handleClose(self): the Standard Library and the echo WebSocket on ``'/ws'`` path. """ -from __future__ import absolute_import -import asyncore import select import socket from errno import EINTR @@ -40,6 +38,8 @@ def handleClose(self): from shutil import copyfileobj from tempfile import TemporaryFile from wsgiref.simple_server import WSGIServer, ServerHandler, WSGIRequestHandler + +from . import asyncore from .SimpleWebSocketServer import AsyncWebSocketHandler from .. import logging diff --git a/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/asyncore.py b/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/asyncore.py new file mode 100644 index 000000000..828f4d4fe --- /dev/null +++ b/script.module.web-pdb/libs/web_pdb/asyncore_wsgi/asyncore.py @@ -0,0 +1,644 @@ +# -*- Mode: Python -*- +# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp +# Author: Sam Rushing + +# ====================================================================== +# Copyright 1996 by Sam Rushing +# +# All Rights Reserved +# +# Permission to use, copy, modify, and distribute this software and +# its documentation for any purpose and without fee is hereby +# granted, provided that the above copyright notice appear in all +# copies and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of Sam +# Rushing not be used in advertising or publicity pertaining to +# distribution of the software without specific, written prior +# permission. +# +# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN +# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# ====================================================================== + +"""Basic infrastructure for asynchronous socket service clients and servers. + +There are only two ways to have a program on a single processor do "more +than one thing at a time". Multi-threaded programming is the simplest and +most popular way to do it, but there is another very different technique, +that lets you have nearly all the advantages of multi-threading, without +actually using multiple threads. it's really only practical if your program +is largely I/O bound. If your program is CPU bound, then pre-emptive +scheduled threads are probably what you really need. Network servers are +rarely CPU-bound, however. + +If your operating system supports the select() system call in its I/O +library (and nearly all do), then you can use it to juggle multiple +communication channels at once; doing other work while your I/O is taking +place in the "background." Although this strategy can seem strange and +complex, especially at first, it is in many ways easier to understand and +control than multi-threaded programming. The module documented here solves +many of the difficult problems for you, making the task of building +sophisticated high-performance network servers and clients a snap. +""" + +import select +import socket +import sys +import time +import warnings + +import os +from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ + ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ + errorcode + +_DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, + EBADF}) + +try: + socket_map +except NameError: + socket_map = {} + +def _strerror(err): + try: + return os.strerror(err) + except (ValueError, OverflowError, NameError): + if err in errorcode: + return errorcode[err] + return "Unknown error %s" %err + +class ExitNow(Exception): + pass + +_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit) + +def read(obj): + try: + obj.handle_read_event() + except _reraised_exceptions: + raise + except: + obj.handle_error() + +def write(obj): + try: + obj.handle_write_event() + except _reraised_exceptions: + raise + except: + obj.handle_error() + +def _exception(obj): + try: + obj.handle_expt_event() + except _reraised_exceptions: + raise + except: + obj.handle_error() + +def readwrite(obj, flags): + try: + if flags & select.POLLIN: + obj.handle_read_event() + if flags & select.POLLOUT: + obj.handle_write_event() + if flags & select.POLLPRI: + obj.handle_expt_event() + if flags & (select.POLLHUP | select.POLLERR | select.POLLNVAL): + obj.handle_close() + except OSError as e: + if e.args[0] not in _DISCONNECTED: + obj.handle_error() + else: + obj.handle_close() + except _reraised_exceptions: + raise + except: + obj.handle_error() + +def poll(timeout=0.0, map=None): + if map is None: + map = socket_map + if map: + r = []; w = []; e = [] + for fd, obj in list(map.items()): + is_r = obj.readable() + is_w = obj.writable() + if is_r: + r.append(fd) + # accepting sockets should not be writable + if is_w and not obj.accepting: + w.append(fd) + if is_r or is_w: + e.append(fd) + if [] == r == w == e: + time.sleep(timeout) + return + + r, w, e = select.select(r, w, e, timeout) + + for fd in r: + obj = map.get(fd) + if obj is None: + continue + read(obj) + + for fd in w: + obj = map.get(fd) + if obj is None: + continue + write(obj) + + for fd in e: + obj = map.get(fd) + if obj is None: + continue + _exception(obj) + +def poll2(timeout=0.0, map=None): + # Use the poll() support added to the select module in Python 2.0 + if map is None: + map = socket_map + if timeout is not None: + # timeout is in milliseconds + timeout = int(timeout*1000) + pollster = select.poll() + if map: + for fd, obj in list(map.items()): + flags = 0 + if obj.readable(): + flags |= select.POLLIN | select.POLLPRI + # accepting sockets should not be writable + if obj.writable() and not obj.accepting: + flags |= select.POLLOUT + if flags: + pollster.register(fd, flags) + + r = pollster.poll(timeout) + for fd, flags in r: + obj = map.get(fd) + if obj is None: + continue + readwrite(obj, flags) + +poll3 = poll2 # Alias for backward compatibility + +def loop(timeout=30.0, use_poll=False, map=None, count=None): + if map is None: + map = socket_map + + if use_poll and hasattr(select, 'poll'): + poll_fun = poll2 + else: + poll_fun = poll + + if count is None: + while map: + poll_fun(timeout, map) + + else: + while map and count > 0: + poll_fun(timeout, map) + count = count - 1 + +class dispatcher: + + debug = False + connected = False + accepting = False + connecting = False + closing = False + addr = None + ignore_log_types = frozenset({'warning'}) + + def __init__(self, sock=None, map=None): + if map is None: + self._map = socket_map + else: + self._map = map + + self._fileno = None + + if sock: + # Set to nonblocking just to make sure for cases where we + # get a socket from a blocking source. + sock.setblocking(0) + self.set_socket(sock, map) + self.connected = True + # The constructor no longer requires that the socket + # passed be connected. + try: + self.addr = sock.getpeername() + except OSError as err: + if err.args[0] in (ENOTCONN, EINVAL): + # To handle the case where we got an unconnected + # socket. + self.connected = False + else: + # The socket is broken in some unknown way, alert + # the user and remove it from the map (to prevent + # polling of broken sockets). + self.del_channel(map) + raise + else: + self.socket = None + + def __repr__(self): + status = [self.__class__.__module__+"."+self.__class__.__qualname__] + if self.accepting and self.addr: + status.append('listening') + elif self.connected: + status.append('connected') + if self.addr is not None: + try: + status.append('%s:%d' % self.addr) + except TypeError: + status.append(repr(self.addr)) + return '<%s at %#x>' % (' '.join(status), id(self)) + + __str__ = __repr__ + + def add_channel(self, map=None): + #self.log_info('adding channel %s' % self) + if map is None: + map = self._map + map[self._fileno] = self + + def del_channel(self, map=None): + fd = self._fileno + if map is None: + map = self._map + if fd in map: + #self.log_info('closing channel %d:%s' % (fd, self)) + del map[fd] + self._fileno = None + + def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM): + self.family_and_type = family, type + sock = socket.socket(family, type) + sock.setblocking(0) + self.set_socket(sock) + + def set_socket(self, sock, map=None): + self.socket = sock + self._fileno = sock.fileno() + self.add_channel(map) + + def set_reuse_addr(self): + # try to re-use a server port if possible + try: + self.socket.setsockopt( + socket.SOL_SOCKET, socket.SO_REUSEADDR, + self.socket.getsockopt(socket.SOL_SOCKET, + socket.SO_REUSEADDR) | 1 + ) + except OSError: + pass + + # ================================================== + # predicates for select() + # these are used as filters for the lists of sockets + # to pass to select(). + # ================================================== + + def readable(self): + return True + + def writable(self): + return True + + # ================================================== + # socket object methods. + # ================================================== + + def listen(self, num): + self.accepting = True + if os.name == 'nt' and num > 5: + num = 5 + return self.socket.listen(num) + + def bind(self, addr): + self.addr = addr + return self.socket.bind(addr) + + def connect(self, address): + self.connected = False + self.connecting = True + err = self.socket.connect_ex(address) + if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ + or err == EINVAL and os.name == 'nt': + self.addr = address + return + if err in (0, EISCONN): + self.addr = address + self.handle_connect_event() + else: + raise OSError(err, errorcode[err]) + + def accept(self): + # XXX can return either an address pair or None + try: + conn, addr = self.socket.accept() + except TypeError: + return None + except OSError as why: + if why.args[0] in (EWOULDBLOCK, ECONNABORTED, EAGAIN): + return None + else: + raise + else: + return conn, addr + + def send(self, data): + try: + result = self.socket.send(data) + return result + except OSError as why: + if why.args[0] == EWOULDBLOCK: + return 0 + elif why.args[0] in _DISCONNECTED: + self.handle_close() + return 0 + else: + raise + + def recv(self, buffer_size): + try: + data = self.socket.recv(buffer_size) + if not data: + # a closed connection is indicated by signaling + # a read condition, and having recv() return 0. + self.handle_close() + return b'' + else: + return data + except OSError as why: + # winsock sometimes raises ENOTCONN + if why.args[0] in _DISCONNECTED: + self.handle_close() + return b'' + else: + raise + + def close(self): + self.connected = False + self.accepting = False + self.connecting = False + self.del_channel() + if self.socket is not None: + try: + self.socket.close() + except OSError as why: + if why.args[0] not in (ENOTCONN, EBADF): + raise + + # log and log_info may be overridden to provide more sophisticated + # logging and warning methods. In general, log is for 'hit' logging + # and 'log_info' is for informational, warning and error logging. + + def log(self, message): + sys.stderr.write('log: %s\n' % str(message)) + + def log_info(self, message, type='info'): + if type not in self.ignore_log_types: + print('%s: %s' % (type, message)) + + def handle_read_event(self): + if self.accepting: + # accepting sockets are never connected, they "spawn" new + # sockets that are connected + self.handle_accept() + elif not self.connected: + if self.connecting: + self.handle_connect_event() + self.handle_read() + else: + self.handle_read() + + def handle_connect_event(self): + err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) + if err != 0: + raise OSError(err, _strerror(err)) + self.handle_connect() + self.connected = True + self.connecting = False + + def handle_write_event(self): + if self.accepting: + # Accepting sockets shouldn't get a write event. + # We will pretend it didn't happen. + return + + if not self.connected: + if self.connecting: + self.handle_connect_event() + self.handle_write() + + def handle_expt_event(self): + # handle_expt_event() is called if there might be an error on the + # socket, or if there is OOB data + # check for the error condition first + err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) + if err != 0: + # we can get here when select.select() says that there is an + # exceptional condition on the socket + # since there is an error, we'll go ahead and close the socket + # like we would in a subclassed handle_read() that received no + # data + self.handle_close() + else: + self.handle_expt() + + def handle_error(self): + nil, t, v, tbinfo = compact_traceback() + + # sometimes a user repr method will crash. + try: + self_repr = repr(self) + except: + self_repr = '<__repr__(self) failed for object at %0x>' % id(self) + + self.log_info( + 'uncaptured python exception, closing channel %s (%s:%s %s)' % ( + self_repr, + t, + v, + tbinfo + ), + 'error' + ) + self.handle_close() + + def handle_expt(self): + self.log_info('unhandled incoming priority event', 'warning') + + def handle_read(self): + self.log_info('unhandled read event', 'warning') + + def handle_write(self): + self.log_info('unhandled write event', 'warning') + + def handle_connect(self): + self.log_info('unhandled connect event', 'warning') + + def handle_accept(self): + pair = self.accept() + if pair is not None: + self.handle_accepted(*pair) + + def handle_accepted(self, sock, addr): + sock.close() + self.log_info('unhandled accepted event', 'warning') + + def handle_close(self): + self.log_info('unhandled close event', 'warning') + self.close() + +# --------------------------------------------------------------------------- +# adds simple buffered output capability, useful for simple clients. +# [for more sophisticated usage use asynchat.async_chat] +# --------------------------------------------------------------------------- + +class dispatcher_with_send(dispatcher): + + def __init__(self, sock=None, map=None): + dispatcher.__init__(self, sock, map) + self.out_buffer = b'' + + def initiate_send(self): + num_sent = 0 + num_sent = dispatcher.send(self, self.out_buffer[:65536]) + self.out_buffer = self.out_buffer[num_sent:] + + def handle_write(self): + self.initiate_send() + + def writable(self): + return (not self.connected) or len(self.out_buffer) + + def send(self, data): + if self.debug: + self.log_info('sending %s' % repr(data)) + self.out_buffer = self.out_buffer + data + self.initiate_send() + +# --------------------------------------------------------------------------- +# used for debugging. +# --------------------------------------------------------------------------- + +def compact_traceback(): + t, v, tb = sys.exc_info() + tbinfo = [] + if not tb: # Must have a traceback + raise AssertionError("traceback does not exist") + while tb: + tbinfo.append(( + tb.tb_frame.f_code.co_filename, + tb.tb_frame.f_code.co_name, + str(tb.tb_lineno) + )) + tb = tb.tb_next + + # just to be safe + del tb + + file, function, line = tbinfo[-1] + info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo]) + return (file, function, line), t, v, info + +def close_all(map=None, ignore_all=False): + if map is None: + map = socket_map + for x in list(map.values()): + try: + x.close() + except OSError as x: + if x.args[0] == EBADF: + pass + elif not ignore_all: + raise + except _reraised_exceptions: + raise + except: + if not ignore_all: + raise + map.clear() + +# Asynchronous File I/O: +# +# After a little research (reading man pages on various unixen, and +# digging through the linux kernel), I've determined that select() +# isn't meant for doing asynchronous file i/o. +# Heartening, though - reading linux/mm/filemap.c shows that linux +# supports asynchronous read-ahead. So _MOST_ of the time, the data +# will be sitting in memory for us already when we go to read it. +# +# What other OS's (besides NT) support async file i/o? [VMS?] +# +# Regardless, this is useful for pipes, and stdin/stdout... + +if os.name == 'posix': + class file_wrapper: + # Here we override just enough to make a file + # look like a socket for the purposes of asyncore. + # The passed fd is automatically os.dup()'d + + def __init__(self, fd): + self.fd = os.dup(fd) + + def __del__(self): + if self.fd >= 0: + warnings.warn("unclosed file %r" % self, ResourceWarning, + source=self) + self.close() + + def recv(self, *args): + return os.read(self.fd, *args) + + def send(self, *args): + return os.write(self.fd, *args) + + def getsockopt(self, level, optname, buflen=None): + if (level == socket.SOL_SOCKET and + optname == socket.SO_ERROR and + not buflen): + return 0 + raise NotImplementedError("Only asyncore specific behaviour " + "implemented.") + + read = recv + write = send + + def close(self): + if self.fd < 0: + return + fd = self.fd + self.fd = -1 + os.close(fd) + + def fileno(self): + return self.fd + + class file_dispatcher(dispatcher): + + def __init__(self, fd, map=None): + dispatcher.__init__(self, None, map) + self.connected = True + try: + fd = fd.fileno() + except AttributeError: + pass + self.set_file(fd) + # set it to non-blocking mode + os.set_blocking(fd, False) + + def set_file(self, fd): + self.socket = file_wrapper(fd) + self._fileno = self.socket.fileno() + self.add_channel() diff --git a/script.module.web-pdb/libs/web_pdb/logging.py b/script.module.web-pdb/libs/web_pdb/logging.py index 9bbc37a35..320bf9c9e 100644 --- a/script.module.web-pdb/libs/web_pdb/logging.py +++ b/script.module.web-pdb/libs/web_pdb/logging.py @@ -1,41 +1,33 @@ -# coding: utf-8 """Mimics built-in logging module""" -from __future__ import unicode_literals -import sys from traceback import format_exc import xbmc __all__ = ['Logger', 'getLogger'] -PY2 = sys.version_info[0] == 2 - -def encode(string): - if PY2 and isinstance(string, unicode): - string = string.encode('utf-8') - return string - - -class Logger(object): +class Logger: def __init__(self, name=''): self._name = name + def _log(self, msg, level): + xbmc.log(f'{self._name}: {msg}', level) + def info(self, msg): - xbmc.log(encode('{}: {}'.format(self._name, msg)), xbmc.LOGINFO) + self._log(msg, xbmc.LOGINFO) def error(self, msg): - xbmc.log(encode('{}: {}'.format(self._name, msg)), xbmc.LOGERROR) + self._log(msg, xbmc.LOGERROR) def exception(self, msg): - self.error(msg) + self._log(msg, xbmc.LOGERROR) xbmc.log(format_exc(), xbmc.LOGERROR) def debug(self, msg): - xbmc.log(encode('{}: {}'.format(self._name, msg)), xbmc.LOGDEBUG) + self._log(msg, xbmc.LOGDEBUG) def critical(self, msg): - xbmc.log(encode('{}: {}'.format(self._name, msg)), xbmc.LOGFATAL) + self._log(msg, xbmc.LOGFATAL) def getLogger(name): diff --git a/script.module.web-pdb/libs/web_pdb/pdb_py2.py b/script.module.web-pdb/libs/web_pdb/pdb_py2.py deleted file mode 100644 index 2bd2476b5..000000000 --- a/script.module.web-pdb/libs/web_pdb/pdb_py2.py +++ /dev/null @@ -1,56 +0,0 @@ -# coding: utf-8 -# Author: Roman Miroshnychenko aka Roman V.M. -# E-mail: romanvm@yandex.ua -# -# Copyright (c) 2016 Roman Miroshnychenko -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import pprint -from pdb import Pdb - - -class PdbPy2(Pdb): - """ - This class overrides ``do_p`` and ``do_pp`` methods - to enable human-readable printing of Unicode strings in Python 2 - """ - def do_p(self, arg): - try: - repr_value = repr(self._getval(arg)) - # Try to convert Unicode string to human-readable form - try: - repr_value = repr_value.decode('raw_unicode_escape') - except UnicodeError: - repr_value = repr_value.decode('utf-8', 'replace') - print >> self.stdout, repr_value - except: - pass - - def do_pp(self, arg): - try: - repr_value = pprint.pformat(self._getval(arg)) - # Try to convert Unicode string to human-readable form - try: - repr_value = repr_value.decode('raw_unicode_escape') - except UnicodeError: - repr_value = repr_value.decode('utf-8', 'replace') - print >> self.stdout, repr_value - except: - pass diff --git a/script.module.web-pdb/libs/web_pdb/web_console.py b/script.module.web-pdb/libs/web_pdb/web_console.py index 1156dc9b1..91e276750 100644 --- a/script.module.web-pdb/libs/web_pdb/web_console.py +++ b/script.module.web-pdb/libs/web_pdb/web_console.py @@ -1,6 +1,5 @@ -# coding: utf-8 # Author: Roman Miroshnychenko aka Roman V.M. -# E-mail: romanvm@yandex.ua +# E-mail: roman1972@gmail.com # # Copyright (c) 2016 Roman Miroshnychenko # @@ -25,19 +24,17 @@ File-like web-based input/output console """ -from __future__ import absolute_import, unicode_literals +import queue import weakref from threading import Thread, Event, RLock -try: - import queue -except ImportError: - import Queue as queue -from .asyncore_wsgi import make_server, AsyncWebSocketHandler + import xbmc from xbmcaddon import Addon from xbmcgui import DialogProgressBG -from .wsgi_app import app + +from .asyncore_wsgi import make_server, AsyncWebSocketHandler from .logging import getLogger +from .wsgi_app import app __all__ = ['WebConsole'] @@ -131,9 +128,7 @@ def closed(self): def _run_server(self, host, port): app.frame_data = self._frame_data httpd = make_server(host, port, app, ws_handler_class=WebConsoleSocket) - logger.info('Web-PDB: starting web-server on {0}:{1}...'.format( - httpd.server_name, port) - ) + logger.info(f'Web-PDB: starting web-server on {httpd.server_name}:{port}...') dialog = DialogProgressBG() started = False while not (self._stop_all.is_set() or kodi_monitor.abortRequested()): @@ -170,8 +165,6 @@ def readline(self): read = readline def writeline(self, data): - if isinstance(data, bytes): - data = data.decode('utf-8') self._console_history.contents += data try: frame_data = self._debugger.get_current_frame_data() diff --git a/script.module.web-pdb/libs/web_pdb/wsgi_app.py b/script.module.web-pdb/libs/web_pdb/wsgi_app.py index 03a219e4c..70ac5b6ea 100644 --- a/script.module.web-pdb/libs/web_pdb/wsgi_app.py +++ b/script.module.web-pdb/libs/web_pdb/wsgi_app.py @@ -1,4 +1,3 @@ -# coding: utf-8 # Author: Roman Miroshnychenko aka Roman V.M. # E-mail: roman1972@gmail.com # @@ -25,11 +24,12 @@ Web-UI WSGI application """ +import gzip import json import os -import gzip -from io import BytesIO from functools import wraps +from io import BytesIO + import bottle __all__ = ['app'] @@ -39,11 +39,6 @@ cwd = os.path.dirname(os.path.abspath(__file__)) bottle.TEMPLATE_PATH.append(os.path.join(cwd, 'templates')) static_path = os.path.join(cwd, 'static') -try: - string_type = basestring -except NameError: - string_type = (bytes, str) - unicode = str def compress(func): @@ -54,9 +49,9 @@ def compress(func): def wrapper(*args, **kwargs): result = func(*args, **kwargs) if ('gzip' in bottle.request.headers.get('Accept-Encoding', '') and - isinstance(result, string_type) and + isinstance(result, (str, bytes)) and len(result) > 1024): - if isinstance(result, unicode): + if isinstance(result, str): result = result.encode('utf-8') tmp_fo = BytesIO() with gzip.GzipFile(mode='wb', fileobj=tmp_fo) as gzip_fo: diff --git a/script.module.web-pdb/main.py b/script.module.web-pdb/main.py index 90e757cf7..5db416819 100644 --- a/script.module.web-pdb/main.py +++ b/script.module.web-pdb/main.py @@ -21,7 +21,6 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import unicode_literals from xbmcaddon import Addon from xbmcgui import Dialog From 8c93171ac8bab313a167d8eec17fd1c0fd2427a2 Mon Sep 17 00:00:00 2001 From: Thomas Hager Date: Sun, 9 Jul 2023 09:02:05 +0200 Subject: [PATCH 054/145] [script.video.nfl.gamepass] 2023.07.05 (#2477) --- script.video.nfl.gamepass/README.md | 13 ++++++++ script.video.nfl.gamepass/addon.xml | 16 +++++----- script.video.nfl.gamepass/changelog.txt | 13 ++++++++ script.video.nfl.gamepass/default.py | 31 ++++++++++++------- .../resource.language.de_de/strings.po | 8 +++++ .../resource.language.en_gb/strings.po | 8 +++++ .../resource.language.ja_jp/strings.po | 8 +++++ .../resource.language.nl_nl/strings.po | 8 +++++ .../resource.language.ru_ru/strings.po | 8 +++-- .../resource.language.uk_ua/strings.po | 8 +++-- .../resources/lib/pigskin/pigskin.py | 5 ++- .../resources/settings.xml | 16 ++++++++++ 12 files changed, 118 insertions(+), 24 deletions(-) diff --git a/script.video.nfl.gamepass/README.md b/script.video.nfl.gamepass/README.md index 09af42b8c..195fe02e1 100644 --- a/script.video.nfl.gamepass/README.md +++ b/script.video.nfl.gamepass/README.md @@ -1,3 +1,16 @@ +# All good things come to an end + +After retiring NFL Gamepass Domestic in 2022, the NFL decided to shutdown the international Gamepass service +as well in 2023, rendering this add-on obsolete. + +Outside of the States, DAZN is the new home for the NFL Gamepass service. You can watch the games with a DAZN +account and an NFL Gamepass subscription. + +The good news is that there is a DAZN add-on available for Kodi, so it is still possible to watch NFL games on our +most favorite media center. + +--- + # NOTE # This addon supports NFL Game Pass, which is a merger of previous diff --git a/script.video.nfl.gamepass/addon.xml b/script.video.nfl.gamepass/addon.xml index e32ae2f3c..3ea42ee95 100644 --- a/script.video.nfl.gamepass/addon.xml +++ b/script.video.nfl.gamepass/addon.xml @@ -1,7 +1,7 @@  @@ -15,17 +15,17 @@ NFL Game Pass Watch NFL Game Pass streams. + The NFL canceled the NFL Gamepass service, rendering this add-on obsolete. all en GPL-2.0-only https://github.com/pigskin/kodi-gamepass - This addon requires you to have a subscription to NFL Game Pass.[CR]Please note that these subscriptions are region restricted by the NFL.[CR]This addon is completely unofficial and is /not/ endorsed by the NFL in any way. - 2022.05.14 - + Adapt to API changes implemented by Diva (jm-duke) - + Fix issue with LV Raiders logo (jm-duke) - + Fix display of 'None' for focused games in game week view (jm-duke) - + Implemented some improvements highlighted by Bas Rieter (jm-duke) - + Minor refactorings (jm-duke) + The NFL canceled the NFL Gamepass service, rendering this add-on obsolete. + 2023.07.05 + + Mark add-on as broken, NFL has canceled the Gamepass service (jm-duke) + + Show date (or weekday) of game (AleXSR700) + + Toggle display of current week's games (jm-duke) + + Implement workaround for failed content URL retrieval (jm-duke) resources/art/icon.png diff --git a/script.video.nfl.gamepass/changelog.txt b/script.video.nfl.gamepass/changelog.txt index 19a38c6c7..feabbbfba 100644 --- a/script.video.nfl.gamepass/changelog.txt +++ b/script.video.nfl.gamepass/changelog.txt @@ -1,3 +1,16 @@ +2023.07.05 -- Farewell Edition ++ Mark add-on as broken, NFL has canceled the Gamepass service (jm-duke) ++ Show date (or weekday) of game (AleXSR700) ++ Toggle display of current week's games (jm-duke) ++ Implement workaround for failed content URL retrieval (jm-duke) + +2022.11.14 -- Aaron Rodgers Edition ++ Fix open settings from app bug (ohhmyy) ++ Use updated team logos (ohhmyy) ++ Remove code for fixed bitrates - adaptive is default (jm-duke) ++ Add busy dialog to NFL Network (ohhmyy) ++ Fix issue with recent NFL API change (jm-duke) + 2022.05.14 -- Drew Brees Edition + Adapt to API changes implemented by Diva (jm-duke) + Fix issue with LV Raiders logo (jm-duke) diff --git a/script.video.nfl.gamepass/default.py b/script.video.nfl.gamepass/default.py index b0ae155f7..5337909e2 100644 --- a/script.video.nfl.gamepass/default.py +++ b/script.video.nfl.gamepass/default.py @@ -271,6 +271,13 @@ def display_weeks_games(self): listitem.setProperty('is_game', 'true') listitem.setProperty('is_show', 'false') + if addon.getSetting('time_notation') == '0': # 12-hour clock + datetime_format = '%A, %b %d - %I:%M %p' + else: # 24-hour clock + datetime_format = '%A, %b %d - %H:%M' + + datetime_obj = self.gp.nfldate_to_datetime(game['gameDateTimeUtc'], True) + if game['phase'] == 'FINAL' or game['phase'] == 'FINAL_OVERTIME': # show game duration only if user wants to see it if addon.getSetting('hide_game_length') == 'false' and game['video']: @@ -280,16 +287,16 @@ def display_weeks_games(self): game['phase'], str(timedelta(seconds=int(float(game['video']['videoDuration'].replace(',', '.')))))) else: - game_info = game['phase'] - if addon.getSetting('hide_game_length') == 'true' and game_info == 'FINAL_OVERTIME': - game_info = 'FINAL' + if addon.getSetting('display_datetime') == 'true': + if addon.getSetting('hide_game_length') == 'true' and game['phase'] != 'FINAL': + game_info = 'FINAL' + '\n' + '(' + datetime_obj.strftime(datetime_format) +')' + else: + game_info = game['phase'] + '\n' + '(' + datetime_obj.strftime(datetime_format) +')' + else: + game_info = game['phase'] + if addon.getSetting('hide_game_length') == 'true' and game['phase'] != 'FINAL': + game_info = 'FINAL' else: - if addon.getSetting('time_notation') == '0': # 12-hour clock - datetime_format = '%A, %b %d - %I:%M %p' - else: # 24-hour clock - datetime_format = '%A, %b %d - %H:%M' - - datetime_obj = self.gp.nfldate_to_datetime(game['gameDateTimeUtc'], True) game_info = datetime_obj.strftime(datetime_format) if game['videoStatus'] == 'SCHEDULED': @@ -490,11 +497,13 @@ def onClick(self, controlId): # pylint: disable=invalid-name try: self.display_seasons_weeks() - self.display_weeks_games() + if addon.getSetting('display_current_week') == 'true': + self.display_weeks_games() except Exception as e: logger.debug('Error while reading seasons weeks and games') logger.debug('Trace Message:\n{}'.format(format_exc())) elif controlId == 130: + xbmc.executebuiltin('ActivateWindow(busydialognocancel)') self.main_selection = 'NFL Network' self.window.setProperty('NW_clicked', 'true') self.window.setProperty('GP_clicked', 'false') @@ -509,7 +518,7 @@ def onClick(self, controlId): # pylint: disable=invalid-name self.live_list.addItems(self.live_items) self.display_nfln_seasons() - + xbmc.executebuiltin('Dialog.Close(busydialognocancel)') return if self.main_selection == 'GamePass': diff --git a/script.video.nfl.gamepass/resources/language/resource.language.de_de/strings.po b/script.video.nfl.gamepass/resources/language/resource.language.de_de/strings.po index ddb07a494..a59ca6dee 100644 --- a/script.video.nfl.gamepass/resources/language/resource.language.de_de/strings.po +++ b/script.video.nfl.gamepass/resources/language/resource.language.de_de/strings.po @@ -85,6 +85,10 @@ msgctxt "#30030" msgid "Display/Video" msgstr "Anzeige" +msgctxt "#30031" +msgid "Load and display games of current week" +msgstr "Zeige die Spiele der aktuellen Woche" + msgctxt "#30032" msgid "Coaches Film" msgstr "" @@ -152,3 +156,7 @@ msgstr "Bitte geben Sie Benutzernamen und Passwort für Ihr NFL Game Pass Abo ei msgctxt "#30051" msgid "Inputstream Adaptive is not installed or is disabled." msgstr "Inputstream Adaptive ist nicht installiert oder nicht aktiviert." + +msgctxt "#30052" +msgid "Display date and time of kickoff" +msgstr "Zeige das Datum und die Uhrzeit des Kickoffs an" diff --git a/script.video.nfl.gamepass/resources/language/resource.language.en_gb/strings.po b/script.video.nfl.gamepass/resources/language/resource.language.en_gb/strings.po index eda15b610..1933cc512 100644 --- a/script.video.nfl.gamepass/resources/language/resource.language.en_gb/strings.po +++ b/script.video.nfl.gamepass/resources/language/resource.language.en_gb/strings.po @@ -85,6 +85,10 @@ msgctxt "#30030" msgid "Display/Video" msgstr "" +msgctxt "#30031" +msgid "Load and display games of current week" +msgstr "" + msgctxt "#30032" msgid "Coaches Film" msgstr "" @@ -152,3 +156,7 @@ msgstr "" msgctxt "#30051" msgid "Inputstream Adaptive is not installed or is disabled." msgstr "" + +msgctxt "#30052" +msgid "Display date and time of kickoff" +msgstr "" diff --git a/script.video.nfl.gamepass/resources/language/resource.language.ja_jp/strings.po b/script.video.nfl.gamepass/resources/language/resource.language.ja_jp/strings.po index ab80862ce..7bc7dbf9d 100644 --- a/script.video.nfl.gamepass/resources/language/resource.language.ja_jp/strings.po +++ b/script.video.nfl.gamepass/resources/language/resource.language.ja_jp/strings.po @@ -86,6 +86,10 @@ msgctxt "#30030" msgid "Display/Video" msgstr "デイスプレイ・ビデオ" +msgctxt "#30031" +msgid "Load and display games of current week" +msgstr "" + msgctxt "#30032" msgid "Coaches Film" msgstr "監督フィルム集" @@ -153,3 +157,7 @@ msgstr "" msgctxt "#30051" msgid "Inputstream Adaptive is not installed or is disabled." msgstr "" + +msgctxt "#30052" +msgid "Display date and time of kickoff" +msgstr "" diff --git a/script.video.nfl.gamepass/resources/language/resource.language.nl_nl/strings.po b/script.video.nfl.gamepass/resources/language/resource.language.nl_nl/strings.po index 7334d658d..63d5646a4 100644 --- a/script.video.nfl.gamepass/resources/language/resource.language.nl_nl/strings.po +++ b/script.video.nfl.gamepass/resources/language/resource.language.nl_nl/strings.po @@ -85,6 +85,10 @@ msgctxt "#30030" msgid "Display/Video" msgstr "Weergave/Video" +msgctxt "#30031" +msgid "Load and display games of current week" +msgstr "" + msgctxt "#30032" msgid "Coaches Film" msgstr "Coaches Film" @@ -152,3 +156,7 @@ msgstr "Vul de gebruikersnaam en wachtwoord in van uw NFL Game Pass abonnement." msgctxt "#30051" msgid "Inputstream Adaptive is not installed or is disabled." msgstr "" + +msgctxt "#30052" +msgid "Display date and time of kickoff" +msgstr "" diff --git a/script.video.nfl.gamepass/resources/language/resource.language.ru_ru/strings.po b/script.video.nfl.gamepass/resources/language/resource.language.ru_ru/strings.po index a5fbcb2c2..ad66d482d 100644 --- a/script.video.nfl.gamepass/resources/language/resource.language.ru_ru/strings.po +++ b/script.video.nfl.gamepass/resources/language/resource.language.ru_ru/strings.po @@ -86,8 +86,8 @@ msgid "Display/Video" msgstr "Воспроизведение/Видео" msgctxt "#30031" -msgid "Advanced" -msgstr "Продвинутые" +msgid "Load and display games of current week" +msgstr "" msgctxt "#30032" msgid "Coaches Film" @@ -156,3 +156,7 @@ msgstr "" msgctxt "#30051" msgid "Inputstream Adaptive is not installed or is disabled." msgstr "" + +msgctxt "#30052" +msgid "Display date and time of kickoff" +msgstr "" diff --git a/script.video.nfl.gamepass/resources/language/resource.language.uk_ua/strings.po b/script.video.nfl.gamepass/resources/language/resource.language.uk_ua/strings.po index e4cc17053..be183c2f0 100644 --- a/script.video.nfl.gamepass/resources/language/resource.language.uk_ua/strings.po +++ b/script.video.nfl.gamepass/resources/language/resource.language.uk_ua/strings.po @@ -86,8 +86,8 @@ msgid "Display/Video" msgstr "Відображення/Відео" msgctxt "#30031" -msgid "Advanced" -msgstr "Просунуті" +msgid "Load and display games of current week" +msgstr "" msgctxt "#30032" msgid "Coaches Film" @@ -156,3 +156,7 @@ msgstr "" msgctxt "#30051" msgid "Inputstream Adaptive is not installed or is disabled." msgstr "" + +msgctxt "#30052" +msgid "Display date and time of kickoff" +msgstr "" diff --git a/script.video.nfl.gamepass/resources/lib/pigskin/pigskin.py b/script.video.nfl.gamepass/resources/lib/pigskin/pigskin.py index 921917100..a9699e66e 100644 --- a/script.video.nfl.gamepass/resources/lib/pigskin/pigskin.py +++ b/script.video.nfl.gamepass/resources/lib/pigskin/pigskin.py @@ -933,7 +933,10 @@ def _get_diva_streams(self, video_id, diva_config_url): except Exception as e: raise e - streams[vs_format] = data['ContentUrl'] + '|' + urlencode(m3u8_header) + if isinstance(data, dict) and 'ContentUrl' in data: + streams[vs_format] = data['ContentUrl'] + '|' + urlencode(m3u8_header) + else: + continue return streams diff --git a/script.video.nfl.gamepass/resources/settings.xml b/script.video.nfl.gamepass/resources/settings.xml index 6c0d4fa23..71dd58e84 100644 --- a/script.video.nfl.gamepass/resources/settings.xml +++ b/script.video.nfl.gamepass/resources/settings.xml @@ -66,6 +66,22 @@ 0 false + + true + +
+ + 0 + false + + + true + + + + 0 + true + From c96e1d92a70ef49db40bc5b59c7ba9bd1e095d14 Mon Sep 17 00:00:00 2001 From: Heckie Date: Sun, 9 Jul 2023 09:02:27 +0200 Subject: [PATCH 055/145] [script.timers] 3.7.0 (#2478) --- script.timers/addon.xml | 11 ++--- .../resource.language.de_de/strings.po | 4 ++ .../resource.language.en_gb/strings.po | 4 ++ script.timers/resources/lib/player/player.py | 36 ++++++++++----- .../resources/lib/timer/notification.py | 13 ++++++ .../resources/lib/timer/scheduleraction.py | 45 ++++++++----------- 6 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 script.timers/resources/lib/timer/notification.py diff --git a/script.timers/addon.xml b/script.timers/addon.xml index 6180c22b0..6d57fdf98 100644 --- a/script.timers/addon.xml +++ b/script.timers/addon.xml @@ -1,5 +1,5 @@ - + @@ -66,6 +66,10 @@ https://github.com/Heckie75/kodi-addon-timers https://github.com/Heckie75/kodi-addon-timers +v3.7.0 (2023-06-30) +- If you stop explicitly playback while a start-stop-timer is running there won't be another stop action anymore when this timer runs out. +- Added workaround that streamed video (probably mpeg-dash) immediately stops after timer has started (only happened if 'seek to correct time if timer starts belatedly' is activated) + v3.6.0 (2023-04-16) - Smart shuffle mode for slideshows (try randomly to find folder that fits into timeframe) - Fixed resuming slideshow at right position @@ -87,10 +91,7 @@ v3.3.1 (2022-11-26) - Bugfix: scheduled timers stop working that are scheduled after Sunday (week change Sun -> Mon) - Refactoring -v3.3.0 (2022-10-08) -- Improved scheduler that enables scheduling to the second, reduces CPU load on idle and enables smoother fading -- Added fields for start and end time in order to schedule to the second (expert only) -- Fixed Zattoo PVR support and other audio/video addons +Complete changelog see https://github.com/Heckie75/kodi-addon-timers resources/assets/icon.png diff --git a/script.timers/resources/language/resource.language.de_de/strings.po b/script.timers/resources/language/resource.language.de_de/strings.po index 838663e97..bab655441 100644 --- a/script.timers/resources/language/resource.language.de_de/strings.po +++ b/script.timers/resources/language/resource.language.de_de/strings.po @@ -677,6 +677,10 @@ msgctxt "#32288" msgid "run addon" msgstr "führe Addon aus" +msgctxt "#32289" +msgid "interrupt running timers" +msgstr "unterbreche laufende Timer" + msgctxt "#32300" msgid "Opens a dialog where you can enter a duration for pause from now." msgstr "Öffnet einen Dialog zur Eingabe der Dauer von jetzt an." diff --git a/script.timers/resources/language/resource.language.en_gb/strings.po b/script.timers/resources/language/resource.language.en_gb/strings.po index 32015f642..e2f0cdeb8 100644 --- a/script.timers/resources/language/resource.language.en_gb/strings.po +++ b/script.timers/resources/language/resource.language.en_gb/strings.po @@ -677,6 +677,10 @@ msgctxt "#32288" msgid "run addon" msgstr "" +msgctxt "#32289" +msgid "interrupt running timers" +msgstr "" + msgctxt "#32300" msgid "Opens a dialog where you can enter a duration for pause from now." msgstr "" diff --git a/script.timers/resources/lib/player/player.py b/script.timers/resources/lib/player/player.py index 32c13359f..7f35f4f7e 100644 --- a/script.timers/resources/lib/player/player.py +++ b/script.timers/resources/lib/player/player.py @@ -5,6 +5,7 @@ from resources.lib.player.mediatype import AUDIO, PICTURE, TYPES, VIDEO from resources.lib.player.playerstatus import PlayerStatus from resources.lib.player.playlist import PlayList +from resources.lib.timer.notification import showNotification from resources.lib.timer.timer import Timer from resources.lib.utils import datetime_utils from resources.lib.utils.vfs_utils import (convert_to_playlist, @@ -33,6 +34,8 @@ def __init__(self) -> None: self._resume_status: 'dict[PlayerStatus]' = dict() + self._running_stop_at_end_timer: 'tuple[Timer, bool]' = (None, False) + def playTimer(self, timer: Timer, dtd: datetime_utils.DateTimeDelta) -> None: def _save_resume(_timer: Timer) -> None: @@ -107,6 +110,9 @@ def _get_delay_for_seektime(_timer: Timer, _dtd: datetime_utils.DateTimeDelta) - repeat=player_utils.REPEAT_ALL if timer.repeat else player_utils.REPEAT_OFF, shuffled=timer.shuffle) + if timer.is_stop_at_end_timer(): + self._running_stop_at_end_timer = (timer, False) + def _playAV(self, playlist: PlayList, startpos=0, seektime=None, repeat=player_utils.REPEAT_OFF, shuffled=False, speed=1.0) -> None: self._playlist = playlist @@ -163,7 +169,11 @@ def onPlayBackStopped(self) -> None: self._skip_next_stop_event_until_started = False else: + _rst = self._running_stop_at_end_timer self._reset() + if _rst[0] and not _rst[1]: + self._running_stop_at_end_timer = (_rst[0], True) + showNotification(_rst[0], msg_id=32289) def onPlayBackEnded(self) -> None: @@ -174,6 +184,9 @@ def onPlayBackEnded(self) -> None: elif AUDIO in self._resume_status: self._resumeFormer(type=AUDIO, keep=True) + else: + self._reset() + def onPlayBackError(self) -> None: self._reset() @@ -195,7 +208,7 @@ def resumeFormerOrStop(self, timer: Timer) -> None: if not timer.is_resuming_timer() or not self._resumeFormer(type=timer.media_type, keep=False): if timer.media_type == PICTURE: self.stopPlayer(PICTURE) - else: + elif timer != self._running_stop_at_end_timer[0] or not self._running_stop_at_end_timer[1]: self.stop() self._reset(type=timer.media_type) @@ -286,7 +299,7 @@ def _seekTimeInPlaylist() -> None: _totalTime = self.getTotalTime() self._playlist_timeline.append(_totalTime) - if self._playlist and self._playlist.getposition() < self._playlist.size() - 1: + if self._playlist.getposition() < self._playlist.size() - 1: self._seektime -= _totalTime self._skip_next_stop_event_until_started = True self.playnext() @@ -322,10 +335,10 @@ def _seekTimeInPlaylist() -> None: tries += 1 _totalTime = self.getTotalTime() - if tries == self._MAX_TRIES or _totalTime < 1: + if tries == self._MAX_TRIES or _totalTime < 10: self._resetSeek() - elif self._seektime >= _totalTime: + elif self._playlist.size() and self._seektime >= _totalTime: _seekTimeInPlaylist() else: @@ -355,6 +368,7 @@ def _reset(self, type=None) -> None: self.setRepeat(player_utils.REPEAT_OFF) self.setShuffled(False) + self._running_stop_at_end_timer = (None, False) def getVolume(self) -> int: @@ -389,9 +403,11 @@ def _getSlideshowStaytime(self) -> int: return player_utils.get_slideshow_staytime() def __str__(self) -> str: - return "Player[_seek_delayed_timer=%s, _default_volume=%i, _recent_volume=%i, _paused=%s, _seektime=%f, _resume_status=[%s]]" % (self._seek_delayed_timer, - self._default_volume or -1, - self._recent_volume or -1, - self._paused, - self._seektime or 0, - ", ".join(["%s=%s" % (k, self._resume_status[k]) for k in self._resume_status])) + return "Player[_seek_delayed_timer=%s, _default_volume=%i, _recent_volume=%i, _paused=%s, _seektime=%f, _running_stop_at_end_timer=%s, _resume_status=[%s]]" % (self._seek_delayed_timer, + self._default_volume or -1, + self._recent_volume or -1, + self._paused, + self._seektime or 0, + str( + self._running_stop_at_end_timer), + ", ".join(["%s=%s" % (k, self._resume_status[k]) for k in self._resume_status])) diff --git a/script.timers/resources/lib/timer/notification.py b/script.timers/resources/lib/timer/notification.py new file mode 100644 index 000000000..2bcdc69bb --- /dev/null +++ b/script.timers/resources/lib/timer/notification.py @@ -0,0 +1,13 @@ +import xbmcaddon +import xbmcgui +from resources.lib.timer.timer import Timer +from resources.lib.utils.vfs_utils import get_asset_path + + +def showNotification(timer: Timer, msg_id: int, icon="icon_timers.png") -> None: + + if timer.notify: + addon = xbmcaddon.Addon() + icon_path = get_asset_path(icon) + xbmcgui.Dialog().notification( + timer.label, addon.getLocalizedString(msg_id), icon_path) diff --git a/script.timers/resources/lib/timer/scheduleraction.py b/script.timers/resources/lib/timer/scheduleraction.py index a6e8e21db..a9b7ef616 100644 --- a/script.timers/resources/lib/timer/scheduleraction.py +++ b/script.timers/resources/lib/timer/scheduleraction.py @@ -7,11 +7,11 @@ from resources.lib.player.player import Player from resources.lib.player.player_utils import (get_types_replaced_by_type, run_addon) +from resources.lib.timer.notification import showNotification from resources.lib.timer.storage import Storage -from resources.lib.timer.timer import (END_TYPE_NO, FADE_IN_FROM_MIN, - FADE_OUT_FROM_CURRENT, STATE_ENDING, - STATE_RUNNING, STATE_STARTING, - STATE_WAITING, +from resources.lib.timer.timer import (FADE_IN_FROM_MIN, FADE_OUT_FROM_CURRENT, + STATE_ENDING, STATE_RUNNING, + STATE_STARTING, STATE_WAITING, SYSTEM_ACTION_CEC_STANDBY, SYSTEM_ACTION_HIBERNATE, SYSTEM_ACTION_POWEROFF, @@ -20,7 +20,6 @@ SYSTEM_ACTION_STANDBY, TIMER_WEEKLY, Timer) from resources.lib.utils.datetime_utils import DateTimeDelta, abs_time_diff -from resources.lib.utils.vfs_utils import get_asset_path class SchedulerAction: @@ -289,34 +288,34 @@ def perform(self, now: DateTimeDelta) -> None: def _performPlayerAction(_now: DateTimeDelta) -> None: if self.timerToPlayAV: - _showNotification(self.timerToPlayAV, msg_id=32280) + showNotification(self.timerToPlayAV, msg_id=32280) self._player.playTimer(self.timerToPlayAV, _now) elif self.timerToStopAV: - _showNotification(self.timerToStopAV, msg_id=32281) + showNotification(self.timerToStopAV, msg_id=32281) self._player.resumeFormerOrStop(self.timerToStopAV) elif self.timerToPauseAV and not self._player.isPaused(): - _showNotification(self.timerToPauseAV, msg_id=32282) + showNotification(self.timerToPauseAV, msg_id=32282) self._player.pause() elif self.timerToUnpauseAV and self._player.isPaused(): - _showNotification(self.timerToUnpauseAV, msg_id=32283) + showNotification(self.timerToUnpauseAV, msg_id=32283) self._player.pause() elif self.fader: - _showNotification(self.fader, msg_id=32284) + showNotification(self.fader, msg_id=32284) for type in set(self._forceResumeResetTypes): self._player.resetResumeStatus(type) if not self.timerToPlayAV or self.timerToPlayAV.media_type != VIDEO: if self.timerToPlaySlideshow: - _showNotification(self.timerToPlaySlideshow, msg_id=32286) + showNotification(self.timerToPlaySlideshow, msg_id=32286) self._player.playTimer(self.timerToPlaySlideshow, _now) elif self.timerToStopSlideshow: - _showNotification(self.timerToStopSlideshow, msg_id=32287) + showNotification(self.timerToStopSlideshow, msg_id=32287) self._player.resumeFormerOrStop(self.timerToStopSlideshow) def _setVolume(dtd: DateTimeDelta) -> None: @@ -334,14 +333,6 @@ def _setVolume(dtd: DateTimeDelta) -> None: self._player.setVolume( max(ending_faders, key=lambda t: t.return_vol).return_vol) - def _showNotification(timer: Timer, msg_id: int, icon="icon_timers.png") -> None: - - if timer.notify: - addon = xbmcaddon.Addon() - icon_path = get_asset_path(icon) - xbmcgui.Dialog().notification( - timer.label, addon.getLocalizedString(msg_id), icon_path) - def _consumeSingleRunTimers() -> None: def _reset(timers: 'list[Timer]') -> None: @@ -363,7 +354,7 @@ def _reset(timers: 'list[Timer]') -> None: def _runScripts() -> None: for timer in self.timersToRunScript: - _showNotification(timer, msg_id=32288) + showNotification(timer, msg_id=32288) run_addon(timer.path) def _performSystemAction() -> None: @@ -372,27 +363,27 @@ def _performSystemAction() -> None: pass elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_SHUTDOWN_KODI: - _showNotification(self.timerWithSystemAction, msg_id=32082) + showNotification(self.timerWithSystemAction, msg_id=32082) xbmc.shutdown() elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_QUIT_KODI: - _showNotification(self.timerWithSystemAction, msg_id=32083) + showNotification(self.timerWithSystemAction, msg_id=32083) xbmc.executebuiltin("Quit()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_STANDBY: - _showNotification(self.timerWithSystemAction, msg_id=32084) + showNotification(self.timerWithSystemAction, msg_id=32084) xbmc.executebuiltin("Suspend()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_HIBERNATE: - _showNotification(self.timerWithSystemAction, msg_id=32085) + showNotification(self.timerWithSystemAction, msg_id=32085) xbmc.executebuiltin("Hibernate()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_POWEROFF: - _showNotification(self.timerWithSystemAction, msg_id=32086) + showNotification(self.timerWithSystemAction, msg_id=32086) xbmc.executebuiltin("Powerdown()") elif self.timerWithSystemAction.system_action == SYSTEM_ACTION_CEC_STANDBY: - _showNotification(self.timerWithSystemAction, msg_id=32093) + showNotification(self.timerWithSystemAction, msg_id=32093) xbmc.executebuiltin("CECStandby()") def _adjustState() -> None: From 91249f6b29138daef0e810ba52edef19c4dcee43 Mon Sep 17 00:00:00 2001 From: snapcase Date: Sun, 9 Jul 2023 03:02:50 -0400 Subject: [PATCH 056/145] [script.service.hue] 1.4.17 (#2479) --- script.service.hue/addon.xml | 11 ++++++-- .../resource.language.zh_cn/strings.po | 4 +-- script.service.hue/resources/lib/ambigroup.py | 28 ++++++++++--------- .../resources/lib/hueconnection.py | 2 ++ script.service.hue/resources/lib/kodiutils.py | 2 +- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/script.service.hue/addon.xml b/script.service.hue/addon.xml index 3a20be1de..a6fd9d165 100644 --- a/script.service.hue/addon.xml +++ b/script.service.hue/addon.xml @@ -1,4 +1,4 @@ - + @@ -21,7 +21,14 @@ https://github.com/zim514/script.service.hue https://forum.kodi.tv/showthread.php?tid=344886 - v1.4.15 + v1.4.17 +- Fix ambilight crash on sunset / activation when no video is playing +- Ignore Bridge throttle errors during discovery + +v1.4.16 +- Translations updates from Weblate + +v1.4.15 - Fix 'disable during daylight' option - Localisation updates from Weblate - Improved connection error handling diff --git a/script.service.hue/resources/language/resource.language.zh_cn/strings.po b/script.service.hue/resources/language/resource.language.zh_cn/strings.po index fcc0983d0..101641aa2 100644 --- a/script.service.hue/resources/language/resource.language.zh_cn/strings.po +++ b/script.service.hue/resources/language/resource.language.zh_cn/strings.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-03-25 05:16+0000\n" +"PO-Revision-Date: 2023-05-09 06:24+0000\n" "Last-Translator: taxigps \n" "Language-Team: Chinese (China) \n" "Language: zh_cn\n" @@ -66,7 +66,7 @@ msgstr "桥接器" msgctxt "#30501" msgid "Discover Hue Bridge / Enter IP" -msgstr "Discover Hue Bridge / Enter IP" +msgstr "发现 Hue 桥接器 / 输入 IP" msgctxt "#30502" msgid "Bridge IP" diff --git a/script.service.hue/resources/lib/ambigroup.py b/script.service.hue/resources/lib/ambigroup.py index 670e9b631..a38c4f859 100644 --- a/script.service.hue/resources/lib/ambigroup.py +++ b/script.service.hue/resources/lib/ambigroup.py @@ -83,23 +83,25 @@ def _force_on(ambi_lights, bridge, saved_light_states): def onAVStarted(self): xbmc.log(f"Ambilight AV Started. Group enabled: {self.enabled} , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}, self.playbackType(): {self.playback_type()}") # xbmc.log(f"Ambilight Settings: Interval: {self.update_interval}, transitionTime: {self.transition_time}") - self.state = STATE_PLAYING - if self.enabled: - # save light state - self.saved_light_states = self._get_light_states(self.ambi_lights, self.bridge) - self.video_info_tag = self.getVideoInfoTag() - if self.isPlayingVideo(): - if self.enabled and self.check_active_time() and self.check_video_activation(self.video_info_tag): + if self.isPlayingVideo(): + self.state = STATE_PLAYING + if self.enabled: + # save light state + self.saved_light_states = self._get_light_states(self.ambi_lights, self.bridge) + + self.video_info_tag = self.getVideoInfoTag() + if self.isPlayingVideo(): + if self.enabled and self.check_active_time() and self.check_video_activation(self.video_info_tag): - if self.disable_labs: - self._stop_effects() + if self.disable_labs: + self._stop_effects() - if self.force_on: - self._force_on(self.ambi_lights, self.bridge, self.saved_light_states) + if self.force_on: + self._force_on(self.ambi_lights, self.bridge, self.saved_light_states) - ambi_loop_thread = Thread(target=self._ambi_loop, name="_ambi_loop", daemon=True) - ambi_loop_thread.start() + ambi_loop_thread = Thread(target=self._ambi_loop, name="_ambi_loop", daemon=True) + ambi_loop_thread.start() def onPlayBackStopped(self): # always stop ambilight even if group is disabled or it'll run forever diff --git a/script.service.hue/resources/lib/hueconnection.py b/script.service.hue/resources/lib/hueconnection.py index a1e671408..61f99af1a 100644 --- a/script.service.hue/resources/lib/hueconnection.py +++ b/script.service.hue/resources/lib/hueconnection.py @@ -193,6 +193,8 @@ def _discover_nupnp(self): req = "" try: req = requests.get('https://discovery.meethue.com/') + if req.status_code == 429: + return None result = req.json() except requests.exceptions.RequestException as error: xbmc.log(f"[script.service.hue] Nupnp failed: {error}") diff --git a/script.service.hue/resources/lib/kodiutils.py b/script.service.hue/resources/lib/kodiutils.py index c1cd08b65..d571e6fac 100644 --- a/script.service.hue/resources/lib/kodiutils.py +++ b/script.service.hue/resources/lib/kodiutils.py @@ -67,7 +67,7 @@ def cache_get(key: str): return None -def cache_set(key, data): +def cache_set(key: str, data): data_str = json.dumps(data) # xbmc.log(f"[script.service.hue] Cache Set: {key}, {data_str} - {data_type}") cache_window.setProperty(f"{ADDONID}.{key}]", data_str) From edc4da2105c0a91234315abea1f7f2cdabe9c88d Mon Sep 17 00:00:00 2001 From: fischerRo <48080326+fischerRo@users.noreply.github.com> Date: Fri, 14 Jul 2023 00:03:04 +0200 Subject: [PATCH 057/145] [script.module.libard] v6.0.2 (#2482) --- script.module.libard/addon.xml | 2 +- script.module.libard/lib/libardnewjsonparser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script.module.libard/addon.xml b/script.module.libard/addon.xml index d02e9e985..98c678c3e 100644 --- a/script.module.libard/addon.xml +++ b/script.module.libard/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/script.module.libard/lib/libardnewjsonparser.py b/script.module.libard/lib/libardnewjsonparser.py index eba62cbec..30c49a413 100644 --- a/script.module.libard/lib/libardnewjsonparser.py +++ b/script.module.libard/lib/libardnewjsonparser.py @@ -144,7 +144,7 @@ def _grabTeaser(self,teaser,client=False): d['metadata']['art']['thumb'] = teaser['images']['aspect16x9']['src'].format(width='512') if 'aspect3x4' in teaser['images']: d['metadata']['art']['poster'] = teaser['images']['aspect3x4']['src'].format(width='512') - if 'show' in teaser and 'images' in teaser['show'] and '16x9' in teaser['show']['images']: + if 'show' in teaser and teaser['show'] and 'images' in teaser['show'] and teaser['show']['images'] and '16x9' in teaser['show']['images']: d['metadata']['art']['fanart'] = teaser['show']['images']['16x9']['src'].format(width='512') if client: d['params']['client'] = client From 1e6abbea67ed4d255e831ba2d9e60aef0cb51ee7 Mon Sep 17 00:00:00 2001 From: William Forde Date: Fri, 14 Jul 2023 11:02:46 +0100 Subject: [PATCH 058/145] [script.module.codequick] 1.0.3+matrix.1 (#2484) --- script.module.codequick/addon.xml | 2 +- script.module.codequick/lib/urlquick.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/script.module.codequick/addon.xml b/script.module.codequick/addon.xml index a4aca2778..5355f41df 100644 --- a/script.module.codequick/addon.xml +++ b/script.module.codequick/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/script.module.codequick/lib/urlquick.py b/script.module.codequick/lib/urlquick.py index f10f20d68..14a749f2b 100644 --- a/script.module.codequick/lib/urlquick.py +++ b/script.module.codequick/lib/urlquick.py @@ -60,7 +60,6 @@ # Third Party from htmlement import HTMLement from requests.structures import CaseInsensitiveDict -from requests.adapters import HTTPResponse from requests import adapters from requests import * import requests From 41f8f49423a8b963c4291a70b0b3a8d70ea28f12 Mon Sep 17 00:00:00 2001 From: L2501 Date: Fri, 14 Jul 2023 17:04:21 +0000 Subject: [PATCH 059/145] [script.module.iso8601] 2.0.0 --- .../{LICENSE => LICENSE.txt} | 2 +- script.module.iso8601/README.rst | 190 ------------------ script.module.iso8601/addon.xml | 14 +- script.module.iso8601/icon.png | Bin 51403 -> 0 bytes script.module.iso8601/lib/iso8601/__init__.py | 4 +- script.module.iso8601/lib/iso8601/iso8601.py | 178 ++++++---------- script.module.iso8601/resources/icon.png | Bin 0 -> 7237 bytes 7 files changed, 73 insertions(+), 315 deletions(-) rename script.module.iso8601/{LICENSE => LICENSE.txt} (96%) delete mode 100644 script.module.iso8601/README.rst delete mode 100644 script.module.iso8601/icon.png create mode 100644 script.module.iso8601/resources/icon.png diff --git a/script.module.iso8601/LICENSE b/script.module.iso8601/LICENSE.txt similarity index 96% rename from script.module.iso8601/LICENSE rename to script.module.iso8601/LICENSE.txt index 4eb54eaff..1137166fa 100644 --- a/script.module.iso8601/LICENSE +++ b/script.module.iso8601/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2007 - 2015 Michael Twomey +Copyright (c) 2007 - 2022 Michael Twomey Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/script.module.iso8601/README.rst b/script.module.iso8601/README.rst deleted file mode 100644 index a9f1761e0..000000000 --- a/script.module.iso8601/README.rst +++ /dev/null @@ -1,190 +0,0 @@ -Simple module to parse ISO 8601 dates - -This module parses the most common forms of ISO 8601 date strings (e.g. -2007-01-14T20:34:22+00:00) into datetime objects. - ->>> import iso8601 ->>> iso8601.parse_date("2007-01-25T12:00:00Z") -datetime.datetime(2007, 1, 25, 12, 0, tzinfo=) ->>> - -See the LICENSE file for the license this package is released under. - -If you want more full featured parsing look at: - -- http://labix.org/python-dateutil - python-dateutil - -Parsed Formats -============== - -You can parse full date + times, or just the date. In both cases a datetime instance is returned but with missing times defaulting to 0, and missing days / months defaulting to 1. - -Dates ------ - -- YYYY-MM-DD -- YYYYMMDD -- YYYY-MM (defaults to 1 for the day) -- YYYY (defaults to 1 for month and day) - -Times ------ - -- hh:mm:ss.nn -- hhmmss.nn -- hh:mm (defaults to 0 for seconds) -- hhmm (defaults to 0 for seconds) -- hh (defaults to 0 for minutes and seconds) - -Time Zones ----------- - -- Nothing, will use the default timezone given (which in turn defaults to UTC). -- Z (UTC) -- +/-hh:mm -- +/-hhmm -- +/-hh - -Where it Differs From ISO 8601 -============================== - -Known differences from the ISO 8601 spec: - -- You can use a " " (space) instead of T for separating date from time. -- Days and months without a leading 0 (2 vs 02) will be parsed. -- If time zone information is omitted the default time zone given is used (which in turn defaults to UTC). Use a default of None to yield naive datetime instances. - -Homepage -======== - -- Documentation: http://pyiso8601.readthedocs.org/ -- Source: https://bitbucket.org/micktwomey/pyiso8601/ - -This was originally hosted at https://code.google.com/p/pyiso8601/ - -References -========== - -- http://en.wikipedia.org/wiki/ISO_8601 - -- http://www.cl.cam.ac.uk/~mgk25/iso-time.html - simple overview - -- http://hydracen.com/dx/iso8601.htm - more detailed enumeration of valid formats. - -Testing -======= - -1. pip install -r dev-requirements.txt -2. tox - -Note that you need all the pythons installed to perform a tox run (see below). Homebrew helps a lot on the mac, however you wind up having to add cellars to your PATH or symlinking the pythonX.Y executables. - -Alternatively, to test only with your current python: - -1. pip install -r dev-requirements.txt -2. py.test --verbose iso8601 - -Supported Python Versions -========================= - -Tested against: - -- Python 2.6 -- Python 2.7 -- Python 3.2 -- Python 3.3 -- Python 3.4 -- Python 3.5 -- Python 3.6 -- PyPy -- PyPy 3 - -Python 3.0 and 3.1 are untested but should work (tests didn't run under them when last tried). - -Jython is untested but should work (tests failed to run). - -Python 2.5 is not supported (too old for the tests for the most part). It could work with some small changes but I'm not supporting it. - -Changes -======= - -0.1.12 ------- - -* Fix class reference for iso8601.Utc in module docstring (thanks to felixschwarz in https://bitbucket.org/micktwomey/pyiso8601/pull-requests/7/fix-class-reference-for-iso8601utc-in/diff) - -0.1.11 ------- - -* Remove logging (thanks to Quentin Pradet in https://bitbucket.org/micktwomey/pyiso8601/pull-requests/6/remove-debug-logging/diff) -* Add support for , as separator for fractional part (thanks to ecksun in https://bitbucket.org/micktwomey/pyiso8601/pull-requests/5/add-support-for-as-separator-for/diff) -* Add Python 3.4 and 3.5 to tox test config. -* Add PyPy 3 to tox test config. -* Link to documentation at http://pyiso8601.readthedocs.org/ - - -0.1.10 ------- - -* Fixes https://bitbucket.org/micktwomey/pyiso8601/issue/14/regression-yyyy-mm-no-longer-parses (thanks to Kevin Gill for reporting) -* Adds YYYY as a valid date (uses 1 for both month and day) -* Woo, semantic versioning, .10 at last. - -0.1.9 ------ - -* Lots of fixes tightening up parsing from jdanjou. In particular more invalid cases are treated as errors. Also includes fixes for tests (which is how these invalid cases got in in the first place). -* Release addresses https://bitbucket.org/micktwomey/pyiso8601/issue/13/new-release-based-on-critical-bug-fix - -0.1.8 ------ - -* Remove +/- chars from README.rst and ensure tox tests run using LC_ALL=C. The setup.py egg_info command was failing in python 3.* on some setups (basically any where the system encoding wasn't UTF-8). (https://bitbucket.org/micktwomey/pyiso8601/issue/10/setuppy-broken-for-python-33) (thanks to klmitch) - -0.1.7 ------ - -* Fix parsing of microseconds (https://bitbucket.org/micktwomey/pyiso8601/issue/9/regression-parsing-microseconds) (Thanks to dims and bnemec) - -0.1.6 ------ - -* Correct negative timezone offsets (https://bitbucket.org/micktwomey/pyiso8601/issue/8/015-parses-negative-timezones-incorrectly) (thanks to Jonathan Lange) - -0.1.5 ------ - -* Wow, it's alive! First update since 2007 -* Moved over to https://bitbucket.org/micktwomey/pyiso8601 -* Add support for python 3. https://code.google.com/p/pyiso8601/issues/detail?id=23 (thanks to zefciu) -* Switched to py.test and tox for testing -* Make seconds optional in date format ("1997-07-16T19:20+01:00" now valid). https://bitbucket.org/micktwomey/pyiso8601/pull-request/1/make-the-inclusion-of-seconds-optional-in/diff (thanks to Chris Down) -* Correctly raise ParseError for more invalid inputs (https://bitbucket.org/micktwomey/pyiso8601/issue/1/raise-parseerror-for-invalid-input) (thanks to manish.tomar) -* Support more variations of ISO 8601 dates, times and time zone specs. -* Fix microsecond rounding issues (https://bitbucket.org/micktwomey/pyiso8601/issue/2/roundoff-issues-when-parsing-decimal) (thanks to nielsenb@jetfuse.net) -* Fix pickling and deepcopy of returned datetime objects (https://bitbucket.org/micktwomey/pyiso8601/issue/3/dates-returned-by-parse_date-do-not) (thanks to fogathmann and john@openlearning.com) -* Fix timezone offsets without a separator (https://bitbucket.org/micktwomey/pyiso8601/issue/4/support-offsets-without-a-separator) (thanks to joe.walton.gglcd) -* "Z" produces default timezone if one is specified (https://bitbucket.org/micktwomey/pyiso8601/issue/5/z-produces-default-timezone-if-one-is) (thanks to vfaronov). This one may cause problems if you've been relying on default_timezone to use that timezone instead of UTC. Strictly speaking that was wrong but this is potentially backwards incompatible. -* Handle compact date format (https://bitbucket.org/micktwomey/pyiso8601/issue/6/handle-compact-date-format) (thanks to rvandolson@esri.com) - -0.1.4 ------ - -* The default_timezone argument wasn't being passed through correctly, UTC was being used in every case. Fixes issue 10. - -0.1.3 ------ - -* Fixed the microsecond handling, the generated microsecond values were way too small. Fixes issue 9. - -0.1.2 ------ - -* Adding ParseError to __all__ in iso8601 module, allows people to import it. Addresses issue 7. -* Be a little more flexible when dealing with dates without leading zeroes. This violates the spec a little, but handles more dates as seen in the field. Addresses issue 6. -* Allow date/time separators other than T. - -0.1.1 ------ - -* When parsing dates without a timezone the specified default is used. If no default is specified then UTC is used. Addresses issue 4. diff --git a/script.module.iso8601/addon.xml b/script.module.iso8601/addon.xml index af2880820..7ece45558 100644 --- a/script.module.iso8601/addon.xml +++ b/script.module.iso8601/addon.xml @@ -1,20 +1,18 @@ - + Simple module to parse ISO 8601 dates - This module parses the most common forms of ISO 8601 date strings (e.g. 2007-01-14T20:34:22+00:00) into datetime objects. + Simple module to parse ISO 8601 dates MIT - https://pypi.org/project/iso8601/ - https://bitbucket.org/micktwomey/pyiso8601 + all + https://pyiso8601.readthedocs.io/en/latest/ + https://github.com/micktwomey/pyiso8601 - icon.png + resources/icon.png diff --git a/script.module.iso8601/icon.png b/script.module.iso8601/icon.png deleted file mode 100644 index 404a44fb756540d6a3028e177101572626b14490..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51403 zcmV)3K+C_0P)=<#Qbzy)AOJ~3 zK~#9!%)MF9rQ2~H_SE|J*K?nlJm-)UC6TgZNz@S7ilV@F>=?<7fgp*IyW9jYl0T3O z|F0-Of?VV(iI4zRBwL0oYv3SK63N3e^y#^GRW9CDRZrDgyZb1VNRpzu`}_91-?diN zQ_mpZ|NaLi0}%i35C{PHpCT9#Km-tA$nkf9Ktv$NjUe;qW8Oy~fIqGX0D~!DFqj(R zziNO1289`5X7hglOktQm^V@=M1LV)3fF3`C0aosN{CPaV@ft9nW8Nd4BW}aL)A-x* zIPm-8xM4g#=yvmkfS$+1UtIpxe{KedKNjfE`H%U7_?JIi{3HGbnXgA6Fus4>z;ES0 zvg1CO-?=|Zz1i^}@gL3C>^Bg)!Ep)XKkaxWeq9&<@z)@TXFcvG<Ti*mw7JAtvKKzy41TK!4q>y157Rnoe$CaH{nCdC&M=p0K|7)at_5Jg)0T;urkfl#Hta zdJMDU%i=}tyD*>jxslNG$NjC|7Wsu)S%Q3``(~lJJpH1#tOA581Dn-__;U%4=Qk_W zf)@h5u#Fa9-6Z&K{;#~)j|+nYt$(??a^gJbpIc&vB_4&a-Y;ap#A2b- zGRH8?1wKD3444VVn77iSVz9YUm?>n8atMgb_hJ%Nh)C~e$+{rTBkHgEF{!2c^K zC;IFK>Vo%@tNeQwVN^1i)rGPA&sU0REZBK~A1Afd)BU))mIWIB=2N&WaL|cf+KSET z53@Kml}dV>8xE+Ykg{pz>1kF^>ar2cwZmn3-rQnA&U%i|aa!bDb$~XqJVC8&2-K#~ z#vmfOQO?uU1d!QM`7vq`+7zsH6E^QR7ozfW%u~uwOyr-CWAi-Ly2QiVJc&h&{(fv; zl2`EYdc~p|0G)CYXZOf;?K_9c{5I$HZaSZL%=^y=I~y=Yd~PD+*n`F2mqt~BF=7D@ zKaDZJzrml`QH7`ss*-?V3dq3RPvZ0*N0D+ok1A}o0S3dE)q+-6 zimFy@!SArU&+&Mg3w18cI9+3rgSVo1i4w1`Rssc=4GqB^yd=WPiHLmFBm`vI{1{2lQJJmj6f8VR&iLq_6?qZR(AJ) z`>9X>NYu(`0s5@>;tVXJU=RfaG_T6D*Yne^EHl5(_!^7~AQx!%iBzj-z4m?adnwE% zxN*_IEr;YHQ*-cawk+l?MV7X?u^kJ`#$4=yKS;qJCEr4Tj#-J!1s6EU8Niqy$=qNZ zPoT%7{b82f8XI6%%--fqurI2j*(%MA>G-G&hB2!Jfhx5_!(e*6j;ILc)i7qmqY4bM zzyuIyFKq-zDVGI+f5-l=9M4e0$A_7rGKE@1-}k z6#|{w4M^<3U_C`OPV>YbXri!G0ai~@Mo+H-oZS z(3)a^vQ`D$>sub=4y0L|G!*dBmMY*lb?5o4^L(Ctx=HquS>E&On;S}C3ItGjIZcxZ zFZ+*+RWWSD^BoJ(0Y9m2ip=*F$L-v0xNIL2n6sll_uifRc(haA=3)|=pyT;CUF-Yt z&Gx{*%qEC8KOY$a@y%s!ZbNjo0>^baFk;O*o?tdN900@SsXsSuowvygX&jS=L~4(A zgFm~5xA^CL66)Q3q!Hyk_xM7)9)W*eg4jIakFj3c2x9SSBIp}zzyUm?UcO@qxG){C zr93C3+v>@yrn79-`IthJfi^kVfQC{g5j1M#{#>K5uNz?5Q0nPk0K-z+QybehgxW^r zHc`ip)Mn6$ApX83OKzJdrIeFg3wRWulj8>p2EdYaMj%(1hp2bt0$e@lv%@T_^o^~9Y zmS}7wCfq9chNo0%&)>_jS-~te3-$M^`EeKoBdWHn1`Km(VReLC+Aom<1k5sm%Bpg@ zXHUR$fA6Ohe7ad|2tM22Z3wvmBsPFDdZYW6-kneO3oS#86)h(XsHZ>doF}X)%~UP; z1hx9eQ&$4&K{<=*fJFO|SK3j1`2CLFLqrN_DxgsW^B7RT`KUOA+YRdSZLY52 z6#@Ou@dz38TCVOGk-MAea1NVF2O>K!@zJ3u%a^YMK2cT5fjHyFMVip*9!l?88 z3G!(nB^(P_m($z|QD<8XFyL2CZ*3JtJE>`8*vtJ&f_h&+UEadacQ;#b8$hkcQ>O6hgjS$N{5&f_#!%9^YK(kzOgy^lW0LkK8)tc z?W0wONdPq#dY1LklM^l=4DLw`b1QLcu069h?HI?X z&!kOXC&GVV3dd;B@Um%v)Uv*kIt%r7Oqm5rj3fpT__1@T}14El@_ zTZ?bgstBQxA~OPG2xqwp>UL2VO)V?xL@=3TwoD2o9)iYBOh%GUDbCe2AiN@TdJybC zz+~ijkJ|tsQF=+RZp7nRke)<{rYyASp(RLf- z03YjI;VAtVQ=n z?;U+GozfdRo`BjIpBzN{LgX<&S$S5;tHajOp30(NAX?*~O=!T>qDU_@ciLpE4AhK( z%q-;*^j`}O4ecxQyBf!HsnKUXh;^HL#R1s)PE*IX@iK?a4j)IGGe2_?;ui2OVdBGq zZ1K4!oNx3r1hl|Os89qx61$x$o$g)SQ^s~xsGysY-pmTn*8w>$xt(ZJMuDxwU&Rh6 zOvBpSPZ}|79Vsp+JZ}n`V?tR^cqx7Q_qb^=wC`r#2Z3UIs*VVy%R9NY)PM84H!9vJRD5fpvCo zQpW>~2h_TLju7XmWu0$NQvx#<@J#$pXbbT76(c(dT)>!GZ#)|0*}8?AE@cu#Ua=ex zwhkpXq!BO%wF!Q@9h=Y@i4g`Sc5Z||;p5*a)3Yj8ugkOdF^m`$mSdk*Ug!ff-++US z)=5S|h&sx8oxmPu>u`{tyvmqcy|R|5Zy4*}1i;Wkz{D+KY5_K?KJI}m=&|!OGmFzx zHAi!o7JpsDOxUrYq;`6R)(NZ+ap+J{AR39%#{+8aGT>U;x9BMaRnJkj3lJJ6l)7ch!>zJ zeZ6!{Ap4R0ZXIXxNmc;O>~BIi1YD*@KU)UDm3?3v|u-yqRKndo}dHIv_daX$w8txPbtv#~4*-p*A^w z`PrOUlg-p#|Mr#zs8hfbI{8}0$EmJ+Tp+6eW~jD_0<4YOIt9xMsLeVgm@Ai|?4* zA7!?e<02ZA<)rf>2uFG9`eoZWPoi5P?VSg3iBzjCEv)q7&%EBXolh-pouZ1*e0CV9a4x^6#j)-IJho z{jQ^T+@z0-x_)nI6SYFw?S{fFjE|BGBoH%_5FZz*5xQ@om6swyHIpJzi+w;X4zrxy z&&BNDy|CiGivEMt#O;c=p_4?GWzagetT<=64rNOC+5`65nIi}Zx5=lSOGX$ETN;{+p=0b2CXBBi*w3Q26>?1hf))G#<0||JnpZ zzKAR5pl=ctAS{SKZ)n}+r!xvS3Pd!}u%P!1v*6L3H6Fjs9-b}50&H+if7@ITynhs{ z7%O^$tY1p?U{)--a)XdE$v_Zv=tP$sHyJJZ9L>?iZ+^<9mjnb;RmWS_ag?egiYMH~ zki$ui1c`9tBpwplNcAr%6BL6JgHqyqJU_u8a%lR`G%!rvKURW8I+6s+k9lIJLsB2> zIVLbBgV1S3V_tiM_IRB@<*ZQjFcdio#Y2c>(-}ofaOys9u{hOgZw^{m+BEy&$5+dD zKZTek8$A2c*H;x^McA#L#EocV-uhY99%us#yMl0`5VzOkv{&mh`a%fOwh1)yPG|fr zo`FghTUwZe#n7bT1wvqD%3gWlw++NL!Xe)@)B(2DCom^&wzVr00s|}MN1QiYWxYZB ztrG}zZ$t5gW~-^k{G9#JGRfA!=>G?2fam^_egZDvjoUdjS3v%VnzCv){_xFW~zO+a)`5M&(HQ3!@ysHc;VG}(i5Q;-7# z7+IpwsjIHuGlW8~_U4TOY^&jh(@1&lzK;G@GtiC!)V{rz;FrAue4%Loj@oz%@%Rqv zk&M?LkU0bkn~yESW*>f-%v=EbmVf(F(>QVK>D$_gVzz>c577JQCBG2}M)H~1Fk<4x zb4I?7g68}A723! z!xvCWWi+JoDTrv~h^4R)$NBqY9wLS@MpaD04L)pAlS(+~Xh8ygl3yF-X457KdbZfC} zkwi8Q!A<0Eq|>kLd25(pnpy1KfoR;P*$*6xztV$Pb!e=U7gVnxNhV^5W`Y>R8;;QX z5caa9zCE=F!n64~Lx&yeyy6-{#+ql#4a4cNhaDKr>4(LsKTJYn&rOZ0l5tMr3))O` zyksA9)16PXnd(Ux)yUB44>*0lboTa2{$J*$zCvm2sQw<@>Q3xvJ5*pY4mF_p$=nGy z$|rkLda=>$>jfSFBlgN(f7A*nfr-{lJDMzb3?*9bpIs z&G$v1NCsnZ6b7T?ts;=_=@-W^jXU|uAcBr!>j%JnFXMuNAJ8bviXh0EzShW(Zvw|^ z#4eLivMvD+4d&Eo{T0*mv=b{fd0v_i zAEhZVhiD_y)DuWJ`T7)rD~V~M%e*j}B7_qa6&7`B=`vscc&4yh4)c(MKQlD}nqWq3 zLeeo`&4Hoh1_3dMs+updgW%(T*Mg2K&Gvl}G4ifa&abC(E>_Fd!nO667I@w-_fkZ&ZYEf7yhI(yqeM3BC96cRFLnGDiPKz&b-vUVueqsGF z&~7~LTy4pQ5F^hKz%v<-#3q-gyqRH0hJe@{l?rAyfR1J%#InKTamJ38F?)SiH_G%1 zJ*oq;VMnTU-E@?o*LkpLI35{0Jm}HR*kmpV45x*`7ep6w-zh&&an6?d3oIJ|c<~z+ z4nX$xFLw}TZ~v%PVn5PFD*#kZL7C~ZiqL9bZf#VEmOEfZn)}}O1FMh-WZuA=0XEMO z51>U|XLUXoY`S7O9^TN+w2HySV&G8)BdbRsfpKgt?xQfu0AT-q=MQEWM^biUgK2C( zE?Pv0H!yqqBY0yFS)`rnW`W&OK$UxxYF zs|v;(W1f1Mu6%mAa7TNYjmz5p<$o*bXFDzMlNgovzBdygbYGPgdM;+Y032>vfW@}} zYfI4q!?vktq4PJL z)|`Q-xPhlvxAA1$!LzGdcxE^8eB8uy+{DvyGdbuj7fzOuUqk!Q@;~_$LE{t5-wl0^ zYkP_t`V80l95=^PT)%jXoB9Md@EAArS&Qo;D6%V7i!{j;77fj2k5L)UZ$d z42yfb;x-yBl^k=tZu;ngLKobr(Da z&^ZHaM~)2#VG}Oe#WuQ(1zGA`-G0(^XJ;I$#f%iqiAWm}$BP0r!NYM6k5BjU@ajGu zkGpsxw_$R%Z0bfPnKaR>;h_urzfBj=)rhrPEXh9ewV%fcXPoe4+|B1W(L@ht+<5U6 zx9lPA=>y!=2e@;7Fo7!r2W6m4$B$DL>=7VF6GF)|UQw*XQ-e=rB6JQhNWnZVX9qSxOksB=St{!gXdH;5e*B{x-w}L1j1S73p zp`sXi2#HR*EULr-0vQkGpMJ)&zlwRZRTxoKsJ*0`Agw=*_N;ReW{U#byAuU*$*S(Z zI0<2OIObLWm#D){15j0kt8W1R&R{r;;K6tspIp6;Pfu^)@wi7b_U!j1y*bG=lYq3D z7Gqe$L(r`QnBXJUZTpI7iOc+*yinAK`NV3|Dr>{qsk7^ZWr` zJAZ(yn4=TO2AAZfGorBDPoV+OLLaVkAJvX5VMo#f_>1*8GtUJuq6|;)(9$7zaDJnY z{d6-5HOd{NemvQH>QbWPc20HfS$=5{SdB?(%Z?3mY_wjIaz$rS#`M7~+?!wmdGzR! zEn_S%CqyA{7Xb$Ooniq7 zu{r$UIYOx1icB+#qbw?y=MsmYC;+Dq{OjlMl;qdAM>#~XTW&|BcFFQ^ci5ezl?D>6%KOye)#C2rM}&kMI8j5XaiOv&`J_lznW1KR^2_QMfW;cT{@iv8w%Y*7-Y+2gX(swKJ227$*h&M6|9H#Z z$%gmNAL5HozkxgUkUeO!OXtNK7U4+~E<_-adjE~n6*$?N$S}DXfbua0YG%erG7^R4 z4yiGDLSeg=;8O`Wys6}7uwUemIjR)S@0^>2N!j7hy%9 zZf;kBy#+7WstY;hyxNdCkoKwE!(ZI`S$uMOd-B3LHmn+gcv4NN$l1)34DT&5o-%F} zZ07k4_;r^MlcEW(iM|ad(3KR_6tp1zPp0E`}FD!{Ne34@aFk@_~Mg4#kIW1 zoWXgKtJx&4NF)^51mF^=lM;7kp3pr~UOh~jIbhqe!dBaXNWWG_%*{v1R2Vca-57S5 zRJSG5>L_9?3bG~xNGk9Mzm+WcF|!WMY`f#8W86W49wJ*^h(I8pKKRt!ai_KbUZQI< z>KaY><+y;RX-CToJTw8h38=2LUcIon#73ekVP}_1u#%Ff|1VBNsB&Q7f{eH^A;F}d z+&Ew03g5o@RebNp7wf{NalTLw?(=h4>-pO$&gP=-?_O-b`*F^97pz%=c6oeMgE|^P zr?5pOUuU}-y8~F|_U9%s>^Z*p^w042^S^=z)=o}uq2?C4@VxT?wGd8&g%FiEsk})~ zo~K};2#<221G^Hv(|0*P^LU;p%e{JGT5u`rk2K-_Z$HhCQ$FvLbl{QgjZ=F^Yb^%m z`x{9ao}X(}4o(FQrps=0N1zzW;=j-~L>f>oBp6Qua^A10HEyOIx^V#Bcng+*&b_R7 z$r|X4N31PDzFrg;U<0=(SWo@=Rvup6$DiH(6+DxhC5ulu!>I-n}K)_>zLTdC&=0HUsm#sjeDv}C5&fA=E!Z&aJJU%_WhA%z- z<6|M2qB4C6t{+xV__XdSUR%LX^x1u22BW6+*d!V$xe5oFhXK+-1|Gyh7$lT(_Z=lk z^-^q%>5A+sz4_7x5w*qyHobzesc%rT2=Y-_vp#gP)N~m3RG=~PS9BemoPeV*3HS)` zuY+MPvH#``L(T$y2EBHGp_~DP^djDiIV#M_@c&q}TF;t9S9}_8olX(Z9hBIUnJhLuk~;V>t^7EX0$4r+k;Z z1Elf!(;|z?k~Ul$AnP!S1s^6PR?isEL)uHWRNo;2cBx_r^XEW)`Z=k&)y`w(Vo-q#B#hQ z7r;CL&5XPMe+eCV3Fvob^Iuy*KJMYeTd?gi)(`wN3iS6L!#FZAVY$0nnG8~rTQ@=7Q&Y>nV4cJ$9ryiFgl&kIRf$-M-DaPM8{XX~C&s|7k< zw4UMvbtE5Qe|uMVGFZir=ocQKe@VtKfU`a_}NFlha2|%;0Ra-fRcp(;S?k0 z?#}PGk%k{h0J7=8+vpII9)(gA0TV2iC^dV@a)RoHOhYzem9vjcYe3IAH3E9UFJQ?VScpCsJP8{kFmwq5{Mntag&Cu3 z6@*U9WPIhwP8-T@%;vM&;2Wo0_4MEi6kiZ7u`bwJ6{Nt>Djj&k6RH(uB6$NGVK(u1 zMaYBG!?4m_t%H;EbbKtg@%7ukgs(pMy;;^*LlDfqUZ=LeV>3ADGj}VS5?KMx6VsRg zo1PIwq9LhjG&x3Xv3XOFsDw)LsL;BNXIhF+XCj$=52eK{J~9^44R~bvjQZB-N2Zyn zZ(c^Gr0lVnEvuW84%cKb=sX|yv@8PE)!5T2_+@2;*FeA|z*EUT^8roQq#oGn?^g^( zbx9P?IlV5n;5GSXH56I7{bc98goG+tg4@NAk?&srES_E62{26Q7ne z{!}I_5rz8bucyvzhXKkG-_7yYp3jU_b3CPx6>sQarH5OM(@^VkBr8%Dy+Qb6PM+Z- zc@2Ml`{(dekN+q_I5Jq+((6ar(;pPpK~!I5d$JM1od-2{8f(r68I!!AR!utHn{UkP zcE|=hn1H0rl%QdAVUCfZBVlGH2|UhfLL)uc4NL(Wdej*+_``v~j{ikfWNFDBkqegK z@=+Lw`vFwBY;x*r&#d8M%ktp8)YrNETrr?~0PsYijP`cpzdB7=Xa0MTumXE85gU=r zcVPhHQmbH441D*_mx(X2E3vJNyqtT``}voS`>fJ}S1u4a5;ay~%<$2SgM}*uBLIN# z3pz-%@{k%B+GqVBGE?C>)MR84TgHN=SD$6`N7wJ+-m?$z#`%L1Ru-{dTg&m%N3|4{{~Or_zp z{4x>fkl^k+7vlJ{Cjo}_$E*YnAB1573vhzk6j7WOCmezVy88~tc}?!@S}ONAuH9o; z6&7J52HGVJSB0LHM4)v1?L2->d-FCfOuMtSthXLRPLIKW=Lfgm!wb2-5cJu4c=TDn z;@*?*;QpiU;MUWRF!Tuw1JAGS;Nh*$;gdT*g=eSxba3yDy%zD0T6OwS0v!9sV6{Ss zMH;kuD~Nv=5LuTLFwrUS2R`|wk&d#F;Hn+vq6WTw>*sLy(+_dNx!7+zKqix{!~Xv@ zGw zEg4>tgfvHmdG1-5CGNmNKiw~lFwtef)-wSnH$jqN2m?O8et#*?(a?NrY&wYH=Ccp+ z?uWmJn=c*|l_2blYyAXoJo^N%J@^xRa`&h3{nx$*ldA^&R@SJd^}Sm~6!nWwu*;9iU%V`pj)bQOr@Y*Vowe zd{iiUka~0=)rPRxAX#dyQ)pF)hl8J5gZ6wFf)oSIW_NA6rt`2-2$6?y(HhJO4oue&i=8+E2vY7B=Cs! ziQcq5BhS8_+LWJM$c?zz;gwl`V=GxR_#x8_^^ngAxc%V97x4DuZ{pgXlYhXp^d|12 zP|Qi%10En?R%11s({lrcRB$yU*CY`R9@40MXCpUamF(Y{%p?nTqG5<49!SG%tQq2= zW`_g#plWh*5aP8lKp9BKSZKm7vXfzR42Vl=KE!CP{x0dk#X$#X0iae&aSjN1sSEI{ zB*webyRZX0`>+L=fTYhY2cT92^?et&VHh5r-b`;mL0XNK9?+&H{rKtKr{BZpKm1ok zD^WEC^!n!Jaee*>@BP*9;5+aBL)f_5F7S%#TbbV(R*ye+^!G|`LHw=SQSpM2UEjZK zFtsX37Fs%iL_nwO0Hx&-&;Zde@Pixg;qy4JtDFwH$+m7v$B1>QA4b>a|-=K1?kJMsbz&T$yQgtUTr%mky* z7PJK7U=HeGIcDSu$ei|2?|FZXw)n^`IQ9pk`FdPfYWbC1cQYKsaM@Vov;A*pJW3_I zzs|DAdF;3uM|L1oR}O#!a*t21XFJnp{S17~-wiwCoezI^kr-PKSwUKr`@*|^_95%Xw50P6|9kqcTih=>#&LXJDbKUi>U%~4c>ah5W>Pw5cTwPG+HiN^iv$-6T! z5da@uzmK;ce?7VVW(EGM5})kb4_h=)2pffo$|UAYz-|m8*EEYBBOozS#x)bclq(O# ztF3+Xf{fBL2!elc5PHT)5W4pMqkzG(v2X|<$XV44!!ZSb(fE%!@w&6iuFN>qWcktL zu=46l58li9mn93?U*CYlYSod|$Q7N@CQbafxJbM3>op>KPD0FA>%XFh$8Zj z;e=w6fhN06KoHAmTg5YdX1`K|Yk%Aq>vmDA6_j2#Q-+IiWFQX#p2^$BPjG`lEYafy zS2#Y}XX8$_(W0@|Z~?XE&+mWwtu!%hrldx*v>H23DZS@sxb^5S@%Zi+_ouzBQPsQXS|E+cuc298YzbLWN+6?$wvGura-HMAsROX1 zSwASl%mVhd!NJMdGV0{{=jL|Uj~xo-#G_oebh@nmTmAI5>_5)O1IuVh@;iwg=>pXI z?h6XThT7NQQfmU8-RnwLpiw)rqZ0Ri-^iV~<{0GXaK5@h1{pMK_D@4o*a1;oKmMS8 zhNwP*MFg}Y3m-qf`S`ndc;^enva-zbEJs}&y2A;@FsoVxW+u9)fYn9K1d<^7STALh zLm=!i&>zo8EMy#}T8TyxckTwEbMZYGZ{ltJvzd^amRm<9z|`s#1O>^>=j>4loTGsd zjDuVzf@T*uExbp3*Rb7*-^lrDE(1U|AEN;C9acT;=4bp@(3ssVdaQN5V++H=zA(T) z!NlvP7Jvqi-m0FAkn}a2Q%gKorS;n86h~QX*;DHr-BGcmukaI?CuQ{o&{lcWxxT(E zq;!&)lxO=(9^vX$xT*=WJU-iKVIC>oNzTOa^YP;8@%8Rv!#o+NcnqLfjm_ft`Jf~NnDJxl zW*Ky@-HJQt`P}Dwo8G=^MeAY$MMhcSbxF4>M|TIZ0PG@(h9N?6#-TM7FK6N1Z8)Fb zAUi(;#t-Iw&bY>NyTS=Cj*7*TeUEc5I0$2IMtU^Ilaib|0+jAP=XHxX*pW@`R>A{d zDo)r6Te$i7=RD%JlRj*FC_v%kz5`^?VVN^fh5tzuq82N#C&9su7{&z87(3{kZk(`; zp{o41+hUofJhT9MYH_aUBDrlcVXJiBU48)QaTkg1qW&W*GRpDmo`j22FhG^fOTtBC z5=yTPhO=B%ns3+EQ|bL;+*|}wwqyY`Ekda*j{BUiZ!gaQTN!#g%P#97p>#kCF3tL1 zBJgSB#Wb8~a=kDYEfc{d$Fy6E#SyA=k&VQWp34bW_PhXnW?8-)$70PO4wFGu#-tJt zrI}!^NS)P#2aw2Md*ngd#_0z@lw{Mx$tS2fHZufWYV2pQtlaIxlw{1Y{#;j*3z->M zqIQUb1V>xLY``fmHfwu~dnU|{?Zk3lW7Ik08<`YXEjuVL3BHZi3AXLzO+A5{8FGVI4}1?En+s3i{vkpT57sY&KzWX@n6sd`G$@!6hu zG^QIO5PHeXC-uT73O<3ntcxG3+)8 zZ5{$_jc%iq+kxd1C&Q6+f38P&-p7q+-*0I`yvQ{&`C@YtnzW38C%4~EH6K?VjelQS z6U!dnKRh8Z^BY+wsOR72J)>c_fo1W69g=q)8XunIJoOfXPp zrXMEncLHpqQI#ZU#Iv28-Gok}jfa-#%p)`%;YT=1aqf>bHxL?sTC2#8c0+PvlXfyQ zvJ4m#^$UzxavaDbos&{ejFN0?MbVe@dm{6+FQP13y#&tjMxn*s_fnRi8nNP(Pw-^> zfjk5Q#8gf=dI{^0?Z9-GjJ(=_>2z_e(q2pAswoco1wTD<=}cE} zkT#n0^*ua%>z5X@4zr!`--=(Mg!^~alp5t+xkBe*H0#V@D8em;DTq-mDZa zZmU=b&F#0#hMR`~$o8C1&+f=ub^V4%_r8qr)+f04{eRP*AFT>V?fr|ZoA~(se+0d{ z5oo!g_xZqT2uOZ@%u*!NjP4R!or*39e27_B#(j;#pR;}=Ji%IsY1X)rXa(j2)cieP zlxP1Az3Q4a*T-@kHB#NV5tP1@)4F+IwNL=EiHJ`a#sm=)S)WF+6C4y094H2vhvsc< zj42|@enO{q-!Tcp;R9e2HB2A zTYCGQnW%NuAEE3Zw;i$?+gg)*2#100qZ>w_#)%(^M#j8@9zU*&60y4y?;TQv`tSk>-*6(9 z9f6)ltoSGkJ%QBf5idlm_UD(8ZSw#QIWP!muYjDAk`I?X^+5W6bdNz4p-VLvnUe-( z5sGciJh`pNbRsO;{bE&yJgFB0QdA%ln-n5!orK6Td}Ha=Hv(&Yugu4P{Q6h$j(c1H$VLrt{;CGpX(U|&+opE$8UTE&+dIGXJ*zYq-^!vK)>G4vwhaK=iemwFqpSi zHrNVOKJha?87RkXGmZ!i~9-Q>4Da>M6cS1 zjA^KuF2fcMyI#6$8g+Vd@I>ejHR25K^t2+>Q$4f?^P3s-b(#~2j1_}ZWoV=3Mp*h6 z#;P`sKerN>s#>kYPNr-Vn`L=V#$`pI5`ta(bZb5OY875j)N~uR^cdS~36xDMY6@=| zGsdW}x&hThVIJ)8br^K7muMB zuFtQ3_xN4X|@`+vnlp)RyPSHN8rPT+(M%uaY!3xfsJi-H3)XIsbjJ zqg4X@+9XL&X*7u?9$YRg{xXi47qDL6tza12cJ-zn1DnW+@Mn-vgnXgyCYIqJvAIf0V4H71 zBOqI3Q)iB(K<)Z_k^Bf&W?KIw(g*mmX*M$>6@2wRnaKsmJw zj{uzlTW9We(P&fy;A1ik>{4P7k0~!F8iPbXY+%@pQrT{-#DDkYtlj&`nm(VFp>D)K zY+e~IySx$DhOeKYr+%L^QkA!>JXqalmk@ukLOd*703jcK&`6XPg$IXj$t-Bp;I_Il zx6dzlsv+XK7%{p833f2&?C$Bu0j*8B!QI-z+nH z7+HcPIuCZ(Gp!q%s{%KRTpLBWY#$^6MllmbI1_J`eb(s3mn6ejQ;xbn;F>wmQgXSp zS0lS`7P#2P%+nT2FYdc@{@XT?9v5a^*WVO^7ihj}NoFaw;-tsV34;{%APDOS6D)F~ zO{uT8sBEF{){}RQsK9mH*TI-zTgS7nt@TpRD$=L+y%4-+&20x6e z(CR3B!6$%iyjlq#+On6NzPqH*j^wv{SDt~b9v~|=P?#3E^D}oJ7ECrJ+o-}sL?-$K zeY%8rw5rA$i%sgLCo@Mc3_r9o{erein1j*0FGy5@nooQ0p2_FxJ6K!xnT zV?Jzh^K_Psc{1-~zI7oVRaIvM3V( zc1H2SD>blj2&N;|Ij$73Wv}DFk2r@5;%^n1(4@E?>@^}3>HPi%M{p<0UYlh~a&iu| zT;`@XKFdPC;NT_GU?egH$qiVi_dnBbEoS~x>N__Dnbim^GXdQjVmgq8cY!0z%1qHBBO0%H{;lF&C(lf-j0>tYdhL8r~B%rJhzMk z;961mnRhWF%Uoi03ZNKL_t(f#@!JaHn&o*ForcN@;Qo~ zC$<^u3d}7*W|cD19zD=~5+%tr3T2mNC2hhaV0o3t=|P?+ck5 zg^3C&ja)TpO>88E$ zdJHI!{@S=t8a80fu4l~-q?DfCN6V%q(DmepbU(kf4am{%8sD{mlHJhXT5u>BqqG^S zi39=XDPO&L+iSisPjfmizYdX1y-XKjn+iK>ex?PxP}?$aB;<;6jP9kLehPc0<+h81 zy&b_A`(i*+w_&r_F7{o5u=ko*@qtqCP2zjBndL|0S+TzVM)qG&g=gxp#A~*gfYgz3 zY7|7K79dLQ=I>X=d#LktMVnI0=(epgkAhW#J;&Sdppa z{nWNoibWngd%enfbHp1P(9bqMx2CpZd3EFTcdPNH{42qoo5@6{@|w2MAGi0Lwxg>1 zY#H4dwJ{6+P?T}BAqa1dRk&m1&1a|{0ts?a^){v(ut*UC%3MgnmcLN%J9BU#W5l_B z$%Nwz8;GkO$A}XA*f02Vldu~PKOq)mP4kgKKNqRrrNSp1Rt#v502HSQBdpAm^>>UD z6Cs)VsTocza*2^2Y8*KFqGsRxMd;JhbhJ$mvi#&WLtAB0PJ6B%I$waX2`}+CxIqGb z2!qlL5XovlZOsGR<|LA+MQ09tp9u8D-+$%|6I%s!mHun1iw{_Pz-7O!U6H^kY@e&txDU>-7v51LYA&MvKdc zR#W4JikL_{m%meaZEqO5^9W!) zfdN-h^z}uXr`Twx*ZGZ~hJEqxZKTAqa1EqU6G}m%HCEhuRliV&2^pYRFK=WsPmv_c zMyDlaY&TpBz)}}WLyW`JFGq>oPRU5k!H}T)%J6ZTOahK;{|_I(V&;jAKaxn99?3gk zCBFhPCaH(ALZ)D#lBHq{DDgSF>4=e!KtQvUv=o+K&Jqkrahjvd_vR>~n2;k7U7Wf( zy;M>9T2|GmmVJXtYt9VBp5f=ERY%;d-e27Y>0&nE<&1zFM^-Gu+lV;*fyH|KA~0x% zt4H6bgd}a+h%_RRwppbzuDK*nPPjD5u2|z75GiW#?dbP{3fNVifB-k&Xphx9L~C4w zH6^H|4vS@ACtKG=w z>k|YT&(6oT02#gHr?DTs9^TGR<*+w8jY)>PYVNJL*Y14+&_;h84PM8NY>;Ui|G|n4 zXo(vuBqpqygYGV*#bpR&9%>~~xNKgU8<3HaiFSigTe$`qGoGwRZDu2Nleoma=p#X0 zrnq;;VHGryFM(w;3CoIOv`L#!NZtLK zn~OyRHHKSq2H?<_&AvDocJ4#y_TR9>?I!>{$qjnQ>X$gX57+&xjM-)lo^L|+XdTQl z!qg2&YSNE80SSF)60AoaC60*!cqQP8A137Z12R;l4OQF5a4Nm|F0>Mi5fo?6&0+%? zekxtS+I;q2Z7`B{UahCsYSYb+x$ysiO^UDI;suB%y>UrKqYf9skS*g! z-axkIp#HkW!XT4RZ7JCTLSmWvSVETS9;xjoXioX8NpSb$KEozNbeT5NspPtdf-@Ye z)wKgPSD^u;&W=m@eFZ;_TC5>O_2??VW3Ag{rVflT9fK$!L?%nlLq(5M_7L&Q?3t^H zcWyY@S6h&7NJ11Uz2nF>GUZ4E51Cj**rkQFw+5GAK%u8jW%e~V^1D8s_bL;hDOWLA zM7}f2IEX;q`>rlZ!U+1ft_biuKcJSRJz02XBznnYM6q+_Y1N5q8gMy6+!uH1A9Qg7 zQZy!DX-|58uUjF}!eLliAKJ)TOTe22max;R=P%M+_CX-zTuY-~MO3A7U|61mL#-zG zu;B>EX1ddmrE-?4-#`F+22SBKG>xq<_K7R7zQC#E;#qz~T|6wnB)tj5$joDw)T zl=3rxbIN%SMXd*XkdX#$ebK*%UqOTLk*?8UimDRiA5(G*Dn^QfSfXqdW;HQ61Y1Jw zprmw3#zC68qEtd7&^7!3fWmt(4m9m_;)|tb;xUn?x&_sC!uEQ6*7bM)el$?gpKAvQ zGH40G(;Khj#q~WrAGdHGw{VsdY@DFu1l9Qkjv7F+OXy*4fP_!?3<$MO)kW>E!=n)7 z8mtw~*K8lqrNLz8dG7ANwlc$M~d$#RgpO0Ijqq=JoZcK=$ghRLJYyM3?Q^W z@D8&~9`a2x0K%LE2(wK^2(Oyyz*_ol)J0ZKf426jCrZ~5Fi$|aLg>^~t45zn2zj3t z6mEfP0k@8QM)2t7J9u>S^LTvc^LT!BeZR{qbp1^!C z70&cCaw0O?Y*I!WR@bUU9_^u@Uw+^4h0n{*>*&J2Kl^{ofbV{Ig+KoKE&RdP@8Z$Z z8^vHPiV&T);Wip4B9Z&BW|J)Y-5)RjM@ci)1pAWSo2kJFm!E2?a*QUgcq69hHp6rT z@;*un2GIKG?i<*_KxXiP!$h#0_^PY1h_#6WiZr+561f>X9{2I!^`FLr+h4+qs~agC zLF(~~O|{m=rf?qgP*W~s`B-q>(=0$rkfUXs zmSE`SBiP1$`@f%@Uc>iZ`*}RN^?tFn%Eiyus*wQ(oy4U*u1m&^J(MDwnA2Gs^_EAEOGI5W3^fuvNm<}l z(}cRNNz?sPGX3NDzS!p4c?88SUS_#1S?PUtMgL#F1aMcOA^5vL`w)NU%Mb9ofA|J| z=ij~##R=C7UkVFX_jF!Ed2@H_i%2u zr*eYzBw!}u+Umbo6m>{|t^4a+yWmT|&EVI<(FgjJ;@Qd8I=o>NZGYP+x}QS1vdy-?D-~6#5SYlr@m+h4KigmJ^G5pG7|e(nvnWs>f@Pa6rX*%-!RS)Dm$cb<^cIf1@yPF z@C(s9ettCsfB%<0!dJiaDSrF^cpo1Sz_7>z>}Bm53)Y!#&a6YBx-Qf|>Kr_ND^Y$e2|QYC#n9S_2RGlv zH$L}|bMd>+TVuQN2D4lIoKe?pykmDHV#}JS8?LBqAy_U9>x$yTZWZza*iN!lw!C1PeZUdf>= zGe1|8lnj7v*6%-x#c%7+-+b*k{+oaDExiBMBN|KFhGeHXiZ;fNk_um9=#^>tC>UGj zFRt=?=AEF(<+TXvMp!Mg|DU!KOjoIJiMXas08RRvW}A$BTUDa<(W2J*y+ZJpul*Xn z{nl^bJZ_{%{U)BeWCrl!r|)aY6_8xeyZ~Oh_-QI)(k#CD^wkzsW;NDJkm<)voQkr) z8?}@wfd=O2H~k%r2rJWWr@=?_>5Extr~TTFfmd4)M<$+K-NM&D_Yd&V zou9f`-h=!8V%4>RUYRu0PJXHm^i?N+S^Qe69ph1^+D>7ckEPZ&sGLfG3{urLw&vwN zMq@?FEl$#v>7Dn~@DFM6ySEWe(4 z$PS4Ypmn_0NI7C~V6#t<@EU!s=ca_BR9c6^{Jc|D$_3 z=KXG-6#wkE{v0Ad#{abi`b?+66KgE%3XsOG>+UVSQ>OqLV zEtX#O1TYtnsBL>)!%nA=c4c$ME z?~0?>(TH8zg*_n*Nqe@=K6S4GbbIn9B5N2`36T9^S^&FH-tSKROPd0nfN$J?fq(k< z|6&ofX{m&@t_#J|K9`r*!fMNAP@bLvbow3?#YW7`*@Z?iOk|2-t^7*SixyfdV5LOC zX1A)FhD92%gMUhf9WQW&Z@u*&;>q>>dP=fg{?=cQ7Ju~fJd?J~xDU&?@1=`>^R{KsU|`Gy?s4iPR&`?c zg8+Ku9GCvOn7wosqisx1L6v0zlK&QgzL&QGD_-!G_aETrzVLAgldUao=W$pC?nQeV?rr$ersy`L%E3boFeLIEAe#5RKdGTYl-wx$lWBpao zuYPRU5^St=P0aGMV%*U|w|;8ZQ@NV6qKSY=tyu7-3O=Ga4-v|gL9fgpuB5xN+_FoA3!2^0N~@Pf zNM`37c{*<4FYo=*LbX+^-tom5hd+L;U#WKD8;eo4As$xAHA|jhqupxb>K93EL!{Yh zsrO}Uyt)JZ$jdMb4y|+jmhQAVGE)faWc>NbUmSgYo&ULrp{s@4+&-(N0 zE5on+%=ed(s9NPpY;E@$2U=Qmi;xtxP32gbBinet(G_A2RGjn2!2>-KqN&6-+5UiM099f{zvrT3fn?vV%sAMxf(v9A&m@If{9Uq&-trg{oZu%NpDIqHk%<{L+|aax^oxePun!H zanrJfS-BI^;Uy9_&DH&9VQMA4q%hfFJNm0GJGiw_jc)q+S9gD*o%SRREh#eSq+h}S zY@y^<6N<~c`T{f;z;gpQ=!WJiR=NN4)GR4MoOMv*4cnJgI0JLmzi0|<%~G%|32g%a zGU6|&Cx5q4uUN&}0`Ww_N=3utzD=G)_m!|Va&B?&XjKtgrm1r3leQ}BM+fw+kF#zH zcW$2X)9-#<`80%$75jLsZd`>;ibgK#Qv3Efvc+3G%9I0-QY19aI4_)q+s||nZDq8N zd=z_szXq^!daT9_95lUW9EIKl>jv z-#+H}w^(%!6e*=25tA~T0aZHyVh1V~fsb)S*kZ$$h<}}*({pH6U8U?VC!9Q3rYxl zB>Cz!na6r24UwE^@o!3b+mJ5M<*&M7J(k-UdIn(c$-0|wj||t%1;#?9B`c6mf+pkB zR`u|PSvJRIbBk8JO(KMH4B07wB*#d$rMv!!7|!#nVm-fzl+ms`)<~oU^TJ9gaQFe( zVMGEEs%>nM?sjg)XFuKlIzNBOhBN>D)9-$WJ2#%;(bJn4!~GI9oqd|os9w#J#ZA$XL{4cfc|aO}#~L?XtKmd9g19e45Q z<~tWk`U1A|Is^(f(AaNQ^BXE5sFnU3+V4(M%e3NE_S>fc)(({By|-*S)mDvnV5JiR zH0s=0t6dTlG5;Q<5wK0)xY(|FMfb^yILKv!OF>+df( z0(b4Z;|XA^X^WtQQufR*|D#*)zeM0;)eQ&Dt_z(=(-CkhR@Q=De3z9T6ajE@s&5-l z!8R9cr%%)P%-Af$_M;l!iByR(Tyce%1sCxW_sN>!?7~DJb}B{U+b}1v|2K+lDoCV79bqq=<7S>BZCfM+EeJmNw%n?|vNb&8JtYm4z9f@GSY` zyOQ;kvo?Jxh)vlD8Zd2coZb{>t2DQ=;})uCJNZ)2Ui;D#IYm4F$G5(?EX?q1M^ClM zS-3Qge_#9-Wo$Fw=y6+27_g-=pb^(PA*r{oy7(X$v1vy45~NKlrvlohx+@7NUXS`| zo9a8o!V;nsWh@O{%D<~F;=GgiwutvdpLE>4Q?$m)i&zeEPg|paTYKU=|_h} zCe0^vn~pHz-bgxq>{lo~N;8y_GSpaO1x>G{EFS-8QaYqHv6KaIgT65=-tt^ulge-K_DnpgFVHzIZczdyxN`ekrpGh*` z-S^v&dKUOB7hcHOo9euSiP}LhY#_$&*=O~jQCl`MYqnb+p5hv9fi8h7)tjMixTc%n z)q)qGsP5teq?F_kDt0#;XcO*if?3Vhjkk~RHU=P-T8<(O-V%ZMyE;G5jh7w?&&{#f52U6X+>U-Q&?3itWB+i|Yu@=Na59 z)F0k`bajmR^u{|-teYqM%6qzrTgBIM8TIteA$JiiEiq{p?>$p=tJugkx`3s`u|{X62|y=L6-Qv}x~FCW%C^c~T-8#4gwz0F$EGkY zl{nebfe^*N9ub;JUU=l^Z)UJ(50A}BWEx!_@!7X;$xHh5SM=^b)X$gG=;B87<iR1(+~nJ=5(Fh5LtAn%1A&_Rk=l|~ zxR72NdcCj!7a`F6_mfXy`eK<{eE!XWt1JB2fxcI@8TW2K$Ln_=S96)gyrnZBWyM)w z3qfelg8)`5zvFp_-%zkR0+&6rJ$W7H5O2s@!Y?mG+NGXc-NkuagM*ZpabN2TSN35Y z9|@{?}UnSRBxsr6_IER^h`A!j29*4Dd=u@N~( zt6ER3f^c!mZb;EQAG@zyyjw^DNv4bF%o-_*>B8;kZG)!#CI(wUEqQKiA|d;+l`ZzuYel5i zZ3PUEuiq*n9xLO%+F}U#`E8xA8FVvGOzr4rmtM9nOV~gYg;r{f(;s1z>CPHnn=)_{!)8l-991j}27u)%f7vFm zo7ni@^^OtG+P*Y^@v?U zE7dk+AX=n?MTVK1M|Jt_At$`}l^3(JuYWQGnc{0p#n~jw+V~JX#mERpp^L0+ygaJ) z&z>{=Sb3?{1-W!z+>R1jD~4VeWmC5f&Sx zLK!xy>TNT}#S(eN7x2UDH)#TpoPY7?Ff<0AtU`|t!ePhl-&uM!g3bE<*`|6})qT+h z7>)b>|1AFQiUV7Ab?*C3D&|oCe9(?x*-0%x%2u|0)FaGT5CkE(y)z9B~?GbKVJ;!ss z5fPuqmd3_4Bf(qig8JG303ZNKL_t&$vb7`Hw8~8UK0w9cYhoCui>7c@h!l4u4$DI0 zMc20*iUQxv_7>u;LNPyoQb_s8{Mni$C6{h1SP+>oCbpzl>}h6wQP8xKoM zEt}D4E$dO_yrq6_mf;JgvP&g^^^>Iw*BuC;ITo0a(Dw{(;>c%En>U~K821g;*V^JS8YV^zxfFruD0wq3k@2bbZ1M=9;wjXjT>m;ug7aUUB(BR zPoOV&O4Ri61X|WzCnBH;H=bO-R=^%XJ0W>~+zB}O4yyvH!-2Nq_q`S9Kw&?1tf~9d zYU!^VkAV*Qtxi4lbg_j`U`x~(qx!p9Kfjs&IqJ?It$QK}D=%fsn>Z>6iE@YXJPTNq zm<;#&{*_T|rBFmRaz-7=x`ILm7Xat){vqV~qoe#)fsUhZzIPY+tzW;nXNUc*wgNxg zW50d>)A@cil=*>ki5x$dFr#f{1 zV{WF$`jRVR>Kb4wkdZnY5f=@~0^XLr-8Wl^`vLU0p#*l6^#Bz0%?>zA>x244m3am{ zy}nm_lZN;LTjPbARys!idoyN_@+&N$m?hIC3S8FN68Hdq*7dO1}L^8U1v;Rv3k7i2wdep~cru z{VtC!cbA=?9~N}o7Bn4;x(}=2Sra(r##I!3YD?+A*o*hEq}4u!BVVlTsYkR8 zUM5&S!`v$b=Wz??t5X7MKIVjMK|d3wz3##GdhrmKUDgv06l~d(c)|*cCJg-$Q1`Ll zZ1_=vF&3a}Zea&Su}z8HS!uhc-d=^r$*~Y4@U9EEl$>bEDlF1xo6J;+g{GUht_x1S zy(K}rm~CTbu`o}cKgRQa|Gyz4%=5k6zc2W2|BKguqJh3wZ8-0|_HfCr*j5ickFra; zyI^XQm1qq>M)(0tIViWk+^fmPjfE3-_KjtJiV= z-uSUH`hFOPAi(hUYmeFlM2l3M4?;x}g?JPyI}Qv4z4??jYK8-fD^%WrBUCeqhDHMy zY_*K+vgd7{k6TN2UsM6sGxuyk*=6HTXcuPh#Z^vwpW99xk{K6nK{%*(9zcNxNpRz{ zdaep~pj#92G{j%62R>M#by}A?lU;P`3%av!W(T@_))RI(xmHUWZ8{8nw$i@~l&_2-0{^&$LvP%E-1HYxA4Yf`G*TGW z?_+xaHpVS)#wWhm%W2omD=X`D86~A#Z?h+EC&cs9t?APT@LR%eNTp~2AbliQef+Ka z$t??D6Cl}6cL5u7CX2btlx+zCr7u8NJwX{^Ug$H6hhF#2dkNxig;>xXTnSTGVz4e!2v zjeq&ye~zlupIo5tRYs)uZ$CYZIY=gbd~_0bXBqSepm5F$46p&>WJ;FiA_+ih$cs6c#j!ykbNY^jIxJSbVxSwd>oeT0Ua!?Ud%tEk0VxoE$y9`_jQUufX$%7&4B}WXNHdA;(4iFaL-4@Tu>A?{&5S3?%jM6 zf}L6&fyT-#5b||nd|`)SinkGT_{T^v$5axd_7k7ZM_DTwywQ_tnj7ZYGORY+K@px8 z{`2cwAi>!Rq_kPQY~-QXZqQ8V!B%M~ePTe>h80?JX0Hou8BKN0g7N4KSjI)RaV09K zt=d{}fJ{6VR;Ghw9FNxW4sAy{#=3#G=rW@PFAcmCTKHQYz;f!hO`t1GXDNDq@(G^& z(f^L~U;Pn81Tq9_iXnq?00jTypTCWN{2TXv;uw8DOq(%=;Li0EJbHE;B8MDEeBK|6 zn$avt29*Lf4N%5hyMk4r8S8bVph)KTc;XO`a>iO+Hp1LMF9D;8v2!0cRt``D14PdA`ePetyW_{C=cRQg|NJ5U^g z>*9xL<^6SqVVHMFF+>%v2+&h@gxtWm+$RgK?Ww=odC`;L{P6pD`e*+)o`2`xLZBE< z^7;STd(&7=v*SGMsrv5pHXAuRhclFhlBhkDCD4*07!pLu5CqVGvH*z^BZ=X}0iwVO zf&>YIRFlqyHU#SRPkT_&4=*|f90O*E6d+zM&BE4 zGwwNg3Fj}L45qzmC-A^a`EI%IgeqUN9d8j3#zJ)Jp~I2DOG@X31A|b1A)z_8CAlYu zgy!>4rZ>nICHj%=5*v*dvGu;cEf)UD^vL%8#a5fr?ATjrzE(G%eJr^|CTx^vV6#CA z(}yb2r4e9ZT!|qGWL78tzQxaoelFjRO*-sYhFU4^4nEJE|#STIbd@Dn{gt`h~Zl05BuiV>Kt;h2N{h5ZQ>sE zr*U`@7he1t4!`w9Tz=)7xP0b$;P6TWU9>GOri6L=hOs5#Og3F);Z`%{Q)GC(;CXTs zLX6(+)rBs)jgzpU%i0&dDB>g+k?7@B1fT`4qJTEEZNNvH>hK6Q13vLH_u@bM4?ciX zCl79Vpzm7ueXu*s2tHiULt{N;RB!xb2#A7o)6GG~kjBO)zKIOtX&g+HyTaV_6%=Jz zLW~D+n28K+defX~2uF9h!<51ng8?ht&n%53QKl7R#?h$$seuX}x3oCyY@RqU&39$i z&{i8!D_(X^t3JGfE6;ri7oPrOTz>w`Xh%mQprhp&b`y`of zuJ!$6+6JP}c!?#J9MAY@3V`9B6Of+}_(!_!P!f)E?qCV94Y6_N9W_gf%_@afve+Y` zdnRZQaMmG<1@gF0rj0?bINZkIej&{YqB;^qa!koNWG%O|Ap~XF{tYH z=BcKJFfKzQ9a=M(ZmG0LxRK!TM~>lF{`%wi*`K_3*nQnXK;P9~&%v>ye#mO_RfJ6I zcbxoTlSf1pE`;yx37Bu`+}Q(|g_aGLUlL zZL3*-1{(?jzf$+vR61JO#S>p3B+xR#+*>93EJ#gez~L2Kc=BK3;+H=KJG@w2cB`ec z6&o-NN-lkW%fl;)%?nGehHUq3rNwK_N~_gi#pOf%qVbQk&@#8~aU0k9i*Mb?LrAy2 zRjsX04s~5>Kd17xS$P*gVd9iaw^Nq{x_bX8%sA8W7tVDMe=n87TFBfJ0FE69e(Zw@|uAic60=0%_ngBJyo-aOKg~dj=HLAw6s_>JCVSy+0d?7XBeSlNq_ zyKx>vB)UPnbPg9j`+wu`rKhtdf)NKY$9Vre2l$B}xfdV%=zaL%@4Fk1J$e$mo#I{b z^&UEb-|05v%F(tAH+K%lNT|POoq*)iP7+RoSdWYyNQx7XM9w-${y|vGxj-h8|CWn!8r@OY=*raxG$NGJA{cTN!cM$L z=U>5v-~an)=U-c>BayP-fBGlx$0vU7Vf^@yz8?oW!Mp0q_KZhv;S>0s-sBFCc5!V9 zDKeD?S=ma_Af^EdMujS}c_s?AZ<+~O^>{hRw!#>-NV5V1Fh*}nH{P+}7Rh{l;q2@R zuHZzBhB!QPW)<7swqSYT+8qB~PksmU68#tJ>w{;5v*vnK0*B{c!^J=NKVcWn=Ki^a zto-DU-h=<>mp_E>dEzd-E5F{OC-6JH$z5qW^|1k>iuQw2Q~%m6L(|Z2fVC_L+U_HI zIYJJ5G7!`0tzzOOs=EMYR)%&`F}T^{Xm{lTWOw)8;Lc<&DcKldGqzi84K`adw2BuN z#J|dlN!{0`v0f57=V+}9XK?BF{~mDhENZZ(zyBY2=s5oNzyCOX>SOoeUHkPOK7rrq zP44heh!4{_{FTwiWS*k&=L*5szo-x;ctsf&=K&D(W26hf8Wc-aaBzM|6CQoHkje8{ z%zAX`>KCESi*zDGA&Xdya0WOaN4NFAHUjHbIA@)XW6x~^4>-Dl3!nWp;L^F7XVCdb zKk;LC1NVd&QdHP;LsOb{Aqg})v#eCwRa6smC4VL@@n@9ybmXk6Kn5zQL_v4q; z82zs{VrIDVr~ec<_rg?>NFUez+n;y@|KTrxuoGKuKghenM_h z<69+r0Q&b=K6wd)H$nx`rwqLUFtNh=!7f4_;b*XLxDRJ(t|4a@RDsV%0um%Iw7#JnKJy1SJpGkbmje;Qul)57 z;$Q#8M{bgZe;ep~C)+Pq`k4BoPPyJU;Y#%M$+YlM{w5B7i|aGgIbDT!FDQfoNzT4jn`WaB4xtRV$rDR( zaOGTfD>d5-?B@t6!4!BT*}bEU8)I_zNK1LUCoP5@(roYI=gQ&m3%>ztN4Xv8o6ax& z)dy~_#c$Vp(cT=XyW{)sUMp~Zf6rVz3BGI@h?la81=Z!(Vy#;30oY`ePyjb_@nxaI zbyVi3xpbo$eTX3mi(r%AoMgmZ49AboL#!>U7TRud4DT!rm<2sHasne-Jo))aay=Tf z0m*OB3Rqzb;KeV)UVS!<8Tmu{{_j44zxD4t`tDr#-^Rsx{U_PY6~=Mxjp*&$dL(Rq1pc@WX8KV~l+;MoW zFnIRt1pA6t{_5hi_rwYOPH%EAo;jJ?TERTJlNu3D6}pseXHd82;h#+Fz+D}tQK2M%f3^{h zg)g~o$h%jnLZ(%F;_ysaqzlA<+6+j5Bqc#-oblVYiMd!`M=46+0v{_S$wYDzLwo*< zkc(%q5-$IH|Hi|3_`zfE;#2=dFHXECPT+TXll#_7_l-+E_1$unS+z~eSuhLtB()Ya zo+dJo@(*O1<|PQB^#1#fY|BBNAPecfiQIAJ^_eInb@5YHpX7Amm@3GeSs0Yc1%O#G z2j5w9cHi9h`-2~SldSN~#uw43E*+3hL!vac(s1%8?;|b?Z181Kb;0ngh`EPyVfp<^oe;eq#Y1)jl z7mwlG<&$&OYkLy045|9&HEJ*Nq$T=NCoI z@xwFogq-WDT7qbfy;yUNmtpGg&U^LpVg3L?Ax|AF`I@Y6qj&rJaI z*_(d?zu`9Hy#e&?+vJ{q?Ore$t+wI@Ng|+Nx)L&HCJ7C+a_WXDXfGFp#?=zej;N`- zTxMG?Bl_GS^x!tehE`e!MjM4r%sY-Q;Na+D-fToNsc>yjn+QaXAqb(HlEBDu!n2Qt z*h)_zSi+}Xbe#TbyfQ}qKmJqi#~pX*&2{R(SwP?Qwi&qHW~|=ZXJ5LPQhaIc81woi ziGAv&$)I0q<4a4;S8kwp;#q?MK4c^vvHZv{o6p_&D3T*`ND&B z#lYaS&MeG9FSuIAgLm8!w*?L9f7^}>So{9)2EWoF2QoQ$+@4#fl4v(d=E>5TYSD{j8C z2DJ09q)-45*i^Z2KR zn{g~V2Dwc}s7M%xNahsSG?5diN!8|8K%zc9TF6ot)vA~&^h6s^@Z_b_m<>lVWw(|y zR)E9WFNM0#f2UEqzxsu zgS$PMpVoI?e1Xzv0M`7e%_l!(&&kimi2KBXsPbWdPpZukjT`;*Il59Rs_nLSos_r# z)W3ZK-`sox0H1s2(cC_#**>D#Pp!7({Dmk4`r^w5IFf9_%nGnTyc)e)?;v7P_}BeG z%oaV$IEiEI$Ihjppxb_M{K_j(yE4xJO8!T1{M!_RR;mo4!o|Zci042Ri&TJtki#jn zz^-J>0D|34aL2LTZJ_Tq(0Bct9Dqw#c6jo+hhsgMNGX$Tnv1)ek5{1K4CEC-I03Jw zVG@V?w05LWfzy-l&Over!O$N|?nw$+fXj}I9#}#YPF;8*5gDd&A0ODP>$e&%T9bQ; zD1>Euza}5By3q2Q$oA_X*% z(wuWfF#Rbrwl8Lz6Ok+qapAF@M?}d?mYFmCC{G>(L}cJl=*676^ulHkLa9P*>=B@! ztQKR%PD$W19rKvfeQAeki`$7zYC~C}oVS6#+d$t{PJRD+?feOR{iXW>PsN}F-voFw zdr!!?h5-4B^veRQU&@O)`%z?*1LwIvyN<|+%*LWhC=_3zEV=yA$mCKc9Y@%;L)`uP zvsqz3jr*)TGYnxvl<12oN<#cs3$vsnZ|LP>5szVl6)$y644}~)WryMb98-@rTAUG@DR0u^ zf1^Mj-U6WS9c(jh0ibX7b$F!s6tW zT0=%*l@35pGjDVmSdllj@NWZsw=B@N?ESy-2rgVckwNjqvBmOd; z@WR5t7Ng2!??)QT09isFTt=8y$BL39&Vm&taU1Bn4fO5*`lGKA_$SDwev)Is#xj)P z=zm=R03ZNKL_t*f&=X)K?)77Bt}XH{(@%s_1;lc>z*u4ckMy4;f{>(L3wu#=%P*K- z*qs-@g=3drj@V)p5)q%g0BS&$zqRiVPZZ|(PX&!+ki}RAJ??M0kr4VCecFw-0M~s2 z+goq~-{up%T|nRJ>nqPafM;L5k4|2pH6wusDCuYn^F>HkAW%Fv;(!J7cXC!h!sPld zs>nR16G1}o2eNLdhtCrPzHOca@RJskGRhcd?EPoHlt*!V-{cF(7nNNNnir`B&5Zcd zuhwrHL6}k|FgFAQ-p~n*w*ct7-DbR9K;Qh)8$S8@kHl$bbzRrdKWzbwIb|S!{5vUi zq^t!gt%3NO9ESKhwDHtC_h{j$3aDq71p=As6RHxdKiL#wJiP%DJJ!idr*Zd%XO{Sa zC#FOhUfjFW0$;`qm7tJ*+$)En+DZ@U9T4rjaswdXZJ_VgYcp=(>+{ci056=mds^|s zQA^S_o))elDueCznyQH4`h&)Xo+;q$zm;h|mERg%8Lh@1lE4Eii(P0XOWB6_)R&67 zGY}zl6A|3^+82U*Zwqx_t^}A>n0*1$D9`V{&91_{Cn)CA-|tMNzem@*_-~)Uw;rG1 z2EW>o;Gh5b6JP?F^19(-xJ;Qip34^FuGB*FX_(L8bjPV;?~6mDEMS`-nKOHYcayZp zGpHfP)WpJ1uBipcvriGju3g51Fa2TKBpUCYZSj$~YSMCv!2=8HMkN;b0BHqgog}qD zmS!5Y6}S!bz0D`^JH;pXHopGF7oWgO=kG}epb?*htLt%!vq-4d&PgYrWfk)Rm-KC$ zaDpHEn- zW#zN7sr$+s;_oS=r^R}?8G)eCUYaE#&p{H`%2ld(v- zy-t1{QUUh?5b`!5R1Gs$Cz3I|iL!1bTvP-qBA90c^iY<4@FK5NX15WMS$k|;E!0gQ z86aAE4iCKcdE9mG>C7ZFno3~C119J|CW;ajD>4F20~WE=BZNSZKR8))5pDy0?_Hp; zeqFe9fPeVuAHk6+k$8Ca-;Z9&4uI7Sh?fhQaHm$mxMlbI<;}&?eo`LCy44*`3xquM zK~5v7@1HUQW%4rT#b#t9E|WS?x_hsL+|m2&`(FJMoV@VD$VMa3FP`UQfF{f6aVZ-^ z8uwKqP_Yn8(n~CGfZIUddm89VeSZV~$!ESFub#UrPGI)h5HielSAIYF%?}!|nos5t zpix!8GTPW*N-IEK9SL{a0LHm@;0-~ulqbkI%q9Zyn$w;kW7Y{ACUN#-CnjSY=PkK$XfjxxS%Sd%(G&A!O z+=S_P0&{7vWg|TyuK)`{k5H-5pJ@Np9Sje>^ckGF_#wRfz8{8(rq4HWfoSw6K-hd6 zq5om+-Haa3@+Oe(YJf0eZZ6_;*f+9}rw1w{PunxXT%Ewzvj~Az3evZI-&g%U-uQcC zdn~AJWg~5G&SSp8uZvd{|LFIA2w!>bp;R4;P-51K%EKW$jI&jPT;UVEqWYA%;Z=dr z<5CY1!8rW^4%}%Z?7+hvml6bhk+Wz%`h?+DVqq7yft6e8u8j?ak8vA+mDPtYGC2Ms zxcl7Kad7E1ynNqBarxLilk$%>6xN2ccnc7r1EST4#jKI8q97>^l&C?PWPkPL#rY;K zh<%&Fn{wa#HjC>$-QUP2_hxQHZ{R-O;MeIhC-JMF`T;z5=6$_FG>9nSM{J#!leHu< zQLAcJ0{PFIip8uyVRas!*{jSIFJJyLSui)Wt{eL)j=ZA3So{!-0;3Q!a7DNb<9u$fa2W}n{ zCi4YZU5NVcG#Yho)en0h-adif)Dzh3ExvDClgz%&ufrq3r@!<;{MP3`jKiY?n#pU$ z>&e>6HwU58U9#L8?Klm4>@s|2j^deG2DKeGsqT^&wn3@xXYW z%@@Bw&;}Qv5r)7S>HhEL<$kYRx-iMBkW_xfM)n>*fp6q_zbU8tn_N|Wn_p+n-+|9Q z`7nO(%a7sg#SV1obN_Y!1@@?kjXSA7FONyJ?*;+g@nQ#e#MG6xcD`y90%TJLl7L416phJ5Nqq1#W zXgzeq2poMUPvF~a#<#V}-QX#I`pgNOe(gA(dHHU9?YVpL%uDZss6tf2QcFZL>BY9| zhP@=c+E&dVc=DGJcHb%hz4l3&qD6(T5FvM)B@KqXfb8Dd4ay){GGG-AOH6ku5tN$ z1xHRZoe-6;voVhHNe)=)=53+RoRo<#{yqA4`Okq^?TbwNL`I{O-kfbjWLud1IjQ=> zbUwX8M7P_<<7s+6s^dN{AMQ4oO#Nqmd(BfUDM}fss6OKWl7+SI4kX+P6soq@U{Qb0M$e_ z+Oh2<)mZ$#As`m(*c7yEGO8P!Q+y*)#C^p^qy77g2G@!C67g4B)QP!6?`6&C;e{`0 zaaYIpJ)02#AA*lnWrjDXSE<1noG;fHg&M zQv-d1wq59SLKz!YfSI2~Tq2o$=9rEUA6;nyArBCz2Kh~2ztapvbz1$T2BP+6;>aiYjVhm%so*ubV# zW5tN%fEjU7cGH6O3z5hC-Ul0H1n?|g!c~V(W?FEA)87}r8mvjGB*NFvu+9E`u&)AX zIm1T;Fa=;6J^=B>uYeu(F-jZwhK`Vh*hq}&%QU?()@JKQ^`h$K<^}q;lQCt?nNFPQ zw18}^Q6qbFfxn zv=;+dh>OwK@6TU1k%3edt+n88s|Z??zPW^->P-#w^|c2RMWSd_4|i_GB#%V-lH^kv zSe*P)`cL)6jVSZ6XbTW6KpzqN@*yN!G5?MxaZLr}=EW-9gA0Lp5E|QoHZa=k`tDLU zJON5yj~EXyZlJt`WnsCO4m$!9kvAHm{6Q9^qm=I554nRN+}N1Yv&7i@@~scI4ODX) zu8cfB?np2?`@z&>0#HZ(rFpyQ_i5Xk-ufwQlE4t75z4pAd8z0rsUB+*85eyXDEX4e*bOe{rlx~ zBvg^{eH_g^tzN?YFaP*HJo&BTbB|5cgr-G7Z3t?GA*E+0w4F8zUYy>p_ywhjcALw6 zUYx1Q3Gi+)DM(ox$tJijXG!fxr4Lt!U|~E*hqb_{0Me=4S8eNcJ^|iBVSS#UD<(wl z%Pc^6nc2sFzWBycYh%8@)%qPEY|(d{wR9rK3sZp|HOeHG)SpL~qFC9XZJcjvu;vSz zt6$n!h>fUFG_+(fels%qPMuPmI;GdR552(+2Md-}p_ZfknNnM>e*-;!Fo3&U9?K%G zZdFytydh}e-IsnIynyR{rgA?6aH%j?$zUoY{gUhd^cW_?3nZCrRBG{DkyYa@iBbf; z0>D@>2IAnWK-!qYatUl{tmmgOw+6Hk$cQ##9e~lS*_NUt=Hc5Q?gZ&@8|SoUd2SlZ zIge`8kVsCx9jZ38wr#E2fY!-M33$;CY^KMucL~t<9uy8yiL1KC4|wEt_7j5 z$i31?PXbF|bY4=mkVf(Et~{MbJUO2}$?W7?Tz_S2`qY&?#2r{l9gY<+1zSYvbA5QfAox?CyA3l-jrGWMJp}PDez*U$l zP=rR{G2p_E+fP@2lUhgn2eMD6yOFQH$~L<9jl~#2wixY2*-iQ8kx|fl?{UH_Ok2>1 zRRqm=oG4q#ZY2Aq{?=@3F=7hPMMpvRH7g@b-(Tqa+-k^s`~-fNNOwiE;b!XV{m%{v zYOodSxKGlQC?WMRMJOXTrN=|&7$6p=1IRLX1_kx^g`b(0GED_!LFi#JQndsdRe>(} z7~?e`h;(k94bQyM!x3q}A@nfMZRze?DIB7O zuj(^-#Hem6>wVG136C-jpm8K*9`}jn(WYqD*>lU_m;?cKqFf2oG3B;CRBEMxbqhh5 z15msMxx}}zu{e^$!l0-$oCm-sCipZCq}&EGk9_oe)3Ck?G-BMjw2x0@fdhKE|A%F8 zag5(sEjUhQlaU0JLCNeHXg11u3obw>3zg&}qY4Jlt%ZMoDdeih&^Ywx(YzmQ;i=dZK(lBS7B_0U7{#Z5>Gq4I-((8?EHr8)sV`m6 z$u_Lw2uPr#fEDG3=AxyE089qxK%RQ${dyZ{rjdXsstd9TLuUZ? zqr0;J`v@=ug`N>0Fa@-UkMTE|avS3&gF>bC<=tp9Wl$qNf(>-v^9@?{AZK31WQchi z=zII5yW0n?ytsAM0?d?PEsG(Yyx;_$K{l$Y#|{FFia~S6Bo=r?5=rrU>ny^m9xO(* zkSzRx6dH30-pmB0TKxnDFs$*+iSbVDi=$Q{oh4KSHsU-2r{y{e$)dmxqR{XH5HkDN zPIZ+|t+8YTzEub|CJur4J72-40y6Ro!?qmMs^~^)3Q>@5rY21Z-_ZV=%r}fx{)aOd z6tKhFK;PQ{^evaaf_iu6=Ide-Fh+Pv1YFfx!Vl0;0$X6y+KMgcARF}st15eykSzMq zLLW}1v#5fmO#I=gg0LM>N$ZXcPT5E_t2z(ZEK}GF#EixZEfznRiYtWRn*{*qT;k*d zz=9he-=Pb5q=kV<)jr!`Da6Sx-SkWvP5T|Sw=tr0PM-=_2V09^t!ms|`P|ckL}KEQ zmj0$X>O1~zpzkf&qn zI^{!aR9Tf#5$>WyrOM{(qaH=z50>40~i&+ zZJ=*@t!9QVKeNMU{^B^k^@`&43ySyOd4$IwKEz-C{)>3@{x_b&lM#H(_FF0ws-78r z8UiILBep=>bww|pD+zBKl)=N=3ZxNUpEM=MZk<_))Xq#MAuD200!UFrTQZLjLk%cZ z3^HuEhM2hxz>WemHZDD%)Wa`8s4wsIz5xUVtyqVVhm{P!_}xxIa(+MQjh#-UU8>)U z{?2WPX=bqcW&)A+%|Juw(?$Zoi~=Y|s_Jc^Z~Fe1p5Ec_{Ifgpm2ciLY}&UNE2glaQ8V1Oo6GCpDf4Npe4x$vT5i+oR_@dX_hZWu|w?H=PRlqSsw|7Yx?QD zEwZCv?6H@I&hGya80UQl0d36Y&9bMOSMBD)q}B$Vf%GmTwoTBk2|~$j zps(D=uYc+|{_bzwxzVL-G88fCKJ%5k@P%jY#IO9)i}>hwUHmq;0OI&BPWr1&0a$ZmzhBE&Qzy3SN@PGW~-GJ=6uU=u_#rwIvw->JL@IU|RBl!GN$MFVw zfPCWX^?D5E+pB2k>s2M2oA?6K*{@G!v=Bn$K#tBEn*b)2V%8*70S}7lXx15U$+W?3@%MA zF7bu|p4)b?1pG$o)R(Dbie>U@(`t<9ADnv4pO{|Tj=Zp(_7Blx()Y^%r%F@@0kn7@SC5x_r?nVC42623ai%7ZO?z8%Eax&D;QU8 zzZT_qX6X?Yuve3ynSofW#eJb~o2I6zhqub(c3R9qBsmjHB~O(DUo+5VlRO*USG&jdxfBk=ZpYdahs8V(L{3j%%D|CpbD z>IB((vka9H=-dw{;7owiXHVdTR}OAyDsbuOj?xxNstm(lPZ9R#qC^-908dkOsbzMa z5Pr>~p;T>Z=H4gLj;_K^u!km0D1G9!GQZ2c5M62g4JbEwZvIZ$sm0 zQJdwkPvQ+&ENVnpq8R%CgwsBbn5s)t1cZo(NI(8C@q7@^hY@_23UAN7`-g{aU7J0^wkWum?XH@}C zzjo}#Hh?P!i@AAO5IVB>sxjzzY?k@*Qd(gFGHBo+S6(bma$TF6@`l3G0i8SneacYA zc-7|+ZGEAJ=?B6}-1+{n;SJDQR}MCd`~WG2BH@egk>}R% z;;TE{dE)Rr&FH&$cn}pp4&a!HC_ZwPg^1D2FGf*U2k8PQ6Er2vP4DN;_wo!_ofB6``^N}m> zY3c60cO7-0%ErQhB^MeNcMXCKlCJ)qQ%Bdm0X+Z83AAo$F3FF7m~K|b--N8wQm?i6;6&nkqjIjyz_bjk}iM>fX&3i zs_e3xf~pP)vkQef15mvsXk-J{(6NGUQPx`@gW#!W@4%1$zv zumI(0kCjkOgxm86?!SIQ(9@^yOaQG`{s;BZS{D|ypQ=0t6kbCkfMk!cNMHfHh-VelRs+_9QkZ5H40!a`2Y!N2k^%j1yRe4K4$$nIM{(efBg~u zBSY~xl!?Q!SfTjxv!~GP6)0|Ppzmtm|Hxw(aM!7Z*DoGW-U1y6DJe)ZIM%PBk9_bv z?mW@1djt53Z@hn+&V=}9F(HbXy09hpxUSTRA2b%sJ$LmD(BuP<#%_eTW91s8mGOr? z0VuJ9WxFqAc4fK`)kFtQY@KRELikI#p}6&yyYvo+Q?dX@4K)}(Xi-Zh&8WU3%9$5Af(*3Srru?X%qz=vt;EAISqo6=~_G<|JbWNOjDsdf6sRt!%no1>NG}xk>=Y+uOI)B7p{BpU%I0B(l_r7et{-bKac%1 zMvfzZV;dDxTCiqbLSDqPolA7+V!WpyYq6>sm=`}d0&U?Dm^YT}Ly+UakWEh| zPbU)lHpK_)KsG10Q)R;fDdCBE<{tf&F0$XI{zlV6SJ84-LXyLopQ{?AC;w7fO;4z^~zfvr&;Pdjn(GQe)1WJzFX6x z^Xo`c3D3?%x@cQ!bUNaYU5+M8V)3kb&}3ciG}pm`of2Dv+c>MKmKgg}eNvD}fP?MDjDwG?Ke6py>AdZOOi{H2l&%JbT zOECJbo3>oOP98V>%3u2iPMv7+zNwBAUUuW~h)O{f58itTf8*!Be*NU12K?@yKRU|d z6duaG`GOWq0v%s?s-vRQeqhChqJCYhSbZhE7z>IqQ_p>~!fYIZQl1MZ8w1&Fv?e8& z&=H-m1+qY6)+17@u|hhFcUcX2Oz7!Cg{0ZCSSwSH!w=ZwOmzq|LQtaDQKcw|001BW zNkl)V_Z4CSVtkHia|WJx=p6owU;6S5_5Q#2#Ru`?**oc^m!&K?S$%2Mh73_s z(1;bIHPON#jJ6N!3_=n(CAD5*n!?$pm^UV1rY&PS&@$kNkxh~gX_ed_RC5p(3W$U$ z=+OFFV)toJ1Sa2oHV)BY*&XG*b?D8#`-~#Oo!H}geX=4q6=>@=<046qKP<>HP-xIJ z_g~9+De$vT2*ebktzY{DB6i+_mTTWhfMT0lu(T~C)O`WI`pvuXCtp2_kABx#+|mv~ z*ZBJ2{TK1y|MHjd+kf%^e)kLa>klI57HWUHbCLgpwDzF2|qiwGBok*>qDVDWrsiVy|p@k~J%qo`!WoprWN3 znI9t=m2$kg^8jM>CKS8n-dEuX-~k++Mr#!AIoQOp*v*YKW6hF}AQ64Ghw6r%GUoK4 z#GXhLifyJui>hnsAm_z(~cDJ{p14f9thHUcHq{RS>Gwd1i$|2 zNAR5wox{C%8E!d;pd0u)e$4O-AA1qM@Ua*1jngOa!fPjR;gaH>Q-^ru{TK1zy_awJ zKFtij`l;{6h0Dh>>R&zdwbG3JBppH=>=gxFTRn)y@4I3T9DPpd!8tQv<|;^K=Lsgx z0iW86a`MwDZ!|raCL+jHvjc_)?qg;)SbAcXwZLKGDPgCbbH=(QSf|WFY#4Zg$T)rU z7OA~4*$YR{G4``r&#cMO*N|MLhPv#W#FEpZwg1@a1nkkfuy^ z%9BQ2i{#$azU^DwxVotbNa0s2^*r3;_Xz{ffHhk4>>D6HmsMnH+45h2?zp1BkM;I}`BD~Gt{fWCL?>yN(n0DkLFzhi)P9aPNH zY#IGEigX*JS67i~6v+#W@gD2}{3fZeYF-EZc_1cDC^2M+-^pR4x%J6_Mz@nD-7XyT-9CUUql|B;UEH&lqbu6^n`!xK61C->AO7nfa zj$Tf$;uV+fr_)9&nyh^zQXZ|utQmOnxqI<Od3|?%fZn^wA?RK5^*dkqAb#!l zeqcMLG~0J2a*vKlPCBI_)AgV+0V+NLdZX7$jT0YsV%w>#WD7VZm z%~$Tm|MnXn!N2xXU&9j*pTDJmzPIx0(iO!&`Gb$(Po8=>pM)$Vg6zrnQ&RU8`|MSY z0D+0#L(76ve60!q^t=>E-T>3{RN@IN5PKF&v066Cf|Jy`M2XiR(!plS`V0315bZKp zbb0R<05J6a7-Pb4`R%uHMBbByHU(azNx~ucuzP2mk0_eji>ve=@AFs@n};_-WD7D2_QOe%&Y&%Gk8S zJqmq<2U+?6%zb|r8VwJBO{N>VK=w6czEYkiZEn5ol&MX@+MhCMEe45hN*t!2tMm#W zJjcaPcaPLWUsQeUW|6luMu)8Z_wk$!kq`*Mm!2Oe;#qxTVVkG>NRJvHBL2J<*pkd! z58DhpJPI6b3mj?7qrUvRkNg@mrXOx`Fa`xZAjCEoA+M6$y~vX6wV%N{coo0<7azc% zJar#_?xWA*UwPv6>?r(B35VV#UoV|Gj(_&q@4*+p`9R9HQ_)E{#ACfk^j$=L%{~EI zTz3{HIcndpY4K|ElPq>yC}1_Phq{iEHtg1BSg80gB?Sern8ZOeT2xG#1vT`9fysl( zy(KPc*Lc&ojU~UGE3j$5NyP_4(`_+Hx6o3I6yb0SqD@0g`tNO-1qr$3B8`r7^Y#UK4T9)ABtyrT|5?}D!jmv;E%=bpf)zw#&yyEM%iT^7U|?6G+FQ!#;p^jH%Qzn=U))ue_It4Le9#xN`EzO8LTHf??9UPDd3dzd z_^($wUgn$ie8YS@C#+aM^|$xOf%z7Tv6(@&;Rhc(ji315Z{gAVFTCp*eQ)*Gx$_73 z%-0^pr@!yLX`~W})7ci{6tY1jN47~2HW1D$E z{A|R0IVpFTd<6NY=K&6I&w9q7B@@tEQEWANZ&6GDZCmMY9y?~+^D*?>44h(+k=(MZ z8-{d~ionQqh)z0Axfzf;xM`z#;7&re{cyB!?x&y@wrRdGsBF*w&z^n=pL_ZteCWZ~ z@DtzjO?>ZTuWV)DEe!O1{e^q*`(ODWKL3q}aMX6$t)|$BO^LYdp9f;bl_>D3%m-%g z0C((NMu=sX9WCJ<&>zD-MIxLGgXkz0rDcf3;B{*L}U4Ai2uUYa+0zO~%Pcr2vv z_cGr6wOHJy5dp_i8(_WVL1YM69NZS~w?*}2QElCO@&bPFL#OfGkGz7%A9xK1JG*I0 z{?>qRy>b`6`uu(P+%pg2`B(0Va@^Rp762z=CYvip{u%TGrcxf9Ld7%lQvL%u@H0_w z_oel>BD#^4)3tBboVW-|m5C@Lvf`s7gs7}HJ}!? zpAOk^?&s(G8AQAR9PT8Oisb31pSH2s2Vl4TeJp*xqLeeNzi_wp$` z|JvPn?zKDdjnnVLrNe_n92>rS?l;LNIFfypn1pd?{8~-M1q$yy%YIQd61K>SQ(C07 z8LLuU*D~Cd%TBOo`v%}39dYzkZy>Kw2l$u)Kdv6eV%GHiRqByWlZ0ALh^X@bm|kQA z3i<$U>+gkJd=1+;PMe}>+vfXY2!W=6wutwb&ZaO6)y*Ju;0KtIHXY+N6-8^U@2DH$ z#%#C=p=~||Y8z8;GbA0PCYSrA0il~&HjHs!qSF(Y*)77wS%6`Q9?k{*Av|8)g6%sp z2KsX#MWkZmFE|Hd51OH!j*gp1PhqEZ&HsJDg7RS`qAhiS&&{#}mu`rDd z7cR|~bIcnc6ke0^6^Ur0k^@ACp(qx;KLv{d6Q3c!4=735IX!!_2V0PmHX=}8;M-xh zjq%1B)F9i$D6NmG-1)f?jZp!#?)h)NVMxBW<_SCfxVDtQlc$lXau_V&&bxPeaqAf+ zTh-xFLc<~)p2!gS2CZMP%~~V{F^^BAg>%p#_(-oTI&kOS2d$5B97y%?VccVb@vHNN z@5dLrF!e<%phTq58}RK$u7Q^@M&=o5;o5k2FCQMm<-<&^3??VBH7OsKNMaZfZ%LKL zJ2p!21l!6}2Mp063fDFIu+M;r5bxAKxvxes#>-$XWsp*HvSm*5AQ zv-rAOhz_j2TY+^BLLZ}eu7T`&Z{JyrM&rZn!8J~8>5*h6{>rvj+Pqch*#l!-AW=!A zej%b3H9jY$4Pu=BB*Gf6bO3R#*PtChFmxb7I*)|f_s_R#HJH$2DD!=D-oDLL*WTYu zi`Yh_moFTXIZao}V+k!dtfm2F)?SH0J~8kK#M=0Cog59C{i7%oy{f>9RaoiBs5u4u z%}MIXu52vA6_xryJlcbUc(eK`augSX_V_F=;}NRC2>NK_*; z((lh(6hzT57D@nwbdqju)Ku5>cIZ6~i`^Tc? zDn$kh1d6Oai`PqZTs{fn_ewV4s1`H=M7Rt$0_YSng<%fodYOqsszeT&z4n!*>pI^? zXnMd&#wiZGjuy29f+mqtrS#@p!Tl^ie_i}|n3#UmBe33g2&Jf`tBgq}Egg&LjB#EG^w$y*7%u;toXgb}j2;ReO>D_i)%RJ;05VV(VFrlW1qLGxED zT`%YQb(NuXVvg0@nndKezj@6!MzH~qwr!)?8DP@JLGPLXUwYD_BJmBu2LEX+MmUhD zX;E4Lh{L1My$K_^DK;{ybm;MXk$7a9w{QMjw-r@l)H*}b=!%dG(iaJ;B{dtH&rVeU z|31rn3$bSqfa*A}7+NS&Z;L&k;A9=9vm`kGPFYkyviD9Kkz9RZAS>^}g+NH_bO9(C z2ennvBqXYj7mUSfoD+ngZOsM<7;+f{nzsZ#=kCfq4}Ii3&N#R`+i&Y}9ZMKldfrb+ z4mHZNQFi#7=`)2M3LT#7B$XoGYoM&6EWK_J9zFU6Y{@`!loPT@ zXYPEl3dBUWkXAEwe5_xmjsaPKk^!!oBho@-q-e+dTl4Pxo!HG_*dI8%4fg z(-;iIdt2S=q@J!;G^Mh-V+1Xnl)c&+(*lC{V=^#$bs^owT#_TqN!+M}X6y|7nQt+i z*vp#(k3?m9FVpZvN2TIw&^$7x(Pu*S0Zs{)w0p<`Bpj84EqeMy+l>fp%t}BkoT{c1 zHydoQim)mX*Y;nUV!<^z66-bX==SpfXwgzgsmg-aU)u)-QIQuLQw2b2lQ<9t?99`0 z2jXXqxyXE_Xy?gq7rHb~_sysH);35t@d&2Czz|jj9&EZ%(Y%6AhhuMVC49^n(qA73 z@=4r$?m-K`pQ6?*N_ByunP#9Y#0kpRXFxm)ck@_@a^y(6$*rJ&xEP%#y zjv2@p&BZs|+hK8XixDuWBhfh)ZveQK<)fGv|5)k-IALb``SMKKkJ#MCV`u^MlKW3O z#j`A!!#;CR25lJA%)EH%lfY;s1Y-i;u*egr`i4x?y$*+A)Tw}`X!Y#tC(}aS=WQ4S zBG7B2>f}IV>$9b`uc}w$0tOkyhSfRvITr-%Py9*#5rt%8g6S>vi*q z<=6T_)@{8zVy`B!*0Fr0!G9aJDj)>x zbyXq-w4`31s&!a46A6GZV%ibah<_GRs6`SWU|rA%D!;5tdrJl=y$o&bWm#78mMR4v;71>avMQVwr0O7naz z&q0e;VU!Fk1wu^-O6f+!yWn7h3R=wPd5ojzz~0oBZy1600FbSJRx$?B!G(9JWS{v5 z=%<~!D>=`{)pfNSurhUsLfJN1a;O9$eO7N%iMy>I?c=w>7XU_LkSQbQ4i++-$0jlk zqx{x4H3tua1sEr^m-FLP7U900HWnF{Yfe~7BEdnlrvR6(>Qo3p6Y7godk7D4JxF(!_t=WZl|0G~$)MdwC zEN1T6zn?Y!<9W!KQ0R;Uum>SnT;%r`_pMpoIJp+nYn7o}sBOcFBXO{ezO^s^Yqri zva!ZEDJ=^BMh7lW5W)}8GS|=hcn1>wc{v%$u>pa?8UtrSE<+3q`o9uT+IRrWE44A}-(IMpwZSZEHVhS7KNSZ^(WYK10<;~`Nx7)XOl)CZw^+-Ir+8|iHF(?)Y06E7*wsnkO8vH<6k)r zk(tPfm_s=dV-wOLDUQuhCkCNVO7=uerj1TTuAY4XkeMph!KqGT_7=c*zD9;0&ZT$c zS*TtVq1kqy0c+b9aPvF&#h?;i9c|$2;R}pb*9@i7AEF@3!}}}ef&EbFKy!* zghP*0LEAQ-vu*?CrM^gL{fE`3Ckks{aF$7_W}!=PErArFj?0~qvT zA(PQE>u;6-L3Tg#QJ+H`W5z!?5(wO2a45KXs2j+@3!c^6@@Dfqr&HcZnn{J2(D^R-9&${p5R_6A$!=IIv!F6DD z*86(NnK(Vv! zbh=wc`qLDk0Eg7)&-(sSJ{RX8OAbKQOMn*r9EJCsPUY$(p_Lfhw2H$vivE z`2y8GY`=<-7EM$LNUckZ>aLn7|7M&e0)#~qA}u2AfccWr?6oh{`;yOShO+5w~RVS2$dQQ z{;8EkQD5>wDITnvoF*38^Z1$2YZ{ev?Os z$w)+yOf4fv0!7(|x=63GF_er;mH^Lj;)|c@!hkdYMV*v<(?)<=ovaj#nlu)(E3#fY z{A49*mcnHK=Lur-0}ve_fUKA}bn!ap+xBb}*~Di^RJRSp7hykz+?}UeeXF?rmY2Ue ztZ@2etX_>YCbn!Ra+5vjKOuVA08a0ETQ%_@lFwkc4FF(h0%;Zd6vZ<`)LS5p`MyhV z4WpEg)10^g;@0XuH5J-8irzmNfs$*7u>y%kjF#-eiEb>mq*gP1x6+71aY+nBCRztR z(3zzLXQh+BIs^@1&%tLQ+yI&_#H3CYqP)$RainxJvNE zB_nID>Ag<3SMWCGfv-smAY&>LxQa;D8YFgL<^iaVNkkGAsqD27kM;p&4zI2SDV2ca zslpsSIunCX2s~5#m{yQc=TW5Od_E!a&Lkkx+OBXLW24R@000OONklsKe0 ziim6@yuLbBHd7M^GK29;n*$qjSQ8S|Y#>n>c1nwVXV(F*4QsFfzcvanV(D)7X4{41 zW*~9m6Y@X&0%^FJbjg0wj#W2&7JRc(I{aw?l?Q70ahoOMjJj*GGtiBhhe{+HNpHi% zhHKBLWSDO-0M;Nbk;i{feTfM;oQ_tDyAp;*2E}|zuj0W#3$8c=Yc9D%7F<+;JTXuR zE!bIfGl)vM$Aq*n4YBUyp=+(cB>j~+2F*7!>I-PWrBS4)~PuYstueL649Qd&v{ z!g^Ck4nH%akbC`EIhf5wV#899>o0FONF=0WRaTdd{yT%4U1F?Ao2AqWz^tIP zq(oEIj?x>T&T(%sv(CE!1AxhFk7n@#>C|ECoC4`%k=a8S0STfL&04tVRPOq~#d3V|i|2ABd#<4%fKVeDk%)+#gWIp9% z44BJ%AxiN$tx-+;6 z?7j$fBLTV1_~aOz-MccVAKU=40df*dA0?u1YVKFCQFC>S#bo^MPypJX;rasHj_ls% zbU=>15HSKw{RosG7S+XxNK=l&gI$&+YXKaSaKKK;3Z0|Z3%{6(HVOGN1AHEc;un*d z0SCLti)=2aQsx|G9|UFyGNNyB4NzJLj3xoyj@~W9l7XzBfJRjV9Ur_PWsw&!O%j;m ziv-kF($Lh;D^g$x*cwdpbJ5}!ylxHF@?%|0Dy}6pj%tShL7{wrjS0Bf0L6vnQQhh# zVW;l4(A2m2@J}B0tf{r$K1k4o-Rf&I3Ms;!zKS=M0NHU9s9{T`V4u+!XC5J+(?s~? z#oc^d$$fe2%EaMP>KlpcBc#mD9cgEIKHQd^hyrZ24KrdS4)YEWAZyaF6K_qZ?B`S* z^OrJ0NZE?r7-S=bU-BO`%Pvn|KP6F>k~5KE=M-Ns5ZR|7tSUp*8UV5r5@}`6fxu2E z%Z@9G%#a&InZyCW%HX32f|zHZD`(-_Drl|($dp8N&LH4QC4@P+mQMgC`|dhYgsyw~ zlm=8nRG^Y6)k6$4NHz^azT3j2b2G&dX&rzgLyyT##$vpe%*De%#KI$gb&$IQuQeIg z<6WO%t>sgK6^ef9k&BPpbE~!O`)xb1!o1TjdL0YM>HQ|V&5JOqghYxDU^_r7CKWkv zp>rgJsKcI52q|Sfd*G$=8vu5LJ1jQ03hcoox#SNt$de@F2nNE3rakmzb; zceRLd3}kE*lO4Jdhep_54&xH=q{qgKpKYdo+EE!Rg{cC3P7QZ0QLm%4J5)(l07&13@mn9mUhz) zHazycYSHofv~NVMb1@l&R0iPe2f_r zcR;eCDJKIjT!UsiZWJl-B8PxUI4Bqan~7Y-0vt<2l65t~_mvWg>l7d?z-%MfY#M+r z%rRH?ZBH=dxS{BqTYw`vk;y(}@8F5)1g@olX8#RY)cxAE198=9cG}$*iH>NmKBFI_ zE!(gN`W?q0yb=Ji+pmA9*2h(fLa^~N)sDKt(unskHrS|sT+}0ld=rEsGVt&jzY~je z?yFU*aTu3^HZujUGWJXEKONg>woOcSG@=Y?xRKhDjX+s*0g6;ZNeyC$qwX>36lC#s zvCQY~Dk7r6p0mNJPu~5V&yU#;uvP|;5xKSk@sSApSlZ zgCwv1J<36lBhYXW+P~0Kg`n5k3|7`@*-YgB2St5NH{bji2><{907*qoM6N<$f<`d= A9smFU diff --git a/script.module.iso8601/lib/iso8601/__init__.py b/script.module.iso8601/lib/iso8601/__init__.py index 11b1adcbc..5667a2cfb 100644 --- a/script.module.iso8601/lib/iso8601/__init__.py +++ b/script.module.iso8601/lib/iso8601/__init__.py @@ -1 +1,3 @@ -from .iso8601 import * +from .iso8601 import UTC, FixedOffset, ParseError, is_iso8601, parse_date + +__all__ = ["parse_date", "is_iso8601", "ParseError", "UTC", "FixedOffset"] diff --git a/script.module.iso8601/lib/iso8601/iso8601.py b/script.module.iso8601/lib/iso8601/iso8601.py index 0c149f679..2a8289481 100644 --- a/script.module.iso8601/lib/iso8601/iso8601.py +++ b/script.module.iso8601/lib/iso8601/iso8601.py @@ -9,18 +9,11 @@ """ import datetime -from decimal import Decimal -import sys import re +import typing +from decimal import Decimal -__all__ = ["parse_date", "ParseError", "UTC", - "FixedOffset"] - -if sys.version_info >= (3, 0, 0): - _basestring = str -else: - _basestring = basestring - +__all__ = ["parse_date", "ParseError", "UTC", "FixedOffset"] # Adapted from http://delete.me.uk/2005/03/iso8601.html ISO8601_REGEX = re.compile( @@ -64,114 +57,51 @@ ){0,1} # YYYY only $ """, - re.VERBOSE + re.VERBOSE, ) -class ParseError(Exception): - """Raised when there is a problem parsing a date string""" - -if sys.version_info >= (3, 2, 0): - UTC = datetime.timezone.utc - def FixedOffset(offset_hours, offset_minutes, name): - return datetime.timezone( - datetime.timedelta( - hours=offset_hours, minutes=offset_minutes), - name) -else: - # Yoinked from python docs - ZERO = datetime.timedelta(0) - class Utc(datetime.tzinfo): - """UTC Timezone - - """ - def utcoffset(self, dt): - return ZERO - - def tzname(self, dt): - return "UTC" - - def dst(self, dt): - return ZERO - - def __repr__(self): - return "" - - UTC = Utc() - - class FixedOffset(datetime.tzinfo): - """Fixed offset in hours and minutes from UTC - - """ - def __init__(self, offset_hours, offset_minutes, name): - self.__offset_hours = offset_hours # Keep for later __getinitargs__ - self.__offset_minutes = offset_minutes # Keep for later __getinitargs__ - self.__offset = datetime.timedelta( - hours=offset_hours, minutes=offset_minutes) - self.__name = name - - def __eq__(self, other): - if isinstance(other, FixedOffset): - return ( - (other.__offset == self.__offset) - and - (other.__name == self.__name) - ) - return NotImplemented - - def __getinitargs__(self): - return (self.__offset_hours, self.__offset_minutes, self.__name) - - def utcoffset(self, dt): - return self.__offset - - def tzname(self, dt): - return self.__name - def dst(self, dt): - return ZERO +class ParseError(ValueError): + """Raised when there is a problem parsing a date string""" - def __repr__(self): - return "" % (self.__name, self.__offset) +UTC = datetime.timezone.utc -def to_int(d, key, default_to_zero=False, default=None, required=True): - """Pull a value from the dict and convert to int - :param default_to_zero: If the value is None or empty, treat it as zero - :param default: If the value is missing in the dict use this default +def FixedOffset( + offset_hours: float, offset_minutes: float, name: str +) -> datetime.timezone: + return datetime.timezone( + datetime.timedelta(hours=offset_hours, minutes=offset_minutes), name + ) - """ - value = d.get(key) or default - if (value in ["", None]) and default_to_zero: - return 0 - if value is None: - if required: - raise ParseError("Unable to read %s from %s" % (key, d)) - else: - return int(value) - -def parse_timezone(matches, default_timezone=UTC): - """Parses ISO 8601 time zone specs into tzinfo offsets - """ - - if matches["timezone"] == "Z": +def parse_timezone( + matches: typing.Dict[str, str], + default_timezone: typing.Optional[datetime.timezone] = UTC, +) -> typing.Optional[datetime.timezone]: + """Parses ISO 8601 time zone specs into tzinfo offsets""" + tz = matches.get("timezone", None) + if tz == "Z": return UTC # This isn't strictly correct, but it's common to encounter dates without # timezones so I'll assume the default (which defaults to UTC). # Addresses issue 4. - if matches["timezone"] is None: + if tz is None: return default_timezone - sign = matches["tz_sign"] - hours = to_int(matches, "tz_hour") - minutes = to_int(matches, "tz_minute", default_to_zero=True) - description = "%s%02d:%02d" % (sign, hours, minutes) + sign = matches.get("tz_sign", None) + hours = int(matches.get("tz_hour", 0)) + minutes = int(matches.get("tz_minute", 0)) + description = f"{sign}{hours:02d}:{minutes:02d}" if sign == "-": hours = -hours minutes = -minutes return FixedOffset(hours, minutes, description) -def parse_date(datestring, default_timezone=UTC): + +def parse_date( + datestring: str, default_timezone: typing.Optional[datetime.timezone] = UTC +) -> datetime.datetime: """Parses ISO 8601 dates into datetime objects The timezone is parsed from the date string. However it is quite common to @@ -188,27 +118,45 @@ def parse_date(datestring, default_timezone=UTC): constructing the datetime instance. """ - if not isinstance(datestring, _basestring): - raise ParseError("Expecting a string %r" % datestring) - m = ISO8601_REGEX.match(datestring) - if not m: - raise ParseError("Unable to parse date string %r" % datestring) - groups = m.groupdict() + try: + m = ISO8601_REGEX.match(datestring) + except Exception as e: + raise ParseError(e) - tz = parse_timezone(groups, default_timezone=default_timezone) + if not m: + raise ParseError(f"Unable to parse date string {datestring!r}") - groups["second_fraction"] = int(Decimal("0.%s" % (groups["second_fraction"] or 0)) * Decimal("1000000.0")) + # Drop any Nones from the regex matches + # TODO: check if there's a way to omit results in regexes + groups: typing.Dict[str, str] = { + k: v for k, v in m.groupdict().items() if v is not None + } try: return datetime.datetime( - year=to_int(groups, "year"), - month=to_int(groups, "month", default=to_int(groups, "monthdash", required=False, default=1)), - day=to_int(groups, "day", default=to_int(groups, "daydash", required=False, default=1)), - hour=to_int(groups, "hour", default_to_zero=True), - minute=to_int(groups, "minute", default_to_zero=True), - second=to_int(groups, "second", default_to_zero=True), - microsecond=groups["second_fraction"], - tzinfo=tz, + year=int(groups.get("year", 0)), + month=int(groups.get("month", groups.get("monthdash", 1))), + day=int(groups.get("day", groups.get("daydash", 1))), + hour=int(groups.get("hour", 0)), + minute=int(groups.get("minute", 0)), + second=int(groups.get("second", 0)), + microsecond=int( + Decimal(f"0.{groups.get('second_fraction', 0)}") * Decimal("1000000.0") + ), + tzinfo=parse_timezone(groups, default_timezone=default_timezone), ) except Exception as e: raise ParseError(e) + + +def is_iso8601(datestring: str) -> bool: + """Check if a string matches an ISO 8601 format. + + :param datestring: The string to check for validity + :returns: True if the string matches an ISO 8601 format, False otherwise + """ + try: + m = ISO8601_REGEX.match(datestring) + return bool(m) + except Exception as e: + raise ParseError(e) diff --git a/script.module.iso8601/resources/icon.png b/script.module.iso8601/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ca4c53adbfa8d06d0e282d45f9cad195e89d571e GIT binary patch literal 7237 zcmd6segn*PtcXta6B_iEY!_ZO!(hW*?NtZN|0+Q0*Idt6f zyPh}Ce{kQg_FmUH=epM3d#&~T?6X2um1UkhCVvb7z!N!HNp%1Kp{F1K8;l;tp(32< z;kk>Hu8W5K2N!n}CksH#+}_lJM$Xp6(n8(B#N5NN-{KtrP;AOcifMkH-81xZAku0) zJm@Fp#L>;2G$No%IAG+yoYp5GaFu%IUu+;swO88s1zP{pU;HSjZs%mSWk-t&_g@Ho ziEeH*(#E3>d+FdhBsqGE-7A^C1iw#lrA#WCUbnyt#(}cSyFtw7-zZ)*e;ZV!;=a29 zNvMo$PYqt&P;I6i3a&&XS3`gb7`- zv`0p^b-1;)MNL*O`QZBg`Z~2-O6{8@DySvw3zXooW6z-8C5dSQ;;G)FJNM2feEjLd zx3|rD)gR_v#+4k6R(Adtml_@39JU-R9bjWzy^THoA^I+voLSQK=;gxxv4pq1MZl+rfr(Ml0Vruz#l?pv_XVq#QTaK(c^5Me4-ZdI&yGWrnX0PAhx@y>dz3GRnFG*< zYl`Fy+VJgzX_ven;FEj6T&?FSBnn?11$Z5_-lSNU$-TqJSibGu zoT2eUntS50sOvoa84cbSIQicb75taglNv+5r1c8#NYx=&9}CZ2t$7j^JseA;(v z()sgS*PHN?KGWXruYc+jezzPsvjVzEPEhLLBP75pwe_xcrfz7`QwGJ!HK`&Ycx>ng z)V4=aBR=;GKHph7%DPVE-D2DC;tL>aCy`ZAd6+rhZ>ETI5s`cN=n?>?Y42KZ7r9+y z>QFgSYR8cG$l9cYRMZ^>fE@hPN!9XZDp>ee+3&*~xxX_@XA%WEnnK~`P9lM4DsjhC zqUys?TDw6~Frg?iTPidBGrbs}K66yr`+fpsd`!ge6C3}!1y7hVVf&#rQHQYz4XU{V z!ViEYN#qqgy{7%2%8!Elxs138BGO)T*B3kR(H8ki(v@dO`78n0Q0eO#h>G6OVZ7yF z8mIk2^9=ixE@M-d!<0SaM+n0HMIp4oQlaqVfGuA6~$k_n%8)9A?C1k3- zaw~RyQBhH4r5aJ-{#;!wE>R+eL&I4KA4TWn70}NEnVg;V+!|dDrzEwy>1WFHbolfA zawIu9nezz6=c!%E=KLs{AQ^JZ9*U5VFe{F^)~zksE6mSO?CW=SPT#ygV_M*ZOFTsa zp)wj8gjZXXl$7);M&(hZ7DYZ>-p5=;iexCp2@zVBy+L$!VK=B{jWGnBQ{iEP2ryk; zUv~%|;^E;PX_d_Ax0dkB;f)oNy{Czbj~8liTs_+!C-h!Cr@}?Q8-Poyf3bIk5!#x! zFU5EwolL-h8ABiH{?>5qhvf%zA|euY7%ZH74MP<9M_fWe0v)l6{jnKFnwpxrx=C+N zUikx}X=BE&$gYBlEQgB&!%%lMX~SDvL+b9yRiLPspnTIgyQnCPce2FjZX;DDR_QvZ ztc;!g?mWk@6vu(H6-B|aQ(97@Ibn3gR9A>{`-V>rf(VlKSMh+#j9SP?mfP<356g`1 zR?0d$BvHSkIMLb0^Q+Dk3O56P=^!=kl0h!sX+z`Yo7|bUNtaNb7!nTw052f|#YC!w z^M#ly$}-CrK2v2Ow|S9Dm5qZT&R`JM+WO~@Bg^?w-OqTNzVG~bt5Jd}Den}YVe_&R ze3HR!53y>y-`M^7m27qCYdGba5WTtdY<*UKe(%&|PupW%z-vtOQ>6ZTk)366^>8J_ z^i;Ogm(vvAB6E%J?plP6Z7e_9q8ND|eNvf_uhn^QbN7>!d+UDi-lo$;j_qxFdiv1N z(0BS@7*!~KfKE)q*;x?_w|_1G(OgS%k8cY2G&=1c&yuZ+SgC0k4*e9th8u5N5?!7Q zaG-UmdZe0K#At46YJ?Twhr5%?jybGt#oX63^)O(d6~gV{->(ev9cuRI58xMLe2d;U zhd1Yu6Ik-nOk3-eg4fqrTQS-9CLlaIQ6dNa*;$dR_2TlcuQ6r0whK#3g&tToS8$4#yjUJv2?a{0uKU$XiT zGrP8tn~ndK=EKP6Vtd(^oaD;QWIs0od5y9S1LcHss7Yx2DYJB1#8XV;)^L~*HXMHf zXCp`Et3qW7Vz*vG^xue3fsLW?FQ419enoH4zAV)Ay&5oH5x6~{JB$wIOZQ7H1UfIXT` zv@tWsIQ@HE-hJ*9PX)o_p?2^zc|EW45jxNFhfi;(FUM(~$ku zEAr~y`+<$2d=zKhZ;g= z{Io*u4`ikN=CI9ufUVBl(lTm{7_E^~Qr*eizLG{9rbrwjye+x7Pl_e9A|g>;H5FMj zemcjVEg{9lDjDyj#7EwUxS-Fik{?d%|Jc$_SxycI1M`?H5WS?v#zsOW<;&SwhESMK z+!+YONQDJfgm-FRFU6+4hY8h?5R!pcyek?OtJt&>=xYVU}OycPwp?x{g)7b8qwnbpx^XKNd$H?u7(4H zYPA@LscF#)4K}#uo*7&%Mp&u_HZ8Iv??+uf$OrnvK0L!uUjqK1g)$M7gbPotx$BH2 zkP0G8$@n^cB>YqI<3XJ0&(L=EO0o9SWx9T-C$ydM`v_iQsP2T_X793A`f(ZjO}PKVA)tH<}lf1OxXsZ(9BSu$PuQ^VN3yV zQ@{QdPVN+z*X#!d5p1uIWQzFy^2Z`!*FEa=+N{*FOcGEn(ZY)l)t?yUdT+TWw?DRH z#TzqRaYJ|#E`4;uGDsZxlQ%BsDxv1)>2=REnNg8)udIScL)3|9iRT*Ixh#^1;QjG8shTJ$uPc#8mh-7>;j3$JyDCuIbInV4&@1>;9G0vj4DnFfhF=Rf60K%A?T>63)VD7mGsjsiq{ z&Xz-{eb1J!qC`Azk6i=qe=&rUqHV0gSyxzY&KWM~&xQ3j5q|!UFOlbNs%HL!#F;Mw zp_R2^W%2L)P4_or*j9))=zlfG-Q7pSU?xd6d5-lGrb}&hcsyYX&LjBSf7er#%8Rwj z6jf9fD@=T#`^#VkKe_>550d!C_w4!O{i&7R67GBd{w^+-GY5N271EHBlG^LG-DijR zzR+}jskw;t_QnDRnlQ}>qZ!zn2>S~ZPz4(sn5p2o$>F(65R}m2yj8O>)PEH65x2G~ z?zy_<^;=)Ym83??fLrQ;pVPvhrsk%4=g!X0CpC4vS{C;9_B8h!m41=6k3QTtH#a95 zd$QQ5)9$mfu^HAon4tOJ;D+fRrE#Onb}&k%LV~C>2LCa^*2Ee?MVUa4$Ut48QuJ(&7u`%Im#e&#l$4d+b{tExzdlZJU5cv4{Gvz}W;*5tp434muPyl> zr{xaX$qdRBw<)cuiJH1PSXcmk@?yRniMaq1UkFvT=z#nx-{|<<+}iP|-_Q`73#dQ4 zjF%-z16o5>qGRM?u{oTMPTTOXF!i5;Z~hXP>Kd^>zw$*KG-wrTllzZp7#JAnY#!|G z3=aQh)Tr=u6^M1ZE~u#~xsm7Ft*~lw$jIC|7d(K&6u2v23lguU>dqjAeoll8yZsH4f?eB zT&IksFvY~gi1nm1Y^w)^MN()H7cg%GmD@MnJq-z_0Vk;-QfpNU%N*|zi2CvEZxJgD zdp%ps%1FM2&t^j@JTV#m{HmHY1-@`(ppx1=^Hr{|SInN)nI%)O{d}X+SP8Hj&Cop} zOiP_tdmcEoiMsM0esAe<^~(75<@S`X|mp+V!G@-8heL+leWD zexfZBx5x~unqHi0L)-h&x#2?c(lcXl-%P4wALtd-IYXR{fdAmebbgO9Jx|Jr%K+cPv>y zlAdStx)jASsc6K8+B6)<+mtS zoAv|zz`_16O$RLra~x;?)q5s`uf^s z)q>gSyu7qDQrKeXxBP&AM!@cgs2rP+c0zFHc3gS8MMz-Ml0R<5Q=C>&{%p$({1E`x zd;8n+SG_d6!omg?=IG_0H9I^1{yFF=CVyC5;K9yfXCu^i4iXWh3y}89+xP&g*tJo0 z#3mNPG)i7JPs-(%gu%R_KkDjwZ8|=$4K27n&$E%ehvkJo88^!1-Af`U#E<;irt_ij zjAVXlR4}|G88euL(96?H=0yd~vmssx_8`vsoo5924{VBDV>SNe+u-1NYGQ4e0o~RY z_2(^R1tfi6-{@mK+FJ%E!`$>SJ&A&%zMY?)CH+2!;05KDq*{%czxfRzBWZjt=<;mJ zQukDl0AjAw0mhR8d?x93Y48;@<17|>SB^iQHKzT7L|^5Y2;92JGJuIc59nfOHc`8B z!k=JZ1o;s(`8}Z6^3^`oRabMb2>^lw?QeK8hwe}}S7~tDIb*d-Kb7vn;$qzW!_?GF zj$Nz)gwIMPuaCYqt?MHUc6(?@rOcN|obT;8=zLX;S#JkJ^189N;yGS=pYQ3RaS<-o zGMAp2$XCDw!sEh>cCi0fA7ed4$fWY=F4QjuB(ANUkfH=lk`w9sdY;PFHn=l87!Wat zXJ@Io%6TFV)xU_=-E=!8ga7i!K=>|wHD5Khv$KQOx9^i+JYxhP*ht#>l$4#F&X5Fl z!<5+A*z(~RL_=O)FyC~gSxAmj3q9s2?_!(lZo+ND6}_qNL;B&`kXlS4pJnGYDt~u= zd7|x;uxI2#k`_#7+lsldQQQA3w6nY0R8=IB{%_N+0F(Q{znIk6AAcNFgKFbrGL&xw zVhdY7rdJ4*SkLg&)(-HC`UQ{PrPkS~CBAT#&Eb(#naZ>)C@r;!9qAK$Yq}!mq7y!p zQCL=Ha-~7Rr){n>BCO`+?^b&?>v`kJ#vbju@qRk}JFj$>?AXST!I#!O#Fu`X`?Qf= z=fQ>rSJq{1hFTMH!tqHRYyS0DqSbDY3=4~ z(}}K%w2Eodqi;_{^K&dfxP?3IAg45W1qFz!wzyTYbWTUp!P9gWqJ@3V{i(dzqE+o7 zwxOE~ohozS8!GajYqkHZs)8p8XH8zG>QvQfmgo*)R`Jd6;dH^|cY2y7yyOVRJ_a?Yl(1Gn^WUr#a5tMY;dULQokoa)BsUoiRNbr_mZ3%Q6VTTX>30 zW^;zVqobpeE6=Wb{#Nz2JF{j4Uj-uJ|?DRHZx?PF}Q+T6adf-kHGr* zef{Ci*`L{umUbu0(nTKb7Zw)GdJ(9dUjZ8uPEJnK`87)W#zL3mEh!YE zG84!YS66pxuTxzYj)$e?+q^Cg z=Fk2)(|@9OKu=#L8#NsqCnPvqPYFw_e@y5zv!~L+sXlPLo|~JKAsFmy&-Fdb5Hd8J zKVwOE?*G;;z&Mh@PP(==j#HgyA@vRM)vbDNDPD@ym# zEH7UcHWY8I<|9dALeYiExV45XC8olq z#l!|8@RPFp1_vwT&4b}ZL4zgZp9yy;pxF^eyh1>!#P4E|I-_Qd;h}3q7~T6nP;Iv zJwh0pvN_aX?N=S+YzV?*Bh?dwz-l literal 0 HcmV?d00001 From 98bffc7cc1079d00df19518f4c91c23b95ef6d8b Mon Sep 17 00:00:00 2001 From: L2501 Date: Fri, 14 Jul 2023 17:16:29 +0000 Subject: [PATCH 060/145] [script.module.m3u8] 3.5.0 --- script.module.m3u8/{LICENSE => LICENSE.txt} | 0 script.module.m3u8/README.rst | 263 ------------- script.module.m3u8/addon.xml | 33 +- script.module.m3u8/icon.png | Bin 37664 -> 0 bytes script.module.m3u8/lib/m3u8/__init__.py | 64 +-- script.module.m3u8/lib/m3u8/httpclient.py | 32 ++ script.module.m3u8/lib/m3u8/mixins.py | 38 +- script.module.m3u8/lib/m3u8/model.py | 413 +++++++++++++++++--- script.module.m3u8/lib/m3u8/parser.py | 232 ++++++++--- script.module.m3u8/lib/m3u8/protocol.py | 9 +- script.module.m3u8/resources/icon.png | Bin 0 -> 7237 bytes 11 files changed, 620 insertions(+), 464 deletions(-) rename script.module.m3u8/{LICENSE => LICENSE.txt} (100%) delete mode 100644 script.module.m3u8/README.rst delete mode 100644 script.module.m3u8/icon.png create mode 100644 script.module.m3u8/lib/m3u8/httpclient.py create mode 100644 script.module.m3u8/resources/icon.png diff --git a/script.module.m3u8/LICENSE b/script.module.m3u8/LICENSE.txt similarity index 100% rename from script.module.m3u8/LICENSE rename to script.module.m3u8/LICENSE.txt diff --git a/script.module.m3u8/README.rst b/script.module.m3u8/README.rst deleted file mode 100644 index 4574187f5..000000000 --- a/script.module.m3u8/README.rst +++ /dev/null @@ -1,263 +0,0 @@ -.. image:: https://travis-ci.org/globocom/m3u8.svg - :target: https://travis-ci.org/globocom/m3u8 - -.. image:: https://coveralls.io/repos/globocom/m3u8/badge.png?branch=master - :target: https://coveralls.io/r/globocom/m3u8?branch=master - -.. image:: https://badge.fury.io/py/m3u8.svg - :target: https://badge.fury.io/py/m3u8 - -m3u8 -==== - -Python `m3u8`_ parser. - -Documentation -============= - -The basic usage is to create a playlist object from uri, file path or -directly from a string: - -.. code-block:: python - - import m3u8 - - m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8') # this could also be an absolute filename - print m3u8_obj.segments - print m3u8_obj.target_duration - - # if you already have the content as string, use - - m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ... ') - -Supported tags -============== - -* `#EXT-X-TARGETDURATION`_ -* `#EXT-X-MEDIA-SEQUENCE`_ -* `#EXT-X-DISCONTINUITY-SEQUENCE`_ -* `#EXT-X-PROGRAM-DATE-TIME`_ -* `#EXT-X-MEDIA`_ -* `#EXT-X-PLAYLIST-TYPE`_ -* `#EXT-X-KEY`_ -* `#EXT-X-STREAM-INF`_ -* `#EXT-X-VERSION`_ -* #EXT-X-ALLOW-CACHE -* `#EXT-X-ENDLIST`_ -* `#EXTINF`_ -* `#EXT-X-I-FRAMES-ONLY`_ -* `#EXT-X-BYTERANGE`_ -* `#EXT-X-I-FRAME-STREAM-INF`_ -* `#EXT-X-DISCONTINUITY`_ -* #EXT-X-CUE-OUT -* #EXT-X-CUE-OUT-CONT -* #EXT-X-CUE-IN -* #EXT-X-CUE-SPAN -* #EXT-OATCLS-SCTE35 -* `#EXT-X-INDEPENDENT-SEGMENTS`_ -* `#EXT-X-MAP`_ -* `#EXT-X-START`_ -* #EXT-X-SERVER-CONTROL -* #EXT-X-PART-INF -* #EXT-X-PART -* #EXT-X-RENDITION-REPORT -* #EXT-X-SKIP -* `#EXT-X-SESSION-DATA`_ - -Encryption keys ---------------- - -The segments may be or not encrypted. The ``keys`` attribute list will -be an list with all the different keys as described with `#EXT-X-KEY`_: - -Each key has the next properties: - -- ``method``: ex.: "AES-128" -- ``uri``: the key uri, ex.: "http://videoserver.com/key.bin" -- ``iv``: the initialization vector, if available. Otherwise ``None``. - -If no ``#EXT-X-KEY`` is found, the ``keys`` list will have a unique element ``None``. Multiple keys are supported. - -If unencrypted and encrypted segments are mixed in the M3U8 file, then the list will contain a ``None`` element, with one -or more keys afterwards. - -To traverse the list of keys available: - -.. code-block:: python - - import m3u8 - - m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...') - len(m3u8_obj.keys) => returns the number of keys available in the list (normally 1) - for key in m3u8_obj.keys: - if key: # First one could be None - key.uri - key.method - key.iv - - -Getting segments encrypted with one key ---------------------------------------- - -There are cases where listing segments for a given key is important. It's possible to -retrieve the list of segments encrypted with one key via ``by_key`` method in the -``segments`` list. - -Example of getting the segments with no encryption: - -.. code-block:: python - - import m3u8 - - m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...') - segmk1 = m3u8_obj.segments.by_key(None) - - # Get the list of segments encrypted using last key - segm = m3u8_obj.segments.by_key( m3u8_obj.keys[-1] ) - - -With this method, is now possible also to change the key from some of the segments programatically: - - -.. code-block:: python - - import m3u8 - - m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...') - - # Create a new Key and replace it - new_key = m3u8.Key("AES-128", "/encrypted/newkey.bin", None, iv="0xf123ad23f22e441098aa87ee") - for segment in m3u8_obj.segments.by_key( m3u8_obj.keys[-1] ): - segm.key = new_key - # Remember to sync the key from the list as well - m3u8_obj.keys[-1] = new_key - - - -Variant playlists (variable bitrates) -------------------------------------- - -A playlist can have a list to other playlist files, this is used to -represent multiple bitrates videos, and it's called `variant streams`_. -See an `example here`_. - -.. code-block:: python - - variant_m3u8 = m3u8.loads('#EXTM3U8 ... contains a variant stream ...') - variant_m3u8.is_variant # in this case will be True - - for playlist in variant_m3u8.playlists: - playlist.uri - playlist.stream_info.bandwidth - -the playlist object used in the for loop above has a few attributes: - -- ``uri``: the url to the stream -- ``stream_info``: a ``StreamInfo`` object (actually a namedtuple) with - all the attributes available to `#EXT-X-STREAM-INF`_ -- ``media``: a list of related ``Media`` objects with all the attributes - available to `#EXT-X-MEDIA`_ -- ``playlist_type``: the type of the playlist, which can be one of `VOD`_ - (video on demand) or `EVENT`_ - -**NOTE: the following attributes are not implemented yet**, follow -`issue 4`_ for updates - -- ``alternative_audios``: its an empty list, unless it's a playlist - with `Alternative audio`_, in this case it's a list with ``Media`` - objects with all the attributes available to `#EXT-X-MEDIA`_ -- ``alternative_videos``: same as ``alternative_audios`` - -A variant playlist can also have links to `I-frame playlists`_, which are used -to specify where the I-frames are in a video. See `Apple's documentation`_ on -this for more information. These I-frame playlists can be accessed in a similar -way to regular playlists. - -.. code-block:: python - - variant_m3u8 = m3u8.loads('#EXTM3U ... contains a variant stream ...') - - for iframe_playlist in variant_m3u8.iframe_playlists: - iframe_playlist.uri - iframe_playlist.iframe_stream_info.bandwidth - -The iframe_playlist object used in the for loop above has a few attributes: - -- ``uri``: the url to the I-frame playlist -- ``base_uri``: the base uri of the variant playlist (if given) -- ``iframe_stream_info``: a ``StreamInfo`` object (same as a regular playlist) - -Custom tags ------------ - -Quoting the documentation:: - - Lines that start with the character '#' are either comments or tags. - Tags begin with #EXT. They are case-sensitive. All other lines that - begin with '#' are comments and SHOULD be ignored. - -This library ignores all the non standard tags by default. If you want them to be collected while loading the file content, -you need to pass a function to the `load/loads` functions, following the example below: - -.. code-block:: python - - import m3u8 - - def get_movie(line, data, lineno): - if line.startswith('#MOVIE-NAME:'): - custom_tag = line.split(':') - data['movie'] = custom_tag[1].strip() - - m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8', custom_tags_parser=get_movie) - print(m3u8_obj.data['movie']) # million dollar baby - - -Running Tests -============= - -.. code-block:: bash - - $ ./runtests - -Contributing -============ - -All contribution is welcome, but we will merge a pull request if, and only if, it - -- has tests -- follows the code conventions - -If you plan to implement a new feature or something that will take more -than a few minutes, please open an issue to make sure we don't work on -the same thing. - -.. _m3u8: https://tools.ietf.org/html/rfc8216 -.. _#EXT-X-VERSION: https://tools.ietf.org/html/rfc8216#section-4.3.1.2 -.. _#EXTINF: https://tools.ietf.org/html/rfc8216#section-4.3.2.1 -.. _#EXT-X-BYTERANGE: https://tools.ietf.org/html/rfc8216#section-4.3.2.2 -.. _#EXT-X-DISCONTINUITY: https://tools.ietf.org/html/rfc8216#section-4.3.2.3 -.. _#EXT-X-KEY: https://tools.ietf.org/html/rfc8216#section-4.3.2.4 -.. _#EXT-X-MAP: https://tools.ietf.org/html/rfc8216#section-4.3.2.5 -.. _#EXT-X-PROGRAM-DATE-TIME: https://tools.ietf.org/html/rfc8216#section-4.3.2.6 -.. _#EXT-X-DATERANGE: https://tools.ietf.org/html/rfc8216#section-4.3.2.7 -.. _#EXT-X-TARGETDURATION: https://tools.ietf.org/html/rfc8216#section-4.3.3.1 -.. _#EXT-X-MEDIA-SEQUENCE: https://tools.ietf.org/html/rfc8216#section-4.3.3.2 -.. _#EXT-X-DISCONTINUITY-SEQUENCE: https://tools.ietf.org/html/rfc8216#section-4.3.3.3 -.. _#EXT-X-ENDLIST: https://tools.ietf.org/html/rfc8216#section-4.3.3.4 -.. _#EXT-X-PLAYLIST-TYPE: https://tools.ietf.org/html/rfc8216#section-4.3.3.5 -.. _#EXT-X-I-FRAMES-ONLY: https://tools.ietf.org/html/rfc8216#section-4.3.3.6 -.. _#EXT-X-MEDIA: https://tools.ietf.org/html/rfc8216#section-4.3.4.1 -.. _#EXT-X-STREAM-INF: https://tools.ietf.org/html/rfc8216#section-4.3.4.2 -.. _#EXT-X-I-FRAME-STREAM-INF: https://tools.ietf.org/html/rfc8216#section-4.3.4.3 -.. _#EXT-X-SESSION-DATA: https://tools.ietf.org/html/rfc8216#section-4.3.4.4 -.. _#EXT-X-INDEPENDENT-SEGMENTS: https://tools.ietf.org/html/rfc8216#section-4.3.5.1 -.. _#EXT-X-START: https://tools.ietf.org/html/rfc8216#section-4.3.5.2 -.. _issue 1: https://github.com/globocom/m3u8/issues/1 -.. _variant streams: https://tools.ietf.org/html/rfc8216#section-6.2.4 -.. _example here: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.5 -.. _issue 4: https://github.com/globocom/m3u8/issues/4 -.. _I-frame playlists: https://tools.ietf.org/html/rfc8216#section-4.3.4.3 -.. _Apple's documentation: https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-I_FRAME_PLAYLIST -.. _Alternative audio: http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-8.7 -.. _VOD: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-TNTAG2 -.. _EVENT: https://developer.apple.com/library/mac/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-EVENT_PLAYLIST diff --git a/script.module.m3u8/addon.xml b/script.module.m3u8/addon.xml index f691eb54c..9f196113c 100644 --- a/script.module.m3u8/addon.xml +++ b/script.module.m3u8/addon.xml @@ -1,18 +1,19 @@ - - - - - - - - Python m3u8 parser - Packed for XBMC from https://github.com/globocom/m3u8 - MIT - https://pypi.org/project/m3u8/ - https://github.com/globocom/m3u8 - - icon.png - - + + + + + + + + Python m3u8 parser + Python m3u8 parser + MIT + all + https://github.com/globocom/m3u8 + https://github.com/globocom/m3u8 + + resources/icon.png + + diff --git a/script.module.m3u8/icon.png b/script.module.m3u8/icon.png deleted file mode 100644 index bc7f09185052d58cd1560cb173e4e9cbe152d844..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37664 zcmd3tV{;~57lmU_Y}>YNJDJ$FZQHhOXJTt&+sVXE?&!_)FW&0v>aPCOb-H@*wb!~% zq@ujUFBohXARwS$Qj(&|KtRAhx4=M9AU~HyL;d!0klVoc7!ZWn@p;cbk06X>Bt(I}|2qnL%9DYBl4_+yg;YH@u6iKTO;!`hpLb;J ztDFAV-vnNVS$YHj4FFGIIfa3lo064`=ONkmahT{AAxo+d;VPRt9V`G%` z-2?bntwFEvh}%7H(}lO%^e67Zt3{`M$6`)n_eHl|Bz~{Uu6h|}n%E&gVQ13p{p;HP z`#Knb7co+F0GIYmNw(?A;XOh)7iGRXfZ%z zeSN*+TF|!f)Yyp~`X?s5gwto|!|C67`}gC@qrvU9*#nsQT95Cy8x6Tyj`kv z8nBD8(b1C=J1T7qZw>#EG+2ux(3GLOo zZ-Vc!Z>fr?k1!Ibbf1~4TmRRyy@J6f0Av_dR)vO)j7+pcp8+`hEmEx}ulRV#*WHSp zjEhLwzc*Yc7jBe8<7F!{?AQ(V>rk*n9yPgR+JKSe?*0Y;ihBjKB zoF31WB&Ee6_JTZ89Q>IRMP(6CIE1Kem$KhJ^7!5X07wq@hd(M)qp@dcH`0PTFC>X) z{dQulM zgU{CpM&I)pN%_}=z#D}CAevyzh)FYtZpy%2{HV?MXzg=evSZP1{-q_b+CXFaVWCup zgoGsD_c~LnRw!-PrWGfa+*7G%zGC@ICK=!LyH^*qvsbw?Vlgmx=z(OP(Ji5B_9?My&XF2Lc{HD-*w7t!h^p1FU4}y2Vab_lOX1oAX$FY4N_~LYp&D z99oVAt@tM1GO2zVksQMmx2?E7|pS3sF z6&V`R{}^G&<@EcbL#=sd^FlNTFS5kibJLqjfVVv61n>-)srNFtsbi$Vx7xj_vJxBz9@WgtP zsFS5nq7X3`$YlBP6keN?fKwUvmbN}yEJ%N$9aSW`9^$_Rnf>#8wfX(xclrV)Zf|ev z33QgGOaD_vdhd@JJ{J`H0ocHIHtam??CeZTi5EA;pE;LJ%Qg#X(^3SD-h+>iwNq)= zp(2LN>JXp33cHKj9>FhMzpzhIkaoF91@-@;XjmDej{%t+T;kiDnamtZhZ2XlRZGnS zDI$Q<0aUbu31!IC-ptDJQzm|XHNuPD_xSd#Up9?Ijlw>KgdS!u*Y!S6*7iNFt_}t9 zAnMG2)Vr50yWngFiQ?O>u!Q{EOV4OudXF51E7oEK8; z-MNM15IIG64CezKJ~y7ezWjD!=(hCYLNy2;!2zy1Ci0E~*qD8O+$JVp!o2=A`P{5|`c5x4d9q;g2| zZWSh|uZ9kl&*8*^ccxeRvnU>wNUOZ?X4~NI6G(rn-=;guQ8wFtt1)4GKg5_Mv_lDY zXcjQU(?^IKe#@7SpXfh{MiJy|l0Q{syozX-q^Bg^cPdpb#Qf+F^fft~QRm5@UEJS`7+Uzv#L4;k z@sLl2(Qfy5rc}9-!Ds)W)adSHCOgS0DG5{{^%ebV7727WXX;mnUH3c`l$gLSydXO( z8yg=xdsQOb&7|SL*&mS$7`upgC!U@9o=rX z#CgNuqor7zedR18f5Honb$1}583#8quQJ~a5jMd%h`$C4o`bmf@hXDKQU>~iLV->~ zkhjIRUk z@-pF3)kVruOb3GfWWiqs(rqAgYgw5YKDXxgK5u+K`G4bVhwW*f5N~VEns>TK?CkA#|8Ttr6ZrVM*j&yH428oJU}NE*BsD1R z+C(~(4x7RvY&6R@%7U0;wp0h3;ll38Ieb+uPns};Wl|qA=R$Z*t@`a<^o!XQLb{gf zvM|ml>_a2QQ#AShZf-pkZ+eyGe!%hntY6g7FJDqqQ>&2;kaJ%p?O3#8H#ax8-|A@W zXi=?SKC|mKb3@A6SFWp)sKhXnF-qz8DpaII>(oB}G})rE!NkMkb2%GNES4Z29mC5d z8Du-Wy<>|F>P0@eBMYzQEnF-_38sfI2hqI}LEsZTyMFmz?<4df*q;oj4SvEiW%h$` zI??dIcbd!ku;c+ojvN*MNPHjOp-_B%_I1G7POtq{w;;6ynCI^@H5|%0Z!NppxfZkgG^VA?kS^ryd`Zal`N~ z`xhHoFQ$d*L3sU1O)c#Q2-yB6WFFK1w(e^*pUun6Jb%C8aeKQ@HENV}6Gu852!=dp zq?CoE+-*|xf}HRU=`{IgZG91cNnav9$1S?F?yMGk%lrA%}jiV>`&T>?7c!<)dxx|@7rv$^-gj#!CO#x@+WXcZ{LO|p@3JH%pZpO0vdMJ>Y z+j9;@q~^(iU$y#0WntG=r`Lna*6d79^&7qk=`8(TRs0ZHI-#QJNVXWf^~dvJH1;CX#?8P%(STnJ+i*&~0q+iIz3uY*l3n@jAYEja_v2QC z!~U=Dd-pDxKM}@Yy=sfW=C(7(VE7NpI#N5Z#o4x-jPddG>6OXLL1u{eH)!eAeJ3Y}aw0S!;$|Ab- zDT3?j0!Uu}Yh0oF%F1(1TJc$IVQ|bINWu?EZCNlZwR95TuA%8^dhYA-{hxUN`sNO4 zKZLZ`(QCuYMgc&@@qiO5%>VOB3UGorI~u(JwrjH`N7BG27W2Q%`f?doFjr7ia%6mD zT*51Awd%Vb53$YWv+UTvmVg5y+<3vaX?1mT!aMo=qZwy)z33iMk3dm<1zxru%JI2= zDj}MNFw3(`c3d^Jd*14`%a6j6C2AeBTt~;A5nO)m`VJRH5|HK2l_O6^t${3iqnZHm zeVgjLUt*bU`4L1{l6e7tpcg5o$f1U_iOoaSX!a;VefCS!^}2k$^QicYOkkKQhRMG* z?sjNtq}wdCo0~cKo8(i@Gcy@{&!@mnz3$*9ov-Axt=Fm=!$hoL{Ql;4-}c=25&#Rf z=W2!yxj(M8YsF?aug?46)+n%pVdGDbB}yrEC#b|m^bw?_zE zp6$#bRz)}Pq!pE({HPB|ipfTc6@ylnFh+lwN#U2iRis8|(C^~q;$q|EG>Du-^cqG) zT;w3K6TT(o!>&uAfkeQqP`AFo!I_r?;~)BEu{Yvs4CFwXqsrZ>MhUj^7U>=!%k6s* z2+4XiKhK5G`pyLs1Z=rfR~Ji^J>m1*oKI(Cn=9a-cN_1r-sC~V5EY^OrneiGk4v#& z$0jiO0d2cLQf%z~a@9-+x^xms+rvaT3??WlZgtW_IgG)(yA@e#a zo$d{QI&++6)s`8L?`%Vfm^$3$&7m#iLmbU1_#l216MXIU2a5Rm{tlP2>8&jM_eRJX$;vEZTpbEBS~fzB2q8dckk4$-3Wlw#dnx2ZidbNkB8+HAEhF_Ee1 zNym;bdnTzgDc9M!`$C<1*{M^RHm$9#{UO_PkQ6Lu`0t0}8dF6~UcvJ7;JgX#uuq}r zj=ZgK7lXj5$}}gC-gZ&a^E8^WzD!6XYf$*jM?G!$m2j0KQ{Gnr3C)xLb@LpuA9M~ z!D~VAJVd3+%io|Y67;=}+~@1M6h7A1830}LHvk?cD!iOlh@(ovUPf$PF^3I{{B(rZgOr* zOfl91yeEk6=I!n6?i-K)n5*`8oC`vRxFghGZddSkt42bCfNPAK2afA%UwNcAn1luN=%LDS#yKIHbPNPB122d#7I&U#EE5qmYJQ%(^ zBq1p_iGA|QrE-VI?nu~ooR0s~Dq++IXw{c1J*Wf1(Gd{D>r8v>4Y?)Z2{0SE3&eq0 z1Qw2yR_7OBfTq7=`kMgwI#l4jyB$K%&(D40+a>K{_U$a(PyE_4XtOVnB%&gZ~z+In&th(0>Nw=pjoKjp7F+X6pFPAurHBTq(uE0Tae-@D6#EiilIXg z&ozGjPygq2^LSkTl&Pn6Wurq|{*tDomKl^1jj@~~%>gE~7~-(YHKMu`r()kqRoZl! zc}b6#>&$Qhud~!jw zmwH(OE#|f+wH*P!Q^~pw9X%b4Tq_G7+e0aX|9K?^f&a-lMRn@GALohkHbEAN1F6~^ zqjeW?cMyEogIG*RKv%?In7|#<<8@y}A|4O)&p9^V##*Tq__|0c74m~BU$+jMb*pwQ zMZTBQ^XTQ^Aczp`#zuI!M84O*%5Z#MtY~qq@pK;atYBzLD5^lcbU6rP8ejq(kOJz* zBafkZVrRJBi9A|Mz4e_9>a@1xiC5!zey_cLzxzPt#t?ZUnU|BBUH`pK^L)!C>v;>* zJev5E@xnr*pO5#Vw?U04@xZU^ugMxAeY{W^PVnRG`OrKbp(yY^Oedov>2&+mYSQ|B zJuv+71jtIMZp$^;qZ+Xq9es}+-ud{ED5kt>@&Nfp>A(HcI718&3ZJX6tAwDDIk%}Y zA$+V&fCr8$*hNCj!XyxIxZT6C@0EHz3WUV>xu2j23xmkg(QJhSCzz0kV-k+rUECRe z)u!FKF7g^#SJe_+C>n_!X^LJXS+Z{ZI2jeJ`<|D;znVJ!F%vpauN(&GGi85zoPJao zo^JaIA65ihXf&qbOa|(=%Hg+_D?_=T^zAq^i#Nvyc_%?@9PvQ9gR^e=c92e}8Jf6{4!w4yK#Zp{)^uhC? zK}5^k&zV1!yKtsMnd)k{{pB?hkYA+|-&nk)A5UOwP}S&ocxpPsR{hCXV`;i;HG@-o%NsYyt%sdRsUl zJ}&P2x$j+~)~q|5c}0C!4uqw6m?6F0UdNw?@i_hv+Tq}6B3yybNHLa}H@Z%$Ro(aV ziKAmHMV_g8f!WkRcPPn0-K^(U-_fjWaV1t`QcU%t%l73&oXsMPH378Vne{_4Jix;E zxA@VzauQ$MWyg4C6-%lNwi;=RfJG8!-uSnhF+OnzQ(mlIxom zaobA1F@XwG->*PDuO1iX9IsbYJZkgV+|$<*3agFIz;!p;ygh>sJ%pOK!(*UFDgP@C zf4)rF3^)7IOF>9?Qm5z3b&eg69 z2=T%J)phGCPROH>XNE?Oe27}S2H#ht^4=`UBY!5~v|`aR5WP{Fth6Ab}{ zG^s64iUgY26Q^8zu!^d`<)rC5&NzXhOZM(x3#rN6Vx*N{_DZZ z&(B`=Y&mxB)-|r5+2}UsroMrgHh5RCN0LwC6&bffDaH>KAiav00FCTYXJ$pn9L7fC zX@4FSSPw2@D-kKW_tkZrLGdrsjj?zH{2pOY=YtEla1*xu;cZZmKKvCE9qyW95JJIj zwIf11%9B;4(c}IoQkB~Gd8<>C7ClnbbD!qn`^@`Gs5d%{Wd5l&H9!y`l*CG~0{Zmy z#B{gV+}7ScNc83K)3Zki8vfn}U{gI{ZPRGfBZDQ4&-MD8A1o~$osC0{vyfw}qbiLD zMAfcwi&&itHxa^TAA;fOSpBWEx4zten>p9rlaf3h`n#>{ zi$t8FfFY~UaC^NXPeyBKiEl#u)Nb4Byfpo+;NpE_H7pF$5vqa3+pl>&rGIc-^{B_m6~g?PJ{z&%{2^UFtTY-94PSm4*E8_@3pk=>8W1e{nGsT zYFFQ$Rg9k6{QRiEayeFXkcNilXZjP_AjOYf4A-qw9i<>Ad@}?24VWKi0F8d<))6Nk zR(Da>)^4uFcBXSVqZT-a;hzc=Y$xf1M?)#3k9IIpko+y`{rBVVm)f7X24?{uh6*w)d~zb5C5>|c-rp_z{Lhcm z8FV@nkE2}07&UdLcWvD_>R_>Jv?*;C$dUK*z0ZLrOzvg$zmA3Z`#Kw$cv)Ml&B~Uo z0C{CV87;X(`F9HXpHxHyX;?8KTp(_^8~bN=#>U2Rr1yLgWRhG`m3%mhOEyviIPQ#w z1^DGg`p}pG@k&SrMhUp&VV#6Ac(Vomj-8CsTD>`-4U(Z}HF*7b^#+7=bDzEPe>%K7tK^3_x z@WH~V+u`U_>M~k@ag(1-BN%j@em6feGcy<0KA^7lRrp?mKTJokvRULke>;_i6^*#m zmHv!)$?|=3a}%r^8YO*-4B)GRPIRtAPvOCxR4^_=SyVO!2cwhF8?+QpJ?P|KZ(U?K zOymGv3>QxC@!-`Mt>5coY-w4!c+JXpEM_jBUuZ#*D$P_TJQP5_V~B~xM^#v0L(am) zj~sl@s&y-DNS%73NRAZl6D0Pyh4N>jgoRy|e|ch#%l%r1Jz0+QaIH%1O2DLeYNeT%Nln$0%FH#f ziF6Sf8p=@&)zQ_~*3r?@)it$7AW;(T*RR<4cvEJ}jga$`=pGHHIaGd??5CJSJ!dqgsP(b9P%W#*6Q=smruMs4E&Y98n*}9WF5Rih@BDn3CWw)O z>QfnqMC)_-#8F00QC?QYoh5Fye{^1$f^5{~dhtAdh6zkG)#P2AsE4NHb)?FTqIuin z9&lbs#oQ`iKBEX0!%=dJh6Rj9T&-lkm6Z*OX>mu?zgW)JpiaslOcp?pbC~`Qc{AiV zBL)$7z}a^=%cK!3kwL%H>ktqt-ps_yEBk)2^r%XU4K9li&EB*PISpzz zpWoTc!h^F$rOt3)lrXFi2Ll~FOd{;vxijq1jrt9W7B3VhbNuT|XxWRP#`_HD$5>26 zg{jhrqh8wdvM3^q(qwIG`Xie_h#oC6nLkID$r;a=nwx5eg^!<+m**rFhQ4vO7H~rd zau%f_$v7M8j8Ui4D;)@V1sGGn-R<$lAhLPXl|C333NE5!(@I5J_;JH&&S8iSMf$83 z(6??W@|_udlDr5i!xtkSb0;4FJ`)G|Q&|b~FM)d`%54q?-=| zo`IEnu8ik_$5x_LS>5R?kv{Vd?;%np9-ztmhChSt<}NLqZ>I@P zLrBn*5+qHeRO{`$x_)N2S55$r-{j(W;aS!N)_ZK%O zCo3~|6p^NKeIu@zqe?#Zx?-_jpWi3MRl}L`uy~d%sfh3}g~IqRxCA`oe~D3f-kH3z zkjkj?%-ufx-}f{EzqN{D*?qq6-WBqAkBEM$*<0xLQ3aZ#$m%2F3%$q znO$Uk$`*+P5+f_JxC8m|w-1f3h|o4af?!rrkq+qcl_QV)oo8oS@GU_aK>pbDV}r!&dqwtE$^_TDNOm#zPH+@! zoX=39M<3Bunlv4{5ik5q<;J8dHfGIOT|i!A!qNAxD<)IDP z&CN4r#y7pbg9+|6b!mNB53W}mPr^hu7j6#9$?oAFg;{Y# zp;fJ|t?BxHnMRQ=g*IAaWLA=C7o#yWg7Aw0u0owS_=z>U_9vc{yC<;T zKIJwDsa*J<=7xqyh9bh4IDq_2tIy-u?L^(9C%!d7?B_Vk0OK~djyC!TC5@yk#l$5J zoT;*km@vlaUSNREje;8)(yMVWwVk7L+zwCY>&o){jUMlI3MN(*KUB=-SZETQ?#4zX z>h#8!;0;k8@MzdhyGm7Q(nFQxWNEH7Rv~PP1%rsG+sdWAIYooXmo;DuTQryikFZj2 z>^&!@{Jk0opvQa<;y8uGn6SC;xw(XiV_-@`zbixijas*h84d*unXNR}qw)Rud8BA# zqrVLm4!`&Q90-krhKfa~R64F(DJH?O!DQ}$;(LkUsAdG*NGzoh%Wr4#u{3QV$W@EH@S@yJxK>u6~aCy&(`mYo27rACz+ zkHuM3-&9Fzx!L=da4Vld{gQp#;Sto=Cuj(-zZy#$-Uk4}suLq^W{I#)LPu%5jf_A_ zOqV&W=b}RimxU}m-WE!K(h9E@T^5#*bW)&S7jf>!@V#lj+n4^R&X_C0fpZa1l7jEK zfqPfnZOD(KW@kVWu}|3$N7fq8S1hXTV+cK|Y23JS-?z^Ho~KNOCRKdyL6|hXDWxmP{Li znV*IKX{9Cd#a^)U4Z;MB;68X(E`KmyQ*l`CZ=5)+NkheYY7(6XxT zja7+Q^}3VLP#e|1*zrAbh4?=x)NBM2v~$b?{ud+leq_1wi~8-@GvdX-^QbP@BE}K7 z$U+6JtxpwjsZ3AwyvD7{rDI$!XM{R~A!@yuQJ0f~>hiR$y6t$lATP{Nqh9wD<;fN*1U*HT57E%8Am%+8x3pN$NW&xei%{Gfi)W*lf zl_@!Fe3xNCc56>GO%CVH@1Q8^+~QSNPty^j7s6=H5zxW?dX~{(d5EVU+P(pWVv5Tlhfz>o@t)bS)-R^geLJUGYTrwUhid5)QDUmMhwO1OF=BjtwJ(v_E*EFG1Y9`DT7M>;% zOGeCg!Qm7~nN_tHiFZViiT-1hPoOh1H;yZ)K3Sqp`mAdXGl0aWu|KftDALq|m4zXKNd+5PoYwL2o|EE1`)>Z0qtW6t3rtH(xixSw= zy^H`o>ixWCNFHwNz~v5*rdF`FS5nvyEE9oiVB}L24qWJhawgE~^$VxUGz`>(Qu6Iw zmK-VGdx5C#Su6GJPOkIc%2usa=^#nHgv2@KzL0?vMVrK`hU7$(7i`Z0%Qeujv(b_U z-d!E`Y$3Z%CZ`#V&_hD-U&Cb$22=~a57pMxOk2GpHC1cOQIvw?X@tUYLIjeX?#|A) zeo%xQ0e_)@u2q{>LBxNCYz^6UH8s~etup8Rfna3m(%Nr7Y5v_I#n-<7U4H8Z9?WoN z^^%PuAuAjI?e~Ykw>;?*UNwiK4MfF+e9~XDGtM)xo$gu6(;U8eHPnS~&YU+X zY#!6_^bPaJ!O0FWfI48Hr+0#rgYQpNh;Ni07Qw7+Xl3JOKDeOFsh6`*dKB;Zn4C(K zY$54kJ`!%#x@w-~^EUYIwb3UC1%(NJBJ}MpH$aakvy7&K{6YFm0>i?>ln~k8xU#+Z zwPwUs*o_tLx-=;#3x{(5UfGZzW*^0`#3mn+SXjY_Cb_`={ysViL21g|B5=Cpj4KK7 z*@t(;RvPP+cGVT@Z)=3mJ{4R)H|(%bQ&G`C)9u7rI*>3vs4}fFwoF8G;Ry-lDFMOM zca#9H6qD=7bOUgL}@csjJK9btFlh zDXJ)Ho^|dxkH$1=gL>?4ViE=ixD^&RmZ=-YRa_83+TNN@eu|HQ^Y;H87LLzVfw1KY zNhp(*k%NncFAiE#ACgO#A|`hOb)W!HPz^Cgi6k9yD4RmhZ^t4NFH@{vwU{m5ElHwc z%wfXTV-7*LfQMO>afQmkm6@EYC@|d8)J4S2|H&I?|%4A#VNI{K|;hshs%vL z_xM$-7RnFYqP?|MY|g^UY2n&5qIXe3q`ge}ynpgW8jkUYc1p$YcXcpm=<^qZ$aR@x zt#%O_Mz2n-vWifq!o~+C9hRdY6C++lp(Es@7)l@SAqjGx~PxW{JMP9wEzPaDa|AH&^>>%NTn%}!vee*SR3GUC7yQBnob@&) zEyj?H%05-1%(hgy?sBtR!&2lCyRXMN1&d3NH_w1C)xfudqQ808_qlNl{|76(Jvzd) zbxQIRik-M;<+WhXmL5{5%Fd~Q4WH0B6R0#1R=(HMxL8yU1PKsNT+YDDv&V>^>O@kz zw=>v_Fp5%+zm47D=E0vjZsEZkf)aUb5roCQO^k4P+_}MGv#ew<1YSTJ%`4l!`0b95 zkk`lxE|eG8TwMT-<*2iMsD@)6qLOLNvZyjNG{n0}NeueSW?6FYar&cLb#kkkO3iS& zh6Ik}9_#UrlQ|ctI4vzL-Q27!xpIkTxl@)Y{#zj-l0Ub9PT&KDFju~wmJa*+7i;iN=O0|-o-(BfVhmwKk# zc~wyn4X}M?e!l<5-PjM1EiKG4PwbgCn$@Ktl+@?K7g*^3N)hl_1ptv90C$^lAtAMb zqLb{5bmhfW3Qzhd4(5gP%~^XADq&@5bE(P`f!g?be+M}F!ybZ|U;}ZyW9yKyf+@&w zjiVAlZE1OJ6xrSjOosBJrB*!Bq_^;{wxrQeEg;GxXe^ZFv8$YgxNX>uFLn)%1K*z) z2-C))GA~32X;G*CyXNa=qzJPcEVILjAhXk{=FqGWD4+#x$N7c-e>tEsPF zjLyx#T&3cujJD_kd(h6TMLqCqL8nLr5&6DV2#BzmXnLEXU#Y#WfcSm%q?V28w1Zw2 z0H`^oz9P>6D+VJ4^OnqGT{4gYFSHULY}MjRm36un0IOu5Dp6@X4|CNoQnzYg@>FG4 zf;&(@O|*Atxv6%;+dd4!(u-ReU>nEjw!e8ZFm%x5j3EIL!5^yFl?Ei!BB~OE03W6N zc!?sxB1f|wUvA~O4ankau;pZ#oPqB@$hPvLT?&Bpz(`*v{eZK`{$DKj0QK%P#**oVrj)lnV2nn#cnb%ZRi&mQXRk%?qX|p{rB%L!DZNZO4t2w|T$F;+yCP-E1t&Sml zds46I%lV5k&$6{3Jt8YBk9Pt>;&nRVAMd%cqVJFvYOxMgd~B>K^AB}h#_d{Swjg6u zh9OEhp0(FbPi#ex$q9|5W@10l$zEC55?g*_1kkuVe3KcHA#fqblNYJtE2ru`! zlr6u^*A6SLd}Quw6(=OV<-(PCL7ak7yYhN_0od%A!{4)>Vli4 z#Kp$LGNmJ#)z;MfXcl-!`0tZf9?`S{c#Y;S1P|u(az{!!#3GehDNJ z7u|Ade275k;GwaxNs|+ZOTz$7`f@STKQ@3y{8$ksYlWj1@AFzYPCPDGliC{KM?mKb z_#2viUzyBi^?v2i1>~292KmZkrHr3$>kgBJ41B zTIreUcS<$j|T<<<-3ckER!gJIF43o-<&#`+4)Z#>wTwqgZ@3X zix85`b0NZngHH8cSkB$}e|JB$+o@5viZ@55p|-qfRi$nz%|z*{`Rc;0xU|>ZX8X9Z z2JS{w@zDOd3i2dRcJFp>Qp^H50TyQ_(>w}lz#@quS0V3q7f!4-N;O!$-u71D^RY7V zzzj!&2Mgq&o>q)aJYdiB6O3HtBK##K1QQ-i`ot6&jDR^^71&Rg0}Mub9c{r{yzk)e zpKr4eN96A^HIu||*S=B3PAlwaH^zo?3QeHIxLv`a7-Q_H_LnRqko{M-2!b*EiY|N* z1_s9WcHevZ&#)dIkL!EcNWu9upV>rRwdbHfs zZ165A(+wqUypo|Bgr^_Rv5bDX&Rr)qq`GN4RZ(P7J5QfR9qDm-pV|&3zUzK@Rve$# z^^*@yPDY&m`l@wLKv8e(z~z0jEKc#GaFoMMB7hp{ym>=Yqy zaure2u|2IpA~61NR;#Sin*EDw%!uy+S~OkvP{etzXbxZVSvOpeXA5YwVlmIg)8LEp zq79Gb0mOzN0|ghN#^iy>$S$BJ0X2({ZKv8ihMhMGpOxCxkELb=#R-=c6G^ieb=#8T zCxSUSIr#xpoxQvcob%r=TQ64A)6xh$ZiQ48eD&3|e|HkJC{~JFmMWDNh2k4k{;IxD zsxH44g2hLQR_}aB%m*&BV#m3h=Ho+2vnOp?mPvRCRFKRB!eT*Q$$7f3wO}=RiU`r- z6D4F3QolxbAmG=6q(r@^UXJLQID|@?>aj{un-!<{x5GTQ2mu98BvOyUNBdd@86>^F zs}u^dJMxkyKQDMUrm=X=3a?%qu4)I)**kM}WXrZR|Dw?63F!T?&~_2B!x9R$&M?z{&lD*!L)M{S3sDd#9nXoRswkq9h$rnC?m40 zaCw>P6HPwVo2Vz!pwgmctp!xD%MgXEYf;N^$^oJnVWIJGNt52x3HyZ-u!fYBxwxIk z1@^5cr>8Ghn=1CKKaSdu9wXwlngX*I^yznR83C#;U>Z?8_^2BN|F?^NM#w2RcRkcF zcC|N0BC9|d*NvTnD6FsYa%SqXP<4J;s4)}C0>YsN8UfWFi-md$=8{GsjBPPP6;IpzlWKNG zi8@moHd0X0+fsKMtV(3b4`;f7EQ~^4+#WiEi3ei~A_a-IE1zX1&pJhvtmzfJJ zjp-PwsVF5xpYVBYKMlK~!OfsY3xjonO3POE)Z$?%yPOE;5Gu?XchBX#FF*0S%+H31*uGJsOhoj6^y(E7Z@SY@)&j zp?JRn)n&k8af##n%yh_Us7N-VP{cxg9vsY)0C87x7$uDwbhFE;Yzv5+CM_l|5+;0% z(LbYl`n^TAX%D|KuAyG6MYm%#*6iZr4Hk_kU#$acH4&;?8?mTmf#QU-I%xYWlzsumZcr56Y7^ioX&LJ0+buqQY)I~F>c6^p>?nR#d#iL7W`~yyzpHx zxUP0{601uirSe_48$_o_4+{_XY%(gxyCa4O$>3)WPV%jdC~JBcOt}?hM{+f4O47=W zu1U2z9(}@bZa;CGna1UFO39mIGUa5F%ahm*9`mta_-BE$Xm1b{D7hOJtuE)UkuRXI2b;+Wfu6gq6N+Kn1s`Lb&CNUX$v?B}~_VMpsqH^WBTNe#x zU-d0PA0b9qih7dIn|^;6O|mlua`N)@bUOw*dax6}b|at=U~)(!>N4n+AxGX|KVG#a zvS2%QoHA#fy>NNhjhb&E0s#>H4HA?)&NT)tsuFXvg!&S7-03rwEX53E5)zQ38boTO z;wt6NmZm1@=l=jk{^vF0MorXnRq~Gxd`anr%OWUYaU57rDQyC1>SfBmc*sp65`S?^ ztEOUYkYr}OlvkxVMh}_%_G8h*WV6^!jX(K<;b|-Kd9rYir5$`eUhjU$RF|F|TAS2= za@-wf36i2kjglc!LWElHdKAdeWJZaq)Oj;y?@d_ufj=;G!&A362vpVnjB@polZp&^ za-=9pY}x#%@^>jhbB8W24&IPC0v5PF6!YV+Odb^B;zaq}KwIwQ-@ktkn8gEMECdvh zCmKrgXwA~rzT1@WGM%GxjEWRaME-2)WP+1dv++}Ul<0&JCE2HSWVAAqEP{yHs!+9} zD=s;(76NiZkO1!{o?K9Jo+%+WJz-_{~4>@ev&B8#PZFQyY8A!?PXY;fT|1$-v* zLsp#q5XDBB{Pu4jP^WYC7VlIbc+mCA2%pCpg>>pgmAcYei2FpHC`6V)g2&RO^$gL! zG#BsG6k`6Zq!Rgry%HvD2CFhps?i5I97S*%w74ou&J?lEq*3w{`h|v6OhCCx00*27 zP4~sARtj5i1W!UYBn0O%$8@^ssyio4R~B@qr9C!zcg~IeO7H-O&LL8%o=HCim;hY% zcfY@0JfZH^))@T0n)`k>qweTw0#@34vku#&DD99V<6xufjdn(?NUdU)U+ zE_>ho_njGjFqh>EHZ_<8H);~S&E4I;mX0GT*1dObiQlzqII$1|+3+dQLa&L!nA?R~ zwaOn2Jw0+SSa?{5+#=O@@?ilRKp~7-+BrgkX%xlXV134Vjv7!|?^CiUWx`ZS%v4hI z1)jUBLn(~EMukOU>fy=ixQ#`V_WWX+PlGfzTXD(ekeh_h3?=r59(`IlQzs@=x*%Fw zHqFrYHse4NfnY@b2f#r;zG)rNw^mtg)1y@?m9@3C`T6;C=gtlc44yi5>UV$VZ_nPi zwwW(PCBqtxMa2`B+N7&NI_Pf10EE;(``PDdugMqkHHiVRae@^`7G15@#zsdC z$J5rs?8xBi^#)nFZ-PJjj`}DW3eV8(bm$T2Zgh;$X`pF2!0UN4f#20eJy3?b3l2cGMNpo0mo@~rwHYCsPM>Y1T&5F%H61L) z12u{aWM$=Y#kLiR-weRgX`&_)F=UWiTU&#JL(NuGX{3cC+M{ellTsS9g-V2So0zPH z1fp-|7JHgRFY+g9EVe2SBXh*fha4*dQVZ`*4ULRQ$P0yCbXQuoZh3=s>Y-!49%h7N zfetRA7OX>aww*KKe0O6DE?JWooN=)g=d^=!V#@2NT1EP_1Dy4UM)PAKdX8GlE$8{d`T?t9(KAw z1tQg=IVa;@Z0&V23e7_Fk9K=VTcgoAo`^SO0-vHq==nN5H{ zLmucRQ1nP=%-WU#quko@w{O-|@97sH5BbaRTTr zUJEl-4VlyzT;z3SxRA|s4Vt1CBAH4r#xy}Td-7^&%AuEAAyYtj?vewnuB}?Ws@1EhM3!j^;E#Z?{_xO{ zYF4$3EE|7Nl}cG9h@yb8ga-OAcAWtnNh)wf}fC>f*m8N3Z+Dzz$Ya( zt5-Rr3xfC-H2MU#epeh|b7P~~YyiLt{3U+kW4rn^2{Eqxb$AT)yi*f zAk}W)kq_runC;uuN|pYWtfyEi(e9W@r=hH78cI-a77K8Effl;Jg!y)6E{CpO$!u*; z)D*EbI!eP!jV;qEE-W#`3?gBPda_TWETCrw+eS~t(*41z@c;v6w2&x9$RJ!U6-$Le zf$kQI#R$GrWRI&;ygiOUBB@jg{1Iu#VFgvAvdG$RQa?s_4lQJgJ$(Y~$R{z9bUXAO zuB#Ibkn2zWAMzTuP1SFd&vmr5-#xnAWw$&p&s?`@gIY8R70h2Y;UO@Z3P@cFT zK!@At=rFxAW&{DPWFkRP6E276a?3e@?gAqRCjDaVu+&)SfbDI=0A-dQoac_^^Ye2z z&!0Pe{@mHX(C=a)tX8ixejuR9DxVToLI+6n3YpRv3bQKU>bj*z4=JQU0q#~|GoPQD znnY&P^f9vSdOS{o9(-ba{A#JRzP>&&F`n(~D;7(G136@b;J+$aE(VN_b#%}w)pgG3 zNcifgX{Tryz*cI;p(3mZ@swYVWYCF*M>Fm4_(L^^3G6dSj*8Mrn|0n59aWL5_30xK zZDf6YLoS=IxzlDITQm|K7+~?QQn}pW8NeN`PDpA?gh5@U5Go8jXx&M(d|1K&p0$Al zKLYVavxza1+r{nG<>g{=n-k5!pzQZtA42O8+3Li^l%ya%bV7z4TTLXAT{DqL(8>PR z)vKNcC1#R#M+&85qhmn-XciHD*)WnAwR&xMWO!qJU3$(M`}XeTxsgnLQCE%*L)*;1 z&|xdi0!1GZqMIWkZNigqy3ABHpwc$;T1>YwD;#!|2%HazT$nq$H1&8%Rj$&_nM%&B zhpQZtVPSO3g$ozAx3{^m3w^`1RSSn1V(}qvc8lJ3-+l2|%rLzzJ$C~I0kqLbvo+Ja z>0P~Y^{u(Nxl*x6=WxAVr}zK#o3GE^oGq72kPQviU3UNqWN9}lm5XyXZ{EH=pUw8k z_#;P+^^to1p543Odh4xvqtTW7!Ay9`gp7}k$K!GIQb8@p&^!r>U`QT5;J*GovI9ay z$y5@N0E(~3E$U7&NA(FP35l)|S$ zr(d~L=AFLPrfbgUH~-=-Uf#8yVBDa{s7$z5Gr+n-KD^iz^YzLBk^ou15nd}4fgd6{s+ z&6{&%BG*bK3N4b!1fHPVw1sj6(v;msLo})9*WVK zoSdTIxL&WJtJqV$I35^sD=RDC_~So8fKKKfi$$yS&Q@!qqa)Zp=+V~KR|A{=NQ2BcDSJaGEHBSWHXS1k&Se=$8PHZ~TGMLLq= z^tAsYB}y)I?)-&HmA4Xdvtp^Zw!U7iRO$5=Ikv7MDMo>BVAJ>50SMH-_10BsWm4dS zzTYYo28V{|12&Z`4UyRh2^p`iZ2)YbNDOp=v?P7Tg{`ejHZwgnMSpPf=1syvLqkK` z+r=Jz6c?@anr_EMGR0d4KSCNKRdrNrM+@{<3erm6K`O+yhWMJe0dlo139JsVmcV*7 z&CW9%JCp@1%ajQ4O53g0;?fe243uK*=qjmV zQ+&I)xF9W*;T{r;kF6H>USD6|vv*HMqKnxZH*#EC2$#zhKp#Z90!w@)lsa>Blnp5;s9u}JU@7Ho?cCM5jM_OH+NIHLYeHz+q&LfvX~2 z>4Pz2<$X0BN4U@&HxqQZy|4fdwiJeUyyw28T-ifeZyl0hdO&4JrEcxj)wQkw5Js@c z%c1Z4vYFxGA=+68X9foSadCj_*RQp>bPu6rMaJCN*nHrD2h1o>w`bAWO{e_A;v)AX zDk*6d4ojj_^qZYfKA)!#dwOb`Y-MwEvsf(c-o3k2EO(^0-O?m}UnXuq2M+r?m`IUu z1aXJyLx*t-`+yVwTJg5q3;@d(db85$r*DKUhl!Dj8>FNoP*Tt#Fg#@L<{Z5=#rUv$ zH+>yRGfQH7@1DJGM|bG^D(n_5$8f#T*xbyApr@kgZuI_%^os{s2w&>ufkA&<9Dw%w z+Y9qnx95qIEo=RFcLxGUIhkSc^3r0pQU$hF_(w==3R;LM7xIO}M-I_R zLbon1E|FzS&rH|qbs12nj6++X>K${mRG>oh3S22D!j{x(tC5U~?5_ZQ&wMclYCj@A z&cTDoSMlcUYQztQg{RfEFlCJ3{>_`SM$f|1!_?GZV`(;{r>C&^#EFxhrV^>&ij)u? zdRv7piFWLs1{!`5g#TJ({7tSO#}cuC@%Axt0H7c>-AlA`8G?7*^|g(so_b1|m#%bz zxJI8b{ku6g2QGjic!@AzhlN39Zk-omH%)?V7yKxlYG+0|-m)SE$dXoPGm6UWk zJuo!Lv!q&`Kot7kRD$1a(Yb&8{u7KASg#4v40fqhI(YEV>gwwH`nvhR0CT0IoT2&1 z=qRUy^gtw)P`6c1le3DQ4*ANS-MeYmr^pWgW7n?T)oP^!HLjlFDT*tGLV>0{=sp-c zwK}F8z4cl~v&2%Ies}`eS(s%SI+muF8o4-2Q}G-XyxM4-f9ZU7rwY_*DlQZ?T!<)R1kde(xp0Jx>4bCa1{ID%Gl@7we*!?gqnL>yW|VW>l~t z!~uDu>BQt|WFV50$z(&}P^;PS)gV__P0c_Hn19DCG+$D#w{G1!efo^c3h53xPdbxM zCKCj=wu>dq6QHZ4?SEik;OoEnTQWhTse*5X!8oRGG#eK#UZU_j9*<|USqg!2137{` zEuqkr%B5zb35XSs^MN2edckP;kAVYBPE9@a^k--P8vwN6VIf%sM9xHjk&*uXe(s&GRPy;kUw{A5-~b_S)tQ5F zebTEL3Uz7vO6E=XkDIBcLRR%50Tg06H{R@N*QdRkuA|v%s$g0U8N|d&;0zp@)E(GhaW!m_~VbaB>~EULfjS{@^rDH zQmL-4tPc$j4Gj&FeRCsGnGX$_$>3U={3i?~@_|G;o2l2T0Tb>XI{=x;-}~*~OQ%y9 z&7uB@BIT1sx(7uO0wwB2Z~&?CHg`t-$%mkg%^IbV9=WasfX?cjvkn;RSJ^v&P; z`frkD^Ux3pqj9R>sEkIUsbq>U9>#O|%2oG&Ks-{8TQ)K+)6HnZ_HTTL-UTwA7z)18mlgT*b ztWoBJGgE*;juef?==NK;ZU(`?J#zpu?&qHSY=cc%3FbhmL}&IHjg-sf`|dk->C$B~ zUsi$c&%N*qFOV-l6isW0E7q}qceUl)y51xZ*)gnX+9tD^%;@MS*)HKLItnQI>~uT= zNa;)_VI~!zV65Cpbw$buBPSdQMI(_I{duFcStvD{?Myl$9WuJr#!@60z3+W*b#={@@VE!EzkhgSWN2`RgJ9n$b0_y8*!HWx_UmI~V-&l)s^wQ{y)f0s zacKL0^wCF7oIEjmV|IRiJ`#;)(y17a9Z^+edP=%riZ00d>0;<`D3yvUD@*y!&A_|qL>hlfW71_t}GS)NPKXjZEg+8S8XArwA(^yu@?KTrNI1Exf#&e1!%FzrgE(q?}1 z;DLiLyzmRFYikrW(F58_Q8hA{VpNL(#`Ll1*HD&wyl8FQas4048K?|OK=Ne!_q43vUeDUz% zLmVI1s;u!ZGX2B1nJTaJv}qkYBVa9vPnh)ZChHjS#|e<@2RI? z7?PZ=2M$}hb_*&*ty&Ysc8`p3AlJu=g1Hn<; zZ+ds|bzh4InP@GR7(#Em;u>ibPX0;Ii|#ZwHl7g1KV1W1yava5bG7L?q1?hEH?jE*@%9WwEwM~*!F@WT{^FE20C7Er6#WYno^YHFtFK@a=6 z=RY^IYnm*WLt9K4le`mZVIduw%YhalMLH9)`gyQ$9vvtHCIn@H`BO|ze{rcX$dtk&JuM@JvGEPGB`ntU3+h~In<5uHFmC}i!LZE%t4BSO3 z2DL2PQ3Cw7N{Og;O5k>s%p`Fs%7dEDi5>%nJ<>0RrY-cgx7(QHWlQ2xN$z+e!{Dna z#l9p!Ib*|3lDcsbY15~kda}`MUbt{U0FSYJt7jl2yZzCl#||7kP$`#Xnv*JZLr>Sz zbUHMo*V+@l=@Za8o?Jqvzm{p$ zj-{CqYVwy*rA6d0gaH}8$w3KO$kP%j=pDm_QSb^%9CZE3?kP_F!slQ3;upUdk!OK8 zfQgb(An)t%|IBBep-boP_Ey8y0u%Jqw#ZN5^-`FN;#i z#aey#=4^)3nhB^#2uEK{Sw(}n(xR}`tPRzArZf#DjJEvVd8yFcR0A?BHT|W_Z8id< zw$sb`@wH$H@U< zvXkH|aR9jzz%bUJ&*xu%<4tK*aOn_G^f+O&BBeWf<9a{{{dhS5t=ZXG`sCi=_4+J* zMAxtF-nAB%TZvP?Ng(#E!%XU12k(> z*0Qp^m%EM{SPedsh3r%>RnE*GFwHo;wQD&bj6Jn9L6pgDLdq~BwQ)#oZx`vd2OoTp zy!6bOvvnb5XhcUCz5UQb4?pn0NeYX(FUJ+Z3AuVqLoyl`y(3ViBpf++?)>7?A~(%+ zI`w)(XcKJ_-KZ=q%&)902iE^_bO8E9H#RmX)H9X&YuBzl`Q($no|BHC*4ACH2Jq-s zbk*5Nd+q$K`HL4X(gsP7cI(zWndb1&kfV5}RxigB2IP7Qv^ZL<4v$PgsGB))lGvd_4ilHfbNSzf!sU(vN?5z55<}^wCs0h5P$z z&ZLb;Gdpi25{4GKr4Jb(B@JLKY^6{Q>TSrfKyOywD8a7pO0iaHCtBL$fA`_r%sBGasTlL(wTlAGw+4j)o!)7wl;3wxJs{tj&#;O5;TSwUF2TU z$B&;(q*6Q>g`)d%iGH=bv`C;gaDaDMpZnY|Jn`g{!io3wrrXW#n+Zs2c(CuEKKX{e*DE3zxwJ=U;Cf`=l^A8d6~l9#~yq9!3R!25CvQ} zAT%|6z+?TaH{X2owb$PugBu?kKXUZQ_}Ew?5htVk?svaOhXC!tON$FUKPr{V4Ga$C z28TvQ2M32srS17!H`i8|+dN~&VLFg)6GR*w9Lfz2X0rooc9W*%q3KLoKa^`N%z4qE`w5u>xQz~iyUPI+4N%8}w4Sze3hTyS(jHg)^< z?H~N`N95$tJ0jZ}8yh=t;K1_I(&`!oJ}av$oa4`AvcL0tf1e(Pnbk^@9dhbnRLXHY z%CD5~CRih04>*#FZ%9&{bTRa>#bWW#|HFSIbb&gFBTbtK z$H|m4ndGI5tUnox#g5%~|3eQy=9xpVry31tC#Z^trP2nG$)uBs1a85Hoy}%mf8+G> z%6dAT@l<0fMj|+v$UQYRv1@t^Zo@<=aVmO+%|?TqGagSkBKI2(voFc*P0WF%SI07b zwR){yC%>SLiIE>qva)0<0?#@i*D05a^puG>kNEa6@m3_fE9K(G`sz=9@=Cp4`?+uc zT1Sr_`?X*Db>sSIUa`7@`PSIz=-k}gnX~6G2Zi>v1|e&vzF2C`i|(sr{&QcJJ}?5% zgdF<%`p8z8-!BV5+0j)3rJHM+9s>&y*)salI?G9WTfR`Zc=5tpSFdhvZVnF*|GnS- zomey?iVWzQ4}qP5z&b2&%M1w~A0OYhZ~wLH*9-YgOAmWg!)A1e03P_`AHPH|Q>3+R zU*~_w$jQhO$;7_B`x=er(C{#!nzo2a>kNUVTN?POC0EHY;J5cc*2~hjYpzL^LLA8Qos`C47c0P z-MSSQvL_uf?MmAYO8` zE21L@1-?imMjJ4Dk%v;cujZ^VlJi5BQ>&Au!ZzAS9`nEkKNL@7OxLo-jZN*!(vsI9 zAk+lEkd6y-)a_ysdSP){W>0f?p2*;HSOH-6u$RBLo}$oZhyEAe=eKJxts4%1Kh z%?&u)4%qymH#ywn6M!>9Gc$ktZ~xtv90FjB>X4E@RRTN@oP6M$fBxsMzy3PUb{C>( zw`*LdVIZ|YhH_^f9rJdbL?S^^G8q-U#S}W=EC$wseIPAZu2jmUGTG~`TephE?Lr|B zmgUYpBOLyFzx}&oqazAebqf_1jL}dY^dJHsnk(uQlAKRS()nRYLscr3Z+zpAx3{;| zDMaW$67KKs9~hwcH3MnUM3Oe^eq|80CHh{B!|5%mR4Y*)xrgC8F5z=}y_!J9ScOjn z-X0>hdOt#FOHy6ercS4l5K1ph51vt-LpYFS6gg7B7Dm&m8oY}PQ_B@%U#&*rdI=N4 zam*r&j)a-WO0gTA8!7JHNze`SM36=^d2q(J{5bX58`qG-rC@>16M7iJNONtx3y#m^LSFON=9%LBN2F9~o8yH3}e63a?J8SST zm?k|1Ndj%$wmJ6zs3c5o)VNi;WYi;cfTd-gP(8*ppXB*`mg^RHR!HayunuOj!Hh?w)XGaS8p`G{q64% zs4(rqW~d##OBC(VX{+mK=vPsnsmcQJl+xPm`MHJLxBlvLb3gaO3r{`ylma4{93v5} znj&K|Lh=@y$XKaT>uINS`{m1*zw@2%k}GDjSwcHx{XATw-R7p5R@*bYQzD*8r*r*% z5y=$s!~&In2+MC%9C3U8)}Q|ApM2tDfW3S7(RNkb z-iBJg77K*HEp(fmP?YJ%6i1GZjQ;A^Ui{&Yestx^RZ9u4qjS>7j3PF8l|-^Yl9p*3 zw7IE|KbzrV&7s3bmKGOo&R&;E-5+rM_(wlFdgNGtUlu^YkqH;5YPlxJldX=$ZsizK z$#vabKpPqD)|W0_85tR!oE-1#%h45*nNgtFX}67XFgAh^CxmR;O*b|~PsvYUxK7w( zz|2 z(ic*%*G`^1Nl<5HW!V*lT0O^F?2NaQNDm0t`n-z6qY6P}K!Zbrd-ok6WLYVfO-AKs zT4a2MLgD`7Cooq)jb;*a^Gs1sNwKRTVoJP3j{%lMVz|}njE#+w<+VjR1*UIKHk^JD z5rHGfQ7VG&ZeXV%Ks#t0L#mZyZ7u-8VzU+kfelVSo^w39Cl1`>RVT@?%TU} zY;5cYKltJ1W}deg*;jlfpAt5R>XG!_vFW}UTj{Ch0#{ltCnl$+re;dz((206+S)3G zz|Cg!{l9}ZZd|{3@zU|*_W@_2CdHbHK&y`Bs`hq{dX;8GPdq@e;PcNvPuKh(|Kqm^ z{78rl2|7@9%X$OZ)J6LeQiz8lHr0cin^ADRl}nb1S;H)atZjEZuzGh9Z!Pt zxw)Ig?X97qK~Kn}WX;eY*kZrprXPxxQJyD2;;MXu1)etQUcGyS9RhLHDF<$N#sFR z8;L{*hlXc%?b)+;|LDkAG#-Ou``c$vzkRK(uRi#|!@l-dU|z#Hwe{FM_=cIVgbEg2 z>Z6Z7Ix#Wv{qO%E1bI0|v;eoNX?w<=evbnw`r2%#@l*ptEasPHQ3dit?V|6?6$iler- zOXYGc9EmYRkyZ+F21!ey_|>9wV`XK@35Wao`Ykh*$~N5|wwYCBNfYz>+REB0=ZoiW z&(F`_zIBTeJ+v-fxVX8w>AGz?t7RaAC6cWwQzVrHjzETn2lnjVMF;7@g9jge_|&UE zdFA~#h2CQapjUG3+FP^{69z^1lTMqk!9*fqY!#ud1gGjJu9TS?vuoF`g9i@~LZD+B zgA-{7i%K85)on5`d4EgA%P>~u41%;}h_^(LN%DbRd-m_%vzNSrd^6WSzyB$`6# zy|KF;qup|oP3Vy}dm-~h+OF4XyX}r!t2bhj6B7oMhM=|@V2=!@YL8Zl1sg#c#jlBE zS~~b_rZM_lgpre>MITSS-kO@6G%5U^oy@knR4hKXH#gR{*{e#Ni7pe+D{&I3)mm6w zY&BceD$fBL7#udXp(!)W*CMa%%O-~gb96Kk0HaUzm6umET)ler%2o1;bUKZxiAa|Aim;n5 zG^;ncaL4DPIhiVdY8l}=&Z$QtidQGdK9k7|4(2kccn9+6$l-CrBb$1H*N4 z#KCoRqyg>47r(lD_wN7xzyBX*XKzB=hd%zb)zyv7jh1xElj9w`|73%eBs)QQFd%Q0xD+_**hYH8yj4t$r5M1nLsA5w5T;eFl-D=b=@lNk@A%m0sCnzvA6kBI zRg2@=b}PTJA{7)Hndp|N2@<3^fBrmeP2`#MIv;!d$#f>;=~)wco{7wYusb4?7ZN4E z@IU@1|G50VJL5hUg4*=9lJ!nb(m61|6CYY_dgb~2=GIn$-W@_nI*hXJpt!LJLr7@4 z1-HYahz}k*MElrgK2KW^2LpfsR@dk)T_DrDkEI3F&Bug^!k!x8CHjSY{Cjf{>B504HE4AG%P|Kqs;QqACz1+JbwqJnZA zO?AT>e&6WMv`3Kll3j7bYNx%lxKJq<8}%wZOg57qpyQZ{BrLwta|SrjY-F*>XqXA1 ztOL-@Z>}#a%+upg1cEd`BpMqW9NNGCz~JDZr^oPMz=Eaa`TU;r)b>`M!V*VBzwrV( z%-QB&FR!dXf1urVXJ&Sz1+?otdKxYr{7O&W2@%$uyE#ip%-4*pPrwOa&Vk?f>wjZ< zYU=WpE4Sxw6$)Dvn9?g58XErkZ~j(N3PX^B>k>ufZB=zB--^d$WF?)BM@Q%K@+uvv zZD9>{M+R&Dm;pq090b0iLBn&H(aU>E2%i-F6iXz@IQsfh(MU)}3P9w?$2Je14^AA! zi@xsX+93&J*aQIdgj|=Fmj3m>{@3IHLK=(FgA@Gj>(5Qk>`EomN()12YB-qdijz&4 z6uiiq$plke4P-*W;^HC!n-FUPxTuQw`t!DxAF8Rc^j_Ag73O+~+tceE8syT{)YKID ziPR-Rj(#nS!CI~S=H^ymYjJ6DZEd|!C=^SjzP^FUsTl{tV8T_Aj(!)Z?Oxbp_so5u z_hf6kaO>u5IPB16>q<8H0Yy7>n%Ni5Uy$s!ozC>X@cAz)i33%ERvv^+M`#_&-V^aS z!Q1bC>zmiFU;89E0P12hGc%i;c>;o61zd}j!GGzOzI^=n@un28RO6VQg3;|FkVRV; zVRo5!&8k?NvItzNG_%1f{v97o58=eZVama@yvJl-ee?+rb~fi!9Y!jiFxOfqLFa6T`>G+XJ=o3{dJK9=JPF{VE)_i@EF;jts8M1Edm)*Y^Bhy z-7_;&(}`q)OedL0Ks1}_72y!=8h`Kyf3Uu>IW#z&WI&h%;*x|dBQzxwf5&iTfuM9n3>+y?cH|}pZ>`oz5d#(pD+h_k3}EPi4!M(MbzfliaKsr(bkgWqkch9=Ohbfp-(cU zMA8<~p3RN?*48%5RJC}lmSV8zV*#vp`XFforZAeq(70fLL?SLgIc&t!rH-Qp%F8Hk zs8iTR^CzqX(|u4WmzP%xTU(=}ql7Nt6$+^c5B&PI>uU;Z$K2j7k`ePrfsv8^z8oPFNBC-V zUwL-dQDsD1%{LPaVOf?gKRc?DXgUVu4oY0iR>MDSO{d0=u*05ucny}LHV8Try-KCD zxWLU~wR(--j-eqQ@&_WYCmN~bb##&E&YjH-3_kYQQ{$6UQoK_oGW6&nuT>~)Zg1!R z=3oDfsi{d2CBu>M#`?xT_y_-BZtmvCy$2@kriYeKw1S zWJS^HAq-I7bzCOr$!8x9sZJ=RY_5c~LgjLW;N11=*Gr}H#KgptPd>puV8(>GE=4|P z&z@~}+GusB7+Yj+L>7jfVQFc3acP;)sgSDLnrS!m zVrx7ipo#Kosa&T0TUa+a+D8Y+hnNA%(PxL8hrC8ary0??maB)CF)LRORdB2xx*U}2 zwax{<*`8J*(A-iB-PNo&%z%i(27Y6CsQvc#=Ei!tT&7*0{F9#(`+!_L8be$m)!CfU zjz9G9V+Ri(1#y)Hq}U046Ti_r(WuwvZ_QBzNT;YwiRHQ&ouK)`7ToyL;{aHzt1JKN zU;XcY^KX59WO!IgFl`6YKzj0kL71!^Ew%{7!UosRYnnG7HiZTHM}R&SOXAZMSmL!B zZS07^SB?zoKwPXud*tBv6aj`O8(?>2A~z;waC-Op*>mS;lOy~vG&D$8F*|#6-@d&B zSC9n1a^=dIvuDD>hvWIMj{V3Zr;eXEQLohz>d;0`;P~40YaUmHB5@|q5HfZ#)>5Vd zI0CK&;`7-8oe1A*@I-F%E5JO4M(uXJUf(WmFE20C1*8a7q%$KU!v_x?q7chwg(A-S z(~D@fTC^iH4Y)%7Do)dtIqN1u)6frzR%}n}wvGu27(ZcdNj#sg}>@ z$?oZmlry-Eq=Mue+>X>71b~Hexxs-iMv@{mr8^RQFXGn|0( zxK%C2qOR>`iy0->`>SVu!W_VohU@d^&%N-%=P@1_C7v!LS=WrwuMLhqpX~HPJ4j+< zpOo20Y%v|4mgjm#iBSpSn$)YQqp3bdwlrJkc`*4#5n3pMyH#avuJx#Y?xy*~A&2%QSvb@3rFCwu_CPQ{c5esH;5G<}Y>d3U`!gK4+5Lv|z_j>HgXj89CF)k&$KBbpI>ps~k#KA9e!39A-s zjM8&WPEJy=kw|g?JvurP4rk~!#v}(sPaKUzP1iDB^$&jVquJS85uTsGyMn4{DP+j+ zhIGxZyKC(_Pcd(nWJ%7~;-4E0k;6b4gD+0rIzCvkeOU_Lvf2J*Dh-6g?S8(JZ$d%| zI4Uah*IF#M>XWz71#IL?#Zrwv(#eTYiq_sItM?P>07zy_uU1>9mX)vybfk5%Lvc&d z8)a0q1lahx3??6{e0U*@!e;OA(MKkyg{OEmZZ{7DHm|D_K0H6eQtm;!=7o!wE?&Gu zhyI>DyK}i5nGrTdit41_phSl?UB>d#G93$2>jkJ0!8-vPkQv2XZiSn@kQ0gadjh^8VKU1=zR={<%*5ohBvsnYM!nf2YiyWQkH=jxd@S6!af8B8x=3=J z6ggHp#Y`U2wa2u2x-r32%{a0LbgI1k%1<08GCi}4{>0O%Ohv4gZ)g|TE><_!SIA>6 zW;bwo7;hJ-M9`w78z_KJkECg*pO~1W^DPn^hiMw5q&mdm&2=Wos5+TJRpQ*m-4I>FwjO429N0c2E`8t&qV;<@P*QE{+>q(XBK zIXX7*jEu9V`*soiA>xDX6MB5H)vTa-O0CZ1s zvp$N9cvNOeTB|ufL9XRU(g|<5>-GwB=!P4&P1jtlvZ2!+l1#>4d+k-ia`YzWcnv)C z!2MpQ`O{Zl?uh<2>YteJ_UUv0iVk_0oIroqcdah{*+)MIXb3L9pRV6g8p|q2;j8`? z#zl@w=Ct)_UTOI76`4muKhXEd_M@zW%hrk7lJ5Prgp|s7oj##-Dm^qf9F58dFg~Dc z)D`G|v|rLzN3zxAWB#K_n@ z0Q9y{fThR1tM(#aMqASxoi7wtS62rKT;~SJGLY26218p;My>8& zi$gBM8lOl_OzyJOaq62cur75%Cy0b?O6O17P_mIUrd>&MLu?UiaUz@rh|p0(pILuj zZf$*Ib2Cq;r7Lrz>0#+X;?oHVi}Rc7TQUfl74n3ff@~XF-k?$}W#d-I{q)8F^h#%E zZ_LchI4qtlnPc#!Lp;M8#Jw9`+vC*MqB2g}F-FNH|z1nKE zRw`F$tV{+(A7F927?Jb^eLsJD{?et3gc`@j$ET-fcJJOzKmsgw5jm7o zScgjJV?z66mt-LuvLq`QIHN{pL6BLAhR#o7lEbY)Y zXK&DPZFD76)Goa{Vd;5A{=|VIhMZRB9MA)dRaD=WQLX63Wh%FjXUu2<=vbL?3SeHHvSB-00t#jf#N#d zX=!os(&a0;{@m~g{TqJj>8ICL*WNsRy3*hpFMX7*(i30;Hhmn7!Q>P|R}+#MGIF=| zK4rE(kq$uX`n9*nunrtN_{bxVPEJnoh8hlUZf+J!MTqrn6$+c18)%{@Y;fWHdAj}n z`;R~S+-Dg&%K>faes-|y=mTgr>trZQMrm_tOgOnpQHN|Q7LSuX_4Q?px`|M@>2vi7 z`OqCk$3|&mMnC)Z_7+V4?OPFlLak;dokmN(t-1)5Oc25hg&1@i1P%#ODGGnEd_7jx zli3Ki86yG(RkE07qc%P^vTN5=DwPJm;7|YT&t87%Wr9qhkUcrc%JsYtxNekeO zIxbzly12ADK0YBuL+D+oo_BI=`tx)uc3}T53bJ{mtgn=j=!H{gYw>)b+Z5{b_4l{i zE*iC1t1HfxMmihGI=5)6ii92A9f3?8-dOt7mY0_n7Z$i*ED|jg@)(SQ@;_Z-N6cLq zB?NUMmW+-@KL)k~fX`2}0{~iFy>jKo^&3Zy9;MS@WOQVHex5cqQ8d}YTZJV`F0+$;j{#xNeyT*%wZqd9zxr4-E|; zII#ZucYP1ab392cUwHlX*Wuz~zCyWWLaQeSU?&ugAtE9$Xj{EqBK&*Q5ZL7$ zZlCZZjiEKYIm`9_8)81e4xr7tec}AM*&Ek~M@Hy_`AbKnEH5n|J#x(RxwP)uGMR#m z$@dbG=-BA!(&CcQ`0#s_Zpk<37@=*6K0JvlG9Y{EHdlU-^XJab&d&bDU;J=&W#upZ z0M^&nzVn^$(DTsem&*-G>Vu(+q97q6 zvzsi@;VPG^nG{Q$Llak6Hywc=$O(r41y%9YwwjGby;jbq6N%vgGxM0|@GUL>;U6{= z@tDpKa3qG>lVQR^Pdm>eLfk_K_tP7~Z7z~^m7a$R0Z~?f^+0NbWqX{KmE$PHG(qT6 z`kwEbP9pSLplJ<#ZPMQ4B6Ef0L`O2V@3Xb_6Yl_6wC~Q}y7fNE6dkVvjVfC{Hj{Wx zBoa^=QN0_G5wF*1zg)OIPhar}r%%86{PWL?kg_ApHg7XeTmCE^M+A7@=ljkovyHku zegP#A+V7pE4--jSk5e{%2vDqIgYKDf;MfZ0$^a-Zh%Lp#v6My&@;YcP6~0Xygazhw z2u%Y-RJnM9c}+3yPA{PW7eH4-&V1v>jXq}A+K~66uL}zcblH7CD%5d>SM5ChF$PT$eRh2&zQ z%rR2pty)BY4}r$}?(P1RIKcZ~v=22KO_tsVvd}8vQhQ?LkC1@g;yMo}UFK%_N~QM^ z&YwGT^5n^ZT#j(?{H^&bS1&IwFV`f!^8pjP7ALc5uSTRukXou#P;Kx*H8V2hzS%5= z_=!>*8;6*b)V^#q)=BS62y+ZXR@IG2-@V!$bxqC+hd@>Nad*zi^a7KNasStmaMQ`Z0zx}Oeo_;!+lva;u1f?8$6X)jUmM92V zTx1a6elHMD!N7-jN%_KNjHP^&=}g)YsWu$?(z(L9QddDDC6XsGU)#631DZV9lFfX1 z7$rnm5Wpa_i_H>Q5&)sLnoZA9N0jBDU1O<2|McZxXqu84wCJ2}x(NbDA;=(sF^U3O zM{?6JZq$ikkwzOpsxoSXq361)e^m(-xIUpE9Cv0^obP*DObDey-VQoSy$gpSJ;iH3 zef53r{XeG;Kx=W~_P_nN{|0<7Zgq-Ak}M&eDwm41@&8P3--i>xRI3!k&&=%F+|0LI z&6U+v0%_1SpbH~|i*mQSEf6APEZ(RdSsE81M{Y{j5L64vKr|Sgss4JpDOq%3kmZC% zPzY^55<)}oG0a7kR@>&b!w&Z?aE_%7{;cUiGy0&?jm$?mc@aCnh*R_qvk@G-Jm%fF66ZrHBSTa6G+0)SEdZ z<)Fg$jr5X4q1dNUwMDD}A}Y|7^xR?Itgr3Kf*3T8Dcvs292{SmOGpQ)LEm0iy%+(E z9kNw3v<=pYuExmg(j*X-Cs6IHU?#afz#GmYmH=d37G?x?WMYD)rRvSQXB0o)BOrFH zV0~;BH+HC+Xm=5=U0q#ak!RZhfm3CKY|9AlN;0TpN~(zOc@wwP2oDcUCmmPsl(-89 ziEAlOk?OZ}+dgJF!;rwARV-SGL(DnJ&nwZ0B@%t$ZkQ*MP(dZCa0@fl^t?7<`D+HK zR0BN~BD+0W!Y%+Ca={P*uw>d7t71b8iU!rsy6RY6blDt_wipWNFfYl z?rj$tJXE{L6hscp7Bpgk!Qp9TMGV~LU#Y~Aw8L`>rK2Z%hmakz^*mO|;V`OE($fOi zJ!vZNcsf`!B)CxoBt2Wxr{tb!iMHXNxIb9r(iIs}BPAVvGz;g81T8-LCv{0j@fXzf z*iv3_;l`*#SF4rRUV9C+lyruxF%-yg6yIv!n!A~oF+6rp`SLGCL4gB&0#<`(+7)vm zozQA>{V2qfFCuQlO(wXhAjHFw;z*ODTp;Nq)c_D;>K>*(+KOgsX$rIyqiq)3iuxQA zw=t&8H`=VMx9v#`pxn$voVFTn>G~bskGWw$_=S=TZDZH>^|Vh-b5IOZX{ZQ!dKwx- zf5-K8C%)Fk42g`S2c+kODHLg*JA1~{eHy}GiuBXll1OZBZdR++9hgUJV*Bsm1Azm4 z63Tql$~XS#{~H+@-L;GPe5v#VsNKSHD^@F&+qdWY`uiuw$5ZJ{oco5k;MJfoTDpOK zOtcr~3`(tf!V(mU)Q&78@gkgdxRuKh>Ah z%OEs28di%Dx(poPlN%_vmzS2_C6(k?Wl_+4`SRtxd-uQiwHKvU%OVjR9ayY4%#8so zC+H+oiELkATj}kn(*Q=#B0Nfrh?@;qo5)oR@EC2(de#9>168e)%&AntJTt)(=BPS~ z+8wkEAhXFsU?m7?G#cE{Ua!&}YPA|+`gkHiml=!4==-n}1`nKmwOQEgHGNCVgem1l z9s8P4K7c?!=aEB$xA|C%%ru>jatBE`l+9){8I}gEi2QJ)-jHcU3F%r4M>!eF=@g#C zY^!9kFxaG0?w}g&8Qn2aO@wr!no&YVOk22WPGGsqFz?)Q0)&)a7%F<+#S0fGW|eLn z9?Rit86Wyv3<%t_ckjmL=E5TVyUi*>#gglGOdZV_y=9d2^#8W8laxLq0? z8g^Bj+%^)bev1d-k?mD$wUyJqdZW={_o#DIOWQ9L3II;;u{5`|Yt|;UZ}dztoVd4xxz`75Llp0E zhTsJFd0h1IV*=RE^jBA}UK$-6?#pJek&`2Yg{w!gIPLM6H1ckLOSZeZvYh9py!wsn z*D;ZxUavEnuU2_T$6rP{*3;|P}ZJ}l8} zz)~;k+$F}8Ap#j|HuxT)hKUpK6-NPnH0OrFKc?Z>HBvJ@^QD6mAXx8jX*SPYr3voH zT^f`R$Ak47sAER;00O}c4Cd*Lca1Ogrh@_q6s(WY>0IL2ME?j45oIHG!3%aQP4HW9$XK&2b=*s2onJt2T%;ww-v%X zU6Kn5VZpk`*8g^rW^Zl>Cfl3ak(n0}gM19)59wvh+O($`D>n>Q6Ixh78Z=lRvC;3y zV;U<|qsMwu`@MTV{z|5wMGVTvt{)LPw81~-DNMX;^$>@8&xChu4+tC}Sa%og>@Yq9 zc#IqL2Dnz2<{5?qSfUbO_IncpsQR;>$76~HilcgG0l_juoOBpq+#qm(V14*o{@WS( zy$O5l`X-PykuFRhe}W0EsNb2iPw#1fJA+$ll0RmI^A0xX+snWvBNRA5us)nj&f9CT z);qBk48%7-n#~>tjYt>wF_;JUfiv_*2)&y+On*m9-P>{hj*AQ&AXp#J;@@rK-|>wB z_r2UTW8appaAC>FkEp>#ChcQo6+k% z5Z)di2M!Rd59kkXM?O|had!t-$6$IrjmCl9n;(sn^b#L>OT`At!=N#>q^%cB->hEK z-*E!$@Pxntg7vfEe(POyrc95b*}RSU8vEXn@aZjq^;UMRw{@>0)nlx=bLWEfL+8)j z*gJgb9b0w+2ME@OgN5Ghx5fv06aV;X(m}nRV`d6kdKzDE;9+17EE`t7;~X%z+%ask zXYUU>!h-cz-TvQh>+gnwtUJX^%w}(rl}O~9JfJ$M-wzzIVMh z`VSl+SbwF}%P;8dIyb+4w>lI|+>)+kRDX@>@8F7>RHpT|T&D?h&DR|cV66Y$>HvWQ z1nd18y7iv=vO5lnUc6y69Sljq+|6*6jp^SZjDDxdY7x7gD5&=vbNdeb^B&uO-~hpT zUl8c+d*_b!Li3I3NHo@r?=c0;@X`?e8mMD<{DvjE zJ8I4LLi`=HvtETZ2wlCs1Ex0-^mbj_9sIUl`|g!{=)J>^2;@CtfIt={SRXtu^xj;c z9g>~a+r+JQWc}YB{`P)-M^?`}+I_FvytnlS4iK!rst;IiV+6fpk+|35dvl|2xBgz@ z!`sWZJ2-IuyRY|-eFFyw)`x!-yyKbh_HTA**}h|Ct=IZ{4}l#&_TI;|#r&nXKX8Cx z-QCk*$1OVw!*9RaJ6iwSBZ1!g^o|mI52{b#0KvNV;laD19qV0KM(>D%b_C@+O#Fjc zf8YSYy1NI0b!V%Cot?-A?<4iK!5QH1c`x4#<%di(9~Xyrev=?4xF ztb21Hy!Rd6<3V2B{B z9RJMM6MQ7W`Z%8t@6)C~fazm}f=?n?AM?}TuC9O#7pzbA`oMdC0D*$_@j3_IO~LaW zjsD$Ir2zyA)~6ODz0b~sU;DHtJy`a6UV?rA0000) or str() ''' output = ['#EXTM3U'] + if self.content_steering: + output.append(str(self.content_steering)) if self.is_independent_segments: output.append('#EXT-X-INDEPENDENT-SEGMENTS') if self.media_sequence: output.append('#EXT-X-MEDIA-SEQUENCE:' + str(self.media_sequence)) if self.discontinuity_sequence: - output.append('#EXT-X-DISCONTINUITY-SEQUENCE:{}'.format( - int_or_float_to_string(self.discontinuity_sequence))) + output.append( + '#EXT-X-DISCONTINUITY-SEQUENCE:{}'.format(self.discontinuity_sequence) + ) if self.allow_cache: output.append('#EXT-X-ALLOW-CACHE:' + self.allow_cache.upper()) if self.version: output.append('#EXT-X-VERSION:' + str(self.version)) if self.target_duration: output.append('#EXT-X-TARGETDURATION:' + - int_or_float_to_string(self.target_duration)) + number_to_string(self.target_duration)) if not (self.playlist_type is None or self.playlist_type == ''): output.append('#EXT-X-PLAYLIST-TYPE:%s' % str(self.playlist_type).upper()) if self.start: @@ -315,6 +347,9 @@ def dumps(self): output.append(str(self.segments)) + if self.preload_hint: + output.append(str(self.preload_hint)) + if self.rendition_reports: output.append(str(self.rendition_reports)) @@ -338,12 +373,8 @@ def dump(self, filename): def _create_sub_directories(self, filename): basename = os.path.dirname(filename) - try: - if basename: - os.makedirs(basename) - except OSError as error: - if error.errno != errno.EEXIST: - raise + if basename: + os.makedirs(basename, exist_ok=True) class Segment(BasePathMixin): @@ -394,6 +425,9 @@ class Segment(BasePathMixin): `base_uri` uri the key comes from in URI hierarchy. ex.: http://example.com/path/to + `bitrate` + bitrate attribute from EXT-X-BITRATE parameter + `byterange` byterange attribute from EXT-X-BYTERANGE parameter @@ -402,16 +436,29 @@ class Segment(BasePathMixin): `parts` partial segments that make up this segment + + `dateranges` + any dateranges that should precede the segment + + `gap_tag` + GAP tag indicates that a Media Segment is missing + + `custom_parser_values` + Additional values which custom_tags_parser might store per segment ''' def __init__(self, uri=None, base_uri=None, program_date_time=None, current_program_date_time=None, - duration=None, title=None, byterange=None, cue_out=False, cue_out_start=False, - cue_in=False, discontinuity=False, key=None, scte35=None, scte35_duration=None, - keyobject=None, parts=None, init_section=None): + duration=None, title=None, bitrate=None, byterange=None, cue_out=False, + cue_out_start=False, cue_in=False, discontinuity=False, key=None, scte35=None, + oatcls_scte35=None, scte35_duration=None, scte35_elapsedtime=None, asset_metadata=None, + keyobject=None, parts=None, init_section=None, dateranges=None, gap_tag=None, + media_sequence=None, custom_parser_values=None): + self.media_sequence = media_sequence self.uri = uri self.duration = duration self.title = title - self.base_uri = base_uri + self._base_uri = base_uri + self.bitrate = bitrate self.byterange = byterange self.program_date_time = program_date_time self.current_program_date_time = current_program_date_time @@ -420,23 +467,26 @@ def __init__(self, uri=None, base_uri=None, program_date_time=None, current_prog self.cue_out = cue_out self.cue_in = cue_in self.scte35 = scte35 + self.oatcls_scte35 = oatcls_scte35 self.scte35_duration = scte35_duration + self.scte35_elapsedtime = scte35_elapsedtime + self.asset_metadata = asset_metadata self.key = keyobject - self.parts = PartialSegmentList( [ PartialSegment(base_uri=self.base_uri, **partial) for partial in parts ] if parts else [] ) + self.parts = PartialSegmentList( [ PartialSegment(base_uri=self._base_uri, **partial) for partial in parts ] if parts else [] ) if init_section is not None: - self.init_section = InitializationSection(self.base_uri, **init_section) + self.init_section = InitializationSection(self._base_uri, **init_section) else: self.init_section = None - - # Key(base_uri=base_uri, **key) if key else None + self.dateranges = DateRangeList( [ DateRange(**daterange) for daterange in dateranges ] if dateranges else [] ) + self.gap_tag = gap_tag + self.custom_parser_values = custom_parser_values or {} def add_part(self, part): self.parts.append(part) - def dumps(self, last_segment): + def dumps(self, last_segment, timespec='milliseconds'): output = [] - if last_segment and self.key != last_segment.key: output.append(str(self.key)) output.append('\n') @@ -461,13 +511,38 @@ def dumps(self, last_segment): output.append('#EXT-X-DISCONTINUITY\n') if self.program_date_time: output.append('#EXT-X-PROGRAM-DATE-TIME:%s\n' % - format_date_time(self.program_date_time)) + format_date_time(self.program_date_time, timespec=timespec)) + + if len(self.dateranges): + output.append(str(self.dateranges)) + output.append('\n') if self.cue_out_start: + if self.oatcls_scte35: + output.append(f'{ext_oatcls_scte35}:{self.oatcls_scte35}\n') + + if self.asset_metadata: + asset_suffix = [] + for metadata_key, metadata_value in self.asset_metadata.items(): + asset_suffix.append(f'{metadata_key.upper()}={metadata_value}') + output.append(f"{ext_x_asset}:{','.join(asset_suffix)}\n") + output.append('#EXT-X-CUE-OUT{}\n'.format( (':' + self.scte35_duration) if self.scte35_duration else '')) elif self.cue_out: - output.append('#EXT-X-CUE-OUT-CONT\n') + cue_out_cont_suffix = [] + if self.scte35_elapsedtime: + cue_out_cont_suffix.append(f'ElapsedTime={self.scte35_elapsedtime}') + if self.scte35_duration: + cue_out_cont_suffix.append(f'Duration={self.scte35_duration}') + if self.scte35: + cue_out_cont_suffix.append(f'SCTE35={self.scte35}') + + if cue_out_cont_suffix: + cue_out_cont_suffix = ':' + ','.join(cue_out_cont_suffix) + else: + cue_out_cont_suffix = '' + output.append(f'#EXT-X-CUE-OUT-CONT{cue_out_cont_suffix}\n') if self.cue_in: output.append('#EXT-X-CUE-IN\n') @@ -477,7 +552,7 @@ def dumps(self, last_segment): if self.uri: if self.duration is not None: - output.append('#EXTINF:%s,' % int_or_float_to_string(self.duration)) + output.append('#EXTINF:%s,' % number_to_string(self.duration)) if self.title: output.append(self.title) output.append('\n') @@ -485,6 +560,12 @@ def dumps(self, last_segment): if self.byterange: output.append('#EXT-X-BYTERANGE:%s\n' % self.byterange) + if self.bitrate: + output.append('#EXT-X-BITRATE:%s\n' % self.bitrate) + + if self.gap_tag: + output.append('#EXT-X-GAP\n') + output.append(self.uri) return ''.join(output) @@ -492,6 +573,27 @@ def dumps(self, last_segment): def __str__(self): return self.dumps(None) + @property + def base_path(self): + return super(Segment, self).base_path + + @base_path.setter + def base_path(self, newbase_path): + super(Segment, self.__class__).base_path.fset(self, newbase_path) + self.parts.base_path = newbase_path + if self.init_section is not None: + self.init_section.base_path = newbase_path + + @property + def base_uri(self): + return self._base_uri + + @base_uri.setter + def base_uri(self, newbase_uri): + self._base_uri = newbase_uri + self.parts.base_uri = newbase_uri + if self.init_section is not None: + self.init_section.base_uri = newbase_uri class SegmentList(list, GroupedBasePathMixin): @@ -540,12 +642,21 @@ class PartialSegment(BasePathMixin): the Partial Segment contains an independent frame `gap` - the Partial Segment is not available + GAP attribute indicates the Partial Segment is not available + + `dateranges` + any dateranges that should precede the partial segment + + `gap_tag` + GAP tag indicates one or more of the parent Media Segment's Partial + Segments have a GAP=YES attribute. This tag should appear immediately + after the first EXT-X-PART tag in the Parent Segment with a GAP=YES + attribute. ''' def __init__(self, base_uri, uri, duration, program_date_time=None, current_program_date_time=None, byterange=None, - independent=None, gap=None): + independent=None, gap=None, dateranges=None, gap_tag=None): self.base_uri = base_uri self.uri = uri self.duration = duration @@ -554,11 +665,22 @@ def __init__(self, base_uri, uri, duration, program_date_time=None, self.byterange = byterange self.independent = independent self.gap = gap + self.dateranges = DateRangeList( [ DateRange(**daterange) for daterange in dateranges ] if dateranges else [] ) + self.gap_tag = gap_tag def dumps(self, last_segment): - output = ['#EXT-X-PART:DURATION=%s,URI="%s"' % ( - int_or_float_to_string(self.duration), self.uri - )] + output = [] + + if len(self.dateranges): + output.append(str(self.dateranges)) + output.append('\n') + + if self.gap_tag: + output.append('#EXT-X-GAP\n') + + output.append('#EXT-X-PART:DURATION=%s,URI="%s"' % ( + number_to_string(self.duration), self.uri + )) if self.independent: output.append(',INDEPENDENT=%s' % self.independent) @@ -600,13 +722,14 @@ class Key(BasePathMixin): tag = ext_x_key - def __init__(self, method, base_uri, uri=None, iv=None, keyformat=None, keyformatversions=None): + def __init__(self, method, base_uri, uri=None, iv=None, keyformat=None, keyformatversions=None, **kwargs): self.method = method self.uri = uri self.iv = iv self.keyformat = keyformat self.keyformatversions = keyformatversions self.base_uri = base_uri + self._extra_params = kwargs def __str__(self): output = [ @@ -663,7 +786,7 @@ def __str__(self): if self.uri: output.append('URI=' + quoted(self.uri)) if self.byterange: - output.append('BYTERANGE=' + self.byterange) + output.append('BYTERANGE=' + quoted(self.byterange)) return "{tag}:{attributes}".format(tag=self.tag, attributes=",".join(output)) def __eq__(self, other): @@ -699,7 +822,7 @@ def __init__(self, uri, stream_info, media, base_uri): self.base_uri = base_uri resolution = stream_info.get('resolution') - if resolution != None: + if resolution is not None: resolution = resolution.strip('"') values = resolution.split('x') resolution_pair = (int(values[0]), int(values[1])) @@ -716,7 +839,11 @@ def __init__(self, uri, stream_info, media, base_uri): program_id=stream_info.get('program_id'), resolution=resolution_pair, codecs=stream_info.get('codecs'), - frame_rate=stream_info.get('frame_rate') + frame_rate=stream_info.get('frame_rate'), + video_range=stream_info.get('video_range'), + hdcp_level=stream_info.get('hdcp_level'), + pathway_id=stream_info.get('pathway_id'), + stable_variant_id=stream_info.get('stable_variant_id') ) self.media = [] for media_type in ('audio', 'video', 'subtitles'): @@ -748,8 +875,8 @@ class IFramePlaylist(BasePathMixin): Attributes: `iframe_stream_info` is a named tuple containing the attributes: - `program_id`, `bandwidth`, `codecs` and `resolution` which - is a tuple (w, h) of integers + `program_id`, `bandwidth`, `average_bandwidth`, `codecs`, `video_range`, + `hdcp_level` and `resolution` which is a tuple (w, h) of integers More info: http://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.13 ''' @@ -767,17 +894,21 @@ def __init__(self, base_uri, uri, iframe_stream_info): self.iframe_stream_info = StreamInfo( bandwidth=iframe_stream_info.get('bandwidth'), + average_bandwidth=iframe_stream_info.get('average_bandwidth'), video=iframe_stream_info.get('video'), # Audio, subtitles, and closed captions should not exist in # EXT-X-I-FRAME-STREAM-INF, so just hardcode them to None. audio=None, subtitles=None, closed_captions=None, - average_bandwidth=None, program_id=iframe_stream_info.get('program_id'), resolution=resolution_pair, codecs=iframe_stream_info.get('codecs'), - frame_rate=None + video_range=iframe_stream_info.get('video_range'), + hdcp_level=iframe_stream_info.get('hdcp_level'), + frame_rate=None, + pathway_id=iframe_stream_info.get('pathway_id'), + stable_variant_id=iframe_stream_info.get('stable_variant_id') ) def __str__(self): @@ -788,6 +919,9 @@ def __str__(self): if self.iframe_stream_info.bandwidth: iframe_stream_inf.append('BANDWIDTH=%d' % self.iframe_stream_info.bandwidth) + if self.iframe_stream_info.average_bandwidth: + iframe_stream_inf.append('AVERAGE-BANDWIDTH=%d' % + self.iframe_stream_info.average_bandwidth) if self.iframe_stream_info.resolution: res = (str(self.iframe_stream_info.resolution[0]) + 'x' + str(self.iframe_stream_info.resolution[1])) @@ -795,8 +929,22 @@ def __str__(self): if self.iframe_stream_info.codecs: iframe_stream_inf.append('CODECS=' + quoted(self.iframe_stream_info.codecs)) + if self.iframe_stream_info.video_range: + iframe_stream_inf.append('VIDEO-RANGE=%s' % + self.iframe_stream_info.video_range) + if self.iframe_stream_info.hdcp_level: + iframe_stream_inf.append('HDCP-LEVEL=%s' % + self.iframe_stream_info.hdcp_level) if self.uri: iframe_stream_inf.append('URI=' + quoted(self.uri)) + if self.iframe_stream_info.pathway_id: + iframe_stream_inf.append( + 'PATHWAY-ID=' + quoted(self.iframe_stream_info.pathway_id) + ) + if self.iframe_stream_info.stable_variant_id: + iframe_stream_inf.append( + 'STABLE-VARIANT-ID=' + quoted(self.iframe_stream_info.stable_variant_id) + ) return '#EXT-X-I-FRAME-STREAM-INF:' + ','.join(iframe_stream_inf) @@ -812,6 +960,10 @@ class StreamInfo(object): video = None subtitles = None frame_rate = None + video_range = None + hdcp_level = None + pathway_id = None + stable_variant_id = None def __init__(self, **kwargs): self.bandwidth = kwargs.get("bandwidth") @@ -824,6 +976,10 @@ def __init__(self, **kwargs): self.video = kwargs.get("video") self.subtitles = kwargs.get("subtitles") self.frame_rate = kwargs.get("frame_rate") + self.video_range = kwargs.get("video_range") + self.hdcp_level = kwargs.get("hdcp_level") + self.pathway_id = kwargs.get("pathway_id") + self.stable_variant_id = kwargs.get("stable_variant_id") def __str__(self): stream_inf = [] @@ -841,9 +997,17 @@ def __str__(self): 0]) + 'x' + str(self.resolution[1]) stream_inf.append('RESOLUTION=' + res) if self.frame_rate is not None: - stream_inf.append('FRAME-RATE=%.5g' % self.frame_rate) + stream_inf.append('FRAME-RATE=%g' % decimal.Decimal(self.frame_rate).quantize(decimal.Decimal('1.000'))) if self.codecs is not None: stream_inf.append('CODECS=' + quoted(self.codecs)) + if self.video_range is not None: + stream_inf.append('VIDEO-RANGE=%s' % self.video_range) + if self.hdcp_level is not None: + stream_inf.append('HDCP-LEVEL=%s' % self.hdcp_level) + if self.pathway_id is not None: + stream_inf.append('PATHWAY-ID=' + quoted(self.pathway_id)) + if self.stable_variant_id is not None: + stream_inf.append('STABLE-VARIANT-ID=' + quoted(self.stable_variant_id)) return ",".join(stream_inf) @@ -865,6 +1029,8 @@ class Media(BasePathMixin): `forced` `instream_id` `characteristics` + `channels` + `stable_rendition_id` attributes in the EXT-MEDIA tag `base_uri` @@ -873,8 +1039,8 @@ class Media(BasePathMixin): def __init__(self, uri=None, type=None, group_id=None, language=None, name=None, default=None, autoselect=None, forced=None, - characteristics=None, assoc_language=None, - instream_id=None, base_uri=None, **extras): + characteristics=None, channels=None, stable_rendition_id=None, + assoc_language=None, instream_id=None, base_uri=None, **extras): self.base_uri = base_uri self.uri = uri self.type = type @@ -887,6 +1053,8 @@ def __init__(self, uri=None, type=None, group_id=None, language=None, self.assoc_language = assoc_language self.instream_id = instream_id self.characteristics = characteristics + self.channels = channels + self.stable_rendition_id = stable_rendition_id self.extras = extras def dumps(self): @@ -914,6 +1082,10 @@ def dumps(self): media_out.append('INSTREAM-ID=' + quoted(self.instream_id)) if self.characteristics: media_out.append('CHARACTERISTICS=' + quoted(self.characteristics)) + if self.channels: + media_out.append('CHANNELS=' + quoted(self.channels)) + if self.stable_rendition_id: + media_out.append('STABLE-RENDITION-ID=' + quoted(self.stable_rendition_id)) return ('#EXT-X-MEDIA:' + ','.join(media_out)) @@ -968,10 +1140,9 @@ def __init__(self, base_uri, uri, last_msn, last_part=None): def dumps(self): report = [] report.append('URI=' + quoted(self.uri)) - report.append('LAST-MSN=' + int_or_float_to_string(self.last_msn)) + report.append('LAST-MSN=' + str(self.last_msn)) if self.last_part is not None: - report.append('LAST-PART=' + int_or_float_to_string( - self.last_part)) + report.append('LAST-PART=' + str(self.last_part)) return ('#EXT-X-RENDITION-REPORT:' + ','.join(report)) @@ -986,11 +1157,13 @@ def __str__(self): class ServerControl(object): def __init__(self, can_skip_until=None, can_block_reload=None, - hold_back=None, part_hold_back=None): + hold_back=None, part_hold_back=None, + can_skip_dateranges=None): self.can_skip_until = can_skip_until self.can_block_reload = can_block_reload self.hold_back = hold_back self.part_hold_back = part_hold_back + self.can_skip_dateranges = can_skip_dateranges def __getitem__(self, item): return getattr(self, item) @@ -999,25 +1172,39 @@ def dumps(self): ctrl = [] if self.can_block_reload: ctrl.append('CAN-BLOCK-RELOAD=%s' % self.can_block_reload) - for attr in ['hold_back', 'part_hold_back', 'can_skip_until']: + + for attr in ['hold_back', 'part_hold_back']: if self[attr]: ctrl.append('%s=%s' % ( denormalize_attribute(attr), - int_or_float_to_string(self[attr]) + number_to_string(self[attr]) )) + if self.can_skip_until: + ctrl.append('CAN-SKIP-UNTIL=%s' % number_to_string( + self.can_skip_until)) + if self.can_skip_dateranges: + ctrl.append('CAN-SKIP-DATERANGES=%s' % + self.can_skip_dateranges) + return '#EXT-X-SERVER-CONTROL:' + ','.join(ctrl) def __str__(self): return self.dumps() class Skip(object): - def __init__(self, skipped_segments=None): + def __init__(self, skipped_segments, recently_removed_dateranges=None): self.skipped_segments = skipped_segments + self.recently_removed_dateranges = recently_removed_dateranges def dumps(self): - return '#EXT-X-SKIP:SKIPPED-SEGMENTS=%s' % int_or_float_to_string( - self.skipped_segments) + skip = [] + skip.append('SKIPPED-SEGMENTS=%s' % self.skipped_segments) + if self.recently_removed_dateranges is not None: + skip.append('RECENTLY-REMOVED-DATERANGES=%s' % + quoted(self.recently_removed_dateranges)) + + return '#EXT-X-SKIP:' + ','.join(skip) def __str__(self): return self.dumps() @@ -1027,12 +1214,41 @@ def __init__(self, part_target=None): self.part_target = part_target def dumps(self): - return '#EXT-X-PART-INF:PART-TARGET=%s' % int_or_float_to_string( + return '#EXT-X-PART-INF:PART-TARGET=%s' % number_to_string( self.part_target) def __str__(self): return self.dumps() +class PreloadHint(BasePathMixin): + def __init__(self, type, base_uri, uri, byterange_start=None, byterange_length=None): + self.hint_type = type + self.base_uri = base_uri + self.uri = uri + self.byterange_start = byterange_start + self.byterange_length = byterange_length + + def __getitem__(self, item): + return getattr(self, item) + + def dumps(self): + hint = [] + hint.append('TYPE=' + self.hint_type) + hint.append('URI=' + quoted(self.uri)) + + for attr in ['byterange_start', 'byterange_length']: + if self[attr] is not None: + hint.append('%s=%s' % ( + denormalize_attribute(attr), + self[attr] + )) + + return ('#EXT-X-PRELOAD-HINT:' + ','.join(hint)) + + def __str__(self): + return self.dumps() + + class SessionData(object): def __init__(self, data_id, value=None, uri=None, language=None): self.data_id = data_id @@ -1055,6 +1271,80 @@ def dumps(self): def __str__(self): return self.dumps() +class DateRangeList(TagList): + pass + +class DateRange(object): + def __init__(self, **kwargs): + self.id = kwargs['id'] + self.start_date = kwargs.get('start_date') + self.class_ = kwargs.get('class') + self.end_date = kwargs.get('end_date') + self.duration = kwargs.get('duration') + self.planned_duration = kwargs.get('planned_duration') + self.scte35_cmd = kwargs.get('scte35_cmd') + self.scte35_out = kwargs.get('scte35_out') + self.scte35_in = kwargs.get('scte35_in') + self.end_on_next = kwargs.get('end_on_next') + self.x_client_attrs = [ (attr, kwargs.get(attr)) for attr in kwargs if attr.startswith('x_') ] + + def dumps(self): + daterange = [] + daterange.append('ID=' + quoted(self.id)) + + # whilst START-DATE is technically REQUIRED by the spec, this is + # contradicted by an example in the same document (see + # https://tools.ietf.org/html/rfc8216#section-8.10), and also by + # real-world implementations, so we make it optional here + if (self.start_date): + daterange.append('START-DATE=' + quoted(self.start_date)) + if (self.class_): + daterange.append('CLASS=' + quoted(self.class_)) + if (self.end_date): + daterange.append('END-DATE=' + quoted(self.end_date)) + if (self.duration): + daterange.append('DURATION=' + number_to_string(self.duration)) + if (self.planned_duration): + daterange.append('PLANNED-DURATION=' + number_to_string(self.planned_duration)) + if (self.scte35_cmd): + daterange.append('SCTE35-CMD=' + self.scte35_cmd) + if (self.scte35_out): + daterange.append('SCTE35-OUT=' + self.scte35_out) + if (self.scte35_in): + daterange.append('SCTE35-IN=' + self.scte35_in) + if (self.end_on_next): + daterange.append('END-ON-NEXT=' + self.end_on_next) + + # client attributes sorted alphabetically output order is predictable + for attr, value in sorted(self.x_client_attrs): + daterange.append('%s=%s' % ( + denormalize_attribute(attr), + value + )) + + return '#EXT-X-DATERANGE:' + ','.join(daterange) + + def __str__(self): + return self.dumps() + +class ContentSteering(BasePathMixin): + def __init__(self, base_uri, server_uri, pathway_id = None): + self.base_uri = base_uri + self.uri = server_uri + self.pathway_id = pathway_id + + def dumps(self): + steering = [] + steering.append('SERVER-URI=' + quoted(self.uri)) + + if self.pathway_id is not None: + steering.append('PATHWAY-ID=' + quoted(self.pathway_id)) + + return '#EXT-X-CONTENT-STEERING:' + ','.join(steering) + + def __str__(self): + return self.dumps() + def find_key(keydata, keylist): if not keydata: return None @@ -1075,5 +1365,8 @@ def quoted(string): return '"%s"' % string -def int_or_float_to_string(number): - return str(int(number)) if number == math.floor(number) else str(number) +def number_to_string(number): + with decimal.localcontext() as ctx: + ctx.prec = 20 # set floating point precision + d = decimal.Decimal(str(number)) + return str(d.quantize(decimal.Decimal(1)) if d == d.to_integral_value() else d.normalize()) diff --git a/script.module.m3u8/lib/m3u8/parser.py b/script.module.m3u8/lib/m3u8/parser.py index d6f32b86e..4a3e7d621 100644 --- a/script.module.m3u8/lib/m3u8/parser.py +++ b/script.module.m3u8/lib/m3u8/parser.py @@ -7,6 +7,7 @@ import datetime import itertools import re +from urllib.parse import urljoin as _urljoin from m3u8 import protocol ''' @@ -15,14 +16,12 @@ ''' ATTRIBUTELISTPATTERN = re.compile(r'''((?:[^,"']|"[^"]*"|'[^']*')+)''') - def cast_date_time(value): return iso8601.parse_date(value) -def format_date_time(value): - return value.isoformat() - +def format_date_time(value, **kwargs): + return value.isoformat(**kwargs) class ParseError(Exception): @@ -56,6 +55,7 @@ def parse(content, strict=False, custom_tags_parser=None): 'part_inf': {}, 'session_data': [], 'session_keys': [], + 'segment_map': [] } state = { @@ -70,9 +70,21 @@ def parse(content, strict=False, custom_tags_parser=None): lineno += 1 line = line.strip() + # Call custom parser if needed + if line.startswith('#') and callable(custom_tags_parser): + go_to_next_line = custom_tags_parser(line, lineno, data, state) + + # Do not try to parse other standard tags on this line if custom_tags_parser function returns 'True' + if go_to_next_line: + continue + if line.startswith(protocol.ext_x_byterange): _parse_byterange(line, state) state['expect_segment'] = True + continue + + if line.startswith(protocol.ext_x_bitrate): + _parse_bitrate(line, state) elif line.startswith(protocol.ext_x_targetduration): _parse_simple_parameter(line, data, float) @@ -98,10 +110,16 @@ def parse(content, strict=False, custom_tags_parser=None): state['cue_out'] = True elif line.startswith(protocol.ext_x_cue_out): - _parse_cueout(line, state, string_to_lines(content)[lineno - 2]) + _parse_cueout(line, state) state['cue_out_start'] = True state['cue_out'] = True + elif line.startswith(f'{protocol.ext_oatcls_scte35}:'): + _parse_oatcls_scte35(line, state) + + elif line.startswith(f'{protocol.ext_x_asset}:'): + _parse_asset(line, state) + elif line.startswith(protocol.ext_x_cue_in): state['cue_in'] = True @@ -147,11 +165,10 @@ def parse(content, strict=False, custom_tags_parser=None): data['is_endlist'] = True elif line.startswith(protocol.ext_x_map): - quoted_parser = remove_quotes_parser('uri') + quoted_parser = remove_quotes_parser('uri', 'byterange') segment_map_info = _parse_attribute_list(protocol.ext_x_map, line, quoted_parser) state['current_segment_map'] = segment_map_info - # left for backward compatibility - data['segment_map'] = segment_map_info + data['segment_map'].append(segment_map_info) elif line.startswith(protocol.ext_x_start): attribute_parser = { @@ -181,10 +198,21 @@ def parse(content, strict=False, custom_tags_parser=None): elif line.startswith(protocol.ext_x_session_key): _parse_session_key(line, data, state) - # Comments and whitespace - elif line.startswith('#'): - if callable(custom_tags_parser): - custom_tags_parser(line, data, lineno) + elif line.startswith(protocol.ext_x_preload_hint): + _parse_preload_hint(line, data, state) + + elif line.startswith(protocol.ext_x_daterange): + _parse_daterange(line, data, state) + + elif line.startswith(protocol.ext_x_gap): + state['gap'] = True + + elif line.startswith(protocol.ext_x_content_steering): + _parse_content_steering(line, data, state) + + elif line.startswith(protocol.ext_m3u): + # We don't parse #EXTM3U, it just should to be present + pass elif line.strip() == '': # blank lines are legal @@ -244,10 +272,12 @@ def _parse_ts_chunk(line, data, state): segment['cue_in'] = state.pop('cue_in', False) segment['cue_out'] = state.pop('cue_out', False) segment['cue_out_start'] = state.pop('cue_out_start', False) - if state.get('current_cue_out_scte35'): - segment['scte35'] = state['current_cue_out_scte35'] - if state.get('current_cue_out_duration'): - segment['scte35_duration'] = state['current_cue_out_duration'] + scte_op = state.pop if segment['cue_in'] else state.get + segment['scte35'] = scte_op('current_cue_out_scte35', None) + segment['oatcls_scte35'] = scte_op('current_cue_out_oatcls_scte35', None) + segment['scte35_duration'] = scte_op('current_cue_out_duration', None) + segment['scte35_elapsedtime'] = scte_op('current_cue_out_elapsedtime', None) + segment['asset_metadata'] = scte_op('asset_metadata', None) segment['discontinuity'] = state.pop('discontinuity', False) if state.get('current_key'): segment['key'] = state['current_key'] @@ -257,10 +287,12 @@ def _parse_ts_chunk(line, data, state): data['keys'].append(None) if state.get('current_segment_map'): segment['init_section'] = state['current_segment_map'] + segment['dateranges'] = state.pop('dateranges', None) + segment['gap_tag'] = state.pop('gap', None) data['segments'].append(segment) -def _parse_attribute_list(prefix, line, atribute_parser): +def _parse_attribute_list(prefix, line, atribute_parser, default_parser=None): params = ATTRIBUTELISTPATTERN.split(line.replace(prefix + ':', ''))[1::2] attributes = {} @@ -270,6 +302,8 @@ def _parse_attribute_list(prefix, line, atribute_parser): if name in atribute_parser: value = atribute_parser[name](value) + elif default_parser is not None: + value = default_parser(value) attributes[name] = value @@ -278,18 +312,23 @@ def _parse_attribute_list(prefix, line, atribute_parser): def _parse_stream_inf(line, data, state): data['is_variant'] = True data['media_sequence'] = None - atribute_parser = remove_quotes_parser('codecs', 'audio', 'video', 'subtitles', 'closed_captions') + atribute_parser = remove_quotes_parser('codecs', 'audio', 'video', 'video_range', 'subtitles', 'pathway_id', 'stable_variant_id') atribute_parser["program_id"] = int atribute_parser["bandwidth"] = lambda x: int(float(x)) atribute_parser["average_bandwidth"] = int atribute_parser["frame_rate"] = float + atribute_parser["video_range"] = str + atribute_parser["hdcp_level"] = str state['stream_info'] = _parse_attribute_list(protocol.ext_x_stream_inf, line, atribute_parser) def _parse_i_frame_stream_inf(line, data): - atribute_parser = remove_quotes_parser('codecs', 'uri') + atribute_parser = remove_quotes_parser('codecs', 'uri', 'pathway_id', 'stable_variant_id') atribute_parser["program_id"] = int atribute_parser["bandwidth"] = int + atribute_parser["average_bandwidth"] = int + atribute_parser["video_range"] = str + atribute_parser["hdcp_level"] = str iframe_stream_info = _parse_attribute_list(protocol.ext_x_i_frame_stream_inf, line, atribute_parser) iframe_playlist = {'uri': iframe_stream_info.pop('uri'), 'iframe_stream_info': iframe_stream_info} @@ -298,7 +337,7 @@ def _parse_i_frame_stream_inf(line, data): def _parse_media(line, data, state): - quoted = remove_quotes_parser('uri', 'group_id', 'language', 'assoc_language', 'name', 'instream_id', 'characteristics') + quoted = remove_quotes_parser('uri', 'group_id', 'language', 'assoc_language', 'name', 'instream_id', 'characteristics', 'channels', 'stable_rendition_id') media = _parse_attribute_list(protocol.ext_x_media, line, quoted) data['media'].append(media) @@ -309,6 +348,10 @@ def _parse_variant_playlist(line, data, state): data['playlists'].append(playlist) +def _parse_bitrate(line, state): + if 'segment' not in state: + state['segment'] = {} + state['segment']['bitrate'] = line.replace(protocol.ext_x_bitrate + ':', '') def _parse_byterange(line, state): if 'segment' not in state: @@ -335,11 +378,27 @@ def _parse_simple_parameter(line, data, cast_to=str): def _parse_cueout_cont(line, state): - param, value = line.split(':', 1) - res = re.match('.*Duration=(.*),SCTE35=(.*)$', value) - if res: - state['current_cue_out_duration'] = res.group(1) - state['current_cue_out_scte35'] = res.group(2) + elements = line.split(':', 1) + if len(elements) != 2: + return + + cue_info = _parse_attribute_list( + protocol.ext_x_cue_out_cont, + line, + remove_quotes_parser('duration', 'elapsedtime', 'scte35') + ) + + duration = cue_info.get('duration') + if duration: + state['current_cue_out_duration'] = duration + + scte35 = cue_info.get('scte35') + if duration: + state['current_cue_out_scte35'] = scte35 + + elapsedtime = cue_info.get('elapsedtime') + if elapsedtime: + state['current_cue_out_elapsedtime'] = elapsedtime def _cueout_no_duration(line): # this needs to be called first since line.split in all other @@ -347,45 +406,45 @@ def _cueout_no_duration(line): if line == protocol.ext_x_cue_out: return (None, None) -def _cueout_elemental(line, state, prevline): +def _cueout_envivio(line, state): param, value = line.split(':', 1) - res = re.match('.*EXT-OATCLS-SCTE35:(.*)$', prevline) + res = re.match('.*DURATION=(.*),.*,CUE="(.*)"', value) if res: - return (res.group(1), value) + return (res.group(2), res.group(1)) else: return None -def _cueout_envivio(line, state, prevline): +def _cueout_duration(line): + # This was added separately rather than modifying "simple" param, value = line.split(':', 1) - res = re.match('.*DURATION=(.*),.*,CUE="(.*)"', value) + res = re.match(r'DURATION=(.*)', value) if res: - return (res.group(2), res.group(1)) - else: - return None + return (None, res.group(1)) def _cueout_simple(line): - # this needs to be called after _cueout_elemental - # as it would capture those cues incompletely param, value = line.split(':', 1) - res = re.match('^(\d+(?:\.\d)?\d*)$', value) + res = re.match(r'^(\d+(?:\.\d)?\d*)$', value) if res: return (None, res.group(1)) -def _parse_cueout(line, state, prevline): +def _parse_cueout(line, state): _cueout_state = (_cueout_no_duration(line) - or _cueout_elemental(line, state, prevline) - or _cueout_envivio(line, state, prevline) + or _cueout_envivio(line, state) + or _cueout_duration(line) or _cueout_simple(line)) if _cueout_state: - state['current_cue_out_scte35'] = _cueout_state[0] - state['current_cue_out_duration'] = _cueout_state[1] + cue_out_scte35, cue_out_duration = _cueout_state + current_cue_out_scte35 = state.get('current_cue_out_scte35') + state['current_cue_out_scte35'] = cue_out_scte35 or current_cue_out_scte35 + state['current_cue_out_duration'] = cue_out_duration def _parse_server_control(line, data, state): attribute_parser = { - "can_block_reload": str, - "hold_back": lambda x: float(x), - "part_hold_back": lambda x: float(x), - "can_skip_until": lambda x: float(x) + "can_block_reload": str, + "hold_back": lambda x: float(x), + "part_hold_back": lambda x: float(x), + "can_skip_until": lambda x: float(x), + "can_skip_dateranges": str } data['server_control'] = _parse_attribute_list( @@ -426,6 +485,9 @@ def _parse_part(line, data, state): part['program_date_time'] = state['current_program_date_time'] state['current_program_date_time'] += datetime.timedelta(seconds=part['duration']) + part['dateranges'] = state.pop('dateranges', None) + part['gap_tag'] = state.pop('gap', None) + if 'segment' not in state: state['segment'] = {} segment = state['segment'] @@ -435,9 +497,8 @@ def _parse_part(line, data, state): segment['parts'].append(part) def _parse_skip(line, data, state): - attribute_parser = { - "skipped_segments": int - } + attribute_parser = remove_quotes_parser('recently_removed_dateranges') + attribute_parser['skipped_segments'] = int data['skip'] = _parse_attribute_list(protocol.ext_x_skip, line, attribute_parser) @@ -454,6 +515,56 @@ def _parse_session_key(line, data, state): key[normalize_attribute(name)] = remove_quotes(value) data['session_keys'].append(key) +def _parse_preload_hint(line, data, state): + attribute_parser = remove_quotes_parser('uri') + attribute_parser['type'] = str + attribute_parser['byterange_start'] = int + attribute_parser['byterange_length'] = int + + data['preload_hint'] = _parse_attribute_list( + protocol.ext_x_preload_hint, line, attribute_parser + ) + +def _parse_daterange(line, date, state): + attribute_parser = remove_quotes_parser('id', 'class', 'start_date', 'end_date') + attribute_parser['duration'] = float + attribute_parser['planned_duration'] = float + attribute_parser['end_on_next'] = str + attribute_parser['scte35_cmd'] = str + attribute_parser['scte35_out'] = str + attribute_parser['scte35_in'] = str + + parsed = _parse_attribute_list( + protocol.ext_x_daterange, line, attribute_parser + ) + + if 'dateranges' not in state: + state['dateranges'] = [] + + state['dateranges'].append(parsed) + +def _parse_content_steering(line, data, state): + attribute_parser = remove_quotes_parser('server_uri', 'pathway_id') + + data['content_steering'] = _parse_attribute_list( + protocol.ext_x_content_steering, line, attribute_parser + ) + + +def _parse_oatcls_scte35(line, state): + scte35_cue = line.split(':', 1)[1] + state['current_cue_out_oatcls_scte35'] = scte35_cue + state['current_cue_out_scte35'] = scte35_cue + + +def _parse_asset(line, state): + # EXT-X-ASSET attribute values may or may not be quoted, and need to be URL-encoded. + # They are preserved as-is here to prevent loss of information. + state['asset_metadata'] = _parse_attribute_list( + protocol.ext_x_asset, line, {}, default_parser=str + ) + + def string_to_lines(string): return string.strip().splitlines() @@ -482,6 +593,27 @@ def normalize_attribute(attribute): return attribute.replace('-', '_').lower().strip() -def is_url(uri): - return uri.startswith(('https://', 'http://')) +def get_segment_custom_value(state, key, default=None): + """ + Helper function for getting custom values for Segment + Are useful with custom_tags_parser + """ + if 'segment' not in state: + return default + if 'custom_parser_values' not in state['segment']: + return default + return state['segment']['custom_parser_values'].get(key, default) + + +def save_segment_custom_value(state, key, value): + """ + Helper function for saving custom values for Segment + Are useful with custom_tags_parser + """ + if 'segment' not in state: + state['segment'] = {} + + if 'custom_parser_values' not in state['segment']: + state['segment']['custom_parser_values'] = {} + state['segment']['custom_parser_values'][key] = value diff --git a/script.module.m3u8/lib/m3u8/protocol.py b/script.module.m3u8/lib/m3u8/protocol.py index 368a05ced..fe60685fd 100644 --- a/script.module.m3u8/lib/m3u8/protocol.py +++ b/script.module.m3u8/lib/m3u8/protocol.py @@ -3,6 +3,7 @@ # Use of this source code is governed by a MIT License # license that can be found in the LICENSE file. +ext_m3u = '#EXTM3U' ext_x_targetduration = '#EXT-X-TARGETDURATION' ext_x_media_sequence = '#EXT-X-MEDIA-SEQUENCE' ext_x_discontinuity_sequence = '#EXT-X-DISCONTINUITY-SEQUENCE' @@ -16,6 +17,8 @@ ext_x_endlist = '#EXT-X-ENDLIST' extinf = '#EXTINF' ext_i_frames_only = '#EXT-X-I-FRAMES-ONLY' +ext_x_asset = "#EXT-X-ASSET" +ext_x_bitrate = "#EXT-X-BITRATE" ext_x_byterange = '#EXT-X-BYTERANGE' ext_x_i_frame_stream_inf = '#EXT-X-I-FRAME-STREAM-INF' ext_x_discontinuity = '#EXT-X-DISCONTINUITY' @@ -23,7 +26,7 @@ ext_x_cue_out_cont = '#EXT-X-CUE-OUT-CONT' ext_x_cue_in = '#EXT-X-CUE-IN' ext_x_cue_span = '#EXT-X-CUE-SPAN' -ext_x_scte35 = '#EXT-OATCLS-SCTE35' +ext_oatcls_scte35 = '#EXT-OATCLS-SCTE35' ext_is_independent_segments = '#EXT-X-INDEPENDENT-SEGMENTS' ext_x_map = '#EXT-X-MAP' ext_x_start = '#EXT-X-START' @@ -34,3 +37,7 @@ ext_x_skip = '#EXT-X-SKIP' ext_x_session_data = '#EXT-X-SESSION-DATA' ext_x_session_key = '#EXT-X-SESSION-KEY' +ext_x_preload_hint = '#EXT-X-PRELOAD-HINT' +ext_x_daterange = "#EXT-X-DATERANGE" +ext_x_gap = "#EXT-X-GAP" +ext_x_content_steering = "#EXT-X-CONTENT-STEERING" diff --git a/script.module.m3u8/resources/icon.png b/script.module.m3u8/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ca4c53adbfa8d06d0e282d45f9cad195e89d571e GIT binary patch literal 7237 zcmd6segn*PtcXta6B_iEY!_ZO!(hW*?NtZN|0+Q0*Idt6f zyPh}Ce{kQg_FmUH=epM3d#&~T?6X2um1UkhCVvb7z!N!HNp%1Kp{F1K8;l;tp(32< z;kk>Hu8W5K2N!n}CksH#+}_lJM$Xp6(n8(B#N5NN-{KtrP;AOcifMkH-81xZAku0) zJm@Fp#L>;2G$No%IAG+yoYp5GaFu%IUu+;swO88s1zP{pU;HSjZs%mSWk-t&_g@Ho ziEeH*(#E3>d+FdhBsqGE-7A^C1iw#lrA#WCUbnyt#(}cSyFtw7-zZ)*e;ZV!;=a29 zNvMo$PYqt&P;I6i3a&&XS3`gb7`- zv`0p^b-1;)MNL*O`QZBg`Z~2-O6{8@DySvw3zXooW6z-8C5dSQ;;G)FJNM2feEjLd zx3|rD)gR_v#+4k6R(Adtml_@39JU-R9bjWzy^THoA^I+voLSQK=;gxxv4pq1MZl+rfr(Ml0Vruz#l?pv_XVq#QTaK(c^5Me4-ZdI&yGWrnX0PAhx@y>dz3GRnFG*< zYl`Fy+VJgzX_ven;FEj6T&?FSBnn?11$Z5_-lSNU$-TqJSibGu zoT2eUntS50sOvoa84cbSIQicb75taglNv+5r1c8#NYx=&9}CZ2t$7j^JseA;(v z()sgS*PHN?KGWXruYc+jezzPsvjVzEPEhLLBP75pwe_xcrfz7`QwGJ!HK`&Ycx>ng z)V4=aBR=;GKHph7%DPVE-D2DC;tL>aCy`ZAd6+rhZ>ETI5s`cN=n?>?Y42KZ7r9+y z>QFgSYR8cG$l9cYRMZ^>fE@hPN!9XZDp>ee+3&*~xxX_@XA%WEnnK~`P9lM4DsjhC zqUys?TDw6~Frg?iTPidBGrbs}K66yr`+fpsd`!ge6C3}!1y7hVVf&#rQHQYz4XU{V z!ViEYN#qqgy{7%2%8!Elxs138BGO)T*B3kR(H8ki(v@dO`78n0Q0eO#h>G6OVZ7yF z8mIk2^9=ixE@M-d!<0SaM+n0HMIp4oQlaqVfGuA6~$k_n%8)9A?C1k3- zaw~RyQBhH4r5aJ-{#;!wE>R+eL&I4KA4TWn70}NEnVg;V+!|dDrzEwy>1WFHbolfA zawIu9nezz6=c!%E=KLs{AQ^JZ9*U5VFe{F^)~zksE6mSO?CW=SPT#ygV_M*ZOFTsa zp)wj8gjZXXl$7);M&(hZ7DYZ>-p5=;iexCp2@zVBy+L$!VK=B{jWGnBQ{iEP2ryk; zUv~%|;^E;PX_d_Ax0dkB;f)oNy{Czbj~8liTs_+!C-h!Cr@}?Q8-Poyf3bIk5!#x! zFU5EwolL-h8ABiH{?>5qhvf%zA|euY7%ZH74MP<9M_fWe0v)l6{jnKFnwpxrx=C+N zUikx}X=BE&$gYBlEQgB&!%%lMX~SDvL+b9yRiLPspnTIgyQnCPce2FjZX;DDR_QvZ ztc;!g?mWk@6vu(H6-B|aQ(97@Ibn3gR9A>{`-V>rf(VlKSMh+#j9SP?mfP<356g`1 zR?0d$BvHSkIMLb0^Q+Dk3O56P=^!=kl0h!sX+z`Yo7|bUNtaNb7!nTw052f|#YC!w z^M#ly$}-CrK2v2Ow|S9Dm5qZT&R`JM+WO~@Bg^?w-OqTNzVG~bt5Jd}Den}YVe_&R ze3HR!53y>y-`M^7m27qCYdGba5WTtdY<*UKe(%&|PupW%z-vtOQ>6ZTk)366^>8J_ z^i;Ogm(vvAB6E%J?plP6Z7e_9q8ND|eNvf_uhn^QbN7>!d+UDi-lo$;j_qxFdiv1N z(0BS@7*!~KfKE)q*;x?_w|_1G(OgS%k8cY2G&=1c&yuZ+SgC0k4*e9th8u5N5?!7Q zaG-UmdZe0K#At46YJ?Twhr5%?jybGt#oX63^)O(d6~gV{->(ev9cuRI58xMLe2d;U zhd1Yu6Ik-nOk3-eg4fqrTQS-9CLlaIQ6dNa*;$dR_2TlcuQ6r0whK#3g&tToS8$4#yjUJv2?a{0uKU$XiT zGrP8tn~ndK=EKP6Vtd(^oaD;QWIs0od5y9S1LcHss7Yx2DYJB1#8XV;)^L~*HXMHf zXCp`Et3qW7Vz*vG^xue3fsLW?FQ419enoH4zAV)Ay&5oH5x6~{JB$wIOZQ7H1UfIXT` zv@tWsIQ@HE-hJ*9PX)o_p?2^zc|EW45jxNFhfi;(FUM(~$ku zEAr~y`+<$2d=zKhZ;g= z{Io*u4`ikN=CI9ufUVBl(lTm{7_E^~Qr*eizLG{9rbrwjye+x7Pl_e9A|g>;H5FMj zemcjVEg{9lDjDyj#7EwUxS-Fik{?d%|Jc$_SxycI1M`?H5WS?v#zsOW<;&SwhESMK z+!+YONQDJfgm-FRFU6+4hY8h?5R!pcyek?OtJt&>=xYVU}OycPwp?x{g)7b8qwnbpx^XKNd$H?u7(4H zYPA@LscF#)4K}#uo*7&%Mp&u_HZ8Iv??+uf$OrnvK0L!uUjqK1g)$M7gbPotx$BH2 zkP0G8$@n^cB>YqI<3XJ0&(L=EO0o9SWx9T-C$ydM`v_iQsP2T_X793A`f(ZjO}PKVA)tH<}lf1OxXsZ(9BSu$PuQ^VN3yV zQ@{QdPVN+z*X#!d5p1uIWQzFy^2Z`!*FEa=+N{*FOcGEn(ZY)l)t?yUdT+TWw?DRH z#TzqRaYJ|#E`4;uGDsZxlQ%BsDxv1)>2=REnNg8)udIScL)3|9iRT*Ixh#^1;QjG8shTJ$uPc#8mh-7>;j3$JyDCuIbInV4&@1>;9G0vj4DnFfhF=Rf60K%A?T>63)VD7mGsjsiq{ z&Xz-{eb1J!qC`Azk6i=qe=&rUqHV0gSyxzY&KWM~&xQ3j5q|!UFOlbNs%HL!#F;Mw zp_R2^W%2L)P4_or*j9))=zlfG-Q7pSU?xd6d5-lGrb}&hcsyYX&LjBSf7er#%8Rwj z6jf9fD@=T#`^#VkKe_>550d!C_w4!O{i&7R67GBd{w^+-GY5N271EHBlG^LG-DijR zzR+}jskw;t_QnDRnlQ}>qZ!zn2>S~ZPz4(sn5p2o$>F(65R}m2yj8O>)PEH65x2G~ z?zy_<^;=)Ym83??fLrQ;pVPvhrsk%4=g!X0CpC4vS{C;9_B8h!m41=6k3QTtH#a95 zd$QQ5)9$mfu^HAon4tOJ;D+fRrE#Onb}&k%LV~C>2LCa^*2Ee?MVUa4$Ut48QuJ(&7u`%Im#e&#l$4d+b{tExzdlZJU5cv4{Gvz}W;*5tp434muPyl> zr{xaX$qdRBw<)cuiJH1PSXcmk@?yRniMaq1UkFvT=z#nx-{|<<+}iP|-_Q`73#dQ4 zjF%-z16o5>qGRM?u{oTMPTTOXF!i5;Z~hXP>Kd^>zw$*KG-wrTllzZp7#JAnY#!|G z3=aQh)Tr=u6^M1ZE~u#~xsm7Ft*~lw$jIC|7d(K&6u2v23lguU>dqjAeoll8yZsH4f?eB zT&IksFvY~gi1nm1Y^w)^MN()H7cg%GmD@MnJq-z_0Vk;-QfpNU%N*|zi2CvEZxJgD zdp%ps%1FM2&t^j@JTV#m{HmHY1-@`(ppx1=^Hr{|SInN)nI%)O{d}X+SP8Hj&Cop} zOiP_tdmcEoiMsM0esAe<^~(75<@S`X|mp+V!G@-8heL+leWD zexfZBx5x~unqHi0L)-h&x#2?c(lcXl-%P4wALtd-IYXR{fdAmebbgO9Jx|Jr%K+cPv>y zlAdStx)jASsc6K8+B6)<+mtS zoAv|zz`_16O$RLra~x;?)q5s`uf^s z)q>gSyu7qDQrKeXxBP&AM!@cgs2rP+c0zFHc3gS8MMz-Ml0R<5Q=C>&{%p$({1E`x zd;8n+SG_d6!omg?=IG_0H9I^1{yFF=CVyC5;K9yfXCu^i4iXWh3y}89+xP&g*tJo0 z#3mNPG)i7JPs-(%gu%R_KkDjwZ8|=$4K27n&$E%ehvkJo88^!1-Af`U#E<;irt_ij zjAVXlR4}|G88euL(96?H=0yd~vmssx_8`vsoo5924{VBDV>SNe+u-1NYGQ4e0o~RY z_2(^R1tfi6-{@mK+FJ%E!`$>SJ&A&%zMY?)CH+2!;05KDq*{%czxfRzBWZjt=<;mJ zQukDl0AjAw0mhR8d?x93Y48;@<17|>SB^iQHKzT7L|^5Y2;92JGJuIc59nfOHc`8B z!k=JZ1o;s(`8}Z6^3^`oRabMb2>^lw?QeK8hwe}}S7~tDIb*d-Kb7vn;$qzW!_?GF zj$Nz)gwIMPuaCYqt?MHUc6(?@rOcN|obT;8=zLX;S#JkJ^189N;yGS=pYQ3RaS<-o zGMAp2$XCDw!sEh>cCi0fA7ed4$fWY=F4QjuB(ANUkfH=lk`w9sdY;PFHn=l87!Wat zXJ@Io%6TFV)xU_=-E=!8ga7i!K=>|wHD5Khv$KQOx9^i+JYxhP*ht#>l$4#F&X5Fl z!<5+A*z(~RL_=O)FyC~gSxAmj3q9s2?_!(lZo+ND6}_qNL;B&`kXlS4pJnGYDt~u= zd7|x;uxI2#k`_#7+lsldQQQA3w6nY0R8=IB{%_N+0F(Q{znIk6AAcNFgKFbrGL&xw zVhdY7rdJ4*SkLg&)(-HC`UQ{PrPkS~CBAT#&Eb(#naZ>)C@r;!9qAK$Yq}!mq7y!p zQCL=Ha-~7Rr){n>BCO`+?^b&?>v`kJ#vbju@qRk}JFj$>?AXST!I#!O#Fu`X`?Qf= z=fQ>rSJq{1hFTMH!tqHRYyS0DqSbDY3=4~ z(}}K%w2Eodqi;_{^K&dfxP?3IAg45W1qFz!wzyTYbWTUp!P9gWqJ@3V{i(dzqE+o7 zwxOE~ohozS8!GajYqkHZs)8p8XH8zG>QvQfmgo*)R`Jd6;dH^|cY2y7yyOVRJ_a?Yl(1Gn^WUr#a5tMY;dULQokoa)BsUoiRNbr_mZ3%Q6VTTX>30 zW^;zVqobpeE6=Wb{#Nz2JF{j4Uj-uJ|?DRHZx?PF}Q+T6adf-kHGr* zef{Ci*`L{umUbu0(nTKb7Zw)GdJ(9dUjZ8uPEJnK`87)W#zL3mEh!YE zG84!YS66pxuTxzYj)$e?+q^Cg z=Fk2)(|@9OKu=#L8#NsqCnPvqPYFw_e@y5zv!~L+sXlPLo|~JKAsFmy&-Fdb5Hd8J zKVwOE?*G;;z&Mh@PP(==j#HgyA@vRM)vbDNDPD@ym# zEH7UcHWY8I<|9dALeYiExV45XC8olq z#l!|8@RPFp1_vwT&4b}ZL4zgZp9yy;pxF^eyh1>!#P4E|I-_Qd;h}3q7~T6nP;Iv zJwh0pvN_aX?N=S+YzV?*Bh?dwz-l literal 0 HcmV?d00001 From a9bf315eb66ef1d0b06f33e34da3246a360a4a6d Mon Sep 17 00:00:00 2001 From: Paul Backhouse Date: Sat, 15 Jul 2023 00:20:05 +0100 Subject: [PATCH 061/145] [weather.metoffice] v4.0.0 (#2486) --- weather.metoffice/addon.xml | 2 +- weather.metoffice/changelog.txt | 7 +- weather.metoffice/resources/settings.xml | 12 +- weather.metoffice/src/default.py | 74 +- weather.metoffice/src/metoffice/astronomy.py | 95 ++- weather.metoffice/src/metoffice/constants.py | 330 +++++---- weather.metoffice/src/metoffice/properties.py | 653 ++++++++---------- weather.metoffice/src/metoffice/urlcache.py | 53 +- weather.metoffice/src/metoffice/utilities.py | 96 ++- weather.metoffice/src/setlocation.py | 137 ++-- 10 files changed, 770 insertions(+), 689 deletions(-) diff --git a/weather.metoffice/addon.xml b/weather.metoffice/addon.xml index 3a1c8d4a2..7d899e8eb 100644 --- a/weather.metoffice/addon.xml +++ b/weather.metoffice/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/weather.metoffice/changelog.txt b/weather.metoffice/changelog.txt index a8c42d4e6..56fc2caa7 100644 --- a/weather.metoffice/changelog.txt +++ b/weather.metoffice/changelog.txt @@ -20,4 +20,9 @@ v2.0.1 - added user agent to requests v3.0.0 -- updated for Matrix \ No newline at end of file +- updated for Matrix + +v4.0.0 +- Cleaned up memory leaks +- Removed unused imaging code. +- Removed default API key and nudged user to get their own. \ No newline at end of file diff --git a/weather.metoffice/resources/settings.xml b/weather.metoffice/resources/settings.xml index a37d91516..57fe05e53 100644 --- a/weather.metoffice/resources/settings.xml +++ b/weather.metoffice/resources/settings.xml @@ -1,13 +1,16 @@ - + - + - + @@ -15,7 +18,8 @@ - + \ No newline at end of file diff --git a/weather.metoffice/src/default.py b/weather.metoffice/src/default.py index 0edab66e3..f5abcd2e8 100644 --- a/weather.metoffice/src/default.py +++ b/weather.metoffice/src/default.py @@ -14,52 +14,76 @@ # * along with XBMC; see the file COPYING. If not, write to # * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # * http://www.gnu.org/copyleft/gpl.html -from metoffice.utilities import gettext as _ -from metoffice.constants import WINDOW, ADDON, API_KEY, ADDON_DATA_PATH, ADDON_BANNER_PATH -from metoffice import urlcache, properties, utilities import socket import sys +from urllib.error import HTTPError + +import xbmc import setlocation +from metoffice import properties, urlcache, utilities +from metoffice.constants import ( + ADDON_BANNER_PATH, + ADDON_DATA_PATH, + API_KEY, + addon, + window, +) +from metoffice.utilities import gettext as _ socket.setdefaulttimeout(20) -@utilities.failgracefully def main(): - if ADDON.getSetting('EraseCache') == 'true': + if addon().getSetting("EraseCache") == "true": try: urlcache.URLCache(ADDON_DATA_PATH).erase() finally: - ADDON.setSetting('EraseCache', 'false') + addon().setSetting("EraseCache", "false") if not API_KEY: - raise Exception(_("No API Key."), _("Enter your Met Office API Key under settings.")) + raise Exception( + _("No API Key."), _("Enter your Met Office API Key under settings.") + ) - if sys.argv[1] in ['ObservationLocation', 'ForecastLocation', 'RegionalLocation']: + if sys.argv[1] in ["ObservationLocation", "ForecastLocation", "RegionalLocation"]: setlocation.main(sys.argv[1]) - properties.observation() - properties.daily() - properties.threehourly() - properties.sunrisesunset() + try: + properties.observation() + properties.daily() + properties.threehourly() + properties.sunrisesunset() + except HTTPError: + utilities.log( + ( + "Error fetching data.\n" + "Ensure the API key in addon configuration is correct and try again.\n" + "You can get an API key by creating an account at\n" + "https://register.metoffice.gov.uk/WaveRegistrationClient/public/register.do?service=datapoint" + ), + xbmc.LOGERROR, + ) + raise - WINDOW.setProperty('WeatherProvider', ADDON.getAddonInfo('name')) - WINDOW.setProperty('WeatherProviderLogo', ADDON_BANNER_PATH) - WINDOW.setProperty('ObservationLocation', ADDON.getSetting('ObservationLocation')) - WINDOW.setProperty('Current.Location', ADDON.getSetting('ForecastLocation')) - WINDOW.setProperty('ForecastLocation', ADDON.getSetting('ForecastLocation')) - WINDOW.setProperty('RegionalLocation', ADDON.getSetting('RegionalLocation')) - WINDOW.setProperty('Location1', ADDON.getSetting('ForecastLocation')) - WINDOW.setProperty('Locations', '1') + window().setProperty("WeatherProvider", addon().getAddonInfo("name")) + window().setProperty("WeatherProviderLogo", ADDON_BANNER_PATH) + window().setProperty( + "ObservationLocation", addon().getSetting("ObservationLocation") + ) + window().setProperty("Current.Location", addon().getSetting("ForecastLocation")) + window().setProperty("ForecastLocation", addon().getSetting("ForecastLocation")) + window().setProperty("RegionalLocation", addon().getSetting("RegionalLocation")) + window().setProperty("Location1", addon().getSetting("ForecastLocation")) + window().setProperty("Locations", "1") # Explicitly set unused flags to false, so there are no unusual side # effects/residual data when moving from another weather provider. - WINDOW.setProperty('36Hour.IsFetched', '') - WINDOW.setProperty('Weekend.IsFetched', '') - WINDOW.setProperty('Map.IsFetched', '') - WINDOW.setProperty('Weather.CurrentView', '') + window().setProperty("36Hour.IsFetched", "") + window().setProperty("Weekend.IsFetched", "") + window().setProperty("Map.IsFetched", "") + window().setProperty("Weather.CurrentView", "") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/weather.metoffice/src/metoffice/astronomy.py b/weather.metoffice/src/metoffice/astronomy.py index 1b5c6b0c5..ab8bca0e1 100644 --- a/weather.metoffice/src/metoffice/astronomy.py +++ b/weather.metoffice/src/metoffice/astronomy.py @@ -2,9 +2,11 @@ Sunrise and Sunset calculations courtesy of Michel Anders http://michelanders.blogspot.co.uk/2010/12/calulating-sunrise-and-sunset-in-python.html """ -from math import cos, sin, acos, asin, tan -from math import degrees as deg, radians as rad from datetime import datetime, time +from math import acos, asin, cos +from math import degrees as deg +from math import radians as rad +from math import sin, tan from .constants import TZ @@ -63,11 +65,11 @@ def __timefromdecimalday(day): day is a decimal day between 0.0 and 1.0, e.g. noon = 0.5 """ - hours = 24.0*day + hours = 24.0 * day h = int(hours) - minutes = (hours-h)*60 + minutes = (hours - h) * 60 m = int(minutes) - seconds = (minutes-m)*60 + seconds = (minutes - m) * 60 s = int(seconds) return time(hour=h, minute=m, second=s) @@ -81,14 +83,14 @@ def __preptime(self, when): # OpenOffice spreadsheets with days numbered from # 1/1/1900. The difference are those numbers taken for # 18/12/2010 - self.day = when.toordinal()-(734124-40529) + self.day = when.toordinal() - (734124 - 40529) t = when.time() - self.time = (t.hour + t.minute/60.0 + t.second/3600.0)/24.0 + self.time = (t.hour + t.minute / 60.0 + t.second / 3600.0) / 24.0 self.timezone = 0 offset = when.utcoffset() if offset is not None: - self.timezone = offset.seconds/3600.0 + self.timezone = offset.seconds / 3600.0 def __calc(self): """ @@ -99,37 +101,56 @@ def __calc(self): sunrise_t, sunset_t and solarnoon_t """ timezone = self.timezone # in hours, east is positive - longitude = self.lng # in decimal degrees, east is positive - latitude = self.lat # in decimal degrees, north is positive + longitude = self.lng # in decimal degrees, east is positive + latitude = self.lat # in decimal degrees, north is positive time = self.time # percentage past midnight, i.e. noon is 0.5 - day = self.day # daynumber 1=1/1/1900 - - jday = day+2415018.5+time-timezone/24 # Julian day - jcent = (jday-2451545)/36525 # Julian century - - manom = 357.52911+jcent*(35999.05029-0.0001537*jcent) - mlong = 280.46646+jcent*(36000.76983+jcent*0.0003032) % 360 - eccent = 0.016708634-jcent*(0.000042037+0.0001537*jcent) - mobliq = 23+(26+((21.448-jcent*(46.815+jcent*(0.00059-jcent*0.001813))))/60)/60 - obliq = mobliq+0.00256*cos(rad(125.04-1934.136*jcent)) - vary = tan(rad(obliq/2))*tan(rad(obliq/2)) - seqcent = sin(rad(manom))*(1.914602-jcent*(0.004817+0.000014*jcent)) +\ - sin(rad(2*manom))*(0.019993-0.000101*jcent)+sin(rad(3*manom))*0.000289 - struelong = mlong+seqcent - sapplong = struelong-0.00569-0.00478*sin(rad(125.04-1934.136*jcent)) - declination = deg(asin(sin(rad(obliq))*sin(rad(sapplong)))) - - eqtime = 4*deg(vary*sin(2*rad(mlong))-2*eccent*sin(rad(manom)) + - 4*eccent*vary*sin(rad(manom))*cos(2*rad(mlong)) - - 0.5*vary*vary*sin(4*rad(mlong))-1.25*eccent*eccent*sin(2*rad(manom))) - - hourangle = deg(acos(cos(rad(90.833))/(cos(rad(latitude)) * - cos(rad(declination)))-tan(rad(latitude))*tan(rad(declination)))) - - self.solarnoon_t = (720-4*longitude-eqtime+timezone*60)/1440 - self.sunrise_t = self.solarnoon_t-hourangle*4/1440 - self.sunset_t = self.solarnoon_t+hourangle*4/1440 + day = self.day # daynumber 1=1/1/1900 + + jday = day + 2415018.5 + time - timezone / 24 # Julian day + jcent = (jday - 2451545) / 36525 # Julian century + + manom = 357.52911 + jcent * (35999.05029 - 0.0001537 * jcent) + mlong = 280.46646 + jcent * (36000.76983 + jcent * 0.0003032) % 360 + eccent = 0.016708634 - jcent * (0.000042037 + 0.0001537 * jcent) + mobliq = ( + 23 + + ( + 26 + + ((21.448 - jcent * (46.815 + jcent * (0.00059 - jcent * 0.001813)))) + / 60 + ) + / 60 + ) + obliq = mobliq + 0.00256 * cos(rad(125.04 - 1934.136 * jcent)) + vary = tan(rad(obliq / 2)) * tan(rad(obliq / 2)) + seqcent = ( + sin(rad(manom)) * (1.914602 - jcent * (0.004817 + 0.000014 * jcent)) + + sin(rad(2 * manom)) * (0.019993 - 0.000101 * jcent) + + sin(rad(3 * manom)) * 0.000289 + ) + struelong = mlong + seqcent + sapplong = struelong - 0.00569 - 0.00478 * sin(rad(125.04 - 1934.136 * jcent)) + declination = deg(asin(sin(rad(obliq)) * sin(rad(sapplong)))) + + eqtime = 4 * deg( + vary * sin(2 * rad(mlong)) + - 2 * eccent * sin(rad(manom)) + + 4 * eccent * vary * sin(rad(manom)) * cos(2 * rad(mlong)) + - 0.5 * vary * vary * sin(4 * rad(mlong)) + - 1.25 * eccent * eccent * sin(2 * rad(manom)) + ) + + hourangle = deg( + acos( + cos(rad(90.833)) / (cos(rad(latitude)) * cos(rad(declination))) + - tan(rad(latitude)) * tan(rad(declination)) + ) + ) + + self.solarnoon_t = (720 - 4 * longitude - eqtime + timezone * 60) / 1440 + self.sunrise_t = self.solarnoon_t - hourangle * 4 / 1440 + self.sunset_t = self.solarnoon_t + hourangle * 4 / 1440 """ diff --git a/weather.metoffice/src/metoffice/constants.py b/weather.metoffice/src/metoffice/constants.py index d1a7f5ee7..965e0cd8d 100644 --- a/weather.metoffice/src/metoffice/constants.py +++ b/weather.metoffice/src/metoffice/constants.py @@ -1,200 +1,226 @@ +import urllib.parse + +import pytz import xbmc -import xbmcgui import xbmcaddon +import xbmcgui import xbmcvfs -import urllib.parse -import pytz # Magic numbers. See https://kodi.wiki/view/Window_IDs WEATHER_WINDOW_ID = 12600 ADDON_BROWSER_WINDOW_ID = 10040 -TZ = pytz.timezone('Europe/London') # TODO: Need to pull the actual timezone out of xbmc. Somehow. -TZUK = pytz.timezone('Europe/London') -WINDOW = xbmcgui.Window(WEATHER_WINDOW_ID) -FORECASTMAP_SLIDER = WINDOW.getProperty('ForecastMap.Slider') or '0' -OBSERVATIONMAP_SLIDER = WINDOW.getProperty('ObservationMap.Slider') or '0' -FORECASTMAP_LAYER_SELECTION = WINDOW.getProperty('ForecastMap.LayerSelection') or 'Rainfall' # @UndefinedVariable -OBSERVATIONMAP_LAYER_SELECTION = WINDOW.getProperty('ObservationMap.LayerSelection') or 'Rainfall' # @UndefinedVariable -CURRENT_VIEW = WINDOW.getProperty('Weather.CurrentView') - -ADDON = xbmcaddon.Addon(id="weather.metoffice") -DIALOG = xbmcgui.Dialog() - -KEYBOARD = xbmc.Keyboard() -ADDON_BANNER_PATH = xbmcvfs.translatePath('special://home/addons/%s/resources/banner.png' % ADDON.getAddonInfo('id')) -ADDON_DATA_PATH = xbmcvfs.translatePath('special://profile/addon_data/%s/' % ADDON.getAddonInfo('id')) - -TEMPERATUREUNITS = xbmc.getRegion('tempunit') - -API_KEY = ADDON.getSetting('ApiKey') -GEOLOCATION = ADDON.getSetting('GeoLocation') -GEOIP = ADDON.getSetting('GeoIPProvider') -FORECAST_LOCATION = ADDON.getSetting('ForecastLocation') -FORECAST_LOCATION_ID = ADDON.getSetting('ForecastLocationID') -OBSERVATION_LOCATION = ADDON.getSetting('ObservationLocation') -OBSERVATION_LOCATION_ID = ADDON.getSetting('ObservationLocationID') -REGIONAL_LOCATION = ADDON.getSetting('RegionalLocation') -REGIONAL_LOCATION_ID = ADDON.getSetting('RegionalLocationID') -LATITUDE = ADDON.getSetting('ForecastLocationLatitude') -LONGITUDE = ADDON.getSetting('ForecastLocationLongitude') - -DATAPOINT_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S' -DATAPOINT_DATE_FORMAT = '%Y-%m-%dZ' +TZ = pytz.timezone( + "Europe/London" +) # TODO: Need to pull the actual timezone out of xbmc. Somehow. + + +def window(): + return xbmcgui.Window(WEATHER_WINDOW_ID) + + +def dialog(): + return xbmcgui.Dialog() + + +def keyboard(): + return xbmc.Keyboard() + + +def addon(): + return xbmcaddon.Addon(id="weather.metoffice") + + +ADDON_BANNER_PATH = xbmcvfs.translatePath( + "special://home/addons/%s/resources/banner.png" % addon().getAddonInfo("id") +) +ADDON_DATA_PATH = xbmcvfs.translatePath( + "special://profile/addon_data/%s/" % addon().getAddonInfo("id") +) + +TEMPERATUREUNITS = xbmc.getRegion("tempunit") + +API_KEY = addon().getSetting("ApiKey") +GEOLOCATION = addon().getSetting("GeoLocation") +GEOIP = addon().getSetting("GeoIPProvider") +FORECAST_LOCATION = addon().getSetting("ForecastLocation") +FORECAST_LOCATION_ID = addon().getSetting("ForecastLocationID") +OBSERVATION_LOCATION = addon().getSetting("ObservationLocation") +OBSERVATION_LOCATION_ID = addon().getSetting("ObservationLocationID") +REGIONAL_LOCATION = addon().getSetting("RegionalLocation") +REGIONAL_LOCATION_ID = addon().getSetting("RegionalLocationID") +LATITUDE = addon().getSetting("ForecastLocationLatitude") +LONGITUDE = addon().getSetting("ForecastLocationLongitude") + +DATAPOINT_DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S" +DATAPOINT_DATE_FORMAT = "%Y-%m-%dZ" SHORT_DAY_FORMAT = "%a" SHORT_DATE_FORMAT = "%d %b" -MAPTIME_FORMAT = '%H%M %a' -ISSUEDAT_FORMAT = '%H:%M %a %d %b %Y' -TIME_FORMAT = '%H:%M' - -GOOGLE_BASE = 'http://maps.googleapis.com/maps/api/staticmap' -GOOGLE_GLOBAL = GOOGLE_BASE + "?sensor=false¢er=55,-3.5&zoom=5&size=323x472" -GOOGLE_SURFACE = GOOGLE_GLOBAL + "&maptype=satellite" -GOOGLE_MARKER = GOOGLE_GLOBAL + \ - '&style=feature:all|element:all|visibility:off&markers={0},{1}'.format(LATITUDE, LONGITUDE) +MAPTIME_FORMAT = "%H%M %a" +ISSUEDAT_FORMAT = "%H:%M %a %d %b %Y" +TIME_FORMAT = "%H:%M" RAW_DATAPOINT_IMG_WIDTH = 500 CROP_WIDTH = 40 CROP_HEIGHT = 20 WEATHER_CODES = { - 'na': ('na', 'Not Available'), - '0': ('31', 'Clear'), # night - '1': ('32', 'Sunny'), - '2': ('29', 'Partly Cloudy'), # night - '3': ('30', 'Partly Cloudy'), + "na": ("na", "Not Available"), + "0": ("31", "Clear"), # night + "1": ("32", "Sunny"), + "2": ("29", "Partly Cloudy"), # night + "3": ("30", "Partly Cloudy"), # '4': ('na', 'Not available'), - '5': ('21', 'Mist'), - '6': ('20', 'Fog'), - '7': ('26', 'Cloudy'), - '8': ('26', 'Overcast'), - '9': ('45', 'Light Rain'), # night - '10': ('11', 'Light Rain'), - '11': ('9', 'Drizzle'), - '12': ('11', 'Light Rain'), - '13': ('45', 'Heavy Rain'), # night - '14': ('40', 'Heavy Rain'), - '15': ('40', 'Heavy Rain'), - '16': ('46', 'Sleet'), # night - '17': ('6', 'Sleet'), - '18': ('6', 'Sleet'), - '19': ('45', 'Hail'), # night - '20': ('18', 'Hail'), - '21': ('18', 'Hail'), - '22': ('46', 'Light Snow'), # night - '23': ('14', 'Light snow'), - '24': ('14', 'Light Snow'), - '25': ('46', 'Heavy Snow'), # night - '26': ('16', 'Heavy Snow'), - '27': ('16', 'Heavy Snow'), - '28': ('47', 'Thunder'), # night - '29': ('17', 'Thunder'), - '30': ('17', 'Thunder') + "5": ("21", "Mist"), + "6": ("20", "Fog"), + "7": ("26", "Cloudy"), + "8": ("26", "Overcast"), + "9": ("45", "Light Rain"), # night + "10": ("11", "Light Rain"), + "11": ("9", "Drizzle"), + "12": ("11", "Light Rain"), + "13": ("45", "Heavy Rain"), # night + "14": ("40", "Heavy Rain"), + "15": ("40", "Heavy Rain"), + "16": ("46", "Sleet"), # night + "17": ("6", "Sleet"), + "18": ("6", "Sleet"), + "19": ("45", "Hail"), # night + "20": ("18", "Hail"), + "21": ("18", "Hail"), + "22": ("46", "Light Snow"), # night + "23": ("14", "Light snow"), + "24": ("14", "Light Snow"), + "25": ("46", "Heavy Snow"), # night + "26": ("16", "Heavy Snow"), + "27": ("16", "Heavy Snow"), + "28": ("47", "Thunder"), # night + "29": ("17", "Thunder"), + "30": ("17", "Thunder"), } # This list must appear in the same order as it appears in # the settings.xml in order for the indexes to align. GEOIP_PROVIDERS = [ - {'url': 'http://ip-api.com/json/', - 'latitude': 'lat', - 'longitude': 'lon'}, - {'url': 'http://freegeoip.net/json/', - 'latitude': 'latitude', - 'longitude': 'longitude'}, - {'url': 'http://geoiplookup.net/geoapi.php?output=json', - 'latitude': 'latitude', - 'longitude': 'longitude'} + {"url": "http://ip-api.com/json/", "latitude": "lat", "longitude": "lon"}, + { + "url": "http://freegeoip.net/json/", + "latitude": "latitude", + "longitude": "longitude", + }, + { + "url": "http://geoiplookup.net/geoapi.php?output=json", + "latitude": "latitude", + "longitude": "longitude", + }, ] GEOIP_PROVIDER = GEOIP_PROVIDERS[int(GEOIP) if GEOIP else 0] URL_TEMPLATE = "http://datapoint.metoffice.gov.uk/public/data/{format}/{resource}/{group}/{datatype}/{object}?{get}" FORECAST_SITELIST_URL = URL_TEMPLATE.format( - format='val', - resource='wxfcs', - group='all', - datatype='json', - object='sitelist', - get=urllib.parse.unquote(urllib.parse.urlencode((('key', API_KEY),)))) + format="val", + resource="wxfcs", + group="all", + datatype="json", + object="sitelist", + get=urllib.parse.unquote(urllib.parse.urlencode((("key", API_KEY),))), +) OBSERVATION_SITELIST_URL = URL_TEMPLATE.format( - format='val', - resource='wxobs', - group='all', - datatype='json', - object='sitelist', - get=urllib.parse.unquote(urllib.parse.urlencode((('key', API_KEY),)))) + format="val", + resource="wxobs", + group="all", + datatype="json", + object="sitelist", + get=urllib.parse.unquote(urllib.parse.urlencode((("key", API_KEY),))), +) REGIONAL_SITELIST_URL = URL_TEMPLATE.format( - format='txt', - resource='wxfcs', - group='regionalforecast', - datatype='json', - object='sitelist', - get=urllib.parse.unquote(urllib.parse.urlencode((('key', API_KEY),)))) + format="txt", + resource="wxfcs", + group="regionalforecast", + datatype="json", + object="sitelist", + get=urllib.parse.unquote(urllib.parse.urlencode((("key", API_KEY),))), +) DAILY_LOCATION_FORECAST_URL = URL_TEMPLATE.format( - format='val', - resource='wxfcs', - group='all', - datatype='json', + format="val", + resource="wxfcs", + group="all", + datatype="json", object=FORECAST_LOCATION_ID, - get=urllib.parse.unquote(urllib.parse.urlencode((('res', 'daily'), ('key', API_KEY))))) + get=urllib.parse.unquote( + urllib.parse.urlencode((("res", "daily"), ("key", API_KEY))) + ), +) THREEHOURLY_LOCATION_FORECAST_URL = URL_TEMPLATE.format( - format='val', - resource='wxfcs', - group='all', - datatype='json', + format="val", + resource="wxfcs", + group="all", + datatype="json", object=FORECAST_LOCATION_ID, - get=urllib.parse.unquote(urllib.parse.urlencode((('res', '3hourly'), ('key', API_KEY))))) + get=urllib.parse.unquote( + urllib.parse.urlencode((("res", "3hourly"), ("key", API_KEY))) + ), +) HOURLY_LOCATION_OBSERVATION_URL = URL_TEMPLATE.format( - format='val', - resource='wxobs', - group='all', - datatype='json', + format="val", + resource="wxobs", + group="all", + datatype="json", object=OBSERVATION_LOCATION_ID, - get=urllib.parse.unquote(urllib.parse.urlencode((('res', 'hourly'), ('key', API_KEY))))) + get=urllib.parse.unquote( + urllib.parse.urlencode((("res", "hourly"), ("key", API_KEY))) + ), +) TEXT_FORECAST_URL = URL_TEMPLATE.format( - format='txt', - resource='wxfcs', - group='regionalforecast', - datatype='json', + format="txt", + resource="wxfcs", + group="regionalforecast", + datatype="json", object=REGIONAL_LOCATION_ID, - get=urllib.parse.unquote(urllib.parse.urlencode((('key', API_KEY),)))) + get=urllib.parse.unquote(urllib.parse.urlencode((("key", API_KEY),))), +) FORECAST_LAYER_CAPABILITIES_URL = URL_TEMPLATE.format( - format='layer', - resource='wxfcs', - group='all', - datatype='json', - object='capabilities', - get=urllib.parse.unquote(urllib.parse.urlencode((('key', API_KEY),)))) + format="layer", + resource="wxfcs", + group="all", + datatype="json", + object="capabilities", + get=urllib.parse.unquote(urllib.parse.urlencode((("key", API_KEY),))), +) OBSERVATION_LAYER_CAPABILITIES_URL = URL_TEMPLATE.format( - format='layer', - resource='wxobs', - group='all', - datatype='json', - object='capabilities', - get=urllib.parse.unquote(urllib.parse.urlencode((('key', API_KEY),)))) - -LONG_REGIONAL_NAMES = {'os': 'Orkney and Shetland', - 'he': 'Highland and Eilean Siar', - 'gr': 'Grampian', - 'ta': 'Tayside', - 'st': 'Strathclyde', - 'dg': 'Dumfries, Galloway, Lothian', - 'ni': 'Northern Ireland', - 'yh': 'Yorkshire and the Humber', - 'ne': 'Northeast England', - 'em': 'East Midlands', - 'ee': 'East of England', - 'se': 'London and Southeast England', - 'nw': 'Northwest England', - 'wm': 'West Midlands', - 'sw': 'Southwest England', - 'wl': 'Wales', - 'uk': 'United Kingdom'} + format="layer", + resource="wxobs", + group="all", + datatype="json", + object="capabilities", + get=urllib.parse.unquote(urllib.parse.urlencode((("key", API_KEY),))), +) + +LONG_REGIONAL_NAMES = { + "os": "Orkney and Shetland", + "he": "Highland and Eilean Siar", + "gr": "Grampian", + "ta": "Tayside", + "st": "Strathclyde", + "dg": "Dumfries, Galloway, Lothian", + "ni": "Northern Ireland", + "yh": "Yorkshire and the Humber", + "ne": "Northeast England", + "em": "East Midlands", + "ee": "East of England", + "se": "London and Southeast England", + "nw": "Northwest England", + "wm": "West Midlands", + "sw": "Southwest England", + "wl": "Wales", + "uk": "United Kingdom", +} diff --git a/weather.metoffice/src/metoffice/properties.py b/weather.metoffice/src/metoffice/properties.py index ae1725423..76164986e 100644 --- a/weather.metoffice/src/metoffice/properties.py +++ b/weather.metoffice/src/metoffice/properties.py @@ -1,447 +1,374 @@ +import json import time +from datetime import timedelta + import pytz -from datetime import datetime, timedelta -import json -from PIL import Image -from . import astronomy -from . import utilities -from . import urlcache -from .constants import ISSUEDAT_FORMAT, DATAPOINT_DATETIME_FORMAT,\ - SHORT_DAY_FORMAT, SHORT_DATE_FORMAT, TIME_FORMAT, DATAPOINT_DATE_FORMAT,\ - WEATHER_CODES, WINDOW, DAILY_LOCATION_FORECAST_URL,\ - API_KEY, ADDON_DATA_PATH, THREEHOURLY_LOCATION_FORECAST_URL,\ - TEXT_FORECAST_URL, HOURLY_LOCATION_OBSERVATION_URL,\ - FORECAST_LAYER_CAPABILITIES_URL, OBSERVATION_LAYER_CAPABILITIES_URL,\ - RAW_DATAPOINT_IMG_WIDTH, CROP_WIDTH, CROP_HEIGHT, GOOGLE_SURFACE,\ - GOOGLE_MARKER, MAPTIME_FORMAT, REGIONAL_LOCATION, REGIONAL_LOCATION_ID,\ - FORECAST_LOCATION, FORECAST_LOCATION_ID, OBSERVATION_LOCATION,\ - OBSERVATION_LOCATION_ID, FORECASTMAP_SLIDER, OBSERVATIONMAP_SLIDER,\ - FORECASTMAP_LAYER_SELECTION, OBSERVATIONMAP_LAYER_SELECTION, TZ, TZUK,\ - TEMPERATUREUNITS, LATITUDE, LONGITUDE +from . import astronomy, urlcache, utilities +from .constants import ( + ADDON_DATA_PATH, + DAILY_LOCATION_FORECAST_URL, + DATAPOINT_DATE_FORMAT, + DATAPOINT_DATETIME_FORMAT, + FORECAST_LOCATION, + FORECAST_LOCATION_ID, + HOURLY_LOCATION_OBSERVATION_URL, + ISSUEDAT_FORMAT, + LATITUDE, + LONGITUDE, + OBSERVATION_LOCATION, + OBSERVATION_LOCATION_ID, + REGIONAL_LOCATION, + REGIONAL_LOCATION_ID, + SHORT_DATE_FORMAT, + SHORT_DAY_FORMAT, + TEMPERATUREUNITS, + TEXT_FORECAST_URL, + THREEHOURLY_LOCATION_FORECAST_URL, + TIME_FORMAT, + TZ, + WEATHER_CODES, + window, +) def observation(): - utilities.log("Fetching Hourly Observation for '%s (%s)' from the Met Office..." % ( - OBSERVATION_LOCATION, OBSERVATION_LOCATION_ID)) + utilities.log( + "Fetching Hourly Observation for '%s (%s)' from the Met Office..." + % (OBSERVATION_LOCATION, OBSERVATION_LOCATION_ID) + ) with urlcache.URLCache(ADDON_DATA_PATH) as cache: - filename = cache.get( - HOURLY_LOCATION_OBSERVATION_URL, observation_expiry) + filename = cache.get(HOURLY_LOCATION_OBSERVATION_URL, observation_expiry) with open(filename) as fh: data = json.load(fh) try: - dv = data['SiteRep']['DV'] - dataDate = utilities.strptime(dv.get('dataDate').rstrip( - 'Z'), DATAPOINT_DATETIME_FORMAT).replace(tzinfo=pytz.utc) - WINDOW.setProperty('HourlyObservation.IssuedAt', dataDate.astimezone( - TZ).strftime(ISSUEDAT_FORMAT)) + dv = data["SiteRep"]["DV"] + dataDate = utilities.strptime( + dv.get("dataDate").rstrip("Z"), DATAPOINT_DATETIME_FORMAT + ).replace(tzinfo=pytz.utc) + window().setProperty( + "HourlyObservation.IssuedAt", + dataDate.astimezone(TZ).strftime(ISSUEDAT_FORMAT), + ) try: - latest_period = dv['Location']['Period'][-1] + latest_period = dv["Location"]["Period"][-1] except KeyError: - latest_period = dv['Location']['Period'] + latest_period = dv["Location"]["Period"] try: - latest_obs = latest_period['Rep'][-1] + latest_obs = latest_period["Rep"][-1] except KeyError: - latest_obs = latest_period['Rep'] - WINDOW.setProperty('Current.Condition', WEATHER_CODES[latest_obs.get( - 'W', 'na')][1]) - WINDOW.setProperty('Current.Visibility', latest_obs.get( - 'V', 'n/a')) - WINDOW.setProperty('Current.Pressure', latest_obs.get( - 'P', 'n/a')) - WINDOW.setProperty('Current.Temperature', str( - round(float(latest_obs.get('T', 'n/a')))).split('.')[0]) - WINDOW.setProperty('Current.FeelsLike', 'n/a') + latest_obs = latest_period["Rep"] + window().setProperty( + "Current.Condition", WEATHER_CODES[latest_obs.get("W", "na")][1] + ) + window().setProperty("Current.Visibility", latest_obs.get("V", "n/a")) + window().setProperty("Current.Pressure", latest_obs.get("P", "n/a")) + window().setProperty( + "Current.Temperature", + str(round(float(latest_obs.get("T", "n/a")))).split(".")[0], + ) + window().setProperty("Current.FeelsLike", "n/a") # if we get Wind, then convert it to kmph. - WINDOW.setProperty('Current.Wind', utilities.mph_to_kmph( - latest_obs, 'S')) - WINDOW.setProperty('Current.WindDirection', latest_obs.get( - 'D', 'n/a')) - WINDOW.setProperty('Current.WindGust', latest_obs.get( - 'G', 'n/a')) - WINDOW.setProperty('Current.OutlookIcon', '%s.png' % - WEATHER_CODES[latest_obs.get('W', 'na')][0]) - WINDOW.setProperty('Current.FanartCode', '%s.png' % WEATHER_CODES[latest_obs.get( - 'W', 'na')][0]) - WINDOW.setProperty('Current.DewPoint', str( - round(float(latest_obs.get('Dp', 'n/a')))).split('.')[0]) - WINDOW.setProperty('Current.Humidity', str( - round(float(latest_obs.get('H', 'n/a')))).split('.')[0]) - - WINDOW.setProperty('HourlyObservation.IsFetched', - 'true') + window().setProperty("Current.Wind", utilities.mph_to_kmph(latest_obs, "S")) + window().setProperty("Current.WindDirection", latest_obs.get("D", "n/a")) + window().setProperty("Current.WindGust", latest_obs.get("G", "n/a")) + window().setProperty( + "Current.OutlookIcon", + "%s.png" % WEATHER_CODES[latest_obs.get("W", "na")][0], + ) + window().setProperty( + "Current.FanartCode", "%s.png" % WEATHER_CODES[latest_obs.get("W", "na")][0] + ) + window().setProperty( + "Current.DewPoint", + str(round(float(latest_obs.get("Dp", "n/a")))).split(".")[0], + ) + window().setProperty( + "Current.Humidity", + str(round(float(latest_obs.get("H", "n/a")))).split(".")[0], + ) + + window().setProperty("HourlyObservation.IsFetched", "true") except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), HOURLY_LOCATION_OBSERVATION_URL) + e.args = ( + "Key Error in JSON File", + "Key '{0}' not found while processing file from url:".format(e.args[0]), + HOURLY_LOCATION_OBSERVATION_URL, + ) raise def daily(): - utilities.log("Fetching Daily Forecast for '%s (%s)' from the Met Office..." % ( - FORECAST_LOCATION, FORECAST_LOCATION_ID)) + utilities.log( + "Fetching Daily Forecast for '%s (%s)' from the Met Office..." + % (FORECAST_LOCATION, FORECAST_LOCATION_ID) + ) with urlcache.URLCache(ADDON_DATA_PATH) as cache: filename = cache.get(DAILY_LOCATION_FORECAST_URL, daily_expiry) with open(filename) as fh: data = json.load(fh) try: - dv = data['SiteRep']['DV'] - dataDate = utilities.strptime(dv.get('dataDate').rstrip( - 'Z'), DATAPOINT_DATETIME_FORMAT).replace(tzinfo=pytz.utc) - WINDOW.setProperty('DailyForecast.IssuedAt', dataDate.astimezone( - TZ).strftime(ISSUEDAT_FORMAT)) - for p, period in enumerate(dv['Location']['Period']): - WINDOW.setProperty('Day%d.Title' % p, time.strftime(SHORT_DAY_FORMAT, time.strptime( - period.get('value'), DATAPOINT_DATE_FORMAT))) - WINDOW.setProperty('Daily.%d.ShortDay' % (p+1), time.strftime(SHORT_DAY_FORMAT, - time.strptime(period.get('value'), DATAPOINT_DATE_FORMAT))) - WINDOW.setProperty('Daily.%d.ShortDate' % (p+1), time.strftime(SHORT_DATE_FORMAT, - time.strptime(period.get('value'), DATAPOINT_DATE_FORMAT))) - for rep in period['Rep']: - weather_type = rep.get('W', 'na') - if rep.get('$') == 'Day': - WINDOW.setProperty('Day%d.HighTemp' % p, rep.get( - 'Dm', 'na')) - WINDOW.setProperty('Day%d.HighTempIcon' % - p, rep.get('Dm')) - WINDOW.setProperty('Day%d.Outlook' % p, WEATHER_CODES.get( - weather_type)[1]) - WINDOW.setProperty('Day%d.OutlookIcon' % p, "%s.png" % WEATHER_CODES.get( - weather_type, 'na')[0]) - WINDOW.setProperty('Day%d.WindSpeed' % p, rep.get( - 'S', 'na')) - WINDOW.setProperty('Day%d.WindDirection' % p, rep.get( - 'D', 'na').lower()) + dv = data["SiteRep"]["DV"] + dataDate = utilities.strptime( + dv.get("dataDate").rstrip("Z"), DATAPOINT_DATETIME_FORMAT + ).replace(tzinfo=pytz.utc) + window().setProperty( + "DailyForecast.IssuedAt", dataDate.astimezone(TZ).strftime(ISSUEDAT_FORMAT) + ) + for p, period in enumerate(dv["Location"]["Period"]): + window().setProperty( + "Day%d.Title" % p, + time.strftime( + SHORT_DAY_FORMAT, + time.strptime(period.get("value"), DATAPOINT_DATE_FORMAT), + ), + ) + window().setProperty( + "Daily.%d.ShortDay" % (p + 1), + time.strftime( + SHORT_DAY_FORMAT, + time.strptime(period.get("value"), DATAPOINT_DATE_FORMAT), + ), + ) + window().setProperty( + "Daily.%d.ShortDate" % (p + 1), + time.strftime( + SHORT_DATE_FORMAT, + time.strptime(period.get("value"), DATAPOINT_DATE_FORMAT), + ), + ) + for rep in period["Rep"]: + weather_type = rep.get("W", "na") + if rep.get("$") == "Day": + window().setProperty("Day%d.HighTemp" % p, rep.get("Dm", "na")) + window().setProperty("Day%d.HighTempIcon" % p, rep.get("Dm")) + window().setProperty( + "Day%d.Outlook" % p, WEATHER_CODES.get(weather_type)[1] + ) + window().setProperty( + "Day%d.OutlookIcon" % p, + "%s.png" % WEATHER_CODES.get(weather_type, "na")[0], + ) + window().setProperty("Day%d.WindSpeed" % p, rep.get("S", "na")) + window().setProperty( + "Day%d.WindDirection" % p, rep.get("D", "na").lower() + ) # "Extended" properties used by some skins. - WINDOW.setProperty('Daily.%d.HighTemperature' % ( - p+1), utilities.localised_temperature(rep.get('Dm', 'na'))+TEMPERATUREUNITS) - WINDOW.setProperty('Daily.%d.HighTempIcon' % ( - p+1), rep.get('Dm')) - WINDOW.setProperty('Daily.%d.Outlook' % ( - p+1), WEATHER_CODES.get(weather_type)[1]) - WINDOW.setProperty('Daily.%d.OutlookIcon' % ( - p+1), "%s.png" % WEATHER_CODES.get(weather_type, 'na')[0]) - WINDOW.setProperty('Daily.%d.FanartCode' % ( - p+1), WEATHER_CODES.get(weather_type, 'na')[0]) - WINDOW.setProperty('Daily.%d.WindSpeed' % ( - p+1), rep.get('S', 'na')) - WINDOW.setProperty('Daily.%d.WindDirection' % ( - p+1), rep.get('D', 'na').lower()) - - elif rep.get('$') == 'Night': - WINDOW.setProperty('Day%d.LowTemp' % p, rep.get( - 'Nm', 'na')) - WINDOW.setProperty('Day%d.LowTempIcon' % - p, rep.get('Nm')) - - WINDOW.setProperty('Daily.%d.LowTemperature' % ( - p+1), utilities.localised_temperature(rep.get('Nm', 'na'))+TEMPERATUREUNITS) - WINDOW.setProperty('Daily.%d.LowTempIcon' % ( - p+1), rep.get('Nm')) + window().setProperty( + "Daily.%d.HighTemperature" % (p + 1), + utilities.localised_temperature(rep.get("Dm", "na")) + + TEMPERATUREUNITS, + ) + window().setProperty( + "Daily.%d.HighTempIcon" % (p + 1), rep.get("Dm") + ) + window().setProperty( + "Daily.%d.Outlook" % (p + 1), WEATHER_CODES.get(weather_type)[1] + ) + window().setProperty( + "Daily.%d.OutlookIcon" % (p + 1), + "%s.png" % WEATHER_CODES.get(weather_type, "na")[0], + ) + window().setProperty( + "Daily.%d.FanartCode" % (p + 1), + WEATHER_CODES.get(weather_type, "na")[0], + ) + window().setProperty( + "Daily.%d.WindSpeed" % (p + 1), rep.get("S", "na") + ) + window().setProperty( + "Daily.%d.WindDirection" % (p + 1), rep.get("D", "na").lower() + ) + + elif rep.get("$") == "Night": + window().setProperty("Day%d.LowTemp" % p, rep.get("Nm", "na")) + window().setProperty("Day%d.LowTempIcon" % p, rep.get("Nm")) + + window().setProperty( + "Daily.%d.LowTemperature" % (p + 1), + utilities.localised_temperature(rep.get("Nm", "na")) + + TEMPERATUREUNITS, + ) + window().setProperty( + "Daily.%d.LowTempIcon" % (p + 1), rep.get("Nm") + ) except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), DAILY_LOCATION_FORECAST_URL) + e.args = ( + "Key Error in JSON File", + "Key '{0}' not found while processing file from url:".format(e.args[0]), + DAILY_LOCATION_FORECAST_URL, + ) raise - WINDOW.setProperty('Daily.IsFetched', 'true') + window().setProperty("Daily.IsFetched", "true") def threehourly(): - utilities.log("Fetching 3 Hourly Forecast for '%s (%s)' from the Met Office..." % ( - FORECAST_LOCATION, FORECAST_LOCATION_ID)) + utilities.log( + "Fetching 3 Hourly Forecast for '%s (%s)' from the Met Office..." + % (FORECAST_LOCATION, FORECAST_LOCATION_ID) + ) with urlcache.URLCache(ADDON_DATA_PATH) as cache: - filename = cache.get( - THREEHOURLY_LOCATION_FORECAST_URL, threehourly_expiry) + filename = cache.get(THREEHOURLY_LOCATION_FORECAST_URL, threehourly_expiry) with open(filename) as fh: data = json.load(fh) try: - dv = data['SiteRep']['DV'] - dataDate = utilities.strptime(dv.get('dataDate').rstrip( - 'Z'), DATAPOINT_DATETIME_FORMAT).replace(tzinfo=pytz.utc) - WINDOW.setProperty('3HourlyForecast.IssuedAt', dataDate.astimezone( - TZ).strftime(ISSUEDAT_FORMAT)) + dv = data["SiteRep"]["DV"] + dataDate = utilities.strptime( + dv.get("dataDate").rstrip("Z"), DATAPOINT_DATETIME_FORMAT + ).replace(tzinfo=pytz.utc) + window().setProperty( + "3HourlyForecast.IssuedAt", + dataDate.astimezone(TZ).strftime(ISSUEDAT_FORMAT), + ) count = 1 - for period in dv['Location']['Period']: - for rep in period['Rep']: + for period in dv["Location"]["Period"]: + for rep in period["Rep"]: # extra xbmc targeted info: - weather_type = rep.get('W', 'na') - WINDOW.setProperty('Hourly.%d.Outlook' % count, WEATHER_CODES.get( - weather_type)[1]) - WINDOW.setProperty('Hourly.%d.WindSpeed' % count, rep.get( - 'S', 'n/a')) - WINDOW.setProperty('Hourly.%d.WindDirection' % count, rep.get( - 'D', 'na').lower()) - WINDOW.setProperty('Hourly.%d.GustSpeed' % count, rep.get( - 'G', 'n/a')) - WINDOW.setProperty('Hourly.%d.UVIndex' % count, rep.get( - 'U', 'n/a')) - WINDOW.setProperty('Hourly.%d.Precipitation' % - count, rep.get('Pp') + "%") - WINDOW.setProperty('Hourly.%d.OutlookIcon' % count, "%s.png" % WEATHER_CODES.get( - weather_type, 'na')[0]) - WINDOW.setProperty('Hourly.%d.ShortDate' % count, time.strftime(SHORT_DATE_FORMAT, time.strptime( - period.get('value'), DATAPOINT_DATE_FORMAT))) - WINDOW.setProperty('Hourly.%d.Time' % count, utilities.minutes_as_time( - int(rep.get('$')))) - WINDOW.setProperty('Hourly.%d.Temperature' % count, utilities.rownd( - utilities.localised_temperature(rep.get('T', 'na')))+TEMPERATUREUNITS) - WINDOW.setProperty('Hourly.%d.ActualTempIcon' % - count, rep.get('T', 'na')) - WINDOW.setProperty('Hourly.%d.FeelsLikeTemp' % count, utilities.rownd( - utilities.localised_temperature(rep.get('F', 'na')))) - WINDOW.setProperty('Hourly.%d.FeelsLikeTempIcon' % - count, rep.get('F', 'na')) + weather_type = rep.get("W", "na") + window().setProperty( + "Hourly.%d.Outlook" % count, WEATHER_CODES.get(weather_type)[1] + ) + window().setProperty("Hourly.%d.WindSpeed" % count, rep.get("S", "n/a")) + window().setProperty( + "Hourly.%d.WindDirection" % count, rep.get("D", "na").lower() + ) + window().setProperty("Hourly.%d.GustSpeed" % count, rep.get("G", "n/a")) + window().setProperty("Hourly.%d.UVIndex" % count, rep.get("U", "n/a")) + window().setProperty( + "Hourly.%d.Precipitation" % count, rep.get("Pp") + "%" + ) + window().setProperty( + "Hourly.%d.OutlookIcon" % count, + "%s.png" % WEATHER_CODES.get(weather_type, "na")[0], + ) + window().setProperty( + "Hourly.%d.ShortDate" % count, + time.strftime( + SHORT_DATE_FORMAT, + time.strptime(period.get("value"), DATAPOINT_DATE_FORMAT), + ), + ) + window().setProperty( + "Hourly.%d.Time" % count, + utilities.minutes_as_time(int(rep.get("$"))), + ) + window().setProperty( + "Hourly.%d.Temperature" % count, + utilities.rownd(utilities.localised_temperature(rep.get("T", "na"))) + + TEMPERATUREUNITS, + ) + window().setProperty( + "Hourly.%d.ActualTempIcon" % count, rep.get("T", "na") + ) + window().setProperty( + "Hourly.%d.FeelsLikeTemp" % count, + utilities.rownd( + utilities.localised_temperature(rep.get("F", "na")) + ), + ) + window().setProperty( + "Hourly.%d.FeelsLikeTempIcon" % count, rep.get("F", "na") + ) count += 1 except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), THREEHOURLY_LOCATION_FORECAST_URL) + e.args = ( + "Key Error in JSON File", + "Key '{0}' not found while processing file from url:".format(e.args[0]), + THREEHOURLY_LOCATION_FORECAST_URL, + ) raise - WINDOW.setProperty('Hourly.IsFetched', 'true') + window().setProperty("Hourly.IsFetched", "true") def sunrisesunset(): sun = astronomy.Sun(lat=float(LATITUDE), lng=float(LONGITUDE)) - WINDOW.setProperty('Today.Sunrise', sun.sunrise().strftime(TIME_FORMAT)) - WINDOW.setProperty('Today.Sunset', sun.sunset().strftime(TIME_FORMAT)) + window().setProperty("Today.Sunrise", sun.sunrise().strftime(TIME_FORMAT)) + window().setProperty("Today.Sunset", sun.sunset().strftime(TIME_FORMAT)) def text(): - utilities.log("Fetching Text Forecast for '%s (%s)' from the Met Office..." % ( - REGIONAL_LOCATION, REGIONAL_LOCATION_ID)) + utilities.log( + "Fetching Text Forecast for '%s (%s)' from the Met Office..." + % (REGIONAL_LOCATION, REGIONAL_LOCATION_ID) + ) with urlcache.URLCache(ADDON_DATA_PATH) as cache: filename = cache.get(TEXT_FORECAST_URL, text_expiry) with open(filename) as fh: data = json.load(fh) try: - rf = data['RegionalFcst'] - issuedat = utilities.strptime(rf['issuedAt'].rstrip( - 'Z'), DATAPOINT_DATETIME_FORMAT).replace(tzinfo=pytz.utc) - WINDOW.setProperty('TextForecast.IssuedAt', issuedat.astimezone( - TZ).strftime(ISSUEDAT_FORMAT)) + rf = data["RegionalFcst"] + issuedat = utilities.strptime( + rf["issuedAt"].rstrip("Z"), DATAPOINT_DATETIME_FORMAT + ).replace(tzinfo=pytz.utc) + window().setProperty( + "TextForecast.IssuedAt", issuedat.astimezone(TZ).strftime(ISSUEDAT_FORMAT) + ) count = 0 - for period in rf['FcstPeriods']['Period']: + for period in rf["FcstPeriods"]["Period"]: # have to check type because json can return list or dict here - if isinstance(period['Paragraph'], list): - for paragraph in period['Paragraph']: - WINDOW.setProperty('Text.Paragraph%d.Title' % count, paragraph['title'].rstrip( - ':').lstrip('UK Outlook for')) - WINDOW.setProperty('Text.Paragraph%d.Content' % - count, paragraph['$']) + if isinstance(period["Paragraph"], list): + for paragraph in period["Paragraph"]: + window().setProperty( + "Text.Paragraph%d.Title" % count, + paragraph["title"].rstrip(":").lstrip("UK Outlook for"), + ) + window().setProperty( + "Text.Paragraph%d.Content" % count, paragraph["$"] + ) count += 1 else: - WINDOW.setProperty('Text.Paragraph%d.Title' % count, period['Paragraph']['title'].rstrip( - ':').lstrip('UK Outlook for')) - - WINDOW.setProperty('Text.Paragraph%d.Content' % - count, period['Paragraph']['$']) + window().setProperty( + "Text.Paragraph%d.Title" % count, + period["Paragraph"]["title"].rstrip(":").lstrip("UK Outlook for"), + ) + + window().setProperty( + "Text.Paragraph%d.Content" % count, period["Paragraph"]["$"] + ) count += 1 except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), TEXT_FORECAST_URL) + e.args = ( + "Key Error in JSON File", + "Key '{0}' not found while processing file from url:".format(e.args[0]), + TEXT_FORECAST_URL, + ) raise - WINDOW.setProperty('TextForecast.IsFetched', 'true') - - -def forecastlayer(): - utilities.log("Fetching '{0}' Forecast Map with index '{1}'...".format( - FORECASTMAP_LAYER_SELECTION, FORECASTMAP_SLIDER)) - with urlcache.URLCache(ADDON_DATA_PATH) as cache: - surface = cache.get( - GOOGLE_SURFACE, lambda x: datetime.utcnow() + timedelta(days=30)) - marker = cache.get( - GOOGLE_MARKER, lambda x: datetime.utcnow() + timedelta(days=30)) - - filename = cache.get(FORECAST_LAYER_CAPABILITIES_URL, - forecastlayer_capabilities_expiry) - with open(filename) as fh: - data = json.load(fh) - # pull parameters out of capabilities file - TODO: consider using jsonpath here - try: - for thislayer in data['Layers']['Layer']: - if thislayer['@displayName'] == FORECASTMAP_LAYER_SELECTION: - layer_name = thislayer['Service']['LayerName'] - image_format = thislayer['Service']['ImageFormat'] - default_time = thislayer['Service']['Timesteps']['@defaultTime'] - timesteps = thislayer['Service']['Timesteps']['Timestep'] - break - else: - raise Exception('Error', "Couldn't find layer '%s'" % - FORECASTMAP_LAYER_SELECTION) - except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), FORECAST_LAYER_CAPABILITIES_URL) - raise - - issuedat = utilities.strptime( - default_time, DATAPOINT_DATETIME_FORMAT).replace(tzinfo=pytz.utc) - - index = FORECASTMAP_SLIDER - if int(index) < 0: - utilities.log('Slider is negative. Fetching with index 0') - WINDOW.setProperty('ForecastMap.Slider', '0') - index = '0' - elif int(index) > len(timesteps)-1: - utilities.log('Slider exceeds available index range. Fetching with index {0}'.format( - str(len(timesteps)-1))) - WINDOW.setProperty('ForecastMap.Slider', str( - len(timesteps)-1)) - index = str(len(timesteps)-1) - - timestep = timesteps[int(index)] - delta = timedelta(hours=timestep) - maptime = TZUK.normalize(issuedat + delta) - - # get overlay using parameters from gui settings - try: - LayerURL = data['Layers']['BaseUrl']['$'] - except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), FORECAST_LAYER_CAPABILITIES_URL) - raise - - url = LayerURL.format(LayerName=layer_name, - ImageFormat=image_format, - DefaultTime=default_time, - Timestep=timestep, - key=API_KEY) - layer = cache.get(url, lambda x: datetime.utcnow() + - timedelta(days=1), image_resize) - - WINDOW.setProperty('ForecastMap.Surface', - surface) - WINDOW.setProperty('ForecastMap.Marker', marker) - WINDOW.setProperty('ForecastMap.IssuedAt', issuedat.astimezone( - TZ).strftime(ISSUEDAT_FORMAT)) - WINDOW.setProperty('ForecastMap.MapTime', maptime.strftime( - MAPTIME_FORMAT)) - WINDOW.setProperty('ForecastMap.Layer', layer) - WINDOW.setProperty('ForecastMap.IsFetched', - 'true') - - -def observationlayer(): - utilities.log("Fetching '{0}' Observation Map with index '{1}'...".format( - OBSERVATIONMAP_LAYER_SELECTION, OBSERVATIONMAP_SLIDER)) - - with urlcache.URLCache(ADDON_DATA_PATH) as cache: - surface = cache.get( - GOOGLE_SURFACE, lambda x: datetime.utcnow() + timedelta(days=30)) - marker = cache.get( - GOOGLE_MARKER, lambda x: datetime.utcnow() + timedelta(days=30)) - - filename = cache.get(OBSERVATION_LAYER_CAPABILITIES_URL, - observationlayer_capabilities_expiry) - with open(filename) as fh: - data = json.load(fh) - # pull parameters out of capabilities file - TODO: consider using jsonpath here - try: - issued_at = data['Layers']['Layer'][-1]['Service']['Times']['Time'][0] - issuedat = utilities.strptime(issued_at, DATAPOINT_DATETIME_FORMAT).replace(tzinfo=pytz.utc) - for thislayer in data['Layers']['Layer']: - if thislayer['@displayName'] == OBSERVATIONMAP_LAYER_SELECTION: - layer_name = thislayer['Service']['LayerName'] - image_format = thislayer['Service']['ImageFormat'] - times = thislayer['Service']['Times']['Time'] - break - else: - raise Exception('Error', "Couldn't find layer '%s'" % - OBSERVATIONMAP_LAYER_SELECTION) - except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), OBSERVATION_LAYER_CAPABILITIES_URL) - raise - - index = OBSERVATIONMAP_SLIDER - if int(index) < 0: - utilities.log('Slider is negative. Fetching with index 0') - WINDOW.setProperty('ObservationMap.Slider', - '0') - index = '0' - elif int(index) > len(times)-1: - utilities.log('Slider exceeds available index range. Fetching with index {0}'.format( - str(len(times)-1))) - WINDOW.setProperty('ObservationMap.Slider', str( - len(times)-1)) - index = str(len(times)-1) - - indexedtime = times[int(index)] - maptime = utilities.strptime( - indexedtime, DATAPOINT_DATETIME_FORMAT).replace(tzinfo=pytz.utc) - - # get overlay using parameters from gui settings - try: - LayerURL = data['Layers']['BaseUrl']['$'] - except KeyError as e: - e.args = ("Key Error in JSON File", "Key '{0}' not found while processing file from url:".format( - e.args[0]), OBSERVATION_LAYER_CAPABILITIES_URL) - raise - - url = LayerURL.format(LayerName=layer_name, - ImageFormat=image_format, - Time=indexedtime, - key=API_KEY) - layer = cache.get(url, lambda x: datetime.utcnow() + - timedelta(days=1), image_resize) - - WINDOW.setProperty('ObservationMap.Surface', surface) - WINDOW.setProperty('ObservationMap.Marker', marker) - WINDOW.setProperty('ObservationMap.IssuedAt', issuedat.astimezone( - TZ).strftime(ISSUEDAT_FORMAT)) - WINDOW.setProperty('ObservationMap.MapTime', maptime.astimezone( - TZUK).strftime(MAPTIME_FORMAT)) - WINDOW.setProperty('ObservationMap.Layer', layer) - WINDOW.setProperty('ObservationMap.IsFetched', 'true') + window().setProperty("TextForecast.IsFetched", "true") def daily_expiry(filename): with open(filename) as fh: data = json.load(fh) - dataDate = data['SiteRep']['DV']['dataDate'].rstrip('Z') - return utilities.strptime(dataDate, DATAPOINT_DATETIME_FORMAT) + timedelta(hours=1.5) + dataDate = data["SiteRep"]["DV"]["dataDate"].rstrip("Z") + return utilities.strptime(dataDate, DATAPOINT_DATETIME_FORMAT) + timedelta( + hours=1.5 + ) def threehourly_expiry(filename): with open(filename) as fh: data = json.load(fh) - dataDate = data['SiteRep']['DV']['dataDate'].rstrip('Z') - return utilities.strptime(dataDate, DATAPOINT_DATETIME_FORMAT) + timedelta(hours=1.5) + dataDate = data["SiteRep"]["DV"]["dataDate"].rstrip("Z") + return utilities.strptime(dataDate, DATAPOINT_DATETIME_FORMAT) + timedelta( + hours=1.5 + ) def text_expiry(filename): with open(filename) as fh: data = json.load(fh) - issuedAt = data['RegionalFcst']['issuedAt'].rstrip('Z') + issuedAt = data["RegionalFcst"]["issuedAt"].rstrip("Z") return utilities.strptime(issuedAt, DATAPOINT_DATETIME_FORMAT) + timedelta(hours=12) def observation_expiry(filename): with open(filename) as fh: data = json.load(fh) - dataDate = data['SiteRep']['DV']['dataDate'].rstrip('Z') - return utilities.strptime(dataDate, DATAPOINT_DATETIME_FORMAT) + timedelta(hours=1.5) - - -def forecastlayer_capabilities_expiry(filename): - with open(filename) as fh: - data = json.load(fh) - defaultTime = data['Layers']['Layer'][0]['Service']['Timesteps']['@defaultTime'] - return utilities.strptime(defaultTime, DATAPOINT_DATETIME_FORMAT) + timedelta(hours=9) - - -def observationlayer_capabilities_expiry(filename): - # TODO: Assumes 'Rainfall' is the last report in the file, and Rainfall is the best indicator of issue time - with open(filename) as fh: - data = json.load(fh) - tyme = data['Layers']['Layer'][-1]['Service']['Times']['Time'][0] - return utilities.strptime(tyme, DATAPOINT_DATETIME_FORMAT) + timedelta(minutes=30) - - -def image_resize(filename): - # remove the 'cone' from the image - with Image.open(filename) as img: - (width, height) = img.size - if width == RAW_DATAPOINT_IMG_WIDTH: - img.crop((CROP_WIDTH, CROP_HEIGHT, width-CROP_WIDTH, - height-CROP_HEIGHT)).save(filename, img.format) + dataDate = data["SiteRep"]["DV"]["dataDate"].rstrip("Z") + return utilities.strptime(dataDate, DATAPOINT_DATETIME_FORMAT) + timedelta( + hours=1.5 + ) diff --git a/weather.metoffice/src/metoffice/urlcache.py b/weather.metoffice/src/metoffice/urlcache.py index 26e9d055b..3c8a5d77a 100644 --- a/weather.metoffice/src/metoffice/urlcache.py +++ b/weather.metoffice/src/metoffice/urlcache.py @@ -1,34 +1,34 @@ # A basic way of caching files associated with URLs -from datetime import datetime -import os -import urllib.request -import tempfile import json -import socket +import os import shutil +import socket +import tempfile +import urllib.request +from datetime import datetime from . import utilities -throwaway = utilities.strptime('20170101', '%Y%m%d') +throwaway = utilities.strptime("20170101", "%Y%m%d") class URLCache(object): - TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ' + TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" def __init__(self, folder): - self._folder = os.path.join(folder, 'cache') - self._file = os.path.join(folder, 'cache.json') + self._folder = os.path.join(folder, "cache") + self._file = os.path.join(folder, "cache.json") def __enter__(self): if not os.path.exists(self._folder): os.makedirs(self._folder) try: - fyle = open(self._file, 'r') + fyle = open(self._file, "r") except IOError: # create the file and try again. - open(self._file, 'a').close() - fyle = open(self._file, 'r') + open(self._file, "a").close() + fyle = open(self._file, "r") try: self._cache = json.load(fyle) except ValueError: @@ -38,21 +38,24 @@ def __enter__(self): def __exit__(self, typ, value, traceback): self.flush() - with open(self._file, 'w+') as fyle: + with open(self._file, "w+") as fyle: json.dump(self._cache, fyle, indent=2) def remove(self, url): if url in self._cache: entry = self._cache[url] - if os.path.isfile(entry['resource']): - os.remove(entry['resource']) + if os.path.isfile(entry["resource"]): + os.remove(entry["resource"]) del self._cache[url] def flush(self): flushlist = list() for url, entry in self._cache.items(): - if not os.path.isfile(entry['resource']) or \ - utilities.strptime(entry['expiry'], self.TIME_FORMAT) < datetime.utcnow(): + if ( + not os.path.isfile(entry["resource"]) + or utilities.strptime(entry["expiry"], self.TIME_FORMAT) + < datetime.utcnow() + ): flushlist.append(url) for url in flushlist: self.remove(url) @@ -67,15 +70,18 @@ def get(self, url, expiry_callback, resource_callback=None): """ try: entry = self._cache[url] - if not os.path.isfile(entry['resource']) or \ - utilities.strptime(entry['expiry'], self.TIME_FORMAT) < datetime.utcnow(): + if ( + not os.path.isfile(entry["resource"]) + or utilities.strptime(entry["expiry"], self.TIME_FORMAT) + < datetime.utcnow() + ): raise InvalidCacheError else: - return entry['resource'] + return entry["resource"] except (KeyError, InvalidCacheError): # (src, headers) = urllib.urlretrieve(url) try: - req = urllib.request.Request(url, None, {'User-Agent': 'Mozilla/5.0'}) + req = urllib.request.Request(url, None, {"User-Agent": "Mozilla/5.0"}) response = urllib.request.urlopen(req) except (socket.timeout, urllib.request.URLError) as e: e.args = (str(e), url) @@ -88,7 +94,10 @@ def get(self, url, expiry_callback, resource_callback=None): expiry = expiry_callback(tmp.name) if resource_callback: resource_callback(tmp.name) - self._cache[url] = {'resource': tmp.name, 'expiry': expiry.strftime(self.TIME_FORMAT)} + self._cache[url] = { + "resource": tmp.name, + "expiry": expiry.strftime(self.TIME_FORMAT), + } return tmp.name diff --git a/weather.metoffice/src/metoffice/utilities.py b/weather.metoffice/src/metoffice/utilities.py index b8bebbbae..28e15f689 100644 --- a/weather.metoffice/src/metoffice/utilities.py +++ b/weather.metoffice/src/metoffice/utilities.py @@ -1,17 +1,24 @@ -from functools import wraps -from datetime import datetime +import math import time import traceback -import math +from datetime import datetime +from functools import wraps + import xbmc import xbmcgui -from .constants import WEATHER_WINDOW_ID, ADDON_BROWSER_WINDOW_ID, DIALOG, TEMPERATUREUNITS, ADDON +from .constants import ( + ADDON_BROWSER_WINDOW_ID, + TEMPERATUREUNITS, + WEATHER_WINDOW_ID, + addon, + dialog, +) def log(msg, level=xbmc.LOGINFO): # by importing utilities all messages in xbmc log will be prepended with LOGPREFIX - xbmc.log('weather.metoffice: {0}'.format(msg), level) + xbmc.log("weather.metoffice: {0}".format(msg), level) def strptime(dt, fmt): @@ -26,6 +33,7 @@ def failgracefully(f): generic exception, log it and if the user is on a weather page, show something to the user in a dialog box. """ + @wraps(f) def wrapper(*args, **kwds): try: @@ -33,26 +41,33 @@ def wrapper(*args, **kwds): except Exception as e: e.args = map(str, e.args) log(traceback.format_exc(), xbmc.LOGERROR) - if len(e.args) == 0 or e.args[0] == '': - e.args = ('Error',) + if len(e.args) == 0 or e.args[0] == "": + e.args = ("Error",) if len(e.args) == 1: - e.args = e.args + ('See log file for details',) - if (xbmcgui.getCurrentWindowId() == WEATHER_WINDOW_ID or - xbmcgui.getCurrentWindowId() == ADDON_BROWSER_WINDOW_ID): + e.args = e.args + ("See log file for details",) + if ( + xbmcgui.getCurrentWindowId() == WEATHER_WINDOW_ID + or xbmcgui.getCurrentWindowId() == ADDON_BROWSER_WINDOW_ID + ): args = (e.args[0].title(),) + e.args[1:4] - DIALOG.ok(*args) # @UndefinedVariable + dialog().ok(*args) + return wrapper def xbmcbusy(f): @wraps(f) def wrapper(*args, **kwds): - if xbmcgui.getCurrentWindowId() == WEATHER_WINDOW_ID or xbmcgui.getCurrentWindowId() == ADDON_BROWSER_WINDOW_ID: + if ( + xbmcgui.getCurrentWindowId() == WEATHER_WINDOW_ID + or xbmcgui.getCurrentWindowId() == ADDON_BROWSER_WINDOW_ID + ): xbmc.executebuiltin("ActivateWindow(busydialognocancel)") try: return f(*args, **kwds) finally: xbmc.executebuiltin("Dialog.Close(busydialognocancel)") + return wrapper @@ -62,7 +77,8 @@ def wrapper(*args, **kwds): try: return f(*args, **kwds) except KeyError: - return 'n/a' + return "n/a" + return wrapper @@ -72,7 +88,8 @@ def wrapper(*args, **kwds): try: return f(*args, **kwds) except KeyError: - return 'na' + return "na" + return wrapper @@ -81,7 +98,7 @@ def minutes_as_time(minutes): Takes an integer number of minutes and returns it as a time, starting at midnight. """ - return time.strftime('%H:%M', time.gmtime(minutes*60)) + return time.strftime("%H:%M", time.gmtime(minutes * 60)) def haversine_distance(lat1, lon1, lat2, lon2): @@ -92,20 +109,21 @@ def haversine_distance(lat1, lon1, lat2, lon2): """ EARTH_RADIUS = 6371 lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2]) - dlat = lat2-lat1 - dlon = lon2-lon1 - a = math.sin(dlat/2)**2 + \ - math.cos(lat1) * math.cos(lat2) * \ - math.sin(dlon/2)**2 + dlat = lat2 - lat1 + dlon = lon2 - lon1 + a = ( + math.sin(dlat / 2) ** 2 + + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 + ) c = 2 * math.asin(math.sqrt(a)) return EARTH_RADIUS * c def rownd(x): try: - return str(round(float(x), 0)).split('.')[0] + return str(round(float(x), 0)).split(".")[0] except ValueError: - return '' + return "" def localised_temperature(t): @@ -114,13 +132,13 @@ def localised_temperature(t): # and other crazy units. Given that this function is only used # for non-standard pages, which require a custom skin, its # unlikely that anyone will hit the problem. - if TEMPERATUREUNITS[-1] == 'C': + if TEMPERATUREUNITS[-1] == "C": return t else: try: - return str(int(float(t)*9/5+32)) + return str(int(float(t) * 9 / 5 + 32)) except ValueError: - return '' + return "" @f_or_nla @@ -138,20 +156,22 @@ def gettext(s): gettext() gets around XBMCs cryptic "Ints For Strings" translation mechanism requires the translatable table is kept up to date with the contents of strings.po """ - translatable = {"Observation Location": 32000, - "Forecast Location": 32001, - "Regional Location": 32002, - "API Key": 32003, - "Use IP address to determine location": 32004, - "GeoIP Provider": 32005, - "Erase Cache": 32006, - "No API Key.": 32007, - "Enter your Met Office API Key under settings.": 32008, - "No Matches": 32009, - "No locations found containing": 32010, - "Matching Sites": 32011} + translatable = { + "Observation Location": 32000, + "Forecast Location": 32001, + "Regional Location": 32002, + "API Key": 32003, + "Use IP address to determine location": 32004, + "GeoIP Provider": 32005, + "Erase Cache": 32006, + "No API Key.": 32007, + "Enter your Met Office API Key under settings.": 32008, + "No Matches": 32009, + "No locations found containing": 32010, + "Matching Sites": 32011, + } try: - translation = ADDON.getLocalizedString(translatable[s]) + translation = addon().getLocalizedString(translatable[s]) if not translation: raise TranslationError else: diff --git a/weather.metoffice/src/setlocation.py b/weather.metoffice/src/setlocation.py index fc2aea7e9..9e65a51ea 100644 --- a/weather.metoffice/src/setlocation.py +++ b/weather.metoffice/src/setlocation.py @@ -5,30 +5,54 @@ the user. On successful selection internal addon setting is set. """ +import json from datetime import datetime, timedelta from operator import itemgetter -import json -from metoffice import utilities, urlcache -from metoffice.utilities import gettext as _ +from urllib.error import HTTPError +import xbmc + +from metoffice import urlcache, utilities from metoffice.constants import ( - ADDON_DATA_PATH, GEOIP_PROVIDER, KEYBOARD, DIALOG, - ADDON, FORECAST_SITELIST_URL, OBSERVATION_SITELIST_URL, - REGIONAL_SITELIST_URL, LONG_REGIONAL_NAMES, GEOLOCATION + ADDON_DATA_PATH, + FORECAST_SITELIST_URL, + GEOIP_PROVIDER, + GEOLOCATION, + LONG_REGIONAL_NAMES, + OBSERVATION_SITELIST_URL, + REGIONAL_SITELIST_URL, + addon, + dialog, ) +from metoffice.utilities import gettext as _ @utilities.xbmcbusy def getsitelist(location, text=""): with urlcache.URLCache(ADDON_DATA_PATH) as cache: - url = {'ForecastLocation': FORECAST_SITELIST_URL, - 'ObservationLocation': OBSERVATION_SITELIST_URL, - 'RegionalLocation': REGIONAL_SITELIST_URL}[location] - filename = cache.get(url, lambda x: datetime.now()+timedelta(weeks=1)) - with open(filename, encoding='utf-8') as fh: + url = { + "ForecastLocation": FORECAST_SITELIST_URL, + "ObservationLocation": OBSERVATION_SITELIST_URL, + "RegionalLocation": REGIONAL_SITELIST_URL, + }[location] + utilities.log("Fetching %s site list from the Met Office..." % location) + try: + filename = cache.get(url, lambda x: datetime.now() + timedelta(weeks=1)) + except HTTPError: + dialog().ok( + _("Error fetching %s site list" % location), + _("Check your Met Office API Key under settings and try again."), + ) + utilities.log( + "Error fetching %s site list. Check your API Key and try again" + % location, + xbmc.LOGERROR, + ) + raise + with open(filename, encoding="utf-8") as fh: data = json.load(fh) - sitelist = data['Locations']['Location'] - if location == 'RegionalLocation': + sitelist = data["Locations"]["Location"] + if location == "RegionalLocation": # fix datapoint bug where keys start with @ in Regional Sitelist # Fixing up keys has to be a two step process. If we pop and add # in the same loop we'll get `RuntimeError: dictionary keys @@ -37,69 +61,90 @@ def getsitelist(location, text=""): # First add the correct keys. toremove = [] for key in site: - if key.startswith('@'): + if key.startswith("@"): toremove.append(key) # Now remove the keys we found above. for key in toremove: site[key[1:]] = site.pop(key) # Change regional names to long versions. Untouched otherwise. - site['name'] = LONG_REGIONAL_NAMES.get(site['name'], site['name']) + site["name"] = LONG_REGIONAL_NAMES.get(site["name"], site["name"]) if text: - sitelist[:] = filter(lambda x: x['name'].lower().find(text.lower()) >= 0, sitelist) + sitelist[:] = filter( + lambda x: x["name"].lower().find(text.lower()) >= 0, sitelist + ) - if GEOLOCATION == 'true': + if GEOLOCATION == "true": geo = {} - url = GEOIP_PROVIDER['url'] - filename = cache.get(url, lambda x: datetime.now()+timedelta(hours=1)) + url = GEOIP_PROVIDER["url"] + filename = cache.get(url, lambda x: datetime.now() + timedelta(hours=1)) try: with open(filename) as fh: data = json.load(fh) except ValueError: - utilities.log('Failed to fetch valid data from %s' % url) + utilities.log("Failed to fetch valid data from %s" % url) try: - geolat = float(data[GEOIP_PROVIDER['latitude']]) - geolong = float(data[GEOIP_PROVIDER['longitude']]) - geo = {'lat': geolat, 'long': geolong} + geolat = float(data[GEOIP_PROVIDER["latitude"]]) + geolong = float(data[GEOIP_PROVIDER["longitude"]]) + geo = {"lat": geolat, "long": geolong} except KeyError: - utilities.log('Couldn\'t extract lat/long data from %s' % url) + utilities.log("Couldn't extract lat/long data from %s" % url) for site in sitelist: try: - site['distance'] = int(utilities.haversine_distance(geo['lat'], geo['long'], - float(site['latitude']), float(site['longitude']))) - site['display'] = "{0} ({1}km)".format(site['name'], site['distance']) + site["distance"] = int( + utilities.haversine_distance( + geo["lat"], + geo["long"], + float(site["latitude"]), + float(site["longitude"]), + ) + ) + site["display"] = "{0} ({1}km)".format( + site["name"], site["distance"] + ) except KeyError: - site['display'] = site['name'] + site["display"] = site["name"] try: - sitelist = sorted(sitelist, key=itemgetter('distance')) + sitelist = sorted(sitelist, key=itemgetter("distance")) except KeyError: - sitelist = sorted(sitelist, key=itemgetter('name')) + sitelist = sorted(sitelist, key=itemgetter("name")) else: for site in sitelist: - site['display'] = site['name'] - sitelist = sorted(sitelist, key=itemgetter('name')) + site["display"] = site["name"] + sitelist = sorted(sitelist, key=itemgetter("name")) return sitelist -@utilities.failgracefully def main(location): + # In this case we _have_ to create a keyboard object so that + # we can test isConfirmed and getText. + keyboard = xbmc.Keyboard() + keyboard.doModal() + text = keyboard.isConfirmed() and keyboard.getText() - KEYBOARD.doModal() - text = KEYBOARD.isConfirmed() and KEYBOARD.getText() sitelist = getsitelist(location, text) if sitelist == []: - DIALOG.ok(_("No Matches"), _("No locations found containing")+" {0}".format(text)) + dialog().ok( + _("No Matches"), _("No locations found containing") + " {0}".format(text) + ) utilities.log("No locations found containing '%s'" % text) else: - display_list = [site['display'] for site in sitelist] - selected = DIALOG.select(_("Matching Sites"), display_list) + display_list = [site["display"] for site in sitelist] + selected = dialog().select(_("Matching Sites"), display_list) if selected != -1: - ADDON.setSetting(location, sitelist[selected]['name']) - ADDON.setSetting("%sID" % location, sitelist[selected]['id']) - ADDON.setSetting("%sLatitude" % location, str(sitelist[selected].get('latitude'))) - ADDON.setSetting("%sLongitude" % location, str(sitelist[selected].get('longitude'))) - utilities.log("Setting '{location}' to '{name} ({id})'".format(location=location, - name=sitelist[selected]['name'].encode( - 'utf-8'), - id=sitelist[selected]['id'])) + addon().setSetting(location, sitelist[selected]["name"]) + addon().setSetting("%sID" % location, sitelist[selected]["id"]) + addon().setSetting( + "%sLatitude" % location, str(sitelist[selected].get("latitude")) + ) + addon().setSetting( + "%sLongitude" % location, str(sitelist[selected].get("longitude")) + ) + utilities.log( + "Setting '{location}' to '{name} ({id})'".format( + location=location, + name=sitelist[selected]["name"].encode("utf-8"), + id=sitelist[selected]["id"], + ) + ) From 8ecf57e867ddc4de789ebce775300e65e3e2c0b8 Mon Sep 17 00:00:00 2001 From: L2501 Date: Sun, 16 Jul 2023 05:31:03 +0000 Subject: [PATCH 062/145] [script.module.simplejson] 3.19.1+matrix.1 --- script.module.simplejson/CHANGES.txt | 662 ---- script.module.simplejson/README.rst | 40 - script.module.simplejson/addon.xml | 18 +- .../lib/simplejson/__init__.py | 110 +- .../lib/simplejson/_speedups.c | 3384 ----------------- .../lib/simplejson/decoder.py | 80 +- .../lib/simplejson/encoder.py | 86 +- .../lib/simplejson/scanner.py | 6 +- .../lib/simplejson/tests/__init__.py | 74 - .../simplejson/tests/test_bigint_as_string.py | 67 - .../tests/test_bitsize_int_as_string.py | 73 - .../simplejson/tests/test_check_circular.py | 30 - .../lib/simplejson/tests/test_decimal.py | 71 - .../lib/simplejson/tests/test_decode.py | 119 - .../lib/simplejson/tests/test_default.py | 9 - .../lib/simplejson/tests/test_dump.py | 249 -- .../tests/test_encode_basestring_ascii.py | 47 - .../simplejson/tests/test_encode_for_html.py | 38 - .../lib/simplejson/tests/test_errors.py | 68 - .../lib/simplejson/tests/test_fail.py | 176 - .../lib/simplejson/tests/test_float.py | 35 - .../lib/simplejson/tests/test_for_json.py | 97 - .../lib/simplejson/tests/test_indent.py | 86 - .../simplejson/tests/test_item_sort_key.py | 27 - .../lib/simplejson/tests/test_iterable.py | 31 - .../lib/simplejson/tests/test_namedtuple.py | 122 - .../lib/simplejson/tests/test_pass1.py | 71 - .../lib/simplejson/tests/test_pass2.py | 14 - .../lib/simplejson/tests/test_pass3.py | 20 - .../lib/simplejson/tests/test_raw_json.py | 47 - .../lib/simplejson/tests/test_recursion.py | 67 - .../lib/simplejson/tests/test_scanstring.py | 196 - .../lib/simplejson/tests/test_separators.py | 42 - .../lib/simplejson/tests/test_speedups.py | 114 - .../lib/simplejson/tests/test_str_subclass.py | 21 - .../lib/simplejson/tests/test_subclass.py | 37 - .../lib/simplejson/tests/test_tool.py | 114 - .../lib/simplejson/tests/test_tuple.py | 47 - .../lib/simplejson/tests/test_unicode.py | 154 - .../lib/simplejson/tool.py | 42 - .../{ => resources}/icon.png | Bin 41 files changed, 153 insertions(+), 6638 deletions(-) delete mode 100644 script.module.simplejson/CHANGES.txt delete mode 100644 script.module.simplejson/README.rst delete mode 100644 script.module.simplejson/lib/simplejson/_speedups.c delete mode 100644 script.module.simplejson/lib/simplejson/tests/__init__.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_bigint_as_string.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_bitsize_int_as_string.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_check_circular.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_decimal.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_decode.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_default.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_dump.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_encode_basestring_ascii.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_encode_for_html.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_errors.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_fail.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_float.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_for_json.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_indent.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_item_sort_key.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_iterable.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_namedtuple.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_pass1.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_pass2.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_pass3.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_raw_json.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_recursion.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_scanstring.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_separators.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_speedups.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_str_subclass.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_subclass.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_tool.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_tuple.py delete mode 100644 script.module.simplejson/lib/simplejson/tests/test_unicode.py delete mode 100644 script.module.simplejson/lib/simplejson/tool.py rename script.module.simplejson/{ => resources}/icon.png (100%) diff --git a/script.module.simplejson/CHANGES.txt b/script.module.simplejson/CHANGES.txt deleted file mode 100644 index 40083a8ae..000000000 --- a/script.module.simplejson/CHANGES.txt +++ /dev/null @@ -1,662 +0,0 @@ -Version 3.16.1 released 2018-09-07 - -* Added examples for JSON lines use cases - https://github.com/simplejson/simplejson/pull/236 -* Add wheels for more Python versions and platforms - https://github.com/simplejson/simplejson/pull/234 - https://github.com/simplejson/simplejson/pull/233 - https://github.com/simplejson/simplejson/pull/231 - -Version 3.16.0 released 2018-06-28 - -* Restore old behavior with regard to the type of decoded empty - strings with speedups enabled on Python 2.x - https://github.com/simplejson/simplejson/pull/225 -* Add python_requires to setup.py to help pip - https://github.com/simplejson/simplejson/pull/224 -* Fix CSS in docs when built locally - https://github.com/simplejson/simplejson/pull/222 - -Version 3.15.0 released 2018-05-12 - -* Clean up the C code - https://github.com/simplejson/simplejson/pull/220 -* Bypass the decode() method in bytes subclasses - https://github.com/simplejson/simplejson/pull/219 -* Support builds without cStringIO - https://github.com/simplejson/simplejson/pull/217 -* Allow to disable serializing bytes by default in Python 3 - https://github.com/simplejson/simplejson/pull/216 -* Simplify the compatibility code - https://github.com/simplejson/simplejson/pull/215 -* Fix tests in Python 2.5 - https://github.com/simplejson/simplejson/pull/214 - -Version 3.14.0 released 2018-04-21 - -* Defer is_raw_json test (performance improvement) - https://github.com/simplejson/simplejson/pull/212 -* Avoid escaping U+2028 and U+2029 without ensure_ascii - https://github.com/simplejson/simplejson/pull/211 -* Fix an incorrect type test in Python 2, avoiding an unnecessary unicode copy. - https://github.com/simplejson/simplejson/pull/210 - -Version 3.13.2 released 2017-11-24 - -* Fix additional Python 2.x compilation issue on Windows - -Version 3.13.1 released 2017-11-24 - -* Improve CI to catch speedups build regressions -* Fix speedups build regression in Python 2.x - https://github.com/simplejson/simplejson/issues/193 - -Version 3.13.0 released 2017-11-23 - -* Workarounds for NamedTemporaryFile issues with Windows for tool tests -* Make TypeError messages contain type name instead of a repr. - https://github.com/simplejson/simplejson/pull/191 -* Ensure that encoding of text subtypes is consistent with or without speedups - https://github.com/simplejson/simplejson/issues/185 - -Version 3.12.1 released 2017-11-23 - -* Misc updates to build infrastructure -* Fix an assertion failure when make_encoder receives a bad encoder argument - https://github.com/simplejson/simplejson/pull/188 -* Fix potential crash during GC - https://github.com/simplejson/simplejson/pull/187 -* Fix a reference leak when sorting keys - https://github.com/simplejson/simplejson/pull/186 - -Version 3.12.0 released 2017-11-05 - -* Fix threaded import race condition - https://github.com/simplejson/simplejson/issues/184 -* Move RawJSON implementation to simplejson.raw_json module -* Move JSONDecodeError implementation to simplejson.errors module - -Version 3.11.1 released 2017-06-19 - -* Fix issue with item_sort_key when speedups are available, and add - auto-discovery to test suites to prevent similar regressions - https://github.com/simplejson/simplejson/issues/173 - -Version 3.11.0 released 2017-06-18 - -* docstring fix in JSONEncoder - https://github.com/simplejson/simplejson/pull/172 -* Call PyObject_IsTrue() only once for the strict argument of scanner - https://github.com/simplejson/simplejson/pull/170 -* Fix a crash with unencodable encoding in the encoder - https://github.com/simplejson/simplejson/pull/171 -* Remove unused imports - https://github.com/simplejson/simplejson/pull/162 -* Remove remnants of Python 2.4 support - https://github.com/simplejson/simplejson/pull/168 -* Fix argument checking errors in _speedups.c - https://github.com/simplejson/simplejson/pull/169 -* Remove the `__init__` methods in extension classes - https://github.com/simplejson/simplejson/pull/166 -* Fix typo in the doc for loads - https://github.com/simplejson/simplejson/issues/161 -* Add Python 3.6 to testing matrix and PyPI metadata - https://github.com/simplejson/simplejson/pull/153 - https://github.com/simplejson/simplejson/pull/152 - -Version 3.10.0 released 2016-10-28 - -* Add RawJSON class to allow a faster path for already encoded JSON. - https://github.com/simplejson/simplejson/pull/143 - -Version 3.9.0 released 2016-10-21 - -* Workaround for bad behavior in string subclasses - https://github.com/simplejson/simplejson/issues/144 -* Fix warnings flagged by -3 - https://github.com/simplejson/simplejson/pull/146 -* Update readthedocs documentation links - https://github.com/simplejson/simplejson/pull/137 -* Add build status badge to README - https://github.com/simplejson/simplejson/pull/134 - -Version 3.8.2 released 2016-02-14 - -* Fix implicit cast compiler warning in _speedups.c -* simplejson is now available as wheels for OS X and Windows thanks to Travis-CI - and AppVeyor respectively! Many thanks to @aebrahim for getting this party - started. - https://github.com/simplejson/simplejson/pull/130 - https://github.com/simplejson/simplejson/issues/122 - -Version 3.8.1 released 2015-10-27 - -* Fix issue with iterable_as_array and indent option - https://github.com/simplejson/simplejson/issues/128 -* Fix typo in keyword argument name introduced in 3.8.0 - https://github.com/simplejson/simplejson/pull/123 - -Version 3.8.0 released 2015-07-18 - -* New iterable_as_array encoder option to perform lazy serialization of - any iterable objects, without having to convert to tuple or list. - -Version 3.7.3 released 2015-05-31 - -* Fix typo introduced in 3.7.0 (behavior should be indistinguishable) - https://github.com/simplejson/simplejson/commit/e18cc09b688ea1f3305c27616fd3cadd2adc6d31#commitcomment-11443842 - -Version 3.7.2 released 2015-05-22 - -* Do not cache Decimal class in encoder, only reference the decimal module. - This may make reload work in more common scenarios. - -Version 3.7.1 released 2015-05-18 - -* Fix compilation with MSVC - https://github.com/simplejson/simplejson/pull/119 - -Version 3.7.0 released 2015-05-18 - -* simplejson no longer trusts custom str/repr methods for int, long, float - subclasses. These instances are now formatted as if they were exact - instances of those types. - https://github.com/simplejson/simplejson/issues/118 - -Version 3.6.5 released 2014-10-24 - -* Importing bug fix for reference leak when an error occurs during - dict encoding - https://github.com/simplejson/simplejson/issues/109 - -Version 3.6.4 released 2014-09-29 - -* Important bug fix for dump when only sort_keys is set - https://github.com/simplejson/simplejson/issues/106 - -Version 3.6.3 released 2014-08-18 - -* Documentation updates - https://github.com/simplejson/simplejson/issues/103 - -Version 3.6.2 released 2014-08-09 - -* Documentation updates - http://bugs.python.org/issue21514 - -Version 3.6.1 released 2014-08-09 - -* Documentation updates - https://github.com/simplejson/simplejson/issues/102 - -Version 3.6.0 released 2014-07-21 - -* Automatically strip any UTF-8 BOM from input to more closely - follow the latest specs - https://github.com/simplejson/simplejson/pull/101 - -Version 3.5.3 released 2014-06-24 - -* Fix lower bound checking in scan_once / raw_decode API - https://github.com/simplejson/simplejson/issues/98 - -Version 3.5.2 released 2014-05-22 - -* Fix Windows build with VS2008 - https://github.com/simplejson/simplejson/pull/97 - -Version 3.5.1 released 2014-05-21 - -* Consistently reject int_as_string_bitcount settings that are not - positive integers - -Version 3.5.0 released 2014-05-20 - -* Added int_as_string_bitcount encoder option - https://github.com/simplejson/pull/96 -* Fixed potential crash when encoder created with incorrect options - -Version 3.4.1 released 2014-04-30 - -* Fixed tests to run on Python 3.4 - -Version 3.4.0 released 2014-04-02 - -* Native setuptools support re-introduced - https://github.com/simplejson/simplejson/pull/92 - -Version 3.3.3 released 2014-02-14 - -* Improve test suite's Python 3.4 compatibility - https://github.com/simplejson/simplejson/issues/87 - -Version 3.3.2 released 2014-01-06 - -* Docstring fix for decoded string types - https://github.com/simplejson/simplejson/pull/82 - -Version 3.3.1 released 2013-10-05 - -* JSONDecodeError exceptions can now be pickled - https://github.com/simplejson/simplejson/pull/78 - -Version 3.3.0 released 2013-05-07 - -* Unpaired surrogates once again pass through the decoder, to match older - behavior and the RFC-4627 spec. - https://github.com/simplejson/simplejson/issues/62 - -Version 3.2.0 released 2013-05-01 - -* New ignore_nan kwarg in encoder that serializes out - of range floats (Infinity, -Infinity, NaN) as null for ECMA-262 - compliance. - https://github.com/simplejson/simplejson/pull/63 -* New for_json kwarg in encoder to make it possible to for - subclasses of dict and list to be specialized. - https://github.com/simplejson/simplejson/pull/69 - -Version 3.1.3 released 2013-04-06 - -* Updated documentation to discourage subclassing whenever possible. - default, object_hook, and object_pairs_hook provide almost all of - the functionality of subclassing. - -Version 3.1.2 released 2013-03-20 - -* Updated documentation to reflect separators behavior when indent is - not None - https://github.com/simplejson/simplejson/issues/59 -* Test suite should be compatible with debug builds of Python 2.x and 3.x - https://github.com/simplejson/simplejson/pull/65 - -Version 3.1.1 released 2013-02-21 - -* setup.py now has another workaround for Windows machines without - MSVC installed - http://bugs.python.org/issue7511 - -Version 3.1.0 released 2013-02-21 - -* Updated JSON conformance test suite - http://bugs.python.org/issue16559 -* simplejson.tool tests and bugfix for Python 3.x - http://bugs.python.org/issue16549 -* Improve error messages for certain kinds of truncated input - http://bugs.python.org/issue16009 -* Moved JSONDecodeError to json.scanner (still available for import - from json.decoder) -* Changed scanner to use JSONDecodeError directly rather than - StopIteration to improve error messages - -Version 3.0.9 released 2013-02-21 - -* Fix an off-by-one error in the colno property of JSONDecodeError - (when lineno == 1) - http://bugs.python.org/issue17225 - -Version 3.0.8 released 2013-02-19 - -* Fix a Python 2.x compiler warning for narrow unicode builds - https://github.com/simplejson/simplejson/issues/56 - -Version 3.0.7 released 2013-01-11 - -* NOTE: this release only changes the license. -* simplejson is now dual-licensed software, MIT or AFL v2.1. It is - also made explicit that this code is also licensed to the PSF under - a Contributor Agreement. - -Version 3.0.6 released 2013-01-11 - -* Fix for major Python 2.x ensure_ascii=False encoding regression - introduced in simplejson 3.0.0. If you use this setting, please - upgrade immediately. - https://github.com/simplejson/simplejson/issues/50 - -Version 3.0.5 released 2013-01-03 - -* NOTE: this release only changes the tests, it is - not essential to upgrade -* Tests now run with deprecation warnings printed -* Fixed Python 3 syntax error in simplejson.tool - https://github.com/simplejson/simplejson/issues/49 -* Fixed Python 3.3 deprecation warnings in test suite - https://github.com/simplejson/simplejson/issues/48 - -Version 3.0.4 released 2013-01-02 - -* MSVC compatibility for Python 3.3 - https://github.com/simplejson/simplejson/pull/47 - -Version 3.0.3 released 2013-01-01 - -* Fixes for bugs introduced in 3.0.2 -* Fixes for Python 2.5 compatibility -* MSVC compatibility for Python 2.x - https://github.com/simplejson/simplejson/pull/46 - -Version 3.0.2 released 2013-01-01 - -* THIS VERSION HAS BEEN REMOVED -* Missed a changeset to _speedups.c in the 3.0.1 branch cut - -Version 3.0.1 released 2013-01-01 - -* THIS VERSION HAS BEEN REMOVED -* Add accumulator optimization to encoder, equivalent to the usage of - `_Py_Accu` in the Python 3.3 json library. Only relevant if encoding - very large JSON documents. - -Version 3.0.0 released 2012-12-30 - -* Python 3.3 is now supported, thanks to Vinay Sajip - https://github.com/simplejson/simplejson/issues/8 -* `sort_keys`/`item_sort_key` now sort on the stringified version of the - key, rather than the original object. This ensures that the sort - only compares string types and makes the behavior consistent between - Python 2.x and Python 3.x. -* Like other number types, Decimal instances used as keys are now - coerced to strings when use_decimal is True. - -Version 2.6.2 released 2012-09-21 - -* JSONEncoderForHTML was not exported in the simplejson module - https://github.com/simplejson/simplejson/issues/41 - -Version 2.6.1 released 2012-07-27 - -* raw_decode() now skips whitespace before the object - https://github.com/simplejson/simplejson/pull/38 - -Version 2.6.0 released 2012-06-26 - -* Error messages changed to match proposal for Python 3.3.1 - http://bugs.python.org/issue5067 - -Version 2.5.2 released 2012-05-10 - -* Fix for regression introduced in 2.5.1 - https://github.com/simplejson/simplejson/issues/35 - -Version 2.5.1 released 2012-05-10 - -* Support for use_decimal=True in environments that use Python - sub-interpreters such as uWSGI - https://github.com/simplejson/simplejson/issues/34 - -Version 2.5.0 released 2012-03-29 - -* New item_sort_key option for encoder to allow fine grained control of sorted - output - -Version 2.4.0 released 2012-03-06 - -* New bigint_as_string option for encoder to trade JavaScript number precision - issues for type issues. - https://github.com/simplejson/simplejson/issues/31 - -Version 2.3.3 released 2012-02-27 - -* Allow unknown numerical types for indent parameter - https://github.com/simplejson/simplejson/pull/29 - -Version 2.3.2 released 2011-12-30 - -* Fix crashing regression in speedups introduced in 2.3.1 - -Version 2.3.1 released 2011-12-29 - -* namedtuple_as_object now checks _asdict to ensure that it - is callable. - https://github.com/simplejson/simplejson/issues/26 - -Version 2.3.0 released 2011-12-05 - -* Any objects with _asdict() methods are now considered for - namedtuple_as_object. - https://github.com/simplejson/simplejson/pull/22 - -Version 2.2.1 released 2011-09-06 - -* Fix MANIFEST.in issue when building a sdist from a sdist. - https://github.com/simplejson/simplejson/issues/16 - -Version 2.2.0 released 2011-09-04 - -* Remove setuptools requirement, reverted to pure distutils -* use_decimal default for encoding (dump, dumps, JSONEncoder) is now True -* tuple encoding as JSON objects can be turned off with new - tuple_as_array=False option. - https://github.com/simplejson/simplejson/pull/6 -* namedtuple (or other tuple subclasses with _asdict methods) are now - encoded as JSON objects rather than arrays by default. Can be disabled - and treated as a tuple with the new namedtuple_as_object=False option. - https://github.com/simplejson/simplejson/pull/6 -* JSONDecodeError is now raised instead of ValueError when a document - ends with an opening quote and the C speedups are in use. - https://github.com/simplejson/simplejson/issues/15 -* Updated documentation with information about JSONDecodeError -* Force unicode linebreak characters to be escaped (U+2028 and U+2029) - http://timelessrepo.com/json-isnt-a-javascript-subset -* Moved documentation from a git submodule to - https://simplejson.readthedocs.io/ - -Version 2.1.6 released 2011-05-08 - -* Prevent segfaults with deeply nested JSON documents - https://github.com/simplejson/simplejson/issues/11 -* Fix compatibility with Python 2.5 - https://github.com/simplejson/simplejson/issues/5 - -Version 2.1.5 released 2011-04-17 - -* Built sdist tarball with setuptools_git installed. Argh. - -Version 2.1.4 released 2011-04-17 - -* Does not try to build the extension when using PyPy -* Trailing whitespace after commas no longer emitted when indent is used -* Migrated to github http://github.com/simplejson/simplejson - -Version 2.1.3 released 2011-01-17 - -* Support the sort_keys option in C encoding speedups - http://code.google.com/p/simplejson/issues/detail?id=86 -* Allow use_decimal to work with dump() - http://code.google.com/p/simplejson/issues/detail?id=87 - -Version 2.1.2 released 2010-11-01 - -* Correct wrong end when object_pairs_hook is used - http://code.google.com/p/simplejson/issues/detail?id=85 -* Correct output for indent=0 - http://bugs.python.org/issue10019 -* Correctly raise TypeError when non-string keys are used with speedups - http://code.google.com/p/simplejson/issues/detail?id=82 -* Fix the endlineno, endcolno attributes of the JSONDecodeError exception. - http://code.google.com/p/simplejson/issues/detail?id=81 - -Version 2.1.1 released 2010-03-31 - -* Change how setup.py imports ez_setup.py to try and workaround old versions - of setuptools. - http://code.google.com/p/simplejson/issues/detail?id=75 -* Fix compilation on Windows platform (and other platforms with very - picky compilers) -* Corrected simplejson.__version__ and other minor doc changes. -* Do not fail speedups tests if speedups could not be built. - http://code.google.com/p/simplejson/issues/detail?id=73 - -Version 2.1.0 released 2010-03-10 - -* Decimal serialization officially supported for encoding with - use_decimal=True. For encoding this encodes Decimal objects and - for decoding it implies parse_float=Decimal -* Python 2.4 no longer supported (may still work, but no longer tested) -* Decoding performance and memory utilization enhancements - http://bugs.python.org/issue7451 -* JSONEncoderForHTML class for escaping &, <, > - http://code.google.com/p/simplejson/issues/detail?id=66 -* Memoization of object keys during encoding (when using speedups) -* Encoder changed to use PyIter_Next for list iteration to avoid - potential threading issues -* Encoder changed to use iteritems rather than PyDict_Next in order to - support dict subclasses that have a well defined ordering - http://bugs.python.org/issue6105 -* indent encoding parameter changed to be a string rather than an integer - (integer use still supported for backwards compatibility) - http://code.google.com/p/simplejson/issues/detail?id=56 -* Test suite (python setup.py test) now automatically runs with and without - speedups - http://code.google.com/p/simplejson/issues/detail?id=55 -* Fixed support for older versions of easy_install (e.g. stock Mac OS X config) - http://code.google.com/p/simplejson/issues/detail?id=54 -* Fixed str/unicode mismatches when using ensure_ascii=False - http://code.google.com/p/simplejson/issues/detail?id=48 -* Fixed error message when parsing an array with trailing comma with speedups - http://code.google.com/p/simplejson/issues/detail?id=46 -* Refactor decoder errors to raise JSONDecodeError instead of ValueError - http://code.google.com/p/simplejson/issues/detail?id=45 -* New ordered_pairs_hook feature in decoder which makes it possible to - preserve key order. http://bugs.python.org/issue5381 -* Fixed containerless unicode float decoding (same bug as 2.0.4, oops!) - http://code.google.com/p/simplejson/issues/detail?id=43 -* Share PosInf definition between encoder and decoder -* Minor reformatting to make it easier to backport simplejson changes - to Python 2.7/3.1 json module - -Version 2.0.9 released 2009-02-18 - -* Adds cyclic GC to the Encoder and Scanner speedups, which could've - caused uncollectible cycles in some cases when using custom parser - or encoder functions - -Version 2.0.8 released 2009-02-15 - -* Documentation fixes -* Fixes encoding True and False as keys -* Fixes checking for True and False by identity for several parameters - -Version 2.0.7 released 2009-01-04 - -* Documentation fixes -* C extension now always returns unicode strings when the input string is - unicode, even for empty strings - -Version 2.0.6 released 2008-12-19 - -* Windows build fixes - -Version 2.0.5 released 2008-11-23 - -* Fixes a segfault in the C extension when using check_circular=False and - encoding an invalid document - -Version 2.0.4 released 2008-10-24 - -* Fixes a parsing error in the C extension when the JSON document is (only) - a floating point number. It would consume one too few characters in that - case, and claim the document invalid. - -Version 2.0.3 released 2008-10-11 - -* Fixes reference leaks in the encoding speedups (sorry about that!) -* Fixes doctest suite for Python 2.6 -* More optimizations for the decoder - -Version 2.0.2 released 2008-10-06 - -* Fixes MSVC2003 build regression -* Fixes Python 2.4 compatibility in _speedups.c - -Version 2.0.1 released 2008-09-29 - -* Fixes long encoding regression introduced in 2.0.0 -* Fixes MinGW build regression introduced in 2.0.0 - -Version 2.0.0 released 2008-09-27 - -* optimized Python encoding path -* optimized Python decoding path -* optimized C encoding path -* optimized C decoding path -* switched to sphinx docs (nearly the same as the json module in python 2.6) - -Version 1.9.3 released 2008-09-23 - -* Decoding is significantly faster (for our internal benchmarks) -* Pretty-printing tool changed from simplejson to simplejson.tool for better - Python 2.6 comaptibility -* Misc. bug fixes - -Version 1.9 released 2008-05-03 - -* Rewrote test suite with unittest and doctest (no more nosetest dependency) -* Better PEP 7 and PEP 8 source compliance -* Removed simplejson.jsonfilter demo module -* simplejson.jsonfilter is no longer included - -Version 1.8.1 released 2008-03-24 - -* Optional C extension for accelerating the decoding of JSON strings -* Command line interface for pretty-printing JSON (via python -msimplejson) -* Decoding of integers and floats is now extensible (e.g. to use Decimal) via - parse_int, parse_float options. -* Subversion and issue tracker moved to google code: - http://code.google.com/p/simplejson/ -* "/" is no longer escaped, so if you're embedding JSON directly in HTML - you'll want to use .replace("/", "\\/") to prevent a close-tag attack. - -Version 1.7 released 2007-03-18 - -* Improves encoding performance with an optional C extension to speed up - str/unicode encoding (by 10-150x or so), which yields an overall speed - boost of 2x+ (JSON is string-heavy). -* Support for encoding unicode code points outside the BMP to UTF-16 - surrogate code pairs (specified by the Strings section of RFC 4627). - -Version 1.6 released 2007-03-03 - -* Improved str support for encoding. Previous versions of simplejson - integrated strings directly into the output stream, this version ensures - they're of a particular encoding (default is UTF-8) so that the output - stream is valid. - -Version 1.5 released 2007-01-18 - -* Better Python 2.5 compatibility -* Better Windows compatibility -* indent encoding parameter for pretty printing -* separators encoding parameter for generating optimally compact JSON - -Version 1.3 released 2006-04-01 - -* The optional object_hook function is called upon decoding of any JSON - object literal, and its return value is used instead of the dict that - would normally be used. This can be used to efficiently implement - features such as JSON-RPC class hinting, or other custom decodings of - JSON. See the documentation for more information. - -Version 1.1 released 2005-12-31 - -* Renamed from simple_json to simplejson to comply with PEP 8 module naming - guidelines -* Full set of documentation -* More tests -* The encoder and decoder have been extended to understand NaN, Infinity, and - -Infinity (but this can be turned off via allow_nan=False for strict JSON - compliance) -* The decoder's scanner has been fixed so that it no longer accepts invalid - JSON documents -* The decoder now reports line and column information as well as character - numbers for easier debugging -* The encoder now has a circular reference checker, which can be optionally - disabled with check_circular=False -* dump, dumps, load, loads now accept an optional cls kwarg to use an - alternate JSONEncoder or JSONDecoder class for convenience. -* The read/write compatibility shim for json-py now have deprecation warnings - -Version 1.0 released 2005-12-25 - - * Initial release diff --git a/script.module.simplejson/README.rst b/script.module.simplejson/README.rst deleted file mode 100644 index 048a30966..000000000 --- a/script.module.simplejson/README.rst +++ /dev/null @@ -1,40 +0,0 @@ -simplejson ----------- - -.. image:: https://travis-ci.org/simplejson/simplejson.svg?branch=master - :target: https://travis-ci.org/simplejson/simplejson - -.. image:: https://ci.appveyor.com/api/projects/status/3riqhss6vca680gi/branch/master?svg=true - :target: https://ci.appveyor.com/project/etrepum/simplejson/branch/master - -simplejson is a simple, fast, complete, correct and extensible -JSON encoder and decoder for Python 3.3+ -with legacy support for Python 2.5+. It is pure Python code -with no dependencies, but includes an optional C extension -for a serious speed boost. - -The latest documentation for simplejson can be read online here: -https://simplejson.readthedocs.io/ - -simplejson is the externally maintained development version of the -json library included with Python (since 2.6). This version is tested -with the latest Python 3.8 and maintains backwards compatibility -with Python 3.3+ and the legacy Python 2.5 - Python 2.7 releases. - -The encoder can be specialized to provide serialization in any kind of -situation, without any special support by the objects to be serialized -(somewhat like pickle). This is best done with the ``default`` kwarg -to dumps. - -The decoder can handle incoming JSON strings of any specified encoding -(UTF-8 by default). It can also be specialized to post-process JSON -objects with the ``object_hook`` or ``object_pairs_hook`` kwargs. This -is particularly useful for implementing protocols such as JSON-RPC -that have a richer type system than JSON itself. - -For those of you that have legacy systems to maintain, there is a -very old fork of simplejson in the `python2.2`_ branch that supports -Python 2.2. This is based off of a very old version of simplejson, -is not maintained, and should only be used as a last resort. - -.. _python2.2: https://github.com/simplejson/simplejson/tree/python2.2 diff --git a/script.module.simplejson/addon.xml b/script.module.simplejson/addon.xml index b82b081de..a1846e961 100644 --- a/script.module.simplejson/addon.xml +++ b/script.module.simplejson/addon.xml @@ -1,24 +1,18 @@ - + - + - all - Simple, fast, extensible JSON encoder/decoder for Python Simple, fast, extensible JSON encoder/decoder for Python - Code taken from https://pypi.org/project/simplejson/ - MIT License, Academic Free License v. 2.1 - https://pypi.org/project/simplejson/ + MIT + all + https://github.com/simplejson/simplejson https://github.com/simplejson/simplejson - icon.png + resources/icon.png diff --git a/script.module.simplejson/lib/simplejson/__init__.py b/script.module.simplejson/lib/simplejson/__init__.py index 7b5687c85..7e533a24a 100644 --- a/script.module.simplejson/lib/simplejson/__init__.py +++ b/script.module.simplejson/lib/simplejson/__init__.py @@ -118,7 +118,7 @@ """ from __future__ import absolute_import -__version__ = '3.17.0' +__version__ = '3.19.1' __all__ = [ 'dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', @@ -149,28 +149,10 @@ def _import_c_make_encoder(): except ImportError: return None -_default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8', - default=None, - use_decimal=True, - namedtuple_as_object=True, - tuple_as_array=True, - iterable_as_array=False, - bigint_as_string=False, - item_sort_key=None, - for_json=False, - ignore_nan=False, - int_as_string_bitcount=None, -) +_default_encoder = JSONEncoder() def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, + allow_nan=False, cls=None, indent=None, separators=None, encoding='utf-8', default=None, use_decimal=True, namedtuple_as_object=True, tuple_as_array=True, bigint_as_string=False, sort_keys=False, item_sort_key=None, @@ -187,10 +169,10 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, contain non-ASCII characters, so long as they do not need to be escaped by JSON. When it is true, all non-ASCII characters are escaped. - If *allow_nan* is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) - in strict compliance of the original JSON specification, instead of using - the JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). See + If *allow_nan* is true (default: ``False``), then out of range ``float`` + values (``nan``, ``inf``, ``-inf``) will be serialized to + their JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``) + instead of raising a ValueError. See *ignore_nan* for ECMA-262 compliant behavior. If *indent* is a string, then JSON array elements and object members @@ -258,7 +240,7 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, """ # cached encoder if (not skipkeys and ensure_ascii and - check_circular and allow_nan and + check_circular and not allow_nan and cls is None and indent is None and separators is None and encoding == 'utf-8' and default is None and use_decimal and namedtuple_as_object and tuple_as_array and not iterable_as_array @@ -292,7 +274,7 @@ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, + allow_nan=False, cls=None, indent=None, separators=None, encoding='utf-8', default=None, use_decimal=True, namedtuple_as_object=True, tuple_as_array=True, bigint_as_string=False, sort_keys=False, item_sort_key=None, @@ -300,7 +282,7 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, iterable_as_array=False, **kw): """Serialize ``obj`` to a JSON formatted ``str``. - If ``skipkeys`` is false then ``dict`` keys that are not basic types + If ``skipkeys`` is true then ``dict`` keys that are not basic types (``str``, ``int``, ``long``, ``float``, ``bool``, ``None``) will be skipped instead of raising a ``TypeError``. @@ -312,10 +294,11 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, for container types will be skipped and a circular reference will result in an ``OverflowError`` (or worse). - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in - strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). + If *allow_nan* is true (default: ``False``), then out of range ``float`` + values (``nan``, ``inf``, ``-inf``) will be serialized to + their JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``) + instead of raising a ValueError. See + *ignore_nan* for ECMA-262 compliant behavior. If ``indent`` is a string, then JSON array elements and object members will be pretty-printed with a newline followed by that string repeated @@ -360,7 +343,7 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, If specified, *item_sort_key* is a callable used to sort the items in each dictionary. This is useful if you want to sort items other than - in alphabetical order by key. This option takes precendence over + in alphabetical order by key. This option takes precedence over *sort_keys*. If *sort_keys* is true (default: ``False``), the output of dictionaries @@ -383,7 +366,7 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, """ # cached encoder if (not skipkeys and ensure_ascii and - check_circular and allow_nan and + check_circular and not allow_nan and cls is None and indent is None and separators is None and encoding == 'utf-8' and default is None and use_decimal and namedtuple_as_object and tuple_as_array and not iterable_as_array @@ -412,14 +395,12 @@ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, **kw).encode(obj) -_default_decoder = JSONDecoder(encoding=None, object_hook=None, - object_pairs_hook=None) +_default_decoder = JSONDecoder() def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, - use_decimal=False, namedtuple_as_object=True, tuple_as_array=True, - **kw): + use_decimal=False, allow_nan=False, **kw): """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing a JSON document as `str` or `bytes`) to a Python object. @@ -442,23 +423,27 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, takes priority. *parse_float*, if specified, will be called with the string of every - JSON float to be decoded. By default, this is equivalent to + JSON float to be decoded. By default, this is equivalent to ``float(num_str)``. This can be used to use another datatype or parser for JSON floats (e.g. :class:`decimal.Decimal`). *parse_int*, if specified, will be called with the string of every - JSON int to be decoded. By default, this is equivalent to + JSON int to be decoded. By default, this is equivalent to ``int(num_str)``. This can be used to use another datatype or parser for JSON integers (e.g. :class:`float`). - *parse_constant*, if specified, will be called with one of the - following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This - can be used to raise an exception if invalid JSON numbers are - encountered. + *allow_nan*, if True (default false), will allow the parser to + accept the non-standard floats ``NaN``, ``Infinity``, and ``-Infinity`` + and enable the use of the deprecated *parse_constant*. If *use_decimal* is true (default: ``False``) then it implies parse_float=decimal.Decimal for parity with ``dump``. + *parse_constant*, if specified, will be + called with one of the following strings: ``'-Infinity'``, + ``'Infinity'``, ``'NaN'``. It is not recommended to use this feature, + as it is rare to parse non-compliant JSON containing these values. + To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead of subclassing whenever possible. @@ -468,12 +453,12 @@ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, encoding=encoding, cls=cls, object_hook=object_hook, parse_float=parse_float, parse_int=parse_int, parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, - use_decimal=use_decimal, **kw) + use_decimal=use_decimal, allow_nan=allow_nan, **kw) def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, - use_decimal=False, **kw): + use_decimal=False, allow_nan=False, **kw): """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON document) to a Python object. @@ -505,14 +490,18 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, ``int(num_str)``. This can be used to use another datatype or parser for JSON integers (e.g. :class:`float`). - *parse_constant*, if specified, will be called with one of the - following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This - can be used to raise an exception if invalid JSON numbers are - encountered. + *allow_nan*, if True (default false), will allow the parser to + accept the non-standard floats ``NaN``, ``Infinity``, and ``-Infinity`` + and enable the use of the deprecated *parse_constant*. If *use_decimal* is true (default: ``False``) then it implies parse_float=decimal.Decimal for parity with ``dump``. + *parse_constant*, if specified, will be + called with one of the following strings: ``'-Infinity'``, + ``'Infinity'``, ``'NaN'``. It is not recommended to use this feature, + as it is rare to parse non-compliant JSON containing these values. + To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead of subclassing whenever possible. @@ -521,7 +510,7 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, if (cls is None and encoding is None and object_hook is None and parse_int is None and parse_float is None and parse_constant is None and object_pairs_hook is None - and not use_decimal and not kw): + and not use_decimal and not allow_nan and not kw): return _default_decoder.decode(s) if cls is None: cls = JSONDecoder @@ -539,6 +528,8 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, if parse_float is not None: raise TypeError("use_decimal=True implies parse_float=Decimal") kw['parse_float'] = Decimal + if allow_nan: + kw['allow_nan'] = True return cls(encoding=encoding, **kw).decode(s) @@ -560,22 +551,9 @@ def _toggle_speedups(enabled): scan.make_scanner = scan.py_make_scanner dec.make_scanner = scan.make_scanner global _default_decoder - _default_decoder = JSONDecoder( - encoding=None, - object_hook=None, - object_pairs_hook=None, - ) + _default_decoder = JSONDecoder() global _default_encoder - _default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8', - default=None, - ) + _default_encoder = JSONEncoder() def simple_first(kv): """Helper function to pass to item_sort_key to sort simple diff --git a/script.module.simplejson/lib/simplejson/_speedups.c b/script.module.simplejson/lib/simplejson/_speedups.c deleted file mode 100644 index e7101288d..000000000 --- a/script.module.simplejson/lib/simplejson/_speedups.c +++ /dev/null @@ -1,3384 +0,0 @@ -/* -*- mode: C; c-file-style: "python"; c-basic-offset: 4 -*- */ -#include "Python.h" -#include "structmember.h" - -#if PY_MAJOR_VERSION >= 3 -#define PyInt_FromSsize_t PyLong_FromSsize_t -#define PyInt_AsSsize_t PyLong_AsSsize_t -#define PyInt_Check(obj) 0 -#define PyInt_CheckExact(obj) 0 -#define JSON_UNICHR Py_UCS4 -#define JSON_InternFromString PyUnicode_InternFromString -#define PyString_GET_SIZE PyUnicode_GET_LENGTH -#define PY2_UNUSED -#define PY3_UNUSED UNUSED -#else /* PY_MAJOR_VERSION >= 3 */ -#define PY2_UNUSED UNUSED -#define PY3_UNUSED -#define PyBytes_Check PyString_Check -#define PyUnicode_READY(obj) 0 -#define PyUnicode_KIND(obj) (sizeof(Py_UNICODE)) -#define PyUnicode_DATA(obj) ((void *)(PyUnicode_AS_UNICODE(obj))) -#define PyUnicode_READ(kind, data, index) ((JSON_UNICHR)((const Py_UNICODE *)(data))[(index)]) -#define PyUnicode_GET_LENGTH PyUnicode_GET_SIZE -#define JSON_UNICHR Py_UNICODE -#define JSON_InternFromString PyString_InternFromString -#endif /* PY_MAJOR_VERSION < 3 */ - -#if PY_VERSION_HEX < 0x02070000 -#if !defined(PyOS_string_to_double) -#define PyOS_string_to_double json_PyOS_string_to_double -static double -json_PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception); -static double -json_PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception) -{ - double x; - assert(endptr == NULL); - assert(overflow_exception == NULL); - PyFPE_START_PROTECT("json_PyOS_string_to_double", return -1.0;) - x = PyOS_ascii_atof(s); - PyFPE_END_PROTECT(x) - return x; -} -#endif -#endif /* PY_VERSION_HEX < 0x02070000 */ - -#if PY_VERSION_HEX < 0x02060000 -#if !defined(Py_TYPE) -#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) -#endif -#if !defined(Py_SIZE) -#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) -#endif -#if !defined(PyVarObject_HEAD_INIT) -#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, -#endif -#endif /* PY_VERSION_HEX < 0x02060000 */ - -#ifdef __GNUC__ -#define UNUSED __attribute__((__unused__)) -#else -#define UNUSED -#endif - -#define DEFAULT_ENCODING "utf-8" - -#define PyScanner_Check(op) PyObject_TypeCheck(op, &PyScannerType) -#define PyScanner_CheckExact(op) (Py_TYPE(op) == &PyScannerType) -#define PyEncoder_Check(op) PyObject_TypeCheck(op, &PyEncoderType) -#define PyEncoder_CheckExact(op) (Py_TYPE(op) == &PyEncoderType) - -#define JSON_ALLOW_NAN 1 -#define JSON_IGNORE_NAN 2 - -static PyObject *JSON_Infinity = NULL; -static PyObject *JSON_NegInfinity = NULL; -static PyObject *JSON_NaN = NULL; -static PyObject *JSON_EmptyUnicode = NULL; -#if PY_MAJOR_VERSION < 3 -static PyObject *JSON_EmptyStr = NULL; -#endif - -static PyTypeObject PyScannerType; -static PyTypeObject PyEncoderType; - -typedef struct { - PyObject *large_strings; /* A list of previously accumulated large strings */ - PyObject *small_strings; /* Pending small strings */ -} JSON_Accu; - -static int -JSON_Accu_Init(JSON_Accu *acc); -static int -JSON_Accu_Accumulate(JSON_Accu *acc, PyObject *unicode); -static PyObject * -JSON_Accu_FinishAsList(JSON_Accu *acc); -static void -JSON_Accu_Destroy(JSON_Accu *acc); - -#define ERR_EXPECTING_VALUE "Expecting value" -#define ERR_ARRAY_DELIMITER "Expecting ',' delimiter or ']'" -#define ERR_ARRAY_VALUE_FIRST "Expecting value or ']'" -#define ERR_OBJECT_DELIMITER "Expecting ',' delimiter or '}'" -#define ERR_OBJECT_PROPERTY "Expecting property name enclosed in double quotes" -#define ERR_OBJECT_PROPERTY_FIRST "Expecting property name enclosed in double quotes or '}'" -#define ERR_OBJECT_PROPERTY_DELIMITER "Expecting ':' delimiter" -#define ERR_STRING_UNTERMINATED "Unterminated string starting at" -#define ERR_STRING_CONTROL "Invalid control character %r at" -#define ERR_STRING_ESC1 "Invalid \\X escape sequence %r" -#define ERR_STRING_ESC4 "Invalid \\uXXXX escape sequence" - -typedef struct _PyScannerObject { - PyObject_HEAD - PyObject *encoding; - PyObject *strict_bool; - int strict; - PyObject *object_hook; - PyObject *pairs_hook; - PyObject *parse_float; - PyObject *parse_int; - PyObject *parse_constant; - PyObject *memo; -} PyScannerObject; - -static PyMemberDef scanner_members[] = { - {"encoding", T_OBJECT, offsetof(PyScannerObject, encoding), READONLY, "encoding"}, - {"strict", T_OBJECT, offsetof(PyScannerObject, strict_bool), READONLY, "strict"}, - {"object_hook", T_OBJECT, offsetof(PyScannerObject, object_hook), READONLY, "object_hook"}, - {"object_pairs_hook", T_OBJECT, offsetof(PyScannerObject, pairs_hook), READONLY, "object_pairs_hook"}, - {"parse_float", T_OBJECT, offsetof(PyScannerObject, parse_float), READONLY, "parse_float"}, - {"parse_int", T_OBJECT, offsetof(PyScannerObject, parse_int), READONLY, "parse_int"}, - {"parse_constant", T_OBJECT, offsetof(PyScannerObject, parse_constant), READONLY, "parse_constant"}, - {NULL} -}; - -typedef struct _PyEncoderObject { - PyObject_HEAD - PyObject *markers; - PyObject *defaultfn; - PyObject *encoder; - PyObject *indent; - PyObject *key_separator; - PyObject *item_separator; - PyObject *sort_keys; - PyObject *key_memo; - PyObject *encoding; - PyObject *Decimal; - PyObject *skipkeys_bool; - int skipkeys; - int fast_encode; - /* 0, JSON_ALLOW_NAN, JSON_IGNORE_NAN */ - int allow_or_ignore_nan; - int use_decimal; - int namedtuple_as_object; - int tuple_as_array; - int iterable_as_array; - PyObject *max_long_size; - PyObject *min_long_size; - PyObject *item_sort_key; - PyObject *item_sort_kw; - int for_json; -} PyEncoderObject; - -static PyMemberDef encoder_members[] = { - {"markers", T_OBJECT, offsetof(PyEncoderObject, markers), READONLY, "markers"}, - {"default", T_OBJECT, offsetof(PyEncoderObject, defaultfn), READONLY, "default"}, - {"encoder", T_OBJECT, offsetof(PyEncoderObject, encoder), READONLY, "encoder"}, - {"encoding", T_OBJECT, offsetof(PyEncoderObject, encoder), READONLY, "encoding"}, - {"indent", T_OBJECT, offsetof(PyEncoderObject, indent), READONLY, "indent"}, - {"key_separator", T_OBJECT, offsetof(PyEncoderObject, key_separator), READONLY, "key_separator"}, - {"item_separator", T_OBJECT, offsetof(PyEncoderObject, item_separator), READONLY, "item_separator"}, - {"sort_keys", T_OBJECT, offsetof(PyEncoderObject, sort_keys), READONLY, "sort_keys"}, - /* Python 2.5 does not support T_BOOl */ - {"skipkeys", T_OBJECT, offsetof(PyEncoderObject, skipkeys_bool), READONLY, "skipkeys"}, - {"key_memo", T_OBJECT, offsetof(PyEncoderObject, key_memo), READONLY, "key_memo"}, - {"item_sort_key", T_OBJECT, offsetof(PyEncoderObject, item_sort_key), READONLY, "item_sort_key"}, - {"max_long_size", T_OBJECT, offsetof(PyEncoderObject, max_long_size), READONLY, "max_long_size"}, - {"min_long_size", T_OBJECT, offsetof(PyEncoderObject, min_long_size), READONLY, "min_long_size"}, - {NULL} -}; - -static PyObject * -join_list_unicode(PyObject *lst); -static PyObject * -JSON_ParseEncoding(PyObject *encoding); -static PyObject * -maybe_quote_bigint(PyEncoderObject* s, PyObject *encoded, PyObject *obj); -static Py_ssize_t -ascii_char_size(JSON_UNICHR c); -static Py_ssize_t -ascii_escape_char(JSON_UNICHR c, char *output, Py_ssize_t chars); -static PyObject * -ascii_escape_unicode(PyObject *pystr); -static PyObject * -ascii_escape_str(PyObject *pystr); -static PyObject * -py_encode_basestring_ascii(PyObject* self UNUSED, PyObject *pystr); -#if PY_MAJOR_VERSION < 3 -static PyObject * -join_list_string(PyObject *lst); -static PyObject * -scan_once_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr); -static PyObject * -scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_ssize_t *next_end_ptr); -static PyObject * -_parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr); -#endif -static PyObject * -scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next_end_ptr); -static PyObject * -scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr); -static PyObject * -_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx); -static PyObject * -scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds); -static void -scanner_dealloc(PyObject *self); -static int -scanner_clear(PyObject *self); -static PyObject * -encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds); -static void -encoder_dealloc(PyObject *self); -static int -encoder_clear(PyObject *self); -static int -is_raw_json(PyObject *obj); -static PyObject * -encoder_stringify_key(PyEncoderObject *s, PyObject *key); -static int -encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_ssize_t indent_level); -static int -encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ssize_t indent_level); -static int -encoder_listencode_dict(PyEncoderObject *s, JSON_Accu *rval, PyObject *dct, Py_ssize_t indent_level); -static PyObject * -_encoded_const(PyObject *obj); -static void -raise_errmsg(char *msg, PyObject *s, Py_ssize_t end); -static PyObject * -encoder_encode_string(PyEncoderObject *s, PyObject *obj); -static int -_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr); -static PyObject * -_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr); -static PyObject * -encoder_encode_float(PyEncoderObject *s, PyObject *obj); -static int -_is_namedtuple(PyObject *obj); -static int -_has_for_json_hook(PyObject *obj); -static PyObject * -moduleinit(void); - -#define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '"') -#define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r')) - -#define MIN_EXPANSION 6 - -static PyObject* RawJSONType = NULL; -static int -is_raw_json(PyObject *obj) -{ - return PyObject_IsInstance(obj, RawJSONType) ? 1 : 0; -} - -static int -JSON_Accu_Init(JSON_Accu *acc) -{ - /* Lazily allocated */ - acc->large_strings = NULL; - acc->small_strings = PyList_New(0); - if (acc->small_strings == NULL) - return -1; - return 0; -} - -static int -flush_accumulator(JSON_Accu *acc) -{ - Py_ssize_t nsmall = PyList_GET_SIZE(acc->small_strings); - if (nsmall) { - int ret; - PyObject *joined; - if (acc->large_strings == NULL) { - acc->large_strings = PyList_New(0); - if (acc->large_strings == NULL) - return -1; - } -#if PY_MAJOR_VERSION >= 3 - joined = join_list_unicode(acc->small_strings); -#else /* PY_MAJOR_VERSION >= 3 */ - joined = join_list_string(acc->small_strings); -#endif /* PY_MAJOR_VERSION < 3 */ - if (joined == NULL) - return -1; - if (PyList_SetSlice(acc->small_strings, 0, nsmall, NULL)) { - Py_DECREF(joined); - return -1; - } - ret = PyList_Append(acc->large_strings, joined); - Py_DECREF(joined); - return ret; - } - return 0; -} - -static int -JSON_Accu_Accumulate(JSON_Accu *acc, PyObject *unicode) -{ - Py_ssize_t nsmall; -#if PY_MAJOR_VERSION >= 3 - assert(PyUnicode_Check(unicode)); -#else /* PY_MAJOR_VERSION >= 3 */ - assert(PyString_Check(unicode) || PyUnicode_Check(unicode)); -#endif /* PY_MAJOR_VERSION < 3 */ - - if (PyList_Append(acc->small_strings, unicode)) - return -1; - nsmall = PyList_GET_SIZE(acc->small_strings); - /* Each item in a list of unicode objects has an overhead (in 64-bit - * builds) of: - * - 8 bytes for the list slot - * - 56 bytes for the header of the unicode object - * that is, 64 bytes. 100000 such objects waste more than 6MB - * compared to a single concatenated string. - */ - if (nsmall < 100000) - return 0; - return flush_accumulator(acc); -} - -static PyObject * -JSON_Accu_FinishAsList(JSON_Accu *acc) -{ - int ret; - PyObject *res; - - ret = flush_accumulator(acc); - Py_CLEAR(acc->small_strings); - if (ret) { - Py_CLEAR(acc->large_strings); - return NULL; - } - res = acc->large_strings; - acc->large_strings = NULL; - if (res == NULL) - return PyList_New(0); - return res; -} - -static void -JSON_Accu_Destroy(JSON_Accu *acc) -{ - Py_CLEAR(acc->small_strings); - Py_CLEAR(acc->large_strings); -} - -static int -IS_DIGIT(JSON_UNICHR c) -{ - return c >= '0' && c <= '9'; -} - -static PyObject * -maybe_quote_bigint(PyEncoderObject* s, PyObject *encoded, PyObject *obj) -{ - if (s->max_long_size != Py_None && s->min_long_size != Py_None) { - if (PyObject_RichCompareBool(obj, s->max_long_size, Py_GE) || - PyObject_RichCompareBool(obj, s->min_long_size, Py_LE)) { -#if PY_MAJOR_VERSION >= 3 - PyObject* quoted = PyUnicode_FromFormat("\"%U\"", encoded); -#else - PyObject* quoted = PyString_FromFormat("\"%s\"", - PyString_AsString(encoded)); -#endif - Py_DECREF(encoded); - encoded = quoted; - } - } - - return encoded; -} - -static int -_is_namedtuple(PyObject *obj) -{ - int rval = 0; - PyObject *_asdict = PyObject_GetAttrString(obj, "_asdict"); - if (_asdict == NULL) { - PyErr_Clear(); - return 0; - } - rval = PyCallable_Check(_asdict); - Py_DECREF(_asdict); - return rval; -} - -static int -_has_for_json_hook(PyObject *obj) -{ - int rval = 0; - PyObject *for_json = PyObject_GetAttrString(obj, "for_json"); - if (for_json == NULL) { - PyErr_Clear(); - return 0; - } - rval = PyCallable_Check(for_json); - Py_DECREF(for_json); - return rval; -} - -static int -_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr) -{ - /* PyObject to Py_ssize_t converter */ - *size_ptr = PyInt_AsSsize_t(o); - if (*size_ptr == -1 && PyErr_Occurred()) - return 0; - return 1; -} - -static PyObject * -_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr) -{ - /* Py_ssize_t to PyObject converter */ - return PyInt_FromSsize_t(*size_ptr); -} - -static Py_ssize_t -ascii_escape_char(JSON_UNICHR c, char *output, Py_ssize_t chars) -{ - /* Escape unicode code point c to ASCII escape sequences - in char *output. output must have at least 12 bytes unused to - accommodate an escaped surrogate pair "\uXXXX\uXXXX" */ - if (S_CHAR(c)) { - output[chars++] = (char)c; - } - else { - output[chars++] = '\\'; - switch (c) { - case '\\': output[chars++] = (char)c; break; - case '"': output[chars++] = (char)c; break; - case '\b': output[chars++] = 'b'; break; - case '\f': output[chars++] = 'f'; break; - case '\n': output[chars++] = 'n'; break; - case '\r': output[chars++] = 'r'; break; - case '\t': output[chars++] = 't'; break; - default: -#if PY_MAJOR_VERSION >= 3 || defined(Py_UNICODE_WIDE) - if (c >= 0x10000) { - /* UTF-16 surrogate pair */ - JSON_UNICHR v = c - 0x10000; - c = 0xd800 | ((v >> 10) & 0x3ff); - output[chars++] = 'u'; - output[chars++] = "0123456789abcdef"[(c >> 12) & 0xf]; - output[chars++] = "0123456789abcdef"[(c >> 8) & 0xf]; - output[chars++] = "0123456789abcdef"[(c >> 4) & 0xf]; - output[chars++] = "0123456789abcdef"[(c ) & 0xf]; - c = 0xdc00 | (v & 0x3ff); - output[chars++] = '\\'; - } -#endif - output[chars++] = 'u'; - output[chars++] = "0123456789abcdef"[(c >> 12) & 0xf]; - output[chars++] = "0123456789abcdef"[(c >> 8) & 0xf]; - output[chars++] = "0123456789abcdef"[(c >> 4) & 0xf]; - output[chars++] = "0123456789abcdef"[(c ) & 0xf]; - } - } - return chars; -} - -static Py_ssize_t -ascii_char_size(JSON_UNICHR c) -{ - if (S_CHAR(c)) { - return 1; - } - else if (c == '\\' || - c == '"' || - c == '\b' || - c == '\f' || - c == '\n' || - c == '\r' || - c == '\t') { - return 2; - } -#if PY_MAJOR_VERSION >= 3 || defined(Py_UNICODE_WIDE) - else if (c >= 0x10000U) { - return 2 * MIN_EXPANSION; - } -#endif - else { - return MIN_EXPANSION; - } -} - -static PyObject * -ascii_escape_unicode(PyObject *pystr) -{ - /* Take a PyUnicode pystr and return a new ASCII-only escaped PyString */ - Py_ssize_t i; - Py_ssize_t input_chars = PyUnicode_GET_LENGTH(pystr); - Py_ssize_t output_size = 2; - Py_ssize_t chars; - PY2_UNUSED int kind = PyUnicode_KIND(pystr); - void *data = PyUnicode_DATA(pystr); - PyObject *rval; - char *output; - - output_size = 2; - for (i = 0; i < input_chars; i++) { - output_size += ascii_char_size(PyUnicode_READ(kind, data, i)); - } -#if PY_MAJOR_VERSION >= 3 - rval = PyUnicode_New(output_size, 127); - if (rval == NULL) { - return NULL; - } - assert(PyUnicode_KIND(rval) == PyUnicode_1BYTE_KIND); - output = (char *)PyUnicode_DATA(rval); -#else - rval = PyString_FromStringAndSize(NULL, output_size); - if (rval == NULL) { - return NULL; - } - output = PyString_AS_STRING(rval); -#endif - chars = 0; - output[chars++] = '"'; - for (i = 0; i < input_chars; i++) { - chars = ascii_escape_char(PyUnicode_READ(kind, data, i), output, chars); - } - output[chars++] = '"'; - assert(chars == output_size); - return rval; -} - -#if PY_MAJOR_VERSION >= 3 - -static PyObject * -ascii_escape_str(PyObject *pystr) -{ - PyObject *rval; - PyObject *input = PyUnicode_DecodeUTF8(PyBytes_AS_STRING(pystr), PyBytes_GET_SIZE(pystr), NULL); - if (input == NULL) - return NULL; - rval = ascii_escape_unicode(input); - Py_DECREF(input); - return rval; -} - -#else /* PY_MAJOR_VERSION >= 3 */ - -static PyObject * -ascii_escape_str(PyObject *pystr) -{ - /* Take a PyString pystr and return a new ASCII-only escaped PyString */ - Py_ssize_t i; - Py_ssize_t input_chars; - Py_ssize_t output_size; - Py_ssize_t chars; - PyObject *rval; - char *output; - char *input_str; - - input_chars = PyString_GET_SIZE(pystr); - input_str = PyString_AS_STRING(pystr); - output_size = 2; - - /* Fast path for a string that's already ASCII */ - for (i = 0; i < input_chars; i++) { - JSON_UNICHR c = (JSON_UNICHR)input_str[i]; - if (c > 0x7f) { - /* We hit a non-ASCII character, bail to unicode mode */ - PyObject *uni; - uni = PyUnicode_DecodeUTF8(input_str, input_chars, "strict"); - if (uni == NULL) { - return NULL; - } - rval = ascii_escape_unicode(uni); - Py_DECREF(uni); - return rval; - } - output_size += ascii_char_size(c); - } - - rval = PyString_FromStringAndSize(NULL, output_size); - if (rval == NULL) { - return NULL; - } - chars = 0; - output = PyString_AS_STRING(rval); - output[chars++] = '"'; - for (i = 0; i < input_chars; i++) { - chars = ascii_escape_char((JSON_UNICHR)input_str[i], output, chars); - } - output[chars++] = '"'; - assert(chars == output_size); - return rval; -} -#endif /* PY_MAJOR_VERSION < 3 */ - -static PyObject * -encoder_stringify_key(PyEncoderObject *s, PyObject *key) -{ - if (PyUnicode_Check(key)) { - Py_INCREF(key); - return key; - } -#if PY_MAJOR_VERSION >= 3 - else if (PyBytes_Check(key) && s->encoding != NULL) { - const char *encoding = PyUnicode_AsUTF8(s->encoding); - if (encoding == NULL) - return NULL; - return PyUnicode_Decode( - PyBytes_AS_STRING(key), - PyBytes_GET_SIZE(key), - encoding, - NULL); - } -#else /* PY_MAJOR_VERSION >= 3 */ - else if (PyString_Check(key)) { - Py_INCREF(key); - return key; - } -#endif /* PY_MAJOR_VERSION < 3 */ - else if (PyFloat_Check(key)) { - return encoder_encode_float(s, key); - } - else if (key == Py_True || key == Py_False || key == Py_None) { - /* This must come before the PyInt_Check because - True and False are also 1 and 0.*/ - return _encoded_const(key); - } - else if (PyInt_Check(key) || PyLong_Check(key)) { - if (!(PyInt_CheckExact(key) || PyLong_CheckExact(key))) { - /* See #118, do not trust custom str/repr */ - PyObject *res; - PyObject *tmp = PyObject_CallFunctionObjArgs((PyObject *)&PyLong_Type, key, NULL); - if (tmp == NULL) { - return NULL; - } - res = PyObject_Str(tmp); - Py_DECREF(tmp); - return res; - } - else { - return PyObject_Str(key); - } - } - else if (s->use_decimal && PyObject_TypeCheck(key, (PyTypeObject *)s->Decimal)) { - return PyObject_Str(key); - } - if (s->skipkeys) { - Py_INCREF(Py_None); - return Py_None; - } - PyErr_Format(PyExc_TypeError, - "keys must be str, int, float, bool or None, " - "not %.100s", key->ob_type->tp_name); - return NULL; -} - -static PyObject * -encoder_dict_iteritems(PyEncoderObject *s, PyObject *dct) -{ - PyObject *items; - PyObject *iter = NULL; - PyObject *lst = NULL; - PyObject *item = NULL; - PyObject *kstr = NULL; - PyObject *sortfun = NULL; - PyObject *sortres; - static PyObject *sortargs = NULL; - - if (sortargs == NULL) { - sortargs = PyTuple_New(0); - if (sortargs == NULL) - return NULL; - } - - if (PyDict_CheckExact(dct)) - items = PyDict_Items(dct); - else - items = PyMapping_Items(dct); - if (items == NULL) - return NULL; - iter = PyObject_GetIter(items); - Py_DECREF(items); - if (iter == NULL) - return NULL; - if (s->item_sort_kw == Py_None) - return iter; - lst = PyList_New(0); - if (lst == NULL) - goto bail; - while ((item = PyIter_Next(iter))) { - PyObject *key, *value; - if (!PyTuple_Check(item) || Py_SIZE(item) != 2) { - PyErr_SetString(PyExc_ValueError, "items must return 2-tuples"); - goto bail; - } - key = PyTuple_GET_ITEM(item, 0); - if (key == NULL) - goto bail; -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check(key)) { - /* item can be added as-is */ - } -#endif /* PY_MAJOR_VERSION < 3 */ - else if (PyUnicode_Check(key)) { - /* item can be added as-is */ - } - else { - PyObject *tpl; - kstr = encoder_stringify_key(s, key); - if (kstr == NULL) - goto bail; - else if (kstr == Py_None) { - /* skipkeys */ - Py_DECREF(kstr); - continue; - } - value = PyTuple_GET_ITEM(item, 1); - if (value == NULL) - goto bail; - tpl = PyTuple_Pack(2, kstr, value); - if (tpl == NULL) - goto bail; - Py_CLEAR(kstr); - Py_DECREF(item); - item = tpl; - } - if (PyList_Append(lst, item)) - goto bail; - Py_DECREF(item); - } - Py_CLEAR(iter); - if (PyErr_Occurred()) - goto bail; - sortfun = PyObject_GetAttrString(lst, "sort"); - if (sortfun == NULL) - goto bail; - sortres = PyObject_Call(sortfun, sortargs, s->item_sort_kw); - if (!sortres) - goto bail; - Py_DECREF(sortres); - Py_CLEAR(sortfun); - iter = PyObject_GetIter(lst); - Py_CLEAR(lst); - return iter; -bail: - Py_XDECREF(sortfun); - Py_XDECREF(kstr); - Py_XDECREF(item); - Py_XDECREF(lst); - Py_XDECREF(iter); - return NULL; -} - -/* Use JSONDecodeError exception to raise a nice looking ValueError subclass */ -static PyObject *JSONDecodeError = NULL; -static void -raise_errmsg(char *msg, PyObject *s, Py_ssize_t end) -{ - PyObject *exc = PyObject_CallFunction(JSONDecodeError, "(zOO&)", msg, s, _convertPyInt_FromSsize_t, &end); - if (exc) { - PyErr_SetObject(JSONDecodeError, exc); - Py_DECREF(exc); - } -} - -static PyObject * -join_list_unicode(PyObject *lst) -{ - /* return u''.join(lst) */ - return PyUnicode_Join(JSON_EmptyUnicode, lst); -} - -#if PY_MAJOR_VERSION >= 3 -#define join_list_string join_list_unicode -#else /* PY_MAJOR_VERSION >= 3 */ -static PyObject * -join_list_string(PyObject *lst) -{ - /* return ''.join(lst) */ - static PyObject *joinfn = NULL; - if (joinfn == NULL) { - joinfn = PyObject_GetAttrString(JSON_EmptyStr, "join"); - if (joinfn == NULL) - return NULL; - } - return PyObject_CallFunctionObjArgs(joinfn, lst, NULL); -} -#endif /* PY_MAJOR_VERSION < 3 */ - -static PyObject * -_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx) -{ - /* return (rval, idx) tuple, stealing reference to rval */ - PyObject *tpl; - PyObject *pyidx; - /* - steal a reference to rval, returns (rval, idx) - */ - if (rval == NULL) { - assert(PyErr_Occurred()); - return NULL; - } - pyidx = PyInt_FromSsize_t(idx); - if (pyidx == NULL) { - Py_DECREF(rval); - return NULL; - } - tpl = PyTuple_New(2); - if (tpl == NULL) { - Py_DECREF(pyidx); - Py_DECREF(rval); - return NULL; - } - PyTuple_SET_ITEM(tpl, 0, rval); - PyTuple_SET_ITEM(tpl, 1, pyidx); - return tpl; -} - -#define APPEND_OLD_CHUNK \ - if (chunk != NULL) { \ - if (chunks == NULL) { \ - chunks = PyList_New(0); \ - if (chunks == NULL) { \ - goto bail; \ - } \ - } \ - if (PyList_Append(chunks, chunk)) { \ - goto bail; \ - } \ - Py_CLEAR(chunk); \ - } - -#if PY_MAJOR_VERSION < 3 -static PyObject * -scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_ssize_t *next_end_ptr) -{ - /* Read the JSON string from PyString pystr. - end is the index of the first character after the quote. - encoding is the encoding of pystr (must be an ASCII superset) - if strict is zero then literal control characters are allowed - *next_end_ptr is a return-by-reference index of the character - after the end quote - - Return value is a new PyString (if ASCII-only) or PyUnicode - */ - PyObject *rval; - Py_ssize_t len = PyString_GET_SIZE(pystr); - Py_ssize_t begin = end - 1; - Py_ssize_t next = begin; - int has_unicode = 0; - char *buf = PyString_AS_STRING(pystr); - PyObject *chunks = NULL; - PyObject *chunk = NULL; - PyObject *strchunk = NULL; - - if (len == end) { - raise_errmsg(ERR_STRING_UNTERMINATED, pystr, begin); - goto bail; - } - else if (end < 0 || len < end) { - PyErr_SetString(PyExc_ValueError, "end is out of bounds"); - goto bail; - } - while (1) { - /* Find the end of the string or the next escape */ - Py_UNICODE c = 0; - for (next = end; next < len; next++) { - c = (unsigned char)buf[next]; - if (c == '"' || c == '\\') { - break; - } - else if (strict && c <= 0x1f) { - raise_errmsg(ERR_STRING_CONTROL, pystr, next); - goto bail; - } - else if (c > 0x7f) { - has_unicode = 1; - } - } - if (!(c == '"' || c == '\\')) { - raise_errmsg(ERR_STRING_UNTERMINATED, pystr, begin); - goto bail; - } - /* Pick up this chunk if it's not zero length */ - if (next != end) { - APPEND_OLD_CHUNK - strchunk = PyString_FromStringAndSize(&buf[end], next - end); - if (strchunk == NULL) { - goto bail; - } - if (has_unicode) { - chunk = PyUnicode_FromEncodedObject(strchunk, encoding, NULL); - Py_DECREF(strchunk); - if (chunk == NULL) { - goto bail; - } - } - else { - chunk = strchunk; - } - } - next++; - if (c == '"') { - end = next; - break; - } - if (next == len) { - raise_errmsg(ERR_STRING_UNTERMINATED, pystr, begin); - goto bail; - } - c = buf[next]; - if (c != 'u') { - /* Non-unicode backslash escapes */ - end = next + 1; - switch (c) { - case '"': break; - case '\\': break; - case '/': break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - default: c = 0; - } - if (c == 0) { - raise_errmsg(ERR_STRING_ESC1, pystr, end - 2); - goto bail; - } - } - else { - c = 0; - next++; - end = next + 4; - if (end >= len) { - raise_errmsg(ERR_STRING_ESC4, pystr, next - 1); - goto bail; - } - /* Decode 4 hex digits */ - for (; next < end; next++) { - JSON_UNICHR digit = (JSON_UNICHR)buf[next]; - c <<= 4; - switch (digit) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - c |= (digit - '0'); break; - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': - c |= (digit - 'a' + 10); break; - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': - c |= (digit - 'A' + 10); break; - default: - raise_errmsg(ERR_STRING_ESC4, pystr, end - 5); - goto bail; - } - } -#if defined(Py_UNICODE_WIDE) - /* Surrogate pair */ - if ((c & 0xfc00) == 0xd800) { - if (end + 6 < len && buf[next] == '\\' && buf[next+1] == 'u') { - JSON_UNICHR c2 = 0; - end += 6; - /* Decode 4 hex digits */ - for (next += 2; next < end; next++) { - c2 <<= 4; - JSON_UNICHR digit = buf[next]; - switch (digit) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - c2 |= (digit - '0'); break; - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': - c2 |= (digit - 'a' + 10); break; - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': - c2 |= (digit - 'A' + 10); break; - default: - raise_errmsg(ERR_STRING_ESC4, pystr, end - 5); - goto bail; - } - } - if ((c2 & 0xfc00) != 0xdc00) { - /* not a low surrogate, rewind */ - end -= 6; - next = end; - } - else { - c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); - } - } - } -#endif /* Py_UNICODE_WIDE */ - } - if (c > 0x7f) { - has_unicode = 1; - } - APPEND_OLD_CHUNK - if (has_unicode) { - chunk = PyUnicode_FromOrdinal(c); - if (chunk == NULL) { - goto bail; - } - } - else { - char c_char = Py_CHARMASK(c); - chunk = PyString_FromStringAndSize(&c_char, 1); - if (chunk == NULL) { - goto bail; - } - } - } - - if (chunks == NULL) { - if (chunk != NULL) - rval = chunk; - else { - rval = JSON_EmptyStr; - Py_INCREF(rval); - } - } - else { - APPEND_OLD_CHUNK - rval = join_list_string(chunks); - if (rval == NULL) { - goto bail; - } - Py_CLEAR(chunks); - } - - *next_end_ptr = end; - return rval; -bail: - *next_end_ptr = -1; - Py_XDECREF(chunk); - Py_XDECREF(chunks); - return NULL; -} -#endif /* PY_MAJOR_VERSION < 3 */ - -static PyObject * -scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next_end_ptr) -{ - /* Read the JSON string from PyUnicode pystr. - end is the index of the first character after the quote. - if strict is zero then literal control characters are allowed - *next_end_ptr is a return-by-reference index of the character - after the end quote - - Return value is a new PyUnicode - */ - PyObject *rval; - Py_ssize_t begin = end - 1; - Py_ssize_t next = begin; - PY2_UNUSED int kind = PyUnicode_KIND(pystr); - Py_ssize_t len = PyUnicode_GET_LENGTH(pystr); - void *buf = PyUnicode_DATA(pystr); - PyObject *chunks = NULL; - PyObject *chunk = NULL; - - if (len == end) { - raise_errmsg(ERR_STRING_UNTERMINATED, pystr, begin); - goto bail; - } - else if (end < 0 || len < end) { - PyErr_SetString(PyExc_ValueError, "end is out of bounds"); - goto bail; - } - while (1) { - /* Find the end of the string or the next escape */ - JSON_UNICHR c = 0; - for (next = end; next < len; next++) { - c = PyUnicode_READ(kind, buf, next); - if (c == '"' || c == '\\') { - break; - } - else if (strict && c <= 0x1f) { - raise_errmsg(ERR_STRING_CONTROL, pystr, next); - goto bail; - } - } - if (!(c == '"' || c == '\\')) { - raise_errmsg(ERR_STRING_UNTERMINATED, pystr, begin); - goto bail; - } - /* Pick up this chunk if it's not zero length */ - if (next != end) { - APPEND_OLD_CHUNK -#if PY_MAJOR_VERSION < 3 - chunk = PyUnicode_FromUnicode(&((const Py_UNICODE *)buf)[end], next - end); -#else - chunk = PyUnicode_Substring(pystr, end, next); -#endif - if (chunk == NULL) { - goto bail; - } - } - next++; - if (c == '"') { - end = next; - break; - } - if (next == len) { - raise_errmsg(ERR_STRING_UNTERMINATED, pystr, begin); - goto bail; - } - c = PyUnicode_READ(kind, buf, next); - if (c != 'u') { - /* Non-unicode backslash escapes */ - end = next + 1; - switch (c) { - case '"': break; - case '\\': break; - case '/': break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - default: c = 0; - } - if (c == 0) { - raise_errmsg(ERR_STRING_ESC1, pystr, end - 2); - goto bail; - } - } - else { - c = 0; - next++; - end = next + 4; - if (end >= len) { - raise_errmsg(ERR_STRING_ESC4, pystr, next - 1); - goto bail; - } - /* Decode 4 hex digits */ - for (; next < end; next++) { - JSON_UNICHR digit = PyUnicode_READ(kind, buf, next); - c <<= 4; - switch (digit) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - c |= (digit - '0'); break; - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': - c |= (digit - 'a' + 10); break; - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': - c |= (digit - 'A' + 10); break; - default: - raise_errmsg(ERR_STRING_ESC4, pystr, end - 5); - goto bail; - } - } -#if PY_MAJOR_VERSION >= 3 || defined(Py_UNICODE_WIDE) - /* Surrogate pair */ - if ((c & 0xfc00) == 0xd800) { - JSON_UNICHR c2 = 0; - if (end + 6 < len && - PyUnicode_READ(kind, buf, next) == '\\' && - PyUnicode_READ(kind, buf, next + 1) == 'u') { - end += 6; - /* Decode 4 hex digits */ - for (next += 2; next < end; next++) { - JSON_UNICHR digit = PyUnicode_READ(kind, buf, next); - c2 <<= 4; - switch (digit) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - c2 |= (digit - '0'); break; - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': - c2 |= (digit - 'a' + 10); break; - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': - c2 |= (digit - 'A' + 10); break; - default: - raise_errmsg(ERR_STRING_ESC4, pystr, end - 5); - goto bail; - } - } - if ((c2 & 0xfc00) != 0xdc00) { - /* not a low surrogate, rewind */ - end -= 6; - next = end; - } - else { - c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); - } - } - } -#endif - } - APPEND_OLD_CHUNK - chunk = PyUnicode_FromOrdinal(c); - if (chunk == NULL) { - goto bail; - } - } - - if (chunks == NULL) { - if (chunk != NULL) - rval = chunk; - else { - rval = JSON_EmptyUnicode; - Py_INCREF(rval); - } - } - else { - APPEND_OLD_CHUNK - rval = join_list_unicode(chunks); - if (rval == NULL) { - goto bail; - } - Py_CLEAR(chunks); - } - *next_end_ptr = end; - return rval; -bail: - *next_end_ptr = -1; - Py_XDECREF(chunk); - Py_XDECREF(chunks); - return NULL; -} - -PyDoc_STRVAR(pydoc_scanstring, - "scanstring(basestring, end, encoding, strict=True) -> (str, end)\n" - "\n" - "Scan the string s for a JSON string. End is the index of the\n" - "character in s after the quote that started the JSON string.\n" - "Unescapes all valid JSON string escape sequences and raises ValueError\n" - "on attempt to decode an invalid string. If strict is False then literal\n" - "control characters are allowed in the string.\n" - "\n" - "Returns a tuple of the decoded string and the index of the character in s\n" - "after the end quote." -); - -static PyObject * -py_scanstring(PyObject* self UNUSED, PyObject *args) -{ - PyObject *pystr; - PyObject *rval; - Py_ssize_t end; - Py_ssize_t next_end = -1; - char *encoding = NULL; - int strict = 1; - if (!PyArg_ParseTuple(args, "OO&|zi:scanstring", &pystr, _convertPyInt_AsSsize_t, &end, &encoding, &strict)) { - return NULL; - } - if (encoding == NULL) { - encoding = DEFAULT_ENCODING; - } - if (PyUnicode_Check(pystr)) { - if (PyUnicode_READY(pystr)) - return NULL; - rval = scanstring_unicode(pystr, end, strict, &next_end); - } -#if PY_MAJOR_VERSION < 3 - /* Using a bytes input is unsupported for scanning in Python 3. - It is coerced to str in the decoder before it gets here. */ - else if (PyString_Check(pystr)) { - rval = scanstring_str(pystr, end, encoding, strict, &next_end); - } -#endif - else { - PyErr_Format(PyExc_TypeError, - "first argument must be a string, not %.80s", - Py_TYPE(pystr)->tp_name); - return NULL; - } - return _build_rval_index_tuple(rval, next_end); -} - -PyDoc_STRVAR(pydoc_encode_basestring_ascii, - "encode_basestring_ascii(basestring) -> str\n" - "\n" - "Return an ASCII-only JSON representation of a Python string" -); - -static PyObject * -py_encode_basestring_ascii(PyObject* self UNUSED, PyObject *pystr) -{ - /* Return an ASCII-only JSON representation of a Python string */ - /* METH_O */ - if (PyBytes_Check(pystr)) { - return ascii_escape_str(pystr); - } - else if (PyUnicode_Check(pystr)) { - if (PyUnicode_READY(pystr)) - return NULL; - return ascii_escape_unicode(pystr); - } - else { - PyErr_Format(PyExc_TypeError, - "first argument must be a string, not %.80s", - Py_TYPE(pystr)->tp_name); - return NULL; - } -} - -static void -scanner_dealloc(PyObject *self) -{ - /* bpo-31095: UnTrack is needed before calling any callbacks */ - PyObject_GC_UnTrack(self); - scanner_clear(self); - Py_TYPE(self)->tp_free(self); -} - -static int -scanner_traverse(PyObject *self, visitproc visit, void *arg) -{ - PyScannerObject *s; - assert(PyScanner_Check(self)); - s = (PyScannerObject *)self; - Py_VISIT(s->encoding); - Py_VISIT(s->strict_bool); - Py_VISIT(s->object_hook); - Py_VISIT(s->pairs_hook); - Py_VISIT(s->parse_float); - Py_VISIT(s->parse_int); - Py_VISIT(s->parse_constant); - Py_VISIT(s->memo); - return 0; -} - -static int -scanner_clear(PyObject *self) -{ - PyScannerObject *s; - assert(PyScanner_Check(self)); - s = (PyScannerObject *)self; - Py_CLEAR(s->encoding); - Py_CLEAR(s->strict_bool); - Py_CLEAR(s->object_hook); - Py_CLEAR(s->pairs_hook); - Py_CLEAR(s->parse_float); - Py_CLEAR(s->parse_int); - Py_CLEAR(s->parse_constant); - Py_CLEAR(s->memo); - return 0; -} - -#if PY_MAJOR_VERSION < 3 -static PyObject * -_parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) -{ - /* Read a JSON object from PyString pystr. - idx is the index of the first character after the opening curly brace. - *next_idx_ptr is a return-by-reference index to the first character after - the closing curly brace. - - Returns a new PyObject (usually a dict, but object_hook or - object_pairs_hook can change that) - */ - char *str = PyString_AS_STRING(pystr); - Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1; - PyObject *rval = NULL; - PyObject *pairs = NULL; - PyObject *item; - PyObject *key = NULL; - PyObject *val = NULL; - char *encoding = PyString_AS_STRING(s->encoding); - int has_pairs_hook = (s->pairs_hook != Py_None); - int did_parse = 0; - Py_ssize_t next_idx; - if (has_pairs_hook) { - pairs = PyList_New(0); - if (pairs == NULL) - return NULL; - } - else { - rval = PyDict_New(); - if (rval == NULL) - return NULL; - } - - /* skip whitespace after { */ - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - - /* only loop if the object is non-empty */ - if (idx <= end_idx && str[idx] != '}') { - int trailing_delimiter = 0; - while (idx <= end_idx) { - PyObject *memokey; - trailing_delimiter = 0; - - /* read key */ - if (str[idx] != '"') { - raise_errmsg(ERR_OBJECT_PROPERTY, pystr, idx); - goto bail; - } - key = scanstring_str(pystr, idx + 1, encoding, s->strict, &next_idx); - if (key == NULL) - goto bail; - memokey = PyDict_GetItem(s->memo, key); - if (memokey != NULL) { - Py_INCREF(memokey); - Py_DECREF(key); - key = memokey; - } - else { - if (PyDict_SetItem(s->memo, key, key) < 0) - goto bail; - } - idx = next_idx; - - /* skip whitespace between key and : delimiter, read :, skip whitespace */ - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - if (idx > end_idx || str[idx] != ':') { - raise_errmsg(ERR_OBJECT_PROPERTY_DELIMITER, pystr, idx); - goto bail; - } - idx++; - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - - /* read any JSON data type */ - val = scan_once_str(s, pystr, idx, &next_idx); - if (val == NULL) - goto bail; - - if (has_pairs_hook) { - item = PyTuple_Pack(2, key, val); - if (item == NULL) - goto bail; - Py_CLEAR(key); - Py_CLEAR(val); - if (PyList_Append(pairs, item) == -1) { - Py_DECREF(item); - goto bail; - } - Py_DECREF(item); - } - else { - if (PyDict_SetItem(rval, key, val) < 0) - goto bail; - Py_CLEAR(key); - Py_CLEAR(val); - } - idx = next_idx; - - /* skip whitespace before } or , */ - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - - /* bail if the object is closed or we didn't get the , delimiter */ - did_parse = 1; - if (idx > end_idx) break; - if (str[idx] == '}') { - break; - } - else if (str[idx] != ',') { - raise_errmsg(ERR_OBJECT_DELIMITER, pystr, idx); - goto bail; - } - idx++; - - /* skip whitespace after , delimiter */ - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - trailing_delimiter = 1; - } - if (trailing_delimiter) { - raise_errmsg(ERR_OBJECT_PROPERTY, pystr, idx); - goto bail; - } - } - /* verify that idx < end_idx, str[idx] should be '}' */ - if (idx > end_idx || str[idx] != '}') { - if (did_parse) { - raise_errmsg(ERR_OBJECT_DELIMITER, pystr, idx); - } else { - raise_errmsg(ERR_OBJECT_PROPERTY_FIRST, pystr, idx); - } - goto bail; - } - - /* if pairs_hook is not None: rval = object_pairs_hook(pairs) */ - if (s->pairs_hook != Py_None) { - val = PyObject_CallFunctionObjArgs(s->pairs_hook, pairs, NULL); - if (val == NULL) - goto bail; - Py_DECREF(pairs); - *next_idx_ptr = idx + 1; - return val; - } - - /* if object_hook is not None: rval = object_hook(rval) */ - if (s->object_hook != Py_None) { - val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL); - if (val == NULL) - goto bail; - Py_DECREF(rval); - rval = val; - val = NULL; - } - *next_idx_ptr = idx + 1; - return rval; -bail: - Py_XDECREF(rval); - Py_XDECREF(key); - Py_XDECREF(val); - Py_XDECREF(pairs); - return NULL; -} -#endif /* PY_MAJOR_VERSION < 3 */ - -static PyObject * -_parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) -{ - /* Read a JSON object from PyUnicode pystr. - idx is the index of the first character after the opening curly brace. - *next_idx_ptr is a return-by-reference index to the first character after - the closing curly brace. - - Returns a new PyObject (usually a dict, but object_hook can change that) - */ - void *str = PyUnicode_DATA(pystr); - Py_ssize_t end_idx = PyUnicode_GET_LENGTH(pystr) - 1; - PY2_UNUSED int kind = PyUnicode_KIND(pystr); - PyObject *rval = NULL; - PyObject *pairs = NULL; - PyObject *item; - PyObject *key = NULL; - PyObject *val = NULL; - int has_pairs_hook = (s->pairs_hook != Py_None); - int did_parse = 0; - Py_ssize_t next_idx; - - if (has_pairs_hook) { - pairs = PyList_New(0); - if (pairs == NULL) - return NULL; - } - else { - rval = PyDict_New(); - if (rval == NULL) - return NULL; - } - - /* skip whitespace after { */ - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - - /* only loop if the object is non-empty */ - if (idx <= end_idx && PyUnicode_READ(kind, str, idx) != '}') { - int trailing_delimiter = 0; - while (idx <= end_idx) { - PyObject *memokey; - trailing_delimiter = 0; - - /* read key */ - if (PyUnicode_READ(kind, str, idx) != '"') { - raise_errmsg(ERR_OBJECT_PROPERTY, pystr, idx); - goto bail; - } - key = scanstring_unicode(pystr, idx + 1, s->strict, &next_idx); - if (key == NULL) - goto bail; - memokey = PyDict_GetItem(s->memo, key); - if (memokey != NULL) { - Py_INCREF(memokey); - Py_DECREF(key); - key = memokey; - } - else { - if (PyDict_SetItem(s->memo, key, key) < 0) - goto bail; - } - idx = next_idx; - - /* skip whitespace between key and : delimiter, read :, skip - whitespace */ - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - if (idx > end_idx || PyUnicode_READ(kind, str, idx) != ':') { - raise_errmsg(ERR_OBJECT_PROPERTY_DELIMITER, pystr, idx); - goto bail; - } - idx++; - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - - /* read any JSON term */ - val = scan_once_unicode(s, pystr, idx, &next_idx); - if (val == NULL) - goto bail; - - if (has_pairs_hook) { - item = PyTuple_Pack(2, key, val); - if (item == NULL) - goto bail; - Py_CLEAR(key); - Py_CLEAR(val); - if (PyList_Append(pairs, item) == -1) { - Py_DECREF(item); - goto bail; - } - Py_DECREF(item); - } - else { - if (PyDict_SetItem(rval, key, val) < 0) - goto bail; - Py_CLEAR(key); - Py_CLEAR(val); - } - idx = next_idx; - - /* skip whitespace before } or , */ - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - - /* bail if the object is closed or we didn't get the , - delimiter */ - did_parse = 1; - if (idx > end_idx) break; - if (PyUnicode_READ(kind, str, idx) == '}') { - break; - } - else if (PyUnicode_READ(kind, str, idx) != ',') { - raise_errmsg(ERR_OBJECT_DELIMITER, pystr, idx); - goto bail; - } - idx++; - - /* skip whitespace after , delimiter */ - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - trailing_delimiter = 1; - } - if (trailing_delimiter) { - raise_errmsg(ERR_OBJECT_PROPERTY, pystr, idx); - goto bail; - } - } - - /* verify that idx < end_idx, str[idx] should be '}' */ - if (idx > end_idx || PyUnicode_READ(kind, str, idx) != '}') { - if (did_parse) { - raise_errmsg(ERR_OBJECT_DELIMITER, pystr, idx); - } else { - raise_errmsg(ERR_OBJECT_PROPERTY_FIRST, pystr, idx); - } - goto bail; - } - - /* if pairs_hook is not None: rval = object_pairs_hook(pairs) */ - if (s->pairs_hook != Py_None) { - val = PyObject_CallFunctionObjArgs(s->pairs_hook, pairs, NULL); - if (val == NULL) - goto bail; - Py_DECREF(pairs); - *next_idx_ptr = idx + 1; - return val; - } - - /* if object_hook is not None: rval = object_hook(rval) */ - if (s->object_hook != Py_None) { - val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL); - if (val == NULL) - goto bail; - Py_DECREF(rval); - rval = val; - val = NULL; - } - *next_idx_ptr = idx + 1; - return rval; -bail: - Py_XDECREF(rval); - Py_XDECREF(key); - Py_XDECREF(val); - Py_XDECREF(pairs); - return NULL; -} - -#if PY_MAJOR_VERSION < 3 -static PyObject * -_parse_array_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) -{ - /* Read a JSON array from PyString pystr. - idx is the index of the first character after the opening brace. - *next_idx_ptr is a return-by-reference index to the first character after - the closing brace. - - Returns a new PyList - */ - char *str = PyString_AS_STRING(pystr); - Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1; - PyObject *val = NULL; - PyObject *rval = PyList_New(0); - Py_ssize_t next_idx; - if (rval == NULL) - return NULL; - - /* skip whitespace after [ */ - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - - /* only loop if the array is non-empty */ - if (idx <= end_idx && str[idx] != ']') { - int trailing_delimiter = 0; - while (idx <= end_idx) { - trailing_delimiter = 0; - /* read any JSON term and de-tuplefy the (rval, idx) */ - val = scan_once_str(s, pystr, idx, &next_idx); - if (val == NULL) { - goto bail; - } - - if (PyList_Append(rval, val) == -1) - goto bail; - - Py_CLEAR(val); - idx = next_idx; - - /* skip whitespace between term and , */ - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - - /* bail if the array is closed or we didn't get the , delimiter */ - if (idx > end_idx) break; - if (str[idx] == ']') { - break; - } - else if (str[idx] != ',') { - raise_errmsg(ERR_ARRAY_DELIMITER, pystr, idx); - goto bail; - } - idx++; - - /* skip whitespace after , */ - while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++; - trailing_delimiter = 1; - } - if (trailing_delimiter) { - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - goto bail; - } - } - - /* verify that idx < end_idx, str[idx] should be ']' */ - if (idx > end_idx || str[idx] != ']') { - if (PyList_GET_SIZE(rval)) { - raise_errmsg(ERR_ARRAY_DELIMITER, pystr, idx); - } else { - raise_errmsg(ERR_ARRAY_VALUE_FIRST, pystr, idx); - } - goto bail; - } - *next_idx_ptr = idx + 1; - return rval; -bail: - Py_XDECREF(val); - Py_DECREF(rval); - return NULL; -} -#endif /* PY_MAJOR_VERSION < 3 */ - -static PyObject * -_parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) -{ - /* Read a JSON array from PyString pystr. - idx is the index of the first character after the opening brace. - *next_idx_ptr is a return-by-reference index to the first character after - the closing brace. - - Returns a new PyList - */ - PY2_UNUSED int kind = PyUnicode_KIND(pystr); - void *str = PyUnicode_DATA(pystr); - Py_ssize_t end_idx = PyUnicode_GET_LENGTH(pystr) - 1; - PyObject *val = NULL; - PyObject *rval = PyList_New(0); - Py_ssize_t next_idx; - if (rval == NULL) - return NULL; - - /* skip whitespace after [ */ - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - - /* only loop if the array is non-empty */ - if (idx <= end_idx && PyUnicode_READ(kind, str, idx) != ']') { - int trailing_delimiter = 0; - while (idx <= end_idx) { - trailing_delimiter = 0; - /* read any JSON term */ - val = scan_once_unicode(s, pystr, idx, &next_idx); - if (val == NULL) { - goto bail; - } - - if (PyList_Append(rval, val) == -1) - goto bail; - - Py_CLEAR(val); - idx = next_idx; - - /* skip whitespace between term and , */ - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - - /* bail if the array is closed or we didn't get the , delimiter */ - if (idx > end_idx) break; - if (PyUnicode_READ(kind, str, idx) == ']') { - break; - } - else if (PyUnicode_READ(kind, str, idx) != ',') { - raise_errmsg(ERR_ARRAY_DELIMITER, pystr, idx); - goto bail; - } - idx++; - - /* skip whitespace after , */ - while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++; - trailing_delimiter = 1; - } - if (trailing_delimiter) { - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - goto bail; - } - } - - /* verify that idx < end_idx, str[idx] should be ']' */ - if (idx > end_idx || PyUnicode_READ(kind, str, idx) != ']') { - if (PyList_GET_SIZE(rval)) { - raise_errmsg(ERR_ARRAY_DELIMITER, pystr, idx); - } else { - raise_errmsg(ERR_ARRAY_VALUE_FIRST, pystr, idx); - } - goto bail; - } - *next_idx_ptr = idx + 1; - return rval; -bail: - Py_XDECREF(val); - Py_DECREF(rval); - return NULL; -} - -static PyObject * -_parse_constant(PyScannerObject *s, PyObject *constant, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) -{ - /* Read a JSON constant from PyString pystr. - constant is the Python string that was found - ("NaN", "Infinity", "-Infinity"). - idx is the index of the first character of the constant - *next_idx_ptr is a return-by-reference index to the first character after - the constant. - - Returns the result of parse_constant - */ - PyObject *rval; - - /* rval = parse_constant(constant) */ - rval = PyObject_CallFunctionObjArgs(s->parse_constant, constant, NULL); - idx += PyString_GET_SIZE(constant); - *next_idx_ptr = idx; - return rval; -} - -#if PY_MAJOR_VERSION < 3 -static PyObject * -_match_number_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_ssize_t *next_idx_ptr) -{ - /* Read a JSON number from PyString pystr. - idx is the index of the first character of the number - *next_idx_ptr is a return-by-reference index to the first character after - the number. - - Returns a new PyObject representation of that number: - PyInt, PyLong, or PyFloat. - May return other types if parse_int or parse_float are set - */ - char *str = PyString_AS_STRING(pystr); - Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1; - Py_ssize_t idx = start; - int is_float = 0; - PyObject *rval; - PyObject *numstr; - - /* read a sign if it's there, make sure it's not the end of the string */ - if (str[idx] == '-') { - if (idx >= end_idx) { - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - return NULL; - } - idx++; - } - - /* read as many integer digits as we find as long as it doesn't start with 0 */ - if (str[idx] >= '1' && str[idx] <= '9') { - idx++; - while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++; - } - /* if it starts with 0 we only expect one integer digit */ - else if (str[idx] == '0') { - idx++; - } - /* no integer digits, error */ - else { - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - return NULL; - } - - /* if the next char is '.' followed by a digit then read all float digits */ - if (idx < end_idx && str[idx] == '.' && str[idx + 1] >= '0' && str[idx + 1] <= '9') { - is_float = 1; - idx += 2; - while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++; - } - - /* if the next char is 'e' or 'E' then maybe read the exponent (or backtrack) */ - if (idx < end_idx && (str[idx] == 'e' || str[idx] == 'E')) { - - /* save the index of the 'e' or 'E' just in case we need to backtrack */ - Py_ssize_t e_start = idx; - idx++; - - /* read an exponent sign if present */ - if (idx < end_idx && (str[idx] == '-' || str[idx] == '+')) idx++; - - /* read all digits */ - while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++; - - /* if we got a digit, then parse as float. if not, backtrack */ - if (str[idx - 1] >= '0' && str[idx - 1] <= '9') { - is_float = 1; - } - else { - idx = e_start; - } - } - - /* copy the section we determined to be a number */ - numstr = PyString_FromStringAndSize(&str[start], idx - start); - if (numstr == NULL) - return NULL; - if (is_float) { - /* parse as a float using a fast path if available, otherwise call user defined method */ - if (s->parse_float != (PyObject *)&PyFloat_Type) { - rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL); - } - else { - /* rval = PyFloat_FromDouble(PyOS_ascii_atof(PyString_AS_STRING(numstr))); */ - double d = PyOS_string_to_double(PyString_AS_STRING(numstr), - NULL, NULL); - if (d == -1.0 && PyErr_Occurred()) - return NULL; - rval = PyFloat_FromDouble(d); - } - } - else { - /* parse as an int using a fast path if available, otherwise call user defined method */ - if (s->parse_int != (PyObject *)&PyInt_Type) { - rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL); - } - else { - rval = PyInt_FromString(PyString_AS_STRING(numstr), NULL, 10); - } - } - Py_DECREF(numstr); - *next_idx_ptr = idx; - return rval; -} -#endif /* PY_MAJOR_VERSION < 3 */ - -static PyObject * -_match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_ssize_t *next_idx_ptr) -{ - /* Read a JSON number from PyUnicode pystr. - idx is the index of the first character of the number - *next_idx_ptr is a return-by-reference index to the first character after - the number. - - Returns a new PyObject representation of that number: - PyInt, PyLong, or PyFloat. - May return other types if parse_int or parse_float are set - */ - PY2_UNUSED int kind = PyUnicode_KIND(pystr); - void *str = PyUnicode_DATA(pystr); - Py_ssize_t end_idx = PyUnicode_GET_LENGTH(pystr) - 1; - Py_ssize_t idx = start; - int is_float = 0; - JSON_UNICHR c; - PyObject *rval; - PyObject *numstr; - - /* read a sign if it's there, make sure it's not the end of the string */ - if (PyUnicode_READ(kind, str, idx) == '-') { - if (idx >= end_idx) { - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - return NULL; - } - idx++; - } - - /* read as many integer digits as we find as long as it doesn't start with 0 */ - c = PyUnicode_READ(kind, str, idx); - if (c == '0') { - /* if it starts with 0 we only expect one integer digit */ - idx++; - } - else if (IS_DIGIT(c)) { - idx++; - while (idx <= end_idx && IS_DIGIT(PyUnicode_READ(kind, str, idx))) { - idx++; - } - } - else { - /* no integer digits, error */ - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - return NULL; - } - - /* if the next char is '.' followed by a digit then read all float digits */ - if (idx < end_idx && - PyUnicode_READ(kind, str, idx) == '.' && - IS_DIGIT(PyUnicode_READ(kind, str, idx + 1))) { - is_float = 1; - idx += 2; - while (idx <= end_idx && IS_DIGIT(PyUnicode_READ(kind, str, idx))) idx++; - } - - /* if the next char is 'e' or 'E' then maybe read the exponent (or backtrack) */ - if (idx < end_idx && - (PyUnicode_READ(kind, str, idx) == 'e' || - PyUnicode_READ(kind, str, idx) == 'E')) { - Py_ssize_t e_start = idx; - idx++; - - /* read an exponent sign if present */ - if (idx < end_idx && - (PyUnicode_READ(kind, str, idx) == '-' || - PyUnicode_READ(kind, str, idx) == '+')) idx++; - - /* read all digits */ - while (idx <= end_idx && IS_DIGIT(PyUnicode_READ(kind, str, idx))) idx++; - - /* if we got a digit, then parse as float. if not, backtrack */ - if (IS_DIGIT(PyUnicode_READ(kind, str, idx - 1))) { - is_float = 1; - } - else { - idx = e_start; - } - } - - /* copy the section we determined to be a number */ -#if PY_MAJOR_VERSION >= 3 - numstr = PyUnicode_Substring(pystr, start, idx); -#else - numstr = PyUnicode_FromUnicode(&((Py_UNICODE *)str)[start], idx - start); -#endif - if (numstr == NULL) - return NULL; - if (is_float) { - /* parse as a float using a fast path if available, otherwise call user defined method */ - if (s->parse_float != (PyObject *)&PyFloat_Type) { - rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL); - } - else { -#if PY_MAJOR_VERSION >= 3 - rval = PyFloat_FromString(numstr); -#else - rval = PyFloat_FromString(numstr, NULL); -#endif - } - } - else { - /* no fast path for unicode -> int, just call */ - rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL); - } - Py_DECREF(numstr); - *next_idx_ptr = idx; - return rval; -} - -#if PY_MAJOR_VERSION < 3 -static PyObject * -scan_once_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) -{ - /* Read one JSON term (of any kind) from PyString pystr. - idx is the index of the first character of the term - *next_idx_ptr is a return-by-reference index to the first character after - the number. - - Returns a new PyObject representation of the term. - */ - char *str = PyString_AS_STRING(pystr); - Py_ssize_t length = PyString_GET_SIZE(pystr); - PyObject *rval = NULL; - int fallthrough = 0; - if (idx < 0 || idx >= length) { - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - return NULL; - } - switch (str[idx]) { - case '"': - /* string */ - rval = scanstring_str(pystr, idx + 1, - PyString_AS_STRING(s->encoding), - s->strict, - next_idx_ptr); - break; - case '{': - /* object */ - if (Py_EnterRecursiveCall(" while decoding a JSON object " - "from a string")) - return NULL; - rval = _parse_object_str(s, pystr, idx + 1, next_idx_ptr); - Py_LeaveRecursiveCall(); - break; - case '[': - /* array */ - if (Py_EnterRecursiveCall(" while decoding a JSON array " - "from a string")) - return NULL; - rval = _parse_array_str(s, pystr, idx + 1, next_idx_ptr); - Py_LeaveRecursiveCall(); - break; - case 'n': - /* null */ - if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') { - Py_INCREF(Py_None); - *next_idx_ptr = idx + 4; - rval = Py_None; - } - else - fallthrough = 1; - break; - case 't': - /* true */ - if ((idx + 3 < length) && str[idx + 1] == 'r' && str[idx + 2] == 'u' && str[idx + 3] == 'e') { - Py_INCREF(Py_True); - *next_idx_ptr = idx + 4; - rval = Py_True; - } - else - fallthrough = 1; - break; - case 'f': - /* false */ - if ((idx + 4 < length) && str[idx + 1] == 'a' && str[idx + 2] == 'l' && str[idx + 3] == 's' && str[idx + 4] == 'e') { - Py_INCREF(Py_False); - *next_idx_ptr = idx + 5; - rval = Py_False; - } - else - fallthrough = 1; - break; - case 'N': - /* NaN */ - if ((idx + 2 < length) && str[idx + 1] == 'a' && str[idx + 2] == 'N') { - rval = _parse_constant(s, JSON_NaN, idx, next_idx_ptr); - } - else - fallthrough = 1; - break; - case 'I': - /* Infinity */ - if ((idx + 7 < length) && str[idx + 1] == 'n' && str[idx + 2] == 'f' && str[idx + 3] == 'i' && str[idx + 4] == 'n' && str[idx + 5] == 'i' && str[idx + 6] == 't' && str[idx + 7] == 'y') { - rval = _parse_constant(s, JSON_Infinity, idx, next_idx_ptr); - } - else - fallthrough = 1; - break; - case '-': - /* -Infinity */ - if ((idx + 8 < length) && str[idx + 1] == 'I' && str[idx + 2] == 'n' && str[idx + 3] == 'f' && str[idx + 4] == 'i' && str[idx + 5] == 'n' && str[idx + 6] == 'i' && str[idx + 7] == 't' && str[idx + 8] == 'y') { - rval = _parse_constant(s, JSON_NegInfinity, idx, next_idx_ptr); - } - else - fallthrough = 1; - break; - default: - fallthrough = 1; - } - /* Didn't find a string, object, array, or named constant. Look for a number. */ - if (fallthrough) - rval = _match_number_str(s, pystr, idx, next_idx_ptr); - return rval; -} -#endif /* PY_MAJOR_VERSION < 3 */ - - -static PyObject * -scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) -{ - /* Read one JSON term (of any kind) from PyUnicode pystr. - idx is the index of the first character of the term - *next_idx_ptr is a return-by-reference index to the first character after - the number. - - Returns a new PyObject representation of the term. - */ - PY2_UNUSED int kind = PyUnicode_KIND(pystr); - void *str = PyUnicode_DATA(pystr); - Py_ssize_t length = PyUnicode_GET_LENGTH(pystr); - PyObject *rval = NULL; - int fallthrough = 0; - if (idx < 0 || idx >= length) { - raise_errmsg(ERR_EXPECTING_VALUE, pystr, idx); - return NULL; - } - switch (PyUnicode_READ(kind, str, idx)) { - case '"': - /* string */ - rval = scanstring_unicode(pystr, idx + 1, - s->strict, - next_idx_ptr); - break; - case '{': - /* object */ - if (Py_EnterRecursiveCall(" while decoding a JSON object " - "from a unicode string")) - return NULL; - rval = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr); - Py_LeaveRecursiveCall(); - break; - case '[': - /* array */ - if (Py_EnterRecursiveCall(" while decoding a JSON array " - "from a unicode string")) - return NULL; - rval = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr); - Py_LeaveRecursiveCall(); - break; - case 'n': - /* null */ - if ((idx + 3 < length) && - PyUnicode_READ(kind, str, idx + 1) == 'u' && - PyUnicode_READ(kind, str, idx + 2) == 'l' && - PyUnicode_READ(kind, str, idx + 3) == 'l') { - Py_INCREF(Py_None); - *next_idx_ptr = idx + 4; - rval = Py_None; - } - else - fallthrough = 1; - break; - case 't': - /* true */ - if ((idx + 3 < length) && - PyUnicode_READ(kind, str, idx + 1) == 'r' && - PyUnicode_READ(kind, str, idx + 2) == 'u' && - PyUnicode_READ(kind, str, idx + 3) == 'e') { - Py_INCREF(Py_True); - *next_idx_ptr = idx + 4; - rval = Py_True; - } - else - fallthrough = 1; - break; - case 'f': - /* false */ - if ((idx + 4 < length) && - PyUnicode_READ(kind, str, idx + 1) == 'a' && - PyUnicode_READ(kind, str, idx + 2) == 'l' && - PyUnicode_READ(kind, str, idx + 3) == 's' && - PyUnicode_READ(kind, str, idx + 4) == 'e') { - Py_INCREF(Py_False); - *next_idx_ptr = idx + 5; - rval = Py_False; - } - else - fallthrough = 1; - break; - case 'N': - /* NaN */ - if ((idx + 2 < length) && - PyUnicode_READ(kind, str, idx + 1) == 'a' && - PyUnicode_READ(kind, str, idx + 2) == 'N') { - rval = _parse_constant(s, JSON_NaN, idx, next_idx_ptr); - } - else - fallthrough = 1; - break; - case 'I': - /* Infinity */ - if ((idx + 7 < length) && - PyUnicode_READ(kind, str, idx + 1) == 'n' && - PyUnicode_READ(kind, str, idx + 2) == 'f' && - PyUnicode_READ(kind, str, idx + 3) == 'i' && - PyUnicode_READ(kind, str, idx + 4) == 'n' && - PyUnicode_READ(kind, str, idx + 5) == 'i' && - PyUnicode_READ(kind, str, idx + 6) == 't' && - PyUnicode_READ(kind, str, idx + 7) == 'y') { - rval = _parse_constant(s, JSON_Infinity, idx, next_idx_ptr); - } - else - fallthrough = 1; - break; - case '-': - /* -Infinity */ - if ((idx + 8 < length) && - PyUnicode_READ(kind, str, idx + 1) == 'I' && - PyUnicode_READ(kind, str, idx + 2) == 'n' && - PyUnicode_READ(kind, str, idx + 3) == 'f' && - PyUnicode_READ(kind, str, idx + 4) == 'i' && - PyUnicode_READ(kind, str, idx + 5) == 'n' && - PyUnicode_READ(kind, str, idx + 6) == 'i' && - PyUnicode_READ(kind, str, idx + 7) == 't' && - PyUnicode_READ(kind, str, idx + 8) == 'y') { - rval = _parse_constant(s, JSON_NegInfinity, idx, next_idx_ptr); - } - else - fallthrough = 1; - break; - default: - fallthrough = 1; - } - /* Didn't find a string, object, array, or named constant. Look for a number. */ - if (fallthrough) - rval = _match_number_unicode(s, pystr, idx, next_idx_ptr); - return rval; -} - -static PyObject * -scanner_call(PyObject *self, PyObject *args, PyObject *kwds) -{ - /* Python callable interface to scan_once_{str,unicode} */ - PyObject *pystr; - PyObject *rval; - Py_ssize_t idx; - Py_ssize_t next_idx = -1; - static char *kwlist[] = {"string", "idx", NULL}; - PyScannerObject *s; - assert(PyScanner_Check(self)); - s = (PyScannerObject *)self; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&:scan_once", kwlist, &pystr, _convertPyInt_AsSsize_t, &idx)) - return NULL; - - if (PyUnicode_Check(pystr)) { - if (PyUnicode_READY(pystr)) - return NULL; - rval = scan_once_unicode(s, pystr, idx, &next_idx); - } -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check(pystr)) { - rval = scan_once_str(s, pystr, idx, &next_idx); - } -#endif /* PY_MAJOR_VERSION < 3 */ - else { - PyErr_Format(PyExc_TypeError, - "first argument must be a string, not %.80s", - Py_TYPE(pystr)->tp_name); - return NULL; - } - PyDict_Clear(s->memo); - return _build_rval_index_tuple(rval, next_idx); -} - -static PyObject * -JSON_ParseEncoding(PyObject *encoding) -{ - if (encoding == Py_None) - return JSON_InternFromString(DEFAULT_ENCODING); -#if PY_MAJOR_VERSION >= 3 - if (PyUnicode_Check(encoding)) { - if (PyUnicode_AsUTF8(encoding) == NULL) { - return NULL; - } - Py_INCREF(encoding); - return encoding; - } -#else /* PY_MAJOR_VERSION >= 3 */ - if (PyString_Check(encoding)) { - Py_INCREF(encoding); - return encoding; - } - if (PyUnicode_Check(encoding)) - return PyUnicode_AsEncodedString(encoding, NULL, NULL); -#endif /* PY_MAJOR_VERSION >= 3 */ - PyErr_SetString(PyExc_TypeError, "encoding must be a string"); - return NULL; -} - -static PyObject * -scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - /* Initialize Scanner object */ - PyObject *ctx; - static char *kwlist[] = {"context", NULL}; - PyScannerObject *s; - PyObject *encoding; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:make_scanner", kwlist, &ctx)) - return NULL; - - s = (PyScannerObject *)type->tp_alloc(type, 0); - if (s == NULL) - return NULL; - - if (s->memo == NULL) { - s->memo = PyDict_New(); - if (s->memo == NULL) - goto bail; - } - - encoding = PyObject_GetAttrString(ctx, "encoding"); - if (encoding == NULL) - goto bail; - s->encoding = JSON_ParseEncoding(encoding); - Py_XDECREF(encoding); - if (s->encoding == NULL) - goto bail; - - /* All of these will fail "gracefully" so we don't need to verify them */ - s->strict_bool = PyObject_GetAttrString(ctx, "strict"); - if (s->strict_bool == NULL) - goto bail; - s->strict = PyObject_IsTrue(s->strict_bool); - if (s->strict < 0) - goto bail; - s->object_hook = PyObject_GetAttrString(ctx, "object_hook"); - if (s->object_hook == NULL) - goto bail; - s->pairs_hook = PyObject_GetAttrString(ctx, "object_pairs_hook"); - if (s->pairs_hook == NULL) - goto bail; - s->parse_float = PyObject_GetAttrString(ctx, "parse_float"); - if (s->parse_float == NULL) - goto bail; - s->parse_int = PyObject_GetAttrString(ctx, "parse_int"); - if (s->parse_int == NULL) - goto bail; - s->parse_constant = PyObject_GetAttrString(ctx, "parse_constant"); - if (s->parse_constant == NULL) - goto bail; - - return (PyObject *)s; - -bail: - Py_DECREF(s); - return NULL; -} - -PyDoc_STRVAR(scanner_doc, "JSON scanner object"); - -static -PyTypeObject PyScannerType = { - PyVarObject_HEAD_INIT(NULL, 0) - "simplejson._speedups.Scanner", /* tp_name */ - sizeof(PyScannerObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - scanner_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - scanner_call, /* tp_call */ - 0, /* tp_str */ - 0,/* PyObject_GenericGetAttr, */ /* tp_getattro */ - 0,/* PyObject_GenericSetAttr, */ /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - scanner_doc, /* tp_doc */ - scanner_traverse, /* tp_traverse */ - scanner_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - scanner_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0,/* PyType_GenericAlloc, */ /* tp_alloc */ - scanner_new, /* tp_new */ - 0,/* PyObject_GC_Del, */ /* tp_free */ -}; - -static PyObject * -encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = { - "markers", - "default", - "encoder", - "indent", - "key_separator", - "item_separator", - "sort_keys", - "skipkeys", - "allow_nan", - "key_memo", - "use_decimal", - "namedtuple_as_object", - "tuple_as_array", - "int_as_string_bitcount", - "item_sort_key", - "encoding", - "for_json", - "ignore_nan", - "Decimal", - "iterable_as_array", - NULL}; - - PyEncoderObject *s; - PyObject *markers, *defaultfn, *encoder, *indent, *key_separator; - PyObject *item_separator, *sort_keys, *skipkeys, *allow_nan, *key_memo; - PyObject *use_decimal, *namedtuple_as_object, *tuple_as_array, *iterable_as_array; - PyObject *int_as_string_bitcount, *item_sort_key, *encoding, *for_json; - PyObject *ignore_nan, *Decimal; - int is_true; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOOOOOOOOOOOOOOOOO:make_encoder", kwlist, - &markers, &defaultfn, &encoder, &indent, &key_separator, &item_separator, - &sort_keys, &skipkeys, &allow_nan, &key_memo, &use_decimal, - &namedtuple_as_object, &tuple_as_array, - &int_as_string_bitcount, &item_sort_key, &encoding, &for_json, - &ignore_nan, &Decimal, &iterable_as_array)) - return NULL; - - s = (PyEncoderObject *)type->tp_alloc(type, 0); - if (s == NULL) - return NULL; - - Py_INCREF(markers); - s->markers = markers; - Py_INCREF(defaultfn); - s->defaultfn = defaultfn; - Py_INCREF(encoder); - s->encoder = encoder; -#if PY_MAJOR_VERSION >= 3 - if (encoding == Py_None) { - s->encoding = NULL; - } - else -#endif /* PY_MAJOR_VERSION >= 3 */ - { - s->encoding = JSON_ParseEncoding(encoding); - if (s->encoding == NULL) - goto bail; - } - Py_INCREF(indent); - s->indent = indent; - Py_INCREF(key_separator); - s->key_separator = key_separator; - Py_INCREF(item_separator); - s->item_separator = item_separator; - Py_INCREF(skipkeys); - s->skipkeys_bool = skipkeys; - s->skipkeys = PyObject_IsTrue(skipkeys); - if (s->skipkeys < 0) - goto bail; - Py_INCREF(key_memo); - s->key_memo = key_memo; - s->fast_encode = (PyCFunction_Check(s->encoder) && PyCFunction_GetFunction(s->encoder) == (PyCFunction)py_encode_basestring_ascii); - is_true = PyObject_IsTrue(ignore_nan); - if (is_true < 0) - goto bail; - s->allow_or_ignore_nan = is_true ? JSON_IGNORE_NAN : 0; - is_true = PyObject_IsTrue(allow_nan); - if (is_true < 0) - goto bail; - s->allow_or_ignore_nan |= is_true ? JSON_ALLOW_NAN : 0; - s->use_decimal = PyObject_IsTrue(use_decimal); - if (s->use_decimal < 0) - goto bail; - s->namedtuple_as_object = PyObject_IsTrue(namedtuple_as_object); - if (s->namedtuple_as_object < 0) - goto bail; - s->tuple_as_array = PyObject_IsTrue(tuple_as_array); - if (s->tuple_as_array < 0) - goto bail; - s->iterable_as_array = PyObject_IsTrue(iterable_as_array); - if (s->iterable_as_array < 0) - goto bail; - if (PyInt_Check(int_as_string_bitcount) || PyLong_Check(int_as_string_bitcount)) { - static const unsigned long long_long_bitsize = SIZEOF_LONG_LONG * 8; - long int_as_string_bitcount_val = PyLong_AsLong(int_as_string_bitcount); - if (int_as_string_bitcount_val > 0 && int_as_string_bitcount_val < (long)long_long_bitsize) { - s->max_long_size = PyLong_FromUnsignedLongLong(1ULL << (int)int_as_string_bitcount_val); - s->min_long_size = PyLong_FromLongLong(-1LL << (int)int_as_string_bitcount_val); - if (s->min_long_size == NULL || s->max_long_size == NULL) { - goto bail; - } - } - else { - PyErr_Format(PyExc_TypeError, - "int_as_string_bitcount (%ld) must be greater than 0 and less than the number of bits of a `long long` type (%lu bits)", - int_as_string_bitcount_val, long_long_bitsize); - goto bail; - } - } - else if (int_as_string_bitcount == Py_None) { - Py_INCREF(Py_None); - s->max_long_size = Py_None; - Py_INCREF(Py_None); - s->min_long_size = Py_None; - } - else { - PyErr_SetString(PyExc_TypeError, "int_as_string_bitcount must be None or an integer"); - goto bail; - } - if (item_sort_key != Py_None) { - if (!PyCallable_Check(item_sort_key)) { - PyErr_SetString(PyExc_TypeError, "item_sort_key must be None or callable"); - goto bail; - } - } - else { - is_true = PyObject_IsTrue(sort_keys); - if (is_true < 0) - goto bail; - if (is_true) { - static PyObject *itemgetter0 = NULL; - if (!itemgetter0) { - PyObject *operator = PyImport_ImportModule("operator"); - if (!operator) - goto bail; - itemgetter0 = PyObject_CallMethod(operator, "itemgetter", "i", 0); - Py_DECREF(operator); - } - item_sort_key = itemgetter0; - if (!item_sort_key) - goto bail; - } - } - if (item_sort_key == Py_None) { - Py_INCREF(Py_None); - s->item_sort_kw = Py_None; - } - else { - s->item_sort_kw = PyDict_New(); - if (s->item_sort_kw == NULL) - goto bail; - if (PyDict_SetItemString(s->item_sort_kw, "key", item_sort_key)) - goto bail; - } - Py_INCREF(sort_keys); - s->sort_keys = sort_keys; - Py_INCREF(item_sort_key); - s->item_sort_key = item_sort_key; - Py_INCREF(Decimal); - s->Decimal = Decimal; - s->for_json = PyObject_IsTrue(for_json); - if (s->for_json < 0) - goto bail; - - return (PyObject *)s; - -bail: - Py_DECREF(s); - return NULL; -} - -static PyObject * -encoder_call(PyObject *self, PyObject *args, PyObject *kwds) -{ - /* Python callable interface to encode_listencode_obj */ - static char *kwlist[] = {"obj", "_current_indent_level", NULL}; - PyObject *obj; - Py_ssize_t indent_level; - PyEncoderObject *s; - JSON_Accu rval; - assert(PyEncoder_Check(self)); - s = (PyEncoderObject *)self; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&:_iterencode", kwlist, - &obj, _convertPyInt_AsSsize_t, &indent_level)) - return NULL; - if (JSON_Accu_Init(&rval)) - return NULL; - if (encoder_listencode_obj(s, &rval, obj, indent_level)) { - JSON_Accu_Destroy(&rval); - return NULL; - } - return JSON_Accu_FinishAsList(&rval); -} - -static PyObject * -_encoded_const(PyObject *obj) -{ - /* Return the JSON string representation of None, True, False */ - if (obj == Py_None) { - static PyObject *s_null = NULL; - if (s_null == NULL) { - s_null = JSON_InternFromString("null"); - } - Py_INCREF(s_null); - return s_null; - } - else if (obj == Py_True) { - static PyObject *s_true = NULL; - if (s_true == NULL) { - s_true = JSON_InternFromString("true"); - } - Py_INCREF(s_true); - return s_true; - } - else if (obj == Py_False) { - static PyObject *s_false = NULL; - if (s_false == NULL) { - s_false = JSON_InternFromString("false"); - } - Py_INCREF(s_false); - return s_false; - } - else { - PyErr_SetString(PyExc_ValueError, "not a const"); - return NULL; - } -} - -static PyObject * -encoder_encode_float(PyEncoderObject *s, PyObject *obj) -{ - /* Return the JSON representation of a PyFloat */ - double i = PyFloat_AS_DOUBLE(obj); - if (!Py_IS_FINITE(i)) { - if (!s->allow_or_ignore_nan) { - PyErr_SetString(PyExc_ValueError, "Out of range float values are not JSON compliant"); - return NULL; - } - if (s->allow_or_ignore_nan & JSON_IGNORE_NAN) { - return _encoded_const(Py_None); - } - /* JSON_ALLOW_NAN is set */ - else if (i > 0) { - Py_INCREF(JSON_Infinity); - return JSON_Infinity; - } - else if (i < 0) { - Py_INCREF(JSON_NegInfinity); - return JSON_NegInfinity; - } - else { - Py_INCREF(JSON_NaN); - return JSON_NaN; - } - } - /* Use a better float format here? */ - if (PyFloat_CheckExact(obj)) { - return PyObject_Repr(obj); - } - else { - /* See #118, do not trust custom str/repr */ - PyObject *res; - PyObject *tmp = PyObject_CallFunctionObjArgs((PyObject *)&PyFloat_Type, obj, NULL); - if (tmp == NULL) { - return NULL; - } - res = PyObject_Repr(tmp); - Py_DECREF(tmp); - return res; - } -} - -static PyObject * -encoder_encode_string(PyEncoderObject *s, PyObject *obj) -{ - /* Return the JSON representation of a string */ - PyObject *encoded; - - if (s->fast_encode) { - return py_encode_basestring_ascii(NULL, obj); - } - encoded = PyObject_CallFunctionObjArgs(s->encoder, obj, NULL); - if (encoded != NULL && -#if PY_MAJOR_VERSION < 3 - !PyString_Check(encoded) && -#endif /* PY_MAJOR_VERSION < 3 */ - !PyUnicode_Check(encoded)) - { - PyErr_Format(PyExc_TypeError, - "encoder() must return a string, not %.80s", - Py_TYPE(encoded)->tp_name); - Py_DECREF(encoded); - return NULL; - } - return encoded; -} - -static int -_steal_accumulate(JSON_Accu *accu, PyObject *stolen) -{ - /* Append stolen and then decrement its reference count */ - int rval = JSON_Accu_Accumulate(accu, stolen); - Py_DECREF(stolen); - return rval; -} - -static int -encoder_listencode_obj(PyEncoderObject *s, JSON_Accu *rval, PyObject *obj, Py_ssize_t indent_level) -{ - /* Encode Python object obj to a JSON term, rval is a PyList */ - int rv = -1; - do { - if (obj == Py_None || obj == Py_True || obj == Py_False) { - PyObject *cstr = _encoded_const(obj); - if (cstr != NULL) - rv = _steal_accumulate(rval, cstr); - } - else if ((PyBytes_Check(obj) && s->encoding != NULL) || - PyUnicode_Check(obj)) - { - PyObject *encoded = encoder_encode_string(s, obj); - if (encoded != NULL) - rv = _steal_accumulate(rval, encoded); - } - else if (PyInt_Check(obj) || PyLong_Check(obj)) { - PyObject *encoded; - if (PyInt_CheckExact(obj) || PyLong_CheckExact(obj)) { - encoded = PyObject_Str(obj); - } - else { - /* See #118, do not trust custom str/repr */ - PyObject *tmp = PyObject_CallFunctionObjArgs((PyObject *)&PyLong_Type, obj, NULL); - if (tmp == NULL) { - encoded = NULL; - } - else { - encoded = PyObject_Str(tmp); - Py_DECREF(tmp); - } - } - if (encoded != NULL) { - encoded = maybe_quote_bigint(s, encoded, obj); - if (encoded == NULL) - break; - rv = _steal_accumulate(rval, encoded); - } - } - else if (PyFloat_Check(obj)) { - PyObject *encoded = encoder_encode_float(s, obj); - if (encoded != NULL) - rv = _steal_accumulate(rval, encoded); - } - else if (s->for_json && _has_for_json_hook(obj)) { - PyObject *newobj; - if (Py_EnterRecursiveCall(" while encoding a JSON object")) - return rv; - newobj = PyObject_CallMethod(obj, "for_json", NULL); - if (newobj != NULL) { - rv = encoder_listencode_obj(s, rval, newobj, indent_level); - Py_DECREF(newobj); - } - Py_LeaveRecursiveCall(); - } - else if (s->namedtuple_as_object && _is_namedtuple(obj)) { - PyObject *newobj; - if (Py_EnterRecursiveCall(" while encoding a JSON object")) - return rv; - newobj = PyObject_CallMethod(obj, "_asdict", NULL); - if (newobj != NULL) { - rv = encoder_listencode_dict(s, rval, newobj, indent_level); - Py_DECREF(newobj); - } - Py_LeaveRecursiveCall(); - } - else if (PyList_Check(obj) || (s->tuple_as_array && PyTuple_Check(obj))) { - if (Py_EnterRecursiveCall(" while encoding a JSON object")) - return rv; - rv = encoder_listencode_list(s, rval, obj, indent_level); - Py_LeaveRecursiveCall(); - } - else if (PyDict_Check(obj)) { - if (Py_EnterRecursiveCall(" while encoding a JSON object")) - return rv; - rv = encoder_listencode_dict(s, rval, obj, indent_level); - Py_LeaveRecursiveCall(); - } - else if (s->use_decimal && PyObject_TypeCheck(obj, (PyTypeObject *)s->Decimal)) { - PyObject *encoded = PyObject_Str(obj); - if (encoded != NULL) - rv = _steal_accumulate(rval, encoded); - } - else if (is_raw_json(obj)) - { - PyObject *encoded = PyObject_GetAttrString(obj, "encoded_json"); - if (encoded != NULL) - rv = _steal_accumulate(rval, encoded); - } - else { - PyObject *ident = NULL; - PyObject *newobj; - if (s->iterable_as_array) { - newobj = PyObject_GetIter(obj); - if (newobj == NULL) - PyErr_Clear(); - else { - rv = encoder_listencode_list(s, rval, newobj, indent_level); - Py_DECREF(newobj); - break; - } - } - if (s->markers != Py_None) { - int has_key; - ident = PyLong_FromVoidPtr(obj); - if (ident == NULL) - break; - has_key = PyDict_Contains(s->markers, ident); - if (has_key) { - if (has_key != -1) - PyErr_SetString(PyExc_ValueError, "Circular reference detected"); - Py_DECREF(ident); - break; - } - if (PyDict_SetItem(s->markers, ident, obj)) { - Py_DECREF(ident); - break; - } - } - if (Py_EnterRecursiveCall(" while encoding a JSON object")) - return rv; - newobj = PyObject_CallFunctionObjArgs(s->defaultfn, obj, NULL); - if (newobj == NULL) { - Py_XDECREF(ident); - Py_LeaveRecursiveCall(); - break; - } - rv = encoder_listencode_obj(s, rval, newobj, indent_level); - Py_LeaveRecursiveCall(); - Py_DECREF(newobj); - if (rv) { - Py_XDECREF(ident); - rv = -1; - } - else if (ident != NULL) { - if (PyDict_DelItem(s->markers, ident)) { - Py_XDECREF(ident); - rv = -1; - } - Py_XDECREF(ident); - } - } - } while (0); - return rv; -} - -static int -encoder_listencode_dict(PyEncoderObject *s, JSON_Accu *rval, PyObject *dct, Py_ssize_t indent_level) -{ - /* Encode Python dict dct a JSON term */ - static PyObject *open_dict = NULL; - static PyObject *close_dict = NULL; - static PyObject *empty_dict = NULL; - PyObject *kstr = NULL; - PyObject *ident = NULL; - PyObject *iter = NULL; - PyObject *item = NULL; - PyObject *items = NULL; - PyObject *encoded = NULL; - Py_ssize_t idx; - - if (open_dict == NULL || close_dict == NULL || empty_dict == NULL) { - open_dict = JSON_InternFromString("{"); - close_dict = JSON_InternFromString("}"); - empty_dict = JSON_InternFromString("{}"); - if (open_dict == NULL || close_dict == NULL || empty_dict == NULL) - return -1; - } - if (PyDict_Size(dct) == 0) - return JSON_Accu_Accumulate(rval, empty_dict); - - if (s->markers != Py_None) { - int has_key; - ident = PyLong_FromVoidPtr(dct); - if (ident == NULL) - goto bail; - has_key = PyDict_Contains(s->markers, ident); - if (has_key) { - if (has_key != -1) - PyErr_SetString(PyExc_ValueError, "Circular reference detected"); - goto bail; - } - if (PyDict_SetItem(s->markers, ident, dct)) { - goto bail; - } - } - - if (JSON_Accu_Accumulate(rval, open_dict)) - goto bail; - - if (s->indent != Py_None) { - /* TODO: DOES NOT RUN */ - indent_level += 1; - /* - newline_indent = '\n' + (_indent * _current_indent_level) - separator = _item_separator + newline_indent - buf += newline_indent - */ - } - - iter = encoder_dict_iteritems(s, dct); - if (iter == NULL) - goto bail; - - idx = 0; - while ((item = PyIter_Next(iter))) { - PyObject *encoded, *key, *value; - if (!PyTuple_Check(item) || Py_SIZE(item) != 2) { - PyErr_SetString(PyExc_ValueError, "items must return 2-tuples"); - goto bail; - } - key = PyTuple_GET_ITEM(item, 0); - if (key == NULL) - goto bail; - value = PyTuple_GET_ITEM(item, 1); - if (value == NULL) - goto bail; - - encoded = PyDict_GetItem(s->key_memo, key); - if (encoded != NULL) { - Py_INCREF(encoded); - } else { - kstr = encoder_stringify_key(s, key); - if (kstr == NULL) - goto bail; - else if (kstr == Py_None) { - /* skipkeys */ - Py_DECREF(item); - Py_DECREF(kstr); - continue; - } - } - if (idx) { - if (JSON_Accu_Accumulate(rval, s->item_separator)) - goto bail; - } - if (encoded == NULL) { - encoded = encoder_encode_string(s, kstr); - Py_CLEAR(kstr); - if (encoded == NULL) - goto bail; - if (PyDict_SetItem(s->key_memo, key, encoded)) - goto bail; - } - if (JSON_Accu_Accumulate(rval, encoded)) { - goto bail; - } - Py_CLEAR(encoded); - if (JSON_Accu_Accumulate(rval, s->key_separator)) - goto bail; - if (encoder_listencode_obj(s, rval, value, indent_level)) - goto bail; - Py_CLEAR(item); - idx += 1; - } - Py_CLEAR(iter); - if (PyErr_Occurred()) - goto bail; - if (ident != NULL) { - if (PyDict_DelItem(s->markers, ident)) - goto bail; - Py_CLEAR(ident); - } - if (s->indent != Py_None) { - /* TODO: DOES NOT RUN */ - indent_level -= 1; - /* - yield '\n' + (_indent * _current_indent_level) - */ - } - if (JSON_Accu_Accumulate(rval, close_dict)) - goto bail; - return 0; - -bail: - Py_XDECREF(encoded); - Py_XDECREF(items); - Py_XDECREF(item); - Py_XDECREF(iter); - Py_XDECREF(kstr); - Py_XDECREF(ident); - return -1; -} - - -static int -encoder_listencode_list(PyEncoderObject *s, JSON_Accu *rval, PyObject *seq, Py_ssize_t indent_level) -{ - /* Encode Python list seq to a JSON term */ - static PyObject *open_array = NULL; - static PyObject *close_array = NULL; - static PyObject *empty_array = NULL; - PyObject *ident = NULL; - PyObject *iter = NULL; - PyObject *obj = NULL; - int is_true; - int i = 0; - - if (open_array == NULL || close_array == NULL || empty_array == NULL) { - open_array = JSON_InternFromString("["); - close_array = JSON_InternFromString("]"); - empty_array = JSON_InternFromString("[]"); - if (open_array == NULL || close_array == NULL || empty_array == NULL) - return -1; - } - ident = NULL; - is_true = PyObject_IsTrue(seq); - if (is_true == -1) - return -1; - else if (is_true == 0) - return JSON_Accu_Accumulate(rval, empty_array); - - if (s->markers != Py_None) { - int has_key; - ident = PyLong_FromVoidPtr(seq); - if (ident == NULL) - goto bail; - has_key = PyDict_Contains(s->markers, ident); - if (has_key) { - if (has_key != -1) - PyErr_SetString(PyExc_ValueError, "Circular reference detected"); - goto bail; - } - if (PyDict_SetItem(s->markers, ident, seq)) { - goto bail; - } - } - - iter = PyObject_GetIter(seq); - if (iter == NULL) - goto bail; - - if (JSON_Accu_Accumulate(rval, open_array)) - goto bail; - if (s->indent != Py_None) { - /* TODO: DOES NOT RUN */ - indent_level += 1; - /* - newline_indent = '\n' + (_indent * _current_indent_level) - separator = _item_separator + newline_indent - buf += newline_indent - */ - } - while ((obj = PyIter_Next(iter))) { - if (i) { - if (JSON_Accu_Accumulate(rval, s->item_separator)) - goto bail; - } - if (encoder_listencode_obj(s, rval, obj, indent_level)) - goto bail; - i++; - Py_CLEAR(obj); - } - Py_CLEAR(iter); - if (PyErr_Occurred()) - goto bail; - if (ident != NULL) { - if (PyDict_DelItem(s->markers, ident)) - goto bail; - Py_CLEAR(ident); - } - if (s->indent != Py_None) { - /* TODO: DOES NOT RUN */ - indent_level -= 1; - /* - yield '\n' + (_indent * _current_indent_level) - */ - } - if (JSON_Accu_Accumulate(rval, close_array)) - goto bail; - return 0; - -bail: - Py_XDECREF(obj); - Py_XDECREF(iter); - Py_XDECREF(ident); - return -1; -} - -static void -encoder_dealloc(PyObject *self) -{ - /* bpo-31095: UnTrack is needed before calling any callbacks */ - PyObject_GC_UnTrack(self); - encoder_clear(self); - Py_TYPE(self)->tp_free(self); -} - -static int -encoder_traverse(PyObject *self, visitproc visit, void *arg) -{ - PyEncoderObject *s; - assert(PyEncoder_Check(self)); - s = (PyEncoderObject *)self; - Py_VISIT(s->markers); - Py_VISIT(s->defaultfn); - Py_VISIT(s->encoder); - Py_VISIT(s->encoding); - Py_VISIT(s->indent); - Py_VISIT(s->key_separator); - Py_VISIT(s->item_separator); - Py_VISIT(s->key_memo); - Py_VISIT(s->sort_keys); - Py_VISIT(s->item_sort_kw); - Py_VISIT(s->item_sort_key); - Py_VISIT(s->max_long_size); - Py_VISIT(s->min_long_size); - Py_VISIT(s->Decimal); - return 0; -} - -static int -encoder_clear(PyObject *self) -{ - /* Deallocate Encoder */ - PyEncoderObject *s; - assert(PyEncoder_Check(self)); - s = (PyEncoderObject *)self; - Py_CLEAR(s->markers); - Py_CLEAR(s->defaultfn); - Py_CLEAR(s->encoder); - Py_CLEAR(s->encoding); - Py_CLEAR(s->indent); - Py_CLEAR(s->key_separator); - Py_CLEAR(s->item_separator); - Py_CLEAR(s->key_memo); - Py_CLEAR(s->skipkeys_bool); - Py_CLEAR(s->sort_keys); - Py_CLEAR(s->item_sort_kw); - Py_CLEAR(s->item_sort_key); - Py_CLEAR(s->max_long_size); - Py_CLEAR(s->min_long_size); - Py_CLEAR(s->Decimal); - return 0; -} - -PyDoc_STRVAR(encoder_doc, "_iterencode(obj, _current_indent_level) -> iterable"); - -static -PyTypeObject PyEncoderType = { - PyVarObject_HEAD_INIT(NULL, 0) - "simplejson._speedups.Encoder", /* tp_name */ - sizeof(PyEncoderObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - encoder_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - encoder_call, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - encoder_doc, /* tp_doc */ - encoder_traverse, /* tp_traverse */ - encoder_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - encoder_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - encoder_new, /* tp_new */ - 0, /* tp_free */ -}; - -static PyMethodDef speedups_methods[] = { - {"encode_basestring_ascii", - (PyCFunction)py_encode_basestring_ascii, - METH_O, - pydoc_encode_basestring_ascii}, - {"scanstring", - (PyCFunction)py_scanstring, - METH_VARARGS, - pydoc_scanstring}, - {NULL, NULL, 0, NULL} -}; - -PyDoc_STRVAR(module_doc, -"simplejson speedups\n"); - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_speedups", /* m_name */ - module_doc, /* m_doc */ - -1, /* m_size */ - speedups_methods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear*/ - NULL, /* m_free */ -}; -#endif - -PyObject * -import_dependency(char *module_name, char *attr_name) -{ - PyObject *rval; - PyObject *module = PyImport_ImportModule(module_name); - if (module == NULL) - return NULL; - rval = PyObject_GetAttrString(module, attr_name); - Py_DECREF(module); - return rval; -} - -static int -init_constants(void) -{ - JSON_NaN = JSON_InternFromString("NaN"); - if (JSON_NaN == NULL) - return 0; - JSON_Infinity = JSON_InternFromString("Infinity"); - if (JSON_Infinity == NULL) - return 0; - JSON_NegInfinity = JSON_InternFromString("-Infinity"); - if (JSON_NegInfinity == NULL) - return 0; -#if PY_MAJOR_VERSION >= 3 - JSON_EmptyUnicode = PyUnicode_New(0, 127); -#else /* PY_MAJOR_VERSION >= 3 */ - JSON_EmptyStr = PyString_FromString(""); - if (JSON_EmptyStr == NULL) - return 0; - JSON_EmptyUnicode = PyUnicode_FromUnicode(NULL, 0); -#endif /* PY_MAJOR_VERSION >= 3 */ - if (JSON_EmptyUnicode == NULL) - return 0; - - return 1; -} - -static PyObject * -moduleinit(void) -{ - PyObject *m; - if (PyType_Ready(&PyScannerType) < 0) - return NULL; - if (PyType_Ready(&PyEncoderType) < 0) - return NULL; - if (!init_constants()) - return NULL; - -#if PY_MAJOR_VERSION >= 3 - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_speedups", speedups_methods, module_doc); -#endif - Py_INCREF((PyObject*)&PyScannerType); - PyModule_AddObject(m, "make_scanner", (PyObject*)&PyScannerType); - Py_INCREF((PyObject*)&PyEncoderType); - PyModule_AddObject(m, "make_encoder", (PyObject*)&PyEncoderType); - RawJSONType = import_dependency("simplejson.raw_json", "RawJSON"); - if (RawJSONType == NULL) - return NULL; - JSONDecodeError = import_dependency("simplejson.errors", "JSONDecodeError"); - if (JSONDecodeError == NULL) - return NULL; - return m; -} - -#if PY_MAJOR_VERSION >= 3 -PyMODINIT_FUNC -PyInit__speedups(void) -{ - return moduleinit(); -} -#else -void -init_speedups(void) -{ - moduleinit(); -} -#endif diff --git a/script.module.simplejson/lib/simplejson/decoder.py b/script.module.simplejson/lib/simplejson/decoder.py index 7f0b0568f..c99a976d8 100644 --- a/script.module.simplejson/lib/simplejson/decoder.py +++ b/script.module.simplejson/lib/simplejson/decoder.py @@ -46,9 +46,35 @@ def _floatconstants(): DEFAULT_ENCODING = "utf-8" +if hasattr(sys, 'get_int_max_str_digits'): + bounded_int = int +else: + def bounded_int(s, INT_MAX_STR_DIGITS=4300): + """Backport of the integer string length conversion limitation + + https://docs.python.org/3/library/stdtypes.html#int-max-str-digits + """ + if len(s) > INT_MAX_STR_DIGITS: + raise ValueError("Exceeds the limit (%s) for integer string conversion: value has %s digits" % (INT_MAX_STR_DIGITS, len(s))) + return int(s) + + +def scan_four_digit_hex(s, end, _m=re.compile(r'^[0-9a-fA-F]{4}$').match): + """Scan a four digit hex number from s[end:end + 4] + """ + msg = "Invalid \\uXXXX escape sequence" + esc = s[end:end + 4] + if not _m(esc): + raise JSONDecodeError(msg, s, end - 2) + try: + return int(esc, 16), end + 4 + except ValueError: + raise JSONDecodeError(msg, s, end - 2) + def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match, _join=u''.join, - _PY3=PY3, _maxunicode=sys.maxunicode): + _PY3=PY3, _maxunicode=sys.maxunicode, + _scan_four_digit_hex=scan_four_digit_hex): """Scan the string s for a JSON string. End is the index of the character in s after the quote that started the JSON string. Unescapes all valid JSON string escape sequences and raises ValueError @@ -67,6 +93,7 @@ def py_scanstring(s, end, encoding=None, strict=True, if chunk is None: raise JSONDecodeError( "Unterminated string starting at", s, begin) + prev_end = end end = chunk.end() content, terminator = chunk.groups() # Content is contains zero or more unescaped string characters @@ -81,7 +108,7 @@ def py_scanstring(s, end, encoding=None, strict=True, elif terminator != '\\': if strict: msg = "Invalid control character %r at" - raise JSONDecodeError(msg, s, end) + raise JSONDecodeError(msg, s, prev_end) else: _append(terminator) continue @@ -100,33 +127,18 @@ def py_scanstring(s, end, encoding=None, strict=True, end += 1 else: # Unicode escape sequence - msg = "Invalid \\uXXXX escape sequence" - esc = s[end + 1:end + 5] - escX = esc[1:2] - if len(esc) != 4 or escX == 'x' or escX == 'X': - raise JSONDecodeError(msg, s, end - 1) - try: - uni = int(esc, 16) - except ValueError: - raise JSONDecodeError(msg, s, end - 1) - end += 5 + uni, end = _scan_four_digit_hex(s, end + 1) # Check for surrogate pair on UCS-4 systems # Note that this will join high/low surrogate pairs # but will also pass unpaired surrogates through if (_maxunicode > 65535 and uni & 0xfc00 == 0xd800 and s[end:end + 2] == '\\u'): - esc2 = s[end + 2:end + 6] - escX = esc2[1:2] - if len(esc2) == 4 and not (escX == 'x' or escX == 'X'): - try: - uni2 = int(esc2, 16) - except ValueError: - raise JSONDecodeError(msg, s, end) - if uni2 & 0xfc00 == 0xdc00: - uni = 0x10000 + (((uni - 0xd800) << 10) | - (uni2 - 0xdc00)) - end += 6 + uni2, end2 = _scan_four_digit_hex(s, end + 2) + if uni2 & 0xfc00 == 0xdc00: + uni = 0x10000 + (((uni - 0xd800) << 10) | + (uni2 - 0xdc00)) + end = end2 char = unichr(uni) # Append the unescaped character _append(char) @@ -167,7 +179,7 @@ def JSONObject(state, encoding, strict, scan_once, object_hook, return pairs, end + 1 elif nextchar != '"': raise JSONDecodeError( - "Expecting property name enclosed in double quotes", + "Expecting property name enclosed in double quotes or '}'", s, end) end += 1 while True: @@ -294,14 +306,15 @@ class JSONDecoder(object): | null | None | +---------------+-------------------+ - It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as + When allow_nan=True, it also understands + ``NaN``, ``Infinity``, and ``-Infinity`` as their corresponding ``float`` values, which is outside the JSON spec. """ def __init__(self, encoding=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, - object_pairs_hook=None): + object_pairs_hook=None, allow_nan=False): """ *encoding* determines the encoding used to interpret any :class:`str` objects decoded by this instance (``'utf-8'`` by @@ -334,10 +347,13 @@ def __init__(self, encoding=None, object_hook=None, parse_float=None, ``int(num_str)``. This can be used to use another datatype or parser for JSON integers (e.g. :class:`float`). - *parse_constant*, if specified, will be called with one of the - following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This - can be used to raise an exception if invalid JSON numbers are - encountered. + *allow_nan*, if True (default false), will allow the parser to + accept the non-standard floats ``NaN``, ``Infinity``, and ``-Infinity``. + + *parse_constant*, if specified, will be + called with one of the following strings: ``'-Infinity'``, + ``'Infinity'``, ``'NaN'``. It is not recommended to use this feature, + as it is rare to parse non-compliant JSON containing these values. *strict* controls the parser's behavior when it encounters an invalid control character in a string. The default setting of @@ -351,8 +367,8 @@ def __init__(self, encoding=None, object_hook=None, parse_float=None, self.object_hook = object_hook self.object_pairs_hook = object_pairs_hook self.parse_float = parse_float or float - self.parse_int = parse_int or int - self.parse_constant = parse_constant or _CONSTANTS.__getitem__ + self.parse_int = parse_int or bounded_int + self.parse_constant = parse_constant or (allow_nan and _CONSTANTS.__getitem__ or None) self.strict = strict self.parse_object = JSONObject self.parse_array = JSONArray diff --git a/script.module.simplejson/lib/simplejson/encoder.py b/script.module.simplejson/lib/simplejson/encoder.py index 7ea172e7d..661ff361b 100644 --- a/script.module.simplejson/lib/simplejson/encoder.py +++ b/script.module.simplejson/lib/simplejson/encoder.py @@ -5,7 +5,7 @@ from operator import itemgetter # Do not import Decimal directly to avoid reload issues import decimal -from .compat import unichr, binary_type, text_type, string_types, integer_types, PY3 +from .compat import binary_type, text_type, string_types, integer_types, PY3 def _import_speedups(): try: from . import _speedups @@ -32,6 +32,7 @@ def _import_speedups(): for i in range(0x20): #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) +del i FLOAT_REPR = repr @@ -139,7 +140,7 @@ class JSONEncoder(object): key_separator = ': ' def __init__(self, skipkeys=False, ensure_ascii=True, - check_circular=True, allow_nan=True, sort_keys=False, + check_circular=True, allow_nan=False, sort_keys=False, indent=None, separators=None, encoding='utf-8', default=None, use_decimal=True, namedtuple_as_object=True, tuple_as_array=True, bigint_as_string=False, @@ -160,10 +161,11 @@ def __init__(self, skipkeys=False, ensure_ascii=True, prevent an infinite recursion (which would cause an OverflowError). Otherwise, no such check takes place. - If allow_nan is true, then NaN, Infinity, and -Infinity will be - encoded as such. This behavior is not JSON specification compliant, - but is consistent with most JavaScript based encoders and decoders. - Otherwise, it will be a ValueError to encode such floats. + If allow_nan is true (default: False), then out of range float + values (nan, inf, -inf) will be serialized to + their JavaScript equivalents (NaN, Infinity, -Infinity) + instead of raising a ValueError. See + ignore_nan for ECMA-262 compliant behavior. If sort_keys is true, then the output of dictionaries will be sorted by key; this is useful for regression tests to ensure @@ -293,7 +295,7 @@ def encode(self, o): # This doesn't pass the iterator directly to ''.join() because the # exceptions aren't as detailed. The list call should be roughly # equivalent to the PySequence_Fast that ''.join() would do. - chunks = self.iterencode(o, _one_shot=True) + chunks = self.iterencode(o) if not isinstance(chunks, (list, tuple)): chunks = list(chunks) if self.ensure_ascii: @@ -301,7 +303,7 @@ def encode(self, o): else: return u''.join(chunks) - def iterencode(self, o, _one_shot=False): + def iterencode(self, o): """Encode the given object and yield each string representation as available. @@ -355,8 +357,7 @@ def floatstr(o, allow_nan=self.allow_nan, ignore_nan=self.ignore_nan, key_memo = {} int_as_string_bitcount = ( 53 if self.bigint_as_string else self.int_as_string_bitcount) - if (_one_shot and c_make_encoder is not None - and self.indent is None): + if (c_make_encoder is not None and self.indent is None): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, @@ -369,7 +370,7 @@ def floatstr(o, allow_nan=self.allow_nan, ignore_nan=self.ignore_nan, _iterencode = _make_iterencode( markers, self.default, _encoder, self.indent, floatstr, self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, _one_shot, self.use_decimal, + self.skipkeys, self.use_decimal, self.namedtuple_as_object, self.tuple_as_array, int_as_string_bitcount, self.item_sort_key, self.encoding, self.for_json, @@ -397,14 +398,14 @@ class JSONEncoderForHTML(JSONEncoder): def encode(self, o): # Override JSONEncoder.encode because it has hacks for # performance that make things more complicated. - chunks = self.iterencode(o, True) + chunks = self.iterencode(o) if self.ensure_ascii: return ''.join(chunks) else: return u''.join(chunks) - def iterencode(self, o, _one_shot=False): - chunks = super(JSONEncoderForHTML, self).iterencode(o, _one_shot) + def iterencode(self, o): + chunks = super(JSONEncoderForHTML, self).iterencode(o) for chunk in chunks: chunk = chunk.replace('&', '\\u0026') chunk = chunk.replace('<', '\\u003c') @@ -418,7 +419,7 @@ def iterencode(self, o, _one_shot=False): def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, - _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, + _key_separator, _item_separator, _sort_keys, _skipkeys, _use_decimal, _namedtuple_as_object, _tuple_as_array, _int_as_string_bitcount, _item_sort_key, _encoding,_for_json, @@ -450,6 +451,15 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, not isinstance(_int_as_string_bitcount, integer_types))): raise TypeError("int_as_string_bitcount must be a positive integer") + def call_method(obj, method_name): + method = getattr(obj, method_name, None) + if callable(method): + try: + return (method(),) + except TypeError: + pass + return None + def _encode_int(value): skip_quoting = ( _int_as_string_bitcount is None @@ -512,15 +522,18 @@ def _iterencode_list(lst, _current_indent_level): yield buf + str(value) else: yield buf - for_json = _for_json and getattr(value, 'for_json', None) - if for_json and callable(for_json): - chunks = _iterencode(for_json(), _current_indent_level) + for_json = _for_json and call_method(value, 'for_json') + if for_json: + chunks = _iterencode(for_json[0], _current_indent_level) elif isinstance(value, list): chunks = _iterencode_list(value, _current_indent_level) else: - _asdict = _namedtuple_as_object and getattr(value, '_asdict', None) - if _asdict and callable(_asdict): - chunks = _iterencode_dict(_asdict(), + _asdict = _namedtuple_as_object and call_method(value, '_asdict') + if _asdict: + dct = _asdict[0] + if not isinstance(dct, dict): + raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,)) + chunks = _iterencode_dict(dct, _current_indent_level) elif _tuple_as_array and isinstance(value, tuple): chunks = _iterencode_list(value, _current_indent_level) @@ -633,15 +646,18 @@ def _iterencode_dict(dct, _current_indent_level): elif _use_decimal and isinstance(value, Decimal): yield str(value) else: - for_json = _for_json and getattr(value, 'for_json', None) - if for_json and callable(for_json): - chunks = _iterencode(for_json(), _current_indent_level) + for_json = _for_json and call_method(value, 'for_json') + if for_json: + chunks = _iterencode(for_json[0], _current_indent_level) elif isinstance(value, list): chunks = _iterencode_list(value, _current_indent_level) else: - _asdict = _namedtuple_as_object and getattr(value, '_asdict', None) - if _asdict and callable(_asdict): - chunks = _iterencode_dict(_asdict(), + _asdict = _namedtuple_as_object and call_method(value, '_asdict') + if _asdict: + dct = _asdict[0] + if not isinstance(dct, dict): + raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,)) + chunks = _iterencode_dict(dct, _current_indent_level) elif _tuple_as_array and isinstance(value, tuple): chunks = _iterencode_list(value, _current_indent_level) @@ -676,18 +692,20 @@ def _iterencode(o, _current_indent_level): elif isinstance(o, float): yield _floatstr(o) else: - for_json = _for_json and getattr(o, 'for_json', None) - if for_json and callable(for_json): - for chunk in _iterencode(for_json(), _current_indent_level): + for_json = _for_json and call_method(o, 'for_json') + if for_json: + for chunk in _iterencode(for_json[0], _current_indent_level): yield chunk elif isinstance(o, list): for chunk in _iterencode_list(o, _current_indent_level): yield chunk else: - _asdict = _namedtuple_as_object and getattr(o, '_asdict', None) - if _asdict and callable(_asdict): - for chunk in _iterencode_dict(_asdict(), - _current_indent_level): + _asdict = _namedtuple_as_object and call_method(o, '_asdict') + if _asdict: + dct = _asdict[0] + if not isinstance(dct, dict): + raise TypeError("_asdict() must return a dict, not %s" % (type(dct).__name__,)) + for chunk in _iterencode_dict(dct, _current_indent_level): yield chunk elif (_tuple_as_array and isinstance(o, tuple)): for chunk in _iterencode_list(o, _current_indent_level): diff --git a/script.module.simplejson/lib/simplejson/scanner.py b/script.module.simplejson/lib/simplejson/scanner.py index 85e385e14..34710d68c 100644 --- a/script.module.simplejson/lib/simplejson/scanner.py +++ b/script.module.simplejson/lib/simplejson/scanner.py @@ -60,11 +60,11 @@ def _scan_once(string, idx): else: res = parse_int(integer) return res, m.end() - elif nextchar == 'N' and string[idx:idx + 3] == 'NaN': + elif parse_constant and nextchar == 'N' and string[idx:idx + 3] == 'NaN': return parse_constant('NaN'), idx + 3 - elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity': + elif parse_constant and nextchar == 'I' and string[idx:idx + 8] == 'Infinity': return parse_constant('Infinity'), idx + 8 - elif nextchar == '-' and string[idx:idx + 9] == '-Infinity': + elif parse_constant and nextchar == '-' and string[idx:idx + 9] == '-Infinity': return parse_constant('-Infinity'), idx + 9 else: raise JSONDecodeError(errmsg, string, idx) diff --git a/script.module.simplejson/lib/simplejson/tests/__init__.py b/script.module.simplejson/lib/simplejson/tests/__init__.py deleted file mode 100644 index 25d3305b3..000000000 --- a/script.module.simplejson/lib/simplejson/tests/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import absolute_import -import unittest -import sys -import os - - -class NoExtensionTestSuite(unittest.TestSuite): - def run(self, result): - import simplejson - simplejson._toggle_speedups(False) - result = unittest.TestSuite.run(self, result) - simplejson._toggle_speedups(True) - return result - - -class TestMissingSpeedups(unittest.TestCase): - def runTest(self): - if hasattr(sys, 'pypy_translation_info'): - "PyPy doesn't need speedups! :)" - elif hasattr(self, 'skipTest'): - self.skipTest('_speedups.so is missing!') - - -def additional_tests(suite=None): - import simplejson - import simplejson.encoder - import simplejson.decoder - if suite is None: - suite = unittest.TestSuite() - try: - import doctest - except ImportError: - if sys.version_info < (2, 7): - # doctests in 2.6 depends on cStringIO - return suite - raise - for mod in (simplejson, simplejson.encoder, simplejson.decoder): - suite.addTest(doctest.DocTestSuite(mod)) - suite.addTest(doctest.DocFileSuite('../../index.rst')) - return suite - - -def all_tests_suite(): - def get_suite(): - suite_names = [ - 'simplejson.tests.%s' % (os.path.splitext(f)[0],) - for f in os.listdir(os.path.dirname(__file__)) - if f.startswith('test_') and f.endswith('.py') - ] - return additional_tests( - unittest.TestLoader().loadTestsFromNames(suite_names)) - suite = get_suite() - import simplejson - if simplejson._import_c_make_encoder() is None: - suite.addTest(TestMissingSpeedups()) - else: - suite = unittest.TestSuite([ - suite, - NoExtensionTestSuite([get_suite()]), - ]) - return suite - - -def main(): - runner = unittest.TextTestRunner(verbosity=1 + sys.argv.count('-v')) - suite = all_tests_suite() - raise SystemExit(not runner.run(suite).wasSuccessful()) - - -if __name__ == '__main__': - import os - import sys - sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) - main() diff --git a/script.module.simplejson/lib/simplejson/tests/test_bigint_as_string.py b/script.module.simplejson/lib/simplejson/tests/test_bigint_as_string.py deleted file mode 100644 index 2cf2cc296..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_bigint_as_string.py +++ /dev/null @@ -1,67 +0,0 @@ -from unittest import TestCase - -import simplejson as json - - -class TestBigintAsString(TestCase): - # Python 2.5, at least the one that ships on Mac OS X, calculates - # 2 ** 53 as 0! It manages to calculate 1 << 53 correctly. - values = [(200, 200), - ((1 << 53) - 1, 9007199254740991), - ((1 << 53), '9007199254740992'), - ((1 << 53) + 1, '9007199254740993'), - (-100, -100), - ((-1 << 53), '-9007199254740992'), - ((-1 << 53) - 1, '-9007199254740993'), - ((-1 << 53) + 1, -9007199254740991)] - - options = ( - {"bigint_as_string": True}, - {"int_as_string_bitcount": 53} - ) - - def test_ints(self): - for opts in self.options: - for val, expect in self.values: - self.assertEqual( - val, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, **opts))) - - def test_lists(self): - for opts in self.options: - for val, expect in self.values: - val = [val, val] - expect = [expect, expect] - self.assertEqual( - val, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, **opts))) - - def test_dicts(self): - for opts in self.options: - for val, expect in self.values: - val = {'k': val} - expect = {'k': expect} - self.assertEqual( - val, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, **opts))) - - def test_dict_keys(self): - for opts in self.options: - for val, _ in self.values: - expect = {str(val): 'value'} - val = {val: 'value'} - self.assertEqual( - expect, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, **opts))) diff --git a/script.module.simplejson/lib/simplejson/tests/test_bitsize_int_as_string.py b/script.module.simplejson/lib/simplejson/tests/test_bitsize_int_as_string.py deleted file mode 100644 index fd7d103a6..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_bitsize_int_as_string.py +++ /dev/null @@ -1,73 +0,0 @@ -from unittest import TestCase - -import simplejson as json - - -class TestBitSizeIntAsString(TestCase): - # Python 2.5, at least the one that ships on Mac OS X, calculates - # 2 ** 31 as 0! It manages to calculate 1 << 31 correctly. - values = [ - (200, 200), - ((1 << 31) - 1, (1 << 31) - 1), - ((1 << 31), str(1 << 31)), - ((1 << 31) + 1, str((1 << 31) + 1)), - (-100, -100), - ((-1 << 31), str(-1 << 31)), - ((-1 << 31) - 1, str((-1 << 31) - 1)), - ((-1 << 31) + 1, (-1 << 31) + 1), - ] - - def test_invalid_counts(self): - for n in ['foo', -1, 0, 1.0]: - self.assertRaises( - TypeError, - json.dumps, 0, int_as_string_bitcount=n) - - def test_ints_outside_range_fails(self): - self.assertNotEqual( - str(1 << 15), - json.loads(json.dumps(1 << 15, int_as_string_bitcount=16)), - ) - - def test_ints(self): - for val, expect in self.values: - self.assertEqual( - val, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, int_as_string_bitcount=31)), - ) - - def test_lists(self): - for val, expect in self.values: - val = [val, val] - expect = [expect, expect] - self.assertEqual( - val, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, int_as_string_bitcount=31))) - - def test_dicts(self): - for val, expect in self.values: - val = {'k': val} - expect = {'k': expect} - self.assertEqual( - val, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, int_as_string_bitcount=31))) - - def test_dict_keys(self): - for val, _ in self.values: - expect = {str(val): 'value'} - val = {val: 'value'} - self.assertEqual( - expect, - json.loads(json.dumps(val))) - self.assertEqual( - expect, - json.loads(json.dumps(val, int_as_string_bitcount=31))) diff --git a/script.module.simplejson/lib/simplejson/tests/test_check_circular.py b/script.module.simplejson/lib/simplejson/tests/test_check_circular.py deleted file mode 100644 index af6463d6d..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_check_circular.py +++ /dev/null @@ -1,30 +0,0 @@ -from unittest import TestCase -import simplejson as json - -def default_iterable(obj): - return list(obj) - -class TestCheckCircular(TestCase): - def test_circular_dict(self): - dct = {} - dct['a'] = dct - self.assertRaises(ValueError, json.dumps, dct) - - def test_circular_list(self): - lst = [] - lst.append(lst) - self.assertRaises(ValueError, json.dumps, lst) - - def test_circular_composite(self): - dct2 = {} - dct2['a'] = [] - dct2['a'].append(dct2) - self.assertRaises(ValueError, json.dumps, dct2) - - def test_circular_default(self): - json.dumps([set()], default=default_iterable) - self.assertRaises(TypeError, json.dumps, [set()]) - - def test_circular_off_default(self): - json.dumps([set()], default=default_iterable, check_circular=False) - self.assertRaises(TypeError, json.dumps, [set()], check_circular=False) diff --git a/script.module.simplejson/lib/simplejson/tests/test_decimal.py b/script.module.simplejson/lib/simplejson/tests/test_decimal.py deleted file mode 100644 index 2b0940b15..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_decimal.py +++ /dev/null @@ -1,71 +0,0 @@ -import decimal -from decimal import Decimal -from unittest import TestCase -from simplejson.compat import StringIO, reload_module - -import simplejson as json - -class TestDecimal(TestCase): - NUMS = "1.0", "10.00", "1.1", "1234567890.1234567890", "500" - def dumps(self, obj, **kw): - sio = StringIO() - json.dump(obj, sio, **kw) - res = json.dumps(obj, **kw) - self.assertEqual(res, sio.getvalue()) - return res - - def loads(self, s, **kw): - sio = StringIO(s) - res = json.loads(s, **kw) - self.assertEqual(res, json.load(sio, **kw)) - return res - - def test_decimal_encode(self): - for d in map(Decimal, self.NUMS): - self.assertEqual(self.dumps(d, use_decimal=True), str(d)) - - def test_decimal_decode(self): - for s in self.NUMS: - self.assertEqual(self.loads(s, parse_float=Decimal), Decimal(s)) - - def test_stringify_key(self): - for d in map(Decimal, self.NUMS): - v = {d: d} - self.assertEqual( - self.loads( - self.dumps(v, use_decimal=True), parse_float=Decimal), - {str(d): d}) - - def test_decimal_roundtrip(self): - for d in map(Decimal, self.NUMS): - # The type might not be the same (int and Decimal) but they - # should still compare equal. - for v in [d, [d], {'': d}]: - self.assertEqual( - self.loads( - self.dumps(v, use_decimal=True), parse_float=Decimal), - v) - - def test_decimal_defaults(self): - d = Decimal('1.1') - # use_decimal=True is the default - self.assertRaises(TypeError, json.dumps, d, use_decimal=False) - self.assertEqual('1.1', json.dumps(d)) - self.assertEqual('1.1', json.dumps(d, use_decimal=True)) - self.assertRaises(TypeError, json.dump, d, StringIO(), - use_decimal=False) - sio = StringIO() - json.dump(d, sio) - self.assertEqual('1.1', sio.getvalue()) - sio = StringIO() - json.dump(d, sio, use_decimal=True) - self.assertEqual('1.1', sio.getvalue()) - - def test_decimal_reload(self): - # Simulate a subinterpreter that reloads the Python modules but not - # the C code https://github.com/simplejson/simplejson/issues/34 - global Decimal - Decimal = reload_module(decimal).Decimal - import simplejson.encoder - simplejson.encoder.Decimal = Decimal - self.test_decimal_roundtrip() diff --git a/script.module.simplejson/lib/simplejson/tests/test_decode.py b/script.module.simplejson/lib/simplejson/tests/test_decode.py deleted file mode 100644 index 6960ee58b..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_decode.py +++ /dev/null @@ -1,119 +0,0 @@ -from __future__ import absolute_import -import decimal -from unittest import TestCase - -import simplejson as json -from simplejson.compat import StringIO, b, binary_type -from simplejson import OrderedDict - -class MisbehavingBytesSubtype(binary_type): - def decode(self, encoding=None): - return "bad decode" - def __str__(self): - return "bad __str__" - def __bytes__(self): - return b("bad __bytes__") - -class TestDecode(TestCase): - if not hasattr(TestCase, 'assertIs'): - def assertIs(self, a, b): - self.assertTrue(a is b, '%r is %r' % (a, b)) - - def test_decimal(self): - rval = json.loads('1.1', parse_float=decimal.Decimal) - self.assertTrue(isinstance(rval, decimal.Decimal)) - self.assertEqual(rval, decimal.Decimal('1.1')) - - def test_float(self): - rval = json.loads('1', parse_int=float) - self.assertTrue(isinstance(rval, float)) - self.assertEqual(rval, 1.0) - - def test_decoder_optimizations(self): - # Several optimizations were made that skip over calls to - # the whitespace regex, so this test is designed to try and - # exercise the uncommon cases. The array cases are already covered. - rval = json.loads('{ "key" : "value" , "k":"v" }') - self.assertEqual(rval, {"key":"value", "k":"v"}) - - def test_empty_objects(self): - s = '{}' - self.assertEqual(json.loads(s), eval(s)) - s = '[]' - self.assertEqual(json.loads(s), eval(s)) - s = '""' - self.assertEqual(json.loads(s), eval(s)) - - def test_object_pairs_hook(self): - s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' - p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), - ("qrt", 5), ("pad", 6), ("hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook=lambda x: x), p) - self.assertEqual(json.load(StringIO(s), - object_pairs_hook=lambda x: x), p) - od = json.loads(s, object_pairs_hook=OrderedDict) - self.assertEqual(od, OrderedDict(p)) - self.assertEqual(type(od), OrderedDict) - # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook=OrderedDict, - object_hook=lambda x: None), - OrderedDict(p)) - - def check_keys_reuse(self, source, loads): - rval = loads(source) - (a, b), (c, d) = sorted(rval[0]), sorted(rval[1]) - self.assertIs(a, c) - self.assertIs(b, d) - - def test_keys_reuse_str(self): - s = u'[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]'.encode('utf8') - self.check_keys_reuse(s, json.loads) - - def test_keys_reuse_unicode(self): - s = u'[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]' - self.check_keys_reuse(s, json.loads) - - def test_empty_strings(self): - self.assertEqual(json.loads('""'), "") - self.assertEqual(json.loads(u'""'), u"") - self.assertEqual(json.loads('[""]'), [""]) - self.assertEqual(json.loads(u'[""]'), [u""]) - - def test_raw_decode(self): - cls = json.decoder.JSONDecoder - self.assertEqual( - ({'a': {}}, 9), - cls().raw_decode("{\"a\": {}}")) - # http://code.google.com/p/simplejson/issues/detail?id=85 - self.assertEqual( - ({'a': {}}, 9), - cls(object_pairs_hook=dict).raw_decode("{\"a\": {}}")) - # https://github.com/simplejson/simplejson/pull/38 - self.assertEqual( - ({'a': {}}, 11), - cls().raw_decode(" \n{\"a\": {}}")) - - def test_bytes_decode(self): - cls = json.decoder.JSONDecoder - data = b('"\xe2\x82\xac"') - self.assertEqual(cls().decode(data), u'\u20ac') - self.assertEqual(cls(encoding='latin1').decode(data), u'\xe2\x82\xac') - self.assertEqual(cls(encoding=None).decode(data), u'\u20ac') - - data = MisbehavingBytesSubtype(b('"\xe2\x82\xac"')) - self.assertEqual(cls().decode(data), u'\u20ac') - self.assertEqual(cls(encoding='latin1').decode(data), u'\xe2\x82\xac') - self.assertEqual(cls(encoding=None).decode(data), u'\u20ac') - - def test_bounds_checking(self): - # https://github.com/simplejson/simplejson/issues/98 - j = json.decoder.JSONDecoder() - for i in [4, 5, 6, -1, -2, -3, -4, -5, -6]: - self.assertRaises(ValueError, j.scan_once, '1234', i) - self.assertRaises(ValueError, j.raw_decode, '1234', i) - x, y = sorted(['128931233', '472389423'], key=id) - diff = id(x) - id(y) - self.assertRaises(ValueError, j.scan_once, y, diff) - self.assertRaises(ValueError, j.raw_decode, y, i) diff --git a/script.module.simplejson/lib/simplejson/tests/test_default.py b/script.module.simplejson/lib/simplejson/tests/test_default.py deleted file mode 100644 index d1eacb8c4..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_default.py +++ /dev/null @@ -1,9 +0,0 @@ -from unittest import TestCase - -import simplejson as json - -class TestDefault(TestCase): - def test_default(self): - self.assertEqual( - json.dumps(type, default=repr), - json.dumps(repr(type))) diff --git a/script.module.simplejson/lib/simplejson/tests/test_dump.py b/script.module.simplejson/lib/simplejson/tests/test_dump.py deleted file mode 100644 index eff24c299..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_dump.py +++ /dev/null @@ -1,249 +0,0 @@ -from unittest import TestCase -from simplejson.compat import StringIO, long_type, b, binary_type, text_type, PY3 -import simplejson as json - -class MisbehavingTextSubtype(text_type): - def __str__(self): - return "FAIL!" - -class MisbehavingBytesSubtype(binary_type): - def decode(self, encoding=None): - return "bad decode" - def __str__(self): - return "bad __str__" - def __bytes__(self): - return b("bad __bytes__") - -def as_text_type(s): - if PY3 and isinstance(s, bytes): - return s.decode('ascii') - return s - -def decode_iso_8859_15(b): - return b.decode('iso-8859-15') - -class TestDump(TestCase): - def test_dump(self): - sio = StringIO() - json.dump({}, sio) - self.assertEqual(sio.getvalue(), '{}') - - def test_constants(self): - for c in [None, True, False]: - self.assertTrue(json.loads(json.dumps(c)) is c) - self.assertTrue(json.loads(json.dumps([c]))[0] is c) - self.assertTrue(json.loads(json.dumps({'a': c}))['a'] is c) - - def test_stringify_key(self): - items = [(b('bytes'), 'bytes'), - (1.0, '1.0'), - (10, '10'), - (True, 'true'), - (False, 'false'), - (None, 'null'), - (long_type(100), '100')] - for k, expect in items: - self.assertEqual( - json.loads(json.dumps({k: expect})), - {expect: expect}) - self.assertEqual( - json.loads(json.dumps({k: expect}, sort_keys=True)), - {expect: expect}) - self.assertRaises(TypeError, json.dumps, {json: 1}) - for v in [{}, {'other': 1}, {b('derp'): 1, 'herp': 2}]: - for sort_keys in [False, True]: - v0 = dict(v) - v0[json] = 1 - v1 = dict((as_text_type(key), val) for (key, val) in v.items()) - self.assertEqual( - json.loads(json.dumps(v0, skipkeys=True, sort_keys=sort_keys)), - v1) - self.assertEqual( - json.loads(json.dumps({'': v0}, skipkeys=True, sort_keys=sort_keys)), - {'': v1}) - self.assertEqual( - json.loads(json.dumps([v0], skipkeys=True, sort_keys=sort_keys)), - [v1]) - - def test_dumps(self): - self.assertEqual(json.dumps({}), '{}') - - def test_encode_truefalse(self): - self.assertEqual(json.dumps( - {True: False, False: True}, sort_keys=True), - '{"false": true, "true": false}') - self.assertEqual( - json.dumps( - {2: 3.0, - 4.0: long_type(5), - False: 1, - long_type(6): True, - "7": 0}, - sort_keys=True), - '{"2": 3.0, "4.0": 5, "6": true, "7": 0, "false": 1}') - - def test_ordered_dict(self): - # http://bugs.python.org/issue6105 - items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = json.dumps(json.OrderedDict(items)) - self.assertEqual( - s, - '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}') - - def test_indent_unknown_type_acceptance(self): - """ - A test against the regression mentioned at `github issue 29`_. - - The indent parameter should accept any type which pretends to be - an instance of int or long when it comes to being multiplied by - strings, even if it is not actually an int or long, for - backwards compatibility. - - .. _github issue 29: - http://github.com/simplejson/simplejson/issue/29 - """ - - class AwesomeInt(object): - """An awesome reimplementation of integers""" - - def __init__(self, *args, **kwargs): - if len(args) > 0: - # [construct from literals, objects, etc.] - # ... - - # Finally, if args[0] is an integer, store it - if isinstance(args[0], int): - self._int = args[0] - - # [various methods] - - def __mul__(self, other): - # [various ways to multiply AwesomeInt objects] - # ... finally, if the right-hand operand is not awesome enough, - # try to do a normal integer multiplication - if hasattr(self, '_int'): - return self._int * other - else: - raise NotImplementedError("To do non-awesome things with" - " this object, please construct it from an integer!") - - s = json.dumps([0, 1, 2], indent=AwesomeInt(3)) - self.assertEqual(s, '[\n 0,\n 1,\n 2\n]') - - def test_accumulator(self): - # the C API uses an accumulator that collects after 100,000 appends - lst = [0] * 100000 - self.assertEqual(json.loads(json.dumps(lst)), lst) - - def test_sort_keys(self): - # https://github.com/simplejson/simplejson/issues/106 - for num_keys in range(2, 32): - p = dict((str(x), x) for x in range(num_keys)) - sio = StringIO() - json.dump(p, sio, sort_keys=True) - self.assertEqual(sio.getvalue(), json.dumps(p, sort_keys=True)) - self.assertEqual(json.loads(sio.getvalue()), p) - - def test_misbehaving_text_subtype(self): - # https://github.com/simplejson/simplejson/issues/185 - text = "this is some text" - self.assertEqual( - json.dumps(MisbehavingTextSubtype(text)), - json.dumps(text) - ) - self.assertEqual( - json.dumps([MisbehavingTextSubtype(text)]), - json.dumps([text]) - ) - self.assertEqual( - json.dumps({MisbehavingTextSubtype(text): 42}), - json.dumps({text: 42}) - ) - - def test_misbehaving_bytes_subtype(self): - data = b("this is some data \xe2\x82\xac") - self.assertEqual( - json.dumps(MisbehavingBytesSubtype(data)), - json.dumps(data) - ) - self.assertEqual( - json.dumps([MisbehavingBytesSubtype(data)]), - json.dumps([data]) - ) - self.assertEqual( - json.dumps({MisbehavingBytesSubtype(data): 42}), - json.dumps({data: 42}) - ) - - def test_bytes_toplevel(self): - self.assertEqual(json.dumps(b('\xe2\x82\xac')), r'"\u20ac"') - self.assertRaises(UnicodeDecodeError, json.dumps, b('\xa4')) - self.assertEqual(json.dumps(b('\xa4'), encoding='iso-8859-1'), - r'"\u00a4"') - self.assertEqual(json.dumps(b('\xa4'), encoding='iso-8859-15'), - r'"\u20ac"') - if PY3: - self.assertRaises(TypeError, json.dumps, b('\xe2\x82\xac'), - encoding=None) - self.assertRaises(TypeError, json.dumps, b('\xa4'), - encoding=None) - self.assertEqual(json.dumps(b('\xa4'), encoding=None, - default=decode_iso_8859_15), - r'"\u20ac"') - else: - self.assertEqual(json.dumps(b('\xe2\x82\xac'), encoding=None), - r'"\u20ac"') - self.assertRaises(UnicodeDecodeError, json.dumps, b('\xa4'), - encoding=None) - self.assertRaises(UnicodeDecodeError, json.dumps, b('\xa4'), - encoding=None, default=decode_iso_8859_15) - - def test_bytes_nested(self): - self.assertEqual(json.dumps([b('\xe2\x82\xac')]), r'["\u20ac"]') - self.assertRaises(UnicodeDecodeError, json.dumps, [b('\xa4')]) - self.assertEqual(json.dumps([b('\xa4')], encoding='iso-8859-1'), - r'["\u00a4"]') - self.assertEqual(json.dumps([b('\xa4')], encoding='iso-8859-15'), - r'["\u20ac"]') - if PY3: - self.assertRaises(TypeError, json.dumps, [b('\xe2\x82\xac')], - encoding=None) - self.assertRaises(TypeError, json.dumps, [b('\xa4')], - encoding=None) - self.assertEqual(json.dumps([b('\xa4')], encoding=None, - default=decode_iso_8859_15), - r'["\u20ac"]') - else: - self.assertEqual(json.dumps([b('\xe2\x82\xac')], encoding=None), - r'["\u20ac"]') - self.assertRaises(UnicodeDecodeError, json.dumps, [b('\xa4')], - encoding=None) - self.assertRaises(UnicodeDecodeError, json.dumps, [b('\xa4')], - encoding=None, default=decode_iso_8859_15) - - def test_bytes_key(self): - self.assertEqual(json.dumps({b('\xe2\x82\xac'): 42}), r'{"\u20ac": 42}') - self.assertRaises(UnicodeDecodeError, json.dumps, {b('\xa4'): 42}) - self.assertEqual(json.dumps({b('\xa4'): 42}, encoding='iso-8859-1'), - r'{"\u00a4": 42}') - self.assertEqual(json.dumps({b('\xa4'): 42}, encoding='iso-8859-15'), - r'{"\u20ac": 42}') - if PY3: - self.assertRaises(TypeError, json.dumps, {b('\xe2\x82\xac'): 42}, - encoding=None) - self.assertRaises(TypeError, json.dumps, {b('\xa4'): 42}, - encoding=None) - self.assertRaises(TypeError, json.dumps, {b('\xa4'): 42}, - encoding=None, default=decode_iso_8859_15) - self.assertEqual(json.dumps({b('\xa4'): 42}, encoding=None, - skipkeys=True), - r'{}') - else: - self.assertEqual(json.dumps({b('\xe2\x82\xac'): 42}, encoding=None), - r'{"\u20ac": 42}') - self.assertRaises(UnicodeDecodeError, json.dumps, {b('\xa4'): 42}, - encoding=None) - self.assertRaises(UnicodeDecodeError, json.dumps, {b('\xa4'): 42}, - encoding=None, default=decode_iso_8859_15) - self.assertRaises(UnicodeDecodeError, json.dumps, {b('\xa4'): 42}, - encoding=None, skipkeys=True) diff --git a/script.module.simplejson/lib/simplejson/tests/test_encode_basestring_ascii.py b/script.module.simplejson/lib/simplejson/tests/test_encode_basestring_ascii.py deleted file mode 100644 index 49706bfd9..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_encode_basestring_ascii.py +++ /dev/null @@ -1,47 +0,0 @@ -from unittest import TestCase - -import simplejson.encoder -from simplejson.compat import b - -CASES = [ - (u'/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'), - (u'\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), - (u'controls', '"controls"'), - (u'\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'), - (u'{"object with 1 member":["array with 1 element"]}', '"{\\"object with 1 member\\":[\\"array with 1 element\\"]}"'), - (u' s p a c e d ', '" s p a c e d "'), - (u'\U0001d120', '"\\ud834\\udd20"'), - (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), - (b('\xce\xb1\xce\xa9'), '"\\u03b1\\u03a9"'), - (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), - (b('\xce\xb1\xce\xa9'), '"\\u03b1\\u03a9"'), - (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), - (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), - (u"`1~!@#$%^&*()_+-={':[,]}|;.?", '"`1~!@#$%^&*()_+-={\':[,]}|;.?"'), - (u'\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'), - (u'\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), -] - -class TestEncodeBaseStringAscii(TestCase): - def test_py_encode_basestring_ascii(self): - self._test_encode_basestring_ascii(simplejson.encoder.py_encode_basestring_ascii) - - def test_c_encode_basestring_ascii(self): - if not simplejson.encoder.c_encode_basestring_ascii: - return - self._test_encode_basestring_ascii(simplejson.encoder.c_encode_basestring_ascii) - - def _test_encode_basestring_ascii(self, encode_basestring_ascii): - fname = encode_basestring_ascii.__name__ - for input_string, expect in CASES: - result = encode_basestring_ascii(input_string) - #self.assertEqual(result, expect, - # '{0!r} != {1!r} for {2}({3!r})'.format( - # result, expect, fname, input_string)) - self.assertEqual(result, expect, - '%r != %r for %s(%r)' % (result, expect, fname, input_string)) - - def test_sorted_dict(self): - items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] - s = simplejson.dumps(dict(items), sort_keys=True) - self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}') diff --git a/script.module.simplejson/lib/simplejson/tests/test_encode_for_html.py b/script.module.simplejson/lib/simplejson/tests/test_encode_for_html.py deleted file mode 100644 index 3a840aa48..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_encode_for_html.py +++ /dev/null @@ -1,38 +0,0 @@ -import unittest - -import simplejson as json - -class TestEncodeForHTML(unittest.TestCase): - - def setUp(self): - self.decoder = json.JSONDecoder() - self.encoder = json.JSONEncoderForHTML() - self.non_ascii_encoder = json.JSONEncoderForHTML(ensure_ascii=False) - - def test_basic_encode(self): - self.assertEqual(r'"\u0026"', self.encoder.encode('&')) - self.assertEqual(r'"\u003c"', self.encoder.encode('<')) - self.assertEqual(r'"\u003e"', self.encoder.encode('>')) - self.assertEqual(r'"\u2028"', self.encoder.encode(u'\u2028')) - - def test_non_ascii_basic_encode(self): - self.assertEqual(r'"\u0026"', self.non_ascii_encoder.encode('&')) - self.assertEqual(r'"\u003c"', self.non_ascii_encoder.encode('<')) - self.assertEqual(r'"\u003e"', self.non_ascii_encoder.encode('>')) - self.assertEqual(r'"\u2028"', self.non_ascii_encoder.encode(u'\u2028')) - - def test_basic_roundtrip(self): - for char in '&<>': - self.assertEqual( - char, self.decoder.decode( - self.encoder.encode(char))) - - def test_prevent_script_breakout(self): - bad_string = '' - self.assertEqual( - r'"\u003c/script\u003e\u003cscript\u003e' - r'alert(\"gotcha\")\u003c/script\u003e"', - self.encoder.encode(bad_string)) - self.assertEqual( - bad_string, self.decoder.decode( - self.encoder.encode(bad_string))) diff --git a/script.module.simplejson/lib/simplejson/tests/test_errors.py b/script.module.simplejson/lib/simplejson/tests/test_errors.py deleted file mode 100644 index d57382545..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_errors.py +++ /dev/null @@ -1,68 +0,0 @@ -import sys, pickle -from unittest import TestCase - -import simplejson as json -from simplejson.compat import text_type, b - -class TestErrors(TestCase): - def test_string_keys_error(self): - data = [{'a': 'A', 'b': (2, 4), 'c': 3.0, ('d',): 'D tuple'}] - try: - json.dumps(data) - except TypeError: - err = sys.exc_info()[1] - else: - self.fail('Expected TypeError') - self.assertEqual(str(err), - 'keys must be str, int, float, bool or None, not tuple') - - def test_not_serializable(self): - try: - json.dumps(json) - except TypeError: - err = sys.exc_info()[1] - else: - self.fail('Expected TypeError') - self.assertEqual(str(err), - 'Object of type module is not JSON serializable') - - def test_decode_error(self): - err = None - try: - json.loads('{}\na\nb') - except json.JSONDecodeError: - err = sys.exc_info()[1] - else: - self.fail('Expected JSONDecodeError') - self.assertEqual(err.lineno, 2) - self.assertEqual(err.colno, 1) - self.assertEqual(err.endlineno, 3) - self.assertEqual(err.endcolno, 2) - - def test_scan_error(self): - err = None - for t in (text_type, b): - try: - json.loads(t('{"asdf": "')) - except json.JSONDecodeError: - err = sys.exc_info()[1] - else: - self.fail('Expected JSONDecodeError') - self.assertEqual(err.lineno, 1) - self.assertEqual(err.colno, 10) - - def test_error_is_pickable(self): - err = None - try: - json.loads('{}\na\nb') - except json.JSONDecodeError: - err = sys.exc_info()[1] - else: - self.fail('Expected JSONDecodeError') - s = pickle.dumps(err) - e = pickle.loads(s) - - self.assertEqual(err.msg, e.msg) - self.assertEqual(err.doc, e.doc) - self.assertEqual(err.pos, e.pos) - self.assertEqual(err.end, e.end) diff --git a/script.module.simplejson/lib/simplejson/tests/test_fail.py b/script.module.simplejson/lib/simplejson/tests/test_fail.py deleted file mode 100644 index 788f3a525..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_fail.py +++ /dev/null @@ -1,176 +0,0 @@ -import sys -from unittest import TestCase - -import simplejson as json - -# 2007-10-05 -JSONDOCS = [ - # http://json.org/JSON_checker/test/fail1.json - '"A JSON payload should be an object or array, not a string."', - # http://json.org/JSON_checker/test/fail2.json - '["Unclosed array"', - # http://json.org/JSON_checker/test/fail3.json - '{unquoted_key: "keys must be quoted"}', - # http://json.org/JSON_checker/test/fail4.json - '["extra comma",]', - # http://json.org/JSON_checker/test/fail5.json - '["double extra comma",,]', - # http://json.org/JSON_checker/test/fail6.json - '[ , "<-- missing value"]', - # http://json.org/JSON_checker/test/fail7.json - '["Comma after the close"],', - # http://json.org/JSON_checker/test/fail8.json - '["Extra close"]]', - # http://json.org/JSON_checker/test/fail9.json - '{"Extra comma": true,}', - # http://json.org/JSON_checker/test/fail10.json - '{"Extra value after close": true} "misplaced quoted value"', - # http://json.org/JSON_checker/test/fail11.json - '{"Illegal expression": 1 + 2}', - # http://json.org/JSON_checker/test/fail12.json - '{"Illegal invocation": alert()}', - # http://json.org/JSON_checker/test/fail13.json - '{"Numbers cannot have leading zeroes": 013}', - # http://json.org/JSON_checker/test/fail14.json - '{"Numbers cannot be hex": 0x14}', - # http://json.org/JSON_checker/test/fail15.json - '["Illegal backslash escape: \\x15"]', - # http://json.org/JSON_checker/test/fail16.json - '[\\naked]', - # http://json.org/JSON_checker/test/fail17.json - '["Illegal backslash escape: \\017"]', - # http://json.org/JSON_checker/test/fail18.json - '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]', - # http://json.org/JSON_checker/test/fail19.json - '{"Missing colon" null}', - # http://json.org/JSON_checker/test/fail20.json - '{"Double colon":: null}', - # http://json.org/JSON_checker/test/fail21.json - '{"Comma instead of colon", null}', - # http://json.org/JSON_checker/test/fail22.json - '["Colon instead of comma": false]', - # http://json.org/JSON_checker/test/fail23.json - '["Bad value", truth]', - # http://json.org/JSON_checker/test/fail24.json - "['single quote']", - # http://json.org/JSON_checker/test/fail25.json - '["\ttab\tcharacter\tin\tstring\t"]', - # http://json.org/JSON_checker/test/fail26.json - '["tab\\ character\\ in\\ string\\ "]', - # http://json.org/JSON_checker/test/fail27.json - '["line\nbreak"]', - # http://json.org/JSON_checker/test/fail28.json - '["line\\\nbreak"]', - # http://json.org/JSON_checker/test/fail29.json - '[0e]', - # http://json.org/JSON_checker/test/fail30.json - '[0e+]', - # http://json.org/JSON_checker/test/fail31.json - '[0e+-1]', - # http://json.org/JSON_checker/test/fail32.json - '{"Comma instead if closing brace": true,', - # http://json.org/JSON_checker/test/fail33.json - '["mismatch"}', - # http://code.google.com/p/simplejson/issues/detail?id=3 - u'["A\u001FZ control characters in string"]', - # misc based on coverage - '{', - '{]', - '{"foo": "bar"]', - '{"foo": "bar"', - 'nul', - 'nulx', - '-', - '-x', - '-e', - '-e0', - '-Infinite', - '-Inf', - 'Infinit', - 'Infinite', - 'NaM', - 'NuN', - 'falsy', - 'fal', - 'trug', - 'tru', - '1e', - '1ex', - '1e-', - '1e-x', -] - -SKIPS = { - 1: "why not have a string payload?", - 18: "spec doesn't specify any nesting limitations", -} - -class TestFail(TestCase): - def test_failures(self): - for idx, doc in enumerate(JSONDOCS): - idx = idx + 1 - if idx in SKIPS: - json.loads(doc) - continue - try: - json.loads(doc) - except json.JSONDecodeError: - pass - else: - self.fail("Expected failure for fail%d.json: %r" % (idx, doc)) - - def test_array_decoder_issue46(self): - # http://code.google.com/p/simplejson/issues/detail?id=46 - for doc in [u'[,]', '[,]']: - try: - json.loads(doc) - except json.JSONDecodeError: - e = sys.exc_info()[1] - self.assertEqual(e.pos, 1) - self.assertEqual(e.lineno, 1) - self.assertEqual(e.colno, 2) - except Exception: - e = sys.exc_info()[1] - self.fail("Unexpected exception raised %r %s" % (e, e)) - else: - self.fail("Unexpected success parsing '[,]'") - - def test_truncated_input(self): - test_cases = [ - ('', 'Expecting value', 0), - ('[', "Expecting value or ']'", 1), - ('[42', "Expecting ',' delimiter", 3), - ('[42,', 'Expecting value', 4), - ('["', 'Unterminated string starting at', 1), - ('["spam', 'Unterminated string starting at', 1), - ('["spam"', "Expecting ',' delimiter", 7), - ('["spam",', 'Expecting value', 8), - ('{', 'Expecting property name enclosed in double quotes', 1), - ('{"', 'Unterminated string starting at', 1), - ('{"spam', 'Unterminated string starting at', 1), - ('{"spam"', "Expecting ':' delimiter", 7), - ('{"spam":', 'Expecting value', 8), - ('{"spam":42', "Expecting ',' delimiter", 10), - ('{"spam":42,', 'Expecting property name enclosed in double quotes', - 11), - ('"', 'Unterminated string starting at', 0), - ('"spam', 'Unterminated string starting at', 0), - ('[,', "Expecting value", 1), - ] - for data, msg, idx in test_cases: - try: - json.loads(data) - except json.JSONDecodeError: - e = sys.exc_info()[1] - self.assertEqual( - e.msg[:len(msg)], - msg, - "%r doesn't start with %r for %r" % (e.msg, msg, data)) - self.assertEqual( - e.pos, idx, - "pos %r != %r for %r" % (e.pos, idx, data)) - except Exception: - e = sys.exc_info()[1] - self.fail("Unexpected exception raised %r %s" % (e, e)) - else: - self.fail("Unexpected success parsing '%r'" % (data,)) diff --git a/script.module.simplejson/lib/simplejson/tests/test_float.py b/script.module.simplejson/lib/simplejson/tests/test_float.py deleted file mode 100644 index e382ec21a..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_float.py +++ /dev/null @@ -1,35 +0,0 @@ -import math -from unittest import TestCase -from simplejson.compat import long_type, text_type -import simplejson as json -from simplejson.decoder import NaN, PosInf, NegInf - -class TestFloat(TestCase): - def test_degenerates_allow(self): - for inf in (PosInf, NegInf): - self.assertEqual(json.loads(json.dumps(inf)), inf) - # Python 2.5 doesn't have math.isnan - nan = json.loads(json.dumps(NaN)) - self.assertTrue((0 + nan) != nan) - - def test_degenerates_ignore(self): - for f in (PosInf, NegInf, NaN): - self.assertEqual(json.loads(json.dumps(f, ignore_nan=True)), None) - - def test_degenerates_deny(self): - for f in (PosInf, NegInf, NaN): - self.assertRaises(ValueError, json.dumps, f, allow_nan=False) - - def test_floats(self): - for num in [1617161771.7650001, math.pi, math.pi**100, - math.pi**-100, 3.1]: - self.assertEqual(float(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) - self.assertEqual(json.loads(text_type(json.dumps(num))), num) - - def test_ints(self): - for num in [1, long_type(1), 1<<32, 1<<64]: - self.assertEqual(json.dumps(num), str(num)) - self.assertEqual(int(json.dumps(num)), num) - self.assertEqual(json.loads(json.dumps(num)), num) - self.assertEqual(json.loads(text_type(json.dumps(num))), num) diff --git a/script.module.simplejson/lib/simplejson/tests/test_for_json.py b/script.module.simplejson/lib/simplejson/tests/test_for_json.py deleted file mode 100644 index b791b883b..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_for_json.py +++ /dev/null @@ -1,97 +0,0 @@ -import unittest -import simplejson as json - - -class ForJson(object): - def for_json(self): - return {'for_json': 1} - - -class NestedForJson(object): - def for_json(self): - return {'nested': ForJson()} - - -class ForJsonList(object): - def for_json(self): - return ['list'] - - -class DictForJson(dict): - def for_json(self): - return {'alpha': 1} - - -class ListForJson(list): - def for_json(self): - return ['list'] - - -class TestForJson(unittest.TestCase): - def assertRoundTrip(self, obj, other, for_json=True): - if for_json is None: - # None will use the default - s = json.dumps(obj) - else: - s = json.dumps(obj, for_json=for_json) - self.assertEqual( - json.loads(s), - other) - - def test_for_json_encodes_stand_alone_object(self): - self.assertRoundTrip( - ForJson(), - ForJson().for_json()) - - def test_for_json_encodes_object_nested_in_dict(self): - self.assertRoundTrip( - {'hooray': ForJson()}, - {'hooray': ForJson().for_json()}) - - def test_for_json_encodes_object_nested_in_list_within_dict(self): - self.assertRoundTrip( - {'list': [0, ForJson(), 2, 3]}, - {'list': [0, ForJson().for_json(), 2, 3]}) - - def test_for_json_encodes_object_nested_within_object(self): - self.assertRoundTrip( - NestedForJson(), - {'nested': {'for_json': 1}}) - - def test_for_json_encodes_list(self): - self.assertRoundTrip( - ForJsonList(), - ForJsonList().for_json()) - - def test_for_json_encodes_list_within_object(self): - self.assertRoundTrip( - {'nested': ForJsonList()}, - {'nested': ForJsonList().for_json()}) - - def test_for_json_encodes_dict_subclass(self): - self.assertRoundTrip( - DictForJson(a=1), - DictForJson(a=1).for_json()) - - def test_for_json_encodes_list_subclass(self): - self.assertRoundTrip( - ListForJson(['l']), - ListForJson(['l']).for_json()) - - def test_for_json_ignored_if_not_true_with_dict_subclass(self): - for for_json in (None, False): - self.assertRoundTrip( - DictForJson(a=1), - {'a': 1}, - for_json=for_json) - - def test_for_json_ignored_if_not_true_with_list_subclass(self): - for for_json in (None, False): - self.assertRoundTrip( - ListForJson(['l']), - ['l'], - for_json=for_json) - - def test_raises_typeerror_if_for_json_not_true_with_object(self): - self.assertRaises(TypeError, json.dumps, ForJson()) - self.assertRaises(TypeError, json.dumps, ForJson(), for_json=False) diff --git a/script.module.simplejson/lib/simplejson/tests/test_indent.py b/script.module.simplejson/lib/simplejson/tests/test_indent.py deleted file mode 100644 index cea25a575..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_indent.py +++ /dev/null @@ -1,86 +0,0 @@ -from unittest import TestCase -import textwrap - -import simplejson as json -from simplejson.compat import StringIO - -class TestIndent(TestCase): - def test_indent(self): - h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', - 'i-vhbjkhnth', - {'nifty': 87}, {'field': 'yes', 'morefield': False} ] - - expect = textwrap.dedent("""\ - [ - \t[ - \t\t"blorpie" - \t], - \t[ - \t\t"whoops" - \t], - \t[], - \t"d-shtaeou", - \t"d-nthiouh", - \t"i-vhbjkhnth", - \t{ - \t\t"nifty": 87 - \t}, - \t{ - \t\t"field": "yes", - \t\t"morefield": false - \t} - ]""") - - - d1 = json.dumps(h) - d2 = json.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) - d3 = json.dumps(h, indent=' ', sort_keys=True, separators=(',', ': ')) - d4 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) - - h1 = json.loads(d1) - h2 = json.loads(d2) - h3 = json.loads(d3) - h4 = json.loads(d4) - - self.assertEqual(h1, h) - self.assertEqual(h2, h) - self.assertEqual(h3, h) - self.assertEqual(h4, h) - self.assertEqual(d3, expect.replace('\t', ' ')) - self.assertEqual(d4, expect.replace('\t', ' ')) - # NOTE: Python 2.4 textwrap.dedent converts tabs to spaces, - # so the following is expected to fail. Python 2.4 is not a - # supported platform in simplejson 2.1.0+. - self.assertEqual(d2, expect) - - def test_indent0(self): - h = {3: 1} - def check(indent, expected): - d1 = json.dumps(h, indent=indent) - self.assertEqual(d1, expected) - - sio = StringIO() - json.dump(h, sio, indent=indent) - self.assertEqual(sio.getvalue(), expected) - - # indent=0 should emit newlines - check(0, '{\n"3": 1\n}') - # indent=None is more compact - check(None, '{"3": 1}') - - def test_separators(self): - lst = [1,2,3,4] - expect = '[\n1,\n2,\n3,\n4\n]' - expect_spaces = '[\n1, \n2, \n3, \n4\n]' - # Ensure that separators still works - self.assertEqual( - expect_spaces, - json.dumps(lst, indent=0, separators=(', ', ': '))) - # Force the new defaults - self.assertEqual( - expect, - json.dumps(lst, indent=0, separators=(',', ': '))) - # Added in 2.1.4 - self.assertEqual( - expect, - json.dumps(lst, indent=0)) diff --git a/script.module.simplejson/lib/simplejson/tests/test_item_sort_key.py b/script.module.simplejson/lib/simplejson/tests/test_item_sort_key.py deleted file mode 100644 index 98971b86a..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_item_sort_key.py +++ /dev/null @@ -1,27 +0,0 @@ -from unittest import TestCase - -import simplejson as json -from operator import itemgetter - -class TestItemSortKey(TestCase): - def test_simple_first(self): - a = {'a': 1, 'c': 5, 'jack': 'jill', 'pick': 'axe', 'array': [1, 5, 6, 9], 'tuple': (83, 12, 3), 'crate': 'dog', 'zeak': 'oh'} - self.assertEqual( - '{"a": 1, "c": 5, "crate": "dog", "jack": "jill", "pick": "axe", "zeak": "oh", "array": [1, 5, 6, 9], "tuple": [83, 12, 3]}', - json.dumps(a, item_sort_key=json.simple_first)) - - def test_case(self): - a = {'a': 1, 'c': 5, 'Jack': 'jill', 'pick': 'axe', 'Array': [1, 5, 6, 9], 'tuple': (83, 12, 3), 'crate': 'dog', 'zeak': 'oh'} - self.assertEqual( - '{"Array": [1, 5, 6, 9], "Jack": "jill", "a": 1, "c": 5, "crate": "dog", "pick": "axe", "tuple": [83, 12, 3], "zeak": "oh"}', - json.dumps(a, item_sort_key=itemgetter(0))) - self.assertEqual( - '{"a": 1, "Array": [1, 5, 6, 9], "c": 5, "crate": "dog", "Jack": "jill", "pick": "axe", "tuple": [83, 12, 3], "zeak": "oh"}', - json.dumps(a, item_sort_key=lambda kv: kv[0].lower())) - - def test_item_sort_key_value(self): - # https://github.com/simplejson/simplejson/issues/173 - a = {'a': 1, 'b': 0} - self.assertEqual( - '{"b": 0, "a": 1}', - json.dumps(a, item_sort_key=lambda kv: kv[1])) diff --git a/script.module.simplejson/lib/simplejson/tests/test_iterable.py b/script.module.simplejson/lib/simplejson/tests/test_iterable.py deleted file mode 100644 index 35d3e7591..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_iterable.py +++ /dev/null @@ -1,31 +0,0 @@ -import unittest -from simplejson.compat import StringIO - -import simplejson as json - -def iter_dumps(obj, **kw): - return ''.join(json.JSONEncoder(**kw).iterencode(obj)) - -def sio_dump(obj, **kw): - sio = StringIO() - json.dumps(obj, **kw) - return sio.getvalue() - -class TestIterable(unittest.TestCase): - def test_iterable(self): - for l in ([], [1], [1, 2], [1, 2, 3]): - for opts in [{}, {'indent': 2}]: - for dumps in (json.dumps, iter_dumps, sio_dump): - expect = dumps(l, **opts) - default_expect = dumps(sum(l), **opts) - # Default is False - self.assertRaises(TypeError, dumps, iter(l), **opts) - self.assertRaises(TypeError, dumps, iter(l), iterable_as_array=False, **opts) - self.assertEqual(expect, dumps(iter(l), iterable_as_array=True, **opts)) - # Ensure that the "default" gets called - self.assertEqual(default_expect, dumps(iter(l), default=sum, **opts)) - self.assertEqual(default_expect, dumps(iter(l), iterable_as_array=False, default=sum, **opts)) - # Ensure that the "default" does not get called - self.assertEqual( - expect, - dumps(iter(l), iterable_as_array=True, default=sum, **opts)) diff --git a/script.module.simplejson/lib/simplejson/tests/test_namedtuple.py b/script.module.simplejson/lib/simplejson/tests/test_namedtuple.py deleted file mode 100644 index 438789405..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_namedtuple.py +++ /dev/null @@ -1,122 +0,0 @@ -from __future__ import absolute_import -import unittest -import simplejson as json -from simplejson.compat import StringIO - -try: - from collections import namedtuple -except ImportError: - class Value(tuple): - def __new__(cls, *args): - return tuple.__new__(cls, args) - - def _asdict(self): - return {'value': self[0]} - class Point(tuple): - def __new__(cls, *args): - return tuple.__new__(cls, args) - - def _asdict(self): - return {'x': self[0], 'y': self[1]} -else: - Value = namedtuple('Value', ['value']) - Point = namedtuple('Point', ['x', 'y']) - -class DuckValue(object): - def __init__(self, *args): - self.value = Value(*args) - - def _asdict(self): - return self.value._asdict() - -class DuckPoint(object): - def __init__(self, *args): - self.point = Point(*args) - - def _asdict(self): - return self.point._asdict() - -class DeadDuck(object): - _asdict = None - -class DeadDict(dict): - _asdict = None - -CONSTRUCTORS = [ - lambda v: v, - lambda v: [v], - lambda v: [{'key': v}], -] - -class TestNamedTuple(unittest.TestCase): - def test_namedtuple_dumps(self): - for v in [Value(1), Point(1, 2), DuckValue(1), DuckPoint(1, 2)]: - d = v._asdict() - self.assertEqual(d, json.loads(json.dumps(v))) - self.assertEqual( - d, - json.loads(json.dumps(v, namedtuple_as_object=True))) - self.assertEqual(d, json.loads(json.dumps(v, tuple_as_array=False))) - self.assertEqual( - d, - json.loads(json.dumps(v, namedtuple_as_object=True, - tuple_as_array=False))) - - def test_namedtuple_dumps_false(self): - for v in [Value(1), Point(1, 2)]: - l = list(v) - self.assertEqual( - l, - json.loads(json.dumps(v, namedtuple_as_object=False))) - self.assertRaises(TypeError, json.dumps, v, - tuple_as_array=False, namedtuple_as_object=False) - - def test_namedtuple_dump(self): - for v in [Value(1), Point(1, 2), DuckValue(1), DuckPoint(1, 2)]: - d = v._asdict() - sio = StringIO() - json.dump(v, sio) - self.assertEqual(d, json.loads(sio.getvalue())) - sio = StringIO() - json.dump(v, sio, namedtuple_as_object=True) - self.assertEqual( - d, - json.loads(sio.getvalue())) - sio = StringIO() - json.dump(v, sio, tuple_as_array=False) - self.assertEqual(d, json.loads(sio.getvalue())) - sio = StringIO() - json.dump(v, sio, namedtuple_as_object=True, - tuple_as_array=False) - self.assertEqual( - d, - json.loads(sio.getvalue())) - - def test_namedtuple_dump_false(self): - for v in [Value(1), Point(1, 2)]: - l = list(v) - sio = StringIO() - json.dump(v, sio, namedtuple_as_object=False) - self.assertEqual( - l, - json.loads(sio.getvalue())) - self.assertRaises(TypeError, json.dump, v, StringIO(), - tuple_as_array=False, namedtuple_as_object=False) - - def test_asdict_not_callable_dump(self): - for f in CONSTRUCTORS: - self.assertRaises(TypeError, - json.dump, f(DeadDuck()), StringIO(), namedtuple_as_object=True) - sio = StringIO() - json.dump(f(DeadDict()), sio, namedtuple_as_object=True) - self.assertEqual( - json.dumps(f({})), - sio.getvalue()) - - def test_asdict_not_callable_dumps(self): - for f in CONSTRUCTORS: - self.assertRaises(TypeError, - json.dumps, f(DeadDuck()), namedtuple_as_object=True) - self.assertEqual( - json.dumps(f({})), - json.dumps(f(DeadDict()), namedtuple_as_object=True)) diff --git a/script.module.simplejson/lib/simplejson/tests/test_pass1.py b/script.module.simplejson/lib/simplejson/tests/test_pass1.py deleted file mode 100644 index f0b5b10e7..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_pass1.py +++ /dev/null @@ -1,71 +0,0 @@ -from unittest import TestCase - -import simplejson as json - -# from http://json.org/JSON_checker/test/pass1.json -JSON = r''' -[ - "JSON Test Pattern pass1", - {"object with 1 member":["array with 1 element"]}, - {}, - [], - -42, - true, - false, - null, - { - "integer": 1234567890, - "real": -9876.543210, - "e": 0.123456789e-12, - "E": 1.234567890E+34, - "": 23456789012E66, - "zero": 0, - "one": 1, - "space": " ", - "quote": "\"", - "backslash": "\\", - "controls": "\b\f\n\r\t", - "slash": "/ & \/", - "alpha": "abcdefghijklmnopqrstuvwyz", - "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", - "digit": "0123456789", - "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", - "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", - "true": true, - "false": false, - "null": null, - "array":[ ], - "object":{ }, - "address": "50 St. James Street", - "url": "http://www.JSON.org/", - "comment": "// /* */": " ", - " s p a c e d " :[1,2 , 3 - -, - -4 , 5 , 6 ,7 ],"compact": [1,2,3,4,5,6,7], - "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", - "quotes": "" \u0022 %22 0x22 034 "", - "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" -: "A key can be any string" - }, - 0.5 ,98.6 -, -99.44 -, - -1066, -1e1, -0.1e1, -1e-1, -1e00,2e+00,2e-00 -,"rosebud"] -''' - -class TestPass1(TestCase): - def test_parse(self): - # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) diff --git a/script.module.simplejson/lib/simplejson/tests/test_pass2.py b/script.module.simplejson/lib/simplejson/tests/test_pass2.py deleted file mode 100644 index 5d812b3bb..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_pass2.py +++ /dev/null @@ -1,14 +0,0 @@ -from unittest import TestCase -import simplejson as json - -# from http://json.org/JSON_checker/test/pass2.json -JSON = r''' -[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -''' - -class TestPass2(TestCase): - def test_parse(self): - # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) diff --git a/script.module.simplejson/lib/simplejson/tests/test_pass3.py b/script.module.simplejson/lib/simplejson/tests/test_pass3.py deleted file mode 100644 index 821d60b22..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_pass3.py +++ /dev/null @@ -1,20 +0,0 @@ -from unittest import TestCase - -import simplejson as json - -# from http://json.org/JSON_checker/test/pass3.json -JSON = r''' -{ - "JSON Test Pattern pass3": { - "The outermost value": "must be an object or array.", - "In this test": "It is an object." - } -} -''' - -class TestPass3(TestCase): - def test_parse(self): - # test in/out equivalence and parsing - res = json.loads(JSON) - out = json.dumps(res) - self.assertEqual(res, json.loads(out)) diff --git a/script.module.simplejson/lib/simplejson/tests/test_raw_json.py b/script.module.simplejson/lib/simplejson/tests/test_raw_json.py deleted file mode 100644 index 1dfcc2c5f..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_raw_json.py +++ /dev/null @@ -1,47 +0,0 @@ -import unittest -import simplejson as json - -dct1 = { - 'key1': 'value1' -} - -dct2 = { - 'key2': 'value2', - 'd1': dct1 -} - -dct3 = { - 'key2': 'value2', - 'd1': json.dumps(dct1) -} - -dct4 = { - 'key2': 'value2', - 'd1': json.RawJSON(json.dumps(dct1)) -} - - -class TestRawJson(unittest.TestCase): - - def test_normal_str(self): - self.assertNotEqual(json.dumps(dct2), json.dumps(dct3)) - - def test_raw_json_str(self): - self.assertEqual(json.dumps(dct2), json.dumps(dct4)) - self.assertEqual(dct2, json.loads(json.dumps(dct4))) - - def test_list(self): - self.assertEqual( - json.dumps([dct2]), - json.dumps([json.RawJSON(json.dumps(dct2))])) - self.assertEqual( - [dct2], - json.loads(json.dumps([json.RawJSON(json.dumps(dct2))]))) - - def test_direct(self): - self.assertEqual( - json.dumps(dct2), - json.dumps(json.RawJSON(json.dumps(dct2)))) - self.assertEqual( - dct2, - json.loads(json.dumps(json.RawJSON(json.dumps(dct2))))) diff --git a/script.module.simplejson/lib/simplejson/tests/test_recursion.py b/script.module.simplejson/lib/simplejson/tests/test_recursion.py deleted file mode 100644 index 662eb667e..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_recursion.py +++ /dev/null @@ -1,67 +0,0 @@ -from unittest import TestCase - -import simplejson as json - -class JSONTestObject: - pass - - -class RecursiveJSONEncoder(json.JSONEncoder): - recurse = False - def default(self, o): - if o is JSONTestObject: - if self.recurse: - return [JSONTestObject] - else: - return 'JSONTestObject' - return json.JSONEncoder.default(o) - - -class TestRecursion(TestCase): - def test_listrecursion(self): - x = [] - x.append(x) - try: - json.dumps(x) - except ValueError: - pass - else: - self.fail("didn't raise ValueError on list recursion") - x = [] - y = [x] - x.append(y) - try: - json.dumps(x) - except ValueError: - pass - else: - self.fail("didn't raise ValueError on alternating list recursion") - y = [] - x = [y, y] - # ensure that the marker is cleared - json.dumps(x) - - def test_dictrecursion(self): - x = {} - x["test"] = x - try: - json.dumps(x) - except ValueError: - pass - else: - self.fail("didn't raise ValueError on dict recursion") - x = {} - y = {"a": x, "b": x} - # ensure that the marker is cleared - json.dumps(y) - - def test_defaultrecursion(self): - enc = RecursiveJSONEncoder() - self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') - enc.recurse = True - try: - enc.encode(JSONTestObject) - except ValueError: - pass - else: - self.fail("didn't raise ValueError on default recursion") diff --git a/script.module.simplejson/lib/simplejson/tests/test_scanstring.py b/script.module.simplejson/lib/simplejson/tests/test_scanstring.py deleted file mode 100644 index d5de1801a..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_scanstring.py +++ /dev/null @@ -1,196 +0,0 @@ -import sys -from unittest import TestCase - -import simplejson as json -import simplejson.decoder -from simplejson.compat import b, PY3 - -class TestScanString(TestCase): - # The bytes type is intentionally not used in most of these tests - # under Python 3 because the decoder immediately coerces to str before - # calling scanstring. In Python 2 we are testing the code paths - # for both unicode and str. - # - # The reason this is done is because Python 3 would require - # entirely different code paths for parsing bytes and str. - # - def test_py_scanstring(self): - self._test_scanstring(simplejson.decoder.py_scanstring) - - def test_c_scanstring(self): - if not simplejson.decoder.c_scanstring: - return - self._test_scanstring(simplejson.decoder.c_scanstring) - - self.assertTrue(isinstance(simplejson.decoder.c_scanstring('""', 0)[0], str)) - - def _test_scanstring(self, scanstring): - if sys.maxunicode == 65535: - self.assertEqual( - scanstring(u'"z\U0001d120x"', 1, None, True), - (u'z\U0001d120x', 6)) - else: - self.assertEqual( - scanstring(u'"z\U0001d120x"', 1, None, True), - (u'z\U0001d120x', 5)) - - self.assertEqual( - scanstring('"\\u007b"', 1, None, True), - (u'{', 8)) - - self.assertEqual( - scanstring('"A JSON payload should be an object or array, not a string."', 1, None, True), - (u'A JSON payload should be an object or array, not a string.', 60)) - - self.assertEqual( - scanstring('["Unclosed array"', 2, None, True), - (u'Unclosed array', 17)) - - self.assertEqual( - scanstring('["extra comma",]', 2, None, True), - (u'extra comma', 14)) - - self.assertEqual( - scanstring('["double extra comma",,]', 2, None, True), - (u'double extra comma', 21)) - - self.assertEqual( - scanstring('["Comma after the close"],', 2, None, True), - (u'Comma after the close', 24)) - - self.assertEqual( - scanstring('["Extra close"]]', 2, None, True), - (u'Extra close', 14)) - - self.assertEqual( - scanstring('{"Extra comma": true,}', 2, None, True), - (u'Extra comma', 14)) - - self.assertEqual( - scanstring('{"Extra value after close": true} "misplaced quoted value"', 2, None, True), - (u'Extra value after close', 26)) - - self.assertEqual( - scanstring('{"Illegal expression": 1 + 2}', 2, None, True), - (u'Illegal expression', 21)) - - self.assertEqual( - scanstring('{"Illegal invocation": alert()}', 2, None, True), - (u'Illegal invocation', 21)) - - self.assertEqual( - scanstring('{"Numbers cannot have leading zeroes": 013}', 2, None, True), - (u'Numbers cannot have leading zeroes', 37)) - - self.assertEqual( - scanstring('{"Numbers cannot be hex": 0x14}', 2, None, True), - (u'Numbers cannot be hex', 24)) - - self.assertEqual( - scanstring('[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]', 21, None, True), - (u'Too deep', 30)) - - self.assertEqual( - scanstring('{"Missing colon" null}', 2, None, True), - (u'Missing colon', 16)) - - self.assertEqual( - scanstring('{"Double colon":: null}', 2, None, True), - (u'Double colon', 15)) - - self.assertEqual( - scanstring('{"Comma instead of colon", null}', 2, None, True), - (u'Comma instead of colon', 25)) - - self.assertEqual( - scanstring('["Colon instead of comma": false]', 2, None, True), - (u'Colon instead of comma', 25)) - - self.assertEqual( - scanstring('["Bad value", truth]', 2, None, True), - (u'Bad value', 12)) - - for c in map(chr, range(0x00, 0x1f)): - self.assertEqual( - scanstring(c + '"', 0, None, False), - (c, 2)) - self.assertRaises( - ValueError, - scanstring, c + '"', 0, None, True) - - self.assertRaises(ValueError, scanstring, '', 0, None, True) - self.assertRaises(ValueError, scanstring, 'a', 0, None, True) - self.assertRaises(ValueError, scanstring, '\\', 0, None, True) - self.assertRaises(ValueError, scanstring, '\\u', 0, None, True) - self.assertRaises(ValueError, scanstring, '\\u0', 0, None, True) - self.assertRaises(ValueError, scanstring, '\\u01', 0, None, True) - self.assertRaises(ValueError, scanstring, '\\u012', 0, None, True) - self.assertRaises(ValueError, scanstring, '\\u0123', 0, None, True) - if sys.maxunicode > 65535: - self.assertRaises(ValueError, - scanstring, '\\ud834\\u"', 0, None, True) - self.assertRaises(ValueError, - scanstring, '\\ud834\\x0123"', 0, None, True) - - def test_issue3623(self): - self.assertRaises(ValueError, json.decoder.scanstring, "xxx", 1, - "xxx") - self.assertRaises(UnicodeDecodeError, - json.encoder.encode_basestring_ascii, b("xx\xff")) - - def test_overflow(self): - # Python 2.5 does not have maxsize, Python 3 does not have maxint - maxsize = getattr(sys, 'maxsize', getattr(sys, 'maxint', None)) - assert maxsize is not None - self.assertRaises(OverflowError, json.decoder.scanstring, "xxx", - maxsize + 1) - - def test_surrogates(self): - scanstring = json.decoder.scanstring - - def assertScan(given, expect, test_utf8=True): - givens = [given] - if not PY3 and test_utf8: - givens.append(given.encode('utf8')) - for given in givens: - (res, count) = scanstring(given, 1, None, True) - self.assertEqual(len(given), count) - self.assertEqual(res, expect) - - assertScan( - u'"z\\ud834\\u0079x"', - u'z\ud834yx') - assertScan( - u'"z\\ud834\\udd20x"', - u'z\U0001d120x') - assertScan( - u'"z\\ud834\\ud834\\udd20x"', - u'z\ud834\U0001d120x') - assertScan( - u'"z\\ud834x"', - u'z\ud834x') - assertScan( - u'"z\\udd20x"', - u'z\udd20x') - assertScan( - u'"z\ud834x"', - u'z\ud834x') - # It may look strange to join strings together, but Python is drunk. - # https://gist.github.com/etrepum/5538443 - assertScan( - u'"z\\ud834\udd20x12345"', - u''.join([u'z\ud834', u'\udd20x12345'])) - assertScan( - u'"z\ud834\\udd20x"', - u''.join([u'z\ud834', u'\udd20x'])) - # these have different behavior given UTF8 input, because the surrogate - # pair may be joined (in maxunicode > 65535 builds) - assertScan( - u''.join([u'"z\ud834', u'\udd20x"']), - u''.join([u'z\ud834', u'\udd20x']), - test_utf8=False) - - self.assertRaises(ValueError, - scanstring, u'"z\\ud83x"', 1, None, True) - self.assertRaises(ValueError, - scanstring, u'"z\\ud834\\udd2x"', 1, None, True) diff --git a/script.module.simplejson/lib/simplejson/tests/test_separators.py b/script.module.simplejson/lib/simplejson/tests/test_separators.py deleted file mode 100644 index 91b4d4fb6..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_separators.py +++ /dev/null @@ -1,42 +0,0 @@ -import textwrap -from unittest import TestCase - -import simplejson as json - - -class TestSeparators(TestCase): - def test_separators(self): - h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', - {'nifty': 87}, {'field': 'yes', 'morefield': False} ] - - expect = textwrap.dedent("""\ - [ - [ - "blorpie" - ] , - [ - "whoops" - ] , - [] , - "d-shtaeou" , - "d-nthiouh" , - "i-vhbjkhnth" , - { - "nifty" : 87 - } , - { - "field" : "yes" , - "morefield" : false - } - ]""") - - - d1 = json.dumps(h) - d2 = json.dumps(h, indent=' ', sort_keys=True, separators=(' ,', ' : ')) - - h1 = json.loads(d1) - h2 = json.loads(d2) - - self.assertEqual(h1, h) - self.assertEqual(h2, h) - self.assertEqual(d2, expect) diff --git a/script.module.simplejson/lib/simplejson/tests/test_speedups.py b/script.module.simplejson/lib/simplejson/tests/test_speedups.py deleted file mode 100644 index 8b146df9a..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_speedups.py +++ /dev/null @@ -1,114 +0,0 @@ -from __future__ import with_statement - -import sys -import unittest -from unittest import TestCase - -import simplejson -from simplejson import encoder, decoder, scanner -from simplejson.compat import PY3, long_type, b - - -def has_speedups(): - return encoder.c_make_encoder is not None - - -def skip_if_speedups_missing(func): - def wrapper(*args, **kwargs): - if not has_speedups(): - if hasattr(unittest, 'SkipTest'): - raise unittest.SkipTest("C Extension not available") - else: - sys.stdout.write("C Extension not available") - return - return func(*args, **kwargs) - - return wrapper - - -class BadBool: - def __bool__(self): - 1/0 - __nonzero__ = __bool__ - - -class TestDecode(TestCase): - @skip_if_speedups_missing - def test_make_scanner(self): - self.assertRaises(AttributeError, scanner.c_make_scanner, 1) - - @skip_if_speedups_missing - def test_bad_bool_args(self): - def test(value): - decoder.JSONDecoder(strict=BadBool()).decode(value) - self.assertRaises(ZeroDivisionError, test, '""') - self.assertRaises(ZeroDivisionError, test, '{}') - if not PY3: - self.assertRaises(ZeroDivisionError, test, u'""') - self.assertRaises(ZeroDivisionError, test, u'{}') - -class TestEncode(TestCase): - @skip_if_speedups_missing - def test_make_encoder(self): - self.assertRaises( - TypeError, - encoder.c_make_encoder, - None, - ("\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7" - "\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75"), - None - ) - - @skip_if_speedups_missing - def test_bad_str_encoder(self): - # Issue #31505: There shouldn't be an assertion failure in case - # c_make_encoder() receives a bad encoder() argument. - import decimal - def bad_encoder1(*args): - return None - enc = encoder.c_make_encoder( - None, lambda obj: str(obj), - bad_encoder1, None, ': ', ', ', - False, False, False, {}, False, False, False, - None, None, 'utf-8', False, False, decimal.Decimal, False) - self.assertRaises(TypeError, enc, 'spam', 4) - self.assertRaises(TypeError, enc, {'spam': 42}, 4) - - def bad_encoder2(*args): - 1/0 - enc = encoder.c_make_encoder( - None, lambda obj: str(obj), - bad_encoder2, None, ': ', ', ', - False, False, False, {}, False, False, False, - None, None, 'utf-8', False, False, decimal.Decimal, False) - self.assertRaises(ZeroDivisionError, enc, 'spam', 4) - - @skip_if_speedups_missing - def test_bad_bool_args(self): - def test(name): - encoder.JSONEncoder(**{name: BadBool()}).encode({}) - self.assertRaises(ZeroDivisionError, test, 'skipkeys') - self.assertRaises(ZeroDivisionError, test, 'ensure_ascii') - self.assertRaises(ZeroDivisionError, test, 'check_circular') - self.assertRaises(ZeroDivisionError, test, 'allow_nan') - self.assertRaises(ZeroDivisionError, test, 'sort_keys') - self.assertRaises(ZeroDivisionError, test, 'use_decimal') - self.assertRaises(ZeroDivisionError, test, 'namedtuple_as_object') - self.assertRaises(ZeroDivisionError, test, 'tuple_as_array') - self.assertRaises(ZeroDivisionError, test, 'bigint_as_string') - self.assertRaises(ZeroDivisionError, test, 'for_json') - self.assertRaises(ZeroDivisionError, test, 'ignore_nan') - self.assertRaises(ZeroDivisionError, test, 'iterable_as_array') - - @skip_if_speedups_missing - def test_int_as_string_bitcount_overflow(self): - long_count = long_type(2)**32+31 - def test(): - encoder.JSONEncoder(int_as_string_bitcount=long_count).encode(0) - self.assertRaises((TypeError, OverflowError), test) - - if PY3: - @skip_if_speedups_missing - def test_bad_encoding(self): - with self.assertRaises(UnicodeEncodeError): - encoder.JSONEncoder(encoding='\udcff').encode({b('key'): 123}) diff --git a/script.module.simplejson/lib/simplejson/tests/test_str_subclass.py b/script.module.simplejson/lib/simplejson/tests/test_str_subclass.py deleted file mode 100644 index b6c8351f2..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_str_subclass.py +++ /dev/null @@ -1,21 +0,0 @@ -from unittest import TestCase - -import simplejson -from simplejson.compat import text_type - -# Tests for issue demonstrated in https://github.com/simplejson/simplejson/issues/144 -class WonkyTextSubclass(text_type): - def __getslice__(self, start, end): - return self.__class__('not what you wanted!') - -class TestStrSubclass(TestCase): - def test_dump_load(self): - for s in ['', '"hello"', 'text', u'\u005c']: - self.assertEqual( - s, - simplejson.loads(simplejson.dumps(WonkyTextSubclass(s)))) - - self.assertEqual( - s, - simplejson.loads(simplejson.dumps(WonkyTextSubclass(s), - ensure_ascii=False))) diff --git a/script.module.simplejson/lib/simplejson/tests/test_subclass.py b/script.module.simplejson/lib/simplejson/tests/test_subclass.py deleted file mode 100644 index 2bae3b630..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_subclass.py +++ /dev/null @@ -1,37 +0,0 @@ -from unittest import TestCase -import simplejson as json - -from decimal import Decimal - -class AlternateInt(int): - def __repr__(self): - return 'invalid json' - __str__ = __repr__ - - -class AlternateFloat(float): - def __repr__(self): - return 'invalid json' - __str__ = __repr__ - - -# class AlternateDecimal(Decimal): -# def __repr__(self): -# return 'invalid json' - - -class TestSubclass(TestCase): - def test_int(self): - self.assertEqual(json.dumps(AlternateInt(1)), '1') - self.assertEqual(json.dumps(AlternateInt(-1)), '-1') - self.assertEqual(json.loads(json.dumps({AlternateInt(1): 1})), {'1': 1}) - - def test_float(self): - self.assertEqual(json.dumps(AlternateFloat(1.0)), '1.0') - self.assertEqual(json.dumps(AlternateFloat(-1.0)), '-1.0') - self.assertEqual(json.loads(json.dumps({AlternateFloat(1.0): 1})), {'1.0': 1}) - - # NOTE: Decimal subclasses are not supported as-is - # def test_decimal(self): - # self.assertEqual(json.dumps(AlternateDecimal('1.0')), '1.0') - # self.assertEqual(json.dumps(AlternateDecimal('-1.0')), '-1.0') diff --git a/script.module.simplejson/lib/simplejson/tests/test_tool.py b/script.module.simplejson/lib/simplejson/tests/test_tool.py deleted file mode 100644 index 914bff8bc..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_tool.py +++ /dev/null @@ -1,114 +0,0 @@ -from __future__ import with_statement -import os -import sys -import textwrap -import unittest -import subprocess -import tempfile -try: - # Python 3.x - from test.support import strip_python_stderr -except ImportError: - # Python 2.6+ - try: - from test.test_support import strip_python_stderr - except ImportError: - # Python 2.5 - import re - def strip_python_stderr(stderr): - return re.sub( - r"\[\d+ refs\]\r?\n?$".encode(), - "".encode(), - stderr).strip() - -def open_temp_file(): - if sys.version_info >= (2, 6): - file = tempfile.NamedTemporaryFile(delete=False) - filename = file.name - else: - fd, filename = tempfile.mkstemp() - file = os.fdopen(fd, 'w+b') - return file, filename - -class TestTool(unittest.TestCase): - data = """ - - [["blorpie"],[ "whoops" ] , [ - ],\t"d-shtaeou",\r"d-nthiouh", - "i-vhbjkhnth", {"nifty":87}, {"morefield" :\tfalse,"field" - :"yes"} ] - """ - - expect = textwrap.dedent("""\ - [ - [ - "blorpie" - ], - [ - "whoops" - ], - [], - "d-shtaeou", - "d-nthiouh", - "i-vhbjkhnth", - { - "nifty": 87 - }, - { - "field": "yes", - "morefield": false - } - ] - """) - - def runTool(self, args=None, data=None): - argv = [sys.executable, '-m', 'simplejson.tool'] - if args: - argv.extend(args) - proc = subprocess.Popen(argv, - stdin=subprocess.PIPE, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - out, err = proc.communicate(data) - self.assertEqual(strip_python_stderr(err), ''.encode()) - self.assertEqual(proc.returncode, 0) - return out.decode('utf8').splitlines() - - def test_stdin_stdout(self): - self.assertEqual( - self.runTool(data=self.data.encode()), - self.expect.splitlines()) - - def test_infile_stdout(self): - infile, infile_name = open_temp_file() - try: - infile.write(self.data.encode()) - infile.close() - self.assertEqual( - self.runTool(args=[infile_name]), - self.expect.splitlines()) - finally: - os.unlink(infile_name) - - def test_infile_outfile(self): - infile, infile_name = open_temp_file() - try: - infile.write(self.data.encode()) - infile.close() - # outfile will get overwritten by tool, so the delete - # may not work on some platforms. Do it manually. - outfile, outfile_name = open_temp_file() - try: - outfile.close() - self.assertEqual( - self.runTool(args=[infile_name, outfile_name]), - []) - with open(outfile_name, 'rb') as f: - self.assertEqual( - f.read().decode('utf8').splitlines(), - self.expect.splitlines() - ) - finally: - os.unlink(outfile_name) - finally: - os.unlink(infile_name) diff --git a/script.module.simplejson/lib/simplejson/tests/test_tuple.py b/script.module.simplejson/lib/simplejson/tests/test_tuple.py deleted file mode 100644 index 4ad7b0e86..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_tuple.py +++ /dev/null @@ -1,47 +0,0 @@ -import unittest - -from simplejson.compat import StringIO -import simplejson as json - -class TestTuples(unittest.TestCase): - def test_tuple_array_dumps(self): - t = (1, 2, 3) - expect = json.dumps(list(t)) - # Default is True - self.assertEqual(expect, json.dumps(t)) - self.assertEqual(expect, json.dumps(t, tuple_as_array=True)) - self.assertRaises(TypeError, json.dumps, t, tuple_as_array=False) - # Ensure that the "default" does not get called - self.assertEqual(expect, json.dumps(t, default=repr)) - self.assertEqual(expect, json.dumps(t, tuple_as_array=True, - default=repr)) - # Ensure that the "default" gets called - self.assertEqual( - json.dumps(repr(t)), - json.dumps(t, tuple_as_array=False, default=repr)) - - def test_tuple_array_dump(self): - t = (1, 2, 3) - expect = json.dumps(list(t)) - # Default is True - sio = StringIO() - json.dump(t, sio) - self.assertEqual(expect, sio.getvalue()) - sio = StringIO() - json.dump(t, sio, tuple_as_array=True) - self.assertEqual(expect, sio.getvalue()) - self.assertRaises(TypeError, json.dump, t, StringIO(), - tuple_as_array=False) - # Ensure that the "default" does not get called - sio = StringIO() - json.dump(t, sio, default=repr) - self.assertEqual(expect, sio.getvalue()) - sio = StringIO() - json.dump(t, sio, tuple_as_array=True, default=repr) - self.assertEqual(expect, sio.getvalue()) - # Ensure that the "default" gets called - sio = StringIO() - json.dump(t, sio, tuple_as_array=False, default=repr) - self.assertEqual( - json.dumps(repr(t)), - sio.getvalue()) diff --git a/script.module.simplejson/lib/simplejson/tests/test_unicode.py b/script.module.simplejson/lib/simplejson/tests/test_unicode.py deleted file mode 100644 index 0c7b1a6c4..000000000 --- a/script.module.simplejson/lib/simplejson/tests/test_unicode.py +++ /dev/null @@ -1,154 +0,0 @@ -import sys -import codecs -from unittest import TestCase - -import simplejson as json -from simplejson.compat import unichr, text_type, b, BytesIO - -class TestUnicode(TestCase): - def test_encoding1(self): - encoder = json.JSONEncoder(encoding='utf-8') - u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - s = u.encode('utf-8') - ju = encoder.encode(u) - js = encoder.encode(s) - self.assertEqual(ju, js) - - def test_encoding2(self): - u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - s = u.encode('utf-8') - ju = json.dumps(u, encoding='utf-8') - js = json.dumps(s, encoding='utf-8') - self.assertEqual(ju, js) - - def test_encoding3(self): - u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u) - self.assertEqual(j, '"\\u03b1\\u03a9"') - - def test_encoding4(self): - u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u]) - self.assertEqual(j, '["\\u03b1\\u03a9"]') - - def test_encoding5(self): - u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps(u, ensure_ascii=False) - self.assertEqual(j, u'"' + u + u'"') - - def test_encoding6(self): - u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' - j = json.dumps([u], ensure_ascii=False) - self.assertEqual(j, u'["' + u + u'"]') - - def test_big_unicode_encode(self): - u = u'\U0001d120' - self.assertEqual(json.dumps(u), '"\\ud834\\udd20"') - self.assertEqual(json.dumps(u, ensure_ascii=False), u'"\U0001d120"') - - def test_big_unicode_decode(self): - u = u'z\U0001d120x' - self.assertEqual(json.loads('"' + u + '"'), u) - self.assertEqual(json.loads('"z\\ud834\\udd20x"'), u) - - def test_unicode_decode(self): - for i in range(0, 0xd7ff): - u = unichr(i) - #s = '"\\u{0:04x}"'.format(i) - s = '"\\u%04x"' % (i,) - self.assertEqual(json.loads(s), u) - - def test_object_pairs_hook_with_unicode(self): - s = u'{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' - p = [(u"xkd", 1), (u"kcw", 2), (u"art", 3), (u"hxm", 4), - (u"qrt", 5), (u"pad", 6), (u"hoy", 7)] - self.assertEqual(json.loads(s), eval(s)) - self.assertEqual(json.loads(s, object_pairs_hook=lambda x: x), p) - od = json.loads(s, object_pairs_hook=json.OrderedDict) - self.assertEqual(od, json.OrderedDict(p)) - self.assertEqual(type(od), json.OrderedDict) - # the object_pairs_hook takes priority over the object_hook - self.assertEqual(json.loads(s, - object_pairs_hook=json.OrderedDict, - object_hook=lambda x: None), - json.OrderedDict(p)) - - - def test_default_encoding(self): - self.assertEqual(json.loads(u'{"a": "\xe9"}'.encode('utf-8')), - {'a': u'\xe9'}) - - def test_unicode_preservation(self): - self.assertEqual(type(json.loads(u'""')), text_type) - self.assertEqual(type(json.loads(u'"a"')), text_type) - self.assertEqual(type(json.loads(u'["a"]')[0]), text_type) - - def test_ensure_ascii_false_returns_unicode(self): - # http://code.google.com/p/simplejson/issues/detail?id=48 - self.assertEqual(type(json.dumps([], ensure_ascii=False)), text_type) - self.assertEqual(type(json.dumps(0, ensure_ascii=False)), text_type) - self.assertEqual(type(json.dumps({}, ensure_ascii=False)), text_type) - self.assertEqual(type(json.dumps("", ensure_ascii=False)), text_type) - - def test_ensure_ascii_false_bytestring_encoding(self): - # http://code.google.com/p/simplejson/issues/detail?id=48 - doc1 = {u'quux': b('Arr\xc3\xaat sur images')} - doc2 = {u'quux': u'Arr\xeat sur images'} - doc_ascii = '{"quux": "Arr\\u00eat sur images"}' - doc_unicode = u'{"quux": "Arr\xeat sur images"}' - self.assertEqual(json.dumps(doc1), doc_ascii) - self.assertEqual(json.dumps(doc2), doc_ascii) - self.assertEqual(json.dumps(doc1, ensure_ascii=False), doc_unicode) - self.assertEqual(json.dumps(doc2, ensure_ascii=False), doc_unicode) - - def test_ensure_ascii_linebreak_encoding(self): - # http://timelessrepo.com/json-isnt-a-javascript-subset - s1 = u'\u2029\u2028' - s2 = s1.encode('utf8') - expect = '"\\u2029\\u2028"' - expect_non_ascii = u'"\u2029\u2028"' - self.assertEqual(json.dumps(s1), expect) - self.assertEqual(json.dumps(s2), expect) - self.assertEqual(json.dumps(s1, ensure_ascii=False), expect_non_ascii) - self.assertEqual(json.dumps(s2, ensure_ascii=False), expect_non_ascii) - - def test_invalid_escape_sequences(self): - # incomplete escape sequence - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u1') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u12') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u123') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u1234') - # invalid escape sequence - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u123x"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u12x4"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\u1x34"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ux234"') - if sys.maxunicode > 65535: - # invalid escape sequence for low surrogate - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u0"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u00"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u000"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u000x"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u00x0"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u0x00"') - self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\ux000"') - - def test_ensure_ascii_still_works(self): - # in the ascii range, ensure that everything is the same - for c in map(unichr, range(0, 127)): - self.assertEqual( - json.dumps(c, ensure_ascii=False), - json.dumps(c)) - snowman = u'\N{SNOWMAN}' - self.assertEqual( - json.dumps(c, ensure_ascii=False), - '"' + c + '"') - - def test_strip_bom(self): - content = u"\u3053\u3093\u306b\u3061\u308f" - json_doc = codecs.BOM_UTF8 + b(json.dumps(content)) - self.assertEqual(json.load(BytesIO(json_doc)), content) - for doc in json_doc, json_doc.decode('utf8'): - self.assertEqual(json.loads(doc), content) diff --git a/script.module.simplejson/lib/simplejson/tool.py b/script.module.simplejson/lib/simplejson/tool.py deleted file mode 100644 index 062e8e2c1..000000000 --- a/script.module.simplejson/lib/simplejson/tool.py +++ /dev/null @@ -1,42 +0,0 @@ -r"""Command-line tool to validate and pretty-print JSON - -Usage:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) - -""" -from __future__ import with_statement -import sys -import simplejson as json - -def main(): - if len(sys.argv) == 1: - infile = sys.stdin - outfile = sys.stdout - elif len(sys.argv) == 2: - infile = open(sys.argv[1], 'r') - outfile = sys.stdout - elif len(sys.argv) == 3: - infile = open(sys.argv[1], 'r') - outfile = open(sys.argv[2], 'w') - else: - raise SystemExit(sys.argv[0] + " [infile [outfile]]") - with infile: - try: - obj = json.load(infile, - object_pairs_hook=json.OrderedDict, - use_decimal=True) - except ValueError: - raise SystemExit(sys.exc_info()[1]) - with outfile: - json.dump(obj, outfile, sort_keys=True, indent=' ', use_decimal=True) - outfile.write('\n') - - -if __name__ == '__main__': - main() diff --git a/script.module.simplejson/icon.png b/script.module.simplejson/resources/icon.png similarity index 100% rename from script.module.simplejson/icon.png rename to script.module.simplejson/resources/icon.png From fe286b0c31f936c28b2acbab7ea8990f547117ac Mon Sep 17 00:00:00 2001 From: L2501 Date: Sun, 16 Jul 2023 07:35:05 +0000 Subject: [PATCH 063/145] [script.module.soupsieve] 2.4.1 --- .../{LICENSE.md => LICENSE.txt} | 2 +- script.module.soupsieve/README.md | 73 --- script.module.soupsieve/addon.xml | 32 +- .../lib/soupsieve/__init__.py | 92 +++- .../lib/soupsieve/__meta__.py | 28 +- .../lib/soupsieve/css_match.py | 447 +++++++++++------- .../lib/soupsieve/css_parser.py | 305 +++++++----- .../lib/soupsieve/css_types.py | 236 +++++---- .../lib/soupsieve/pretty.py | 138 ++++++ script.module.soupsieve/lib/soupsieve/util.py | 33 +- .../{ => resources}/icon.png | Bin 11 files changed, 881 insertions(+), 505 deletions(-) rename script.module.soupsieve/{LICENSE.md => LICENSE.txt} (94%) delete mode 100644 script.module.soupsieve/README.md create mode 100644 script.module.soupsieve/lib/soupsieve/pretty.py rename script.module.soupsieve/{ => resources}/icon.png (100%) diff --git a/script.module.soupsieve/LICENSE.md b/script.module.soupsieve/LICENSE.txt similarity index 94% rename from script.module.soupsieve/LICENSE.md rename to script.module.soupsieve/LICENSE.txt index a95ea8dcb..ae5fec596 100644 --- a/script.module.soupsieve/LICENSE.md +++ b/script.module.soupsieve/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Isaac Muse +Copyright (c) 2018 - 2023 Isaac Muse Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/script.module.soupsieve/README.md b/script.module.soupsieve/README.md deleted file mode 100644 index 206c3f8a2..000000000 --- a/script.module.soupsieve/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Soup Sieve - -## Overview - -Soup Sieve is a CSS selector library designed to be used with [Beautiful Soup 4][bs4]. It aims to provide selecting, -matching, and filtering using modern CSS selectors. Soup Sieve currently provides selectors from the CSS level 1 -specifications up through the latest CSS level 4 drafts and beyond (though some are not yet implemented). - -Soup Sieve was written with the intent to replace Beautiful Soup's builtin select feature, and as of Beautiful Soup -version 4.7.0, it now is :confetti_ball:. Soup Sieve can also be imported in order to use its API directly for -more controlled, specialized parsing. - -Soup Sieve has implemented most of the CSS selectors up through the latest CSS draft specifications, though there are a -number that don't make sense in a non-browser environment. Selectors that cannot provide meaningful functionality simply -do not match anything. Some of the supported selectors are: - -- `.classes` -- `#ids` -- `[attributes=value]` -- `parent child` -- `parent > child` -- `sibling ~ sibling` -- `sibling + sibling` -- `:not(element.class, element2.class)` -- `:is(element.class, element2.class)` -- `parent:has(> child)` -- and [many more](https://facelessuser.github.io/soupsieve/selectors/) - - -## Installation - -You must have Beautiful Soup already installed: - -``` -pip install beautifulsoup4 -``` - -In most cases, assuming you've installed version 4.7.0, that should be all you need to do, but if you've installed via -some alternative method, and Soup Sieve is not automatically installed for your, you can install it directly: - -``` -pip install soupsieve -``` - -If you want to manually install it from source, navigate to the root of the project and run - -``` -python setup.py build -python setup.py install -``` - -## Documentation - -Documentation is found here: https://facelessuser.github.io/soupsieve/. - -## License - -MIT License - -Copyright (c) 2018 - 2020 Isaac Muse - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit -persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/script.module.soupsieve/addon.xml b/script.module.soupsieve/addon.xml index c4b20bbf9..cd117ca24 100644 --- a/script.module.soupsieve/addon.xml +++ b/script.module.soupsieve/addon.xml @@ -1,18 +1,18 @@ - - - - - - - A CSS selector library - Soup Sieve is a CSS selector library designed to be used with Beautiful Soup 4. It aims to provide selecting, matching, and filtering using modern CSS selectors. - MIT - all - https://pypi.org/project/soupsieve/ - https://github.com/facelessuser/soupsieve - - icon.png - - + + + + + + + A modern CSS selector implementation for Beautiful Soup. + A modern CSS selector implementation for Beautiful Soup. + MIT + all + https://facelessuser.github.io/soupsieve/ + https://github.com/facelessuser/soupsieve + + resources/icon.png + + diff --git a/script.module.soupsieve/lib/soupsieve/__init__.py b/script.module.soupsieve/lib/soupsieve/__init__.py index 1005898ad..06403633a 100644 --- a/script.module.soupsieve/lib/soupsieve/__init__.py +++ b/script.module.soupsieve/lib/soupsieve/__init__.py @@ -25,11 +25,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +from __future__ import annotations from .__meta__ import __version__, __version_info__ # noqa: F401 from . import css_parser as cp from . import css_match as cm from . import css_types as ct from .util import DEBUG, SelectorSyntaxError # noqa: F401 +import bs4 # type: ignore[import] +from typing import Any, Iterator, Iterable __all__ = ( 'DEBUG', 'SelectorSyntaxError', 'SoupSieve', @@ -40,16 +43,16 @@ SoupSieve = cm.SoupSieve -def compile(pattern, namespaces=None, flags=0, **kwargs): # noqa: A001 +def compile( # noqa: A001 + pattern: str, + namespaces: dict[str, str] | None = None, + flags: int = 0, + *, + custom: dict[str, str] | None = None, + **kwargs: Any +) -> cm.SoupSieve: """Compile CSS pattern.""" - if namespaces is not None: - namespaces = ct.Namespaces(**namespaces) - - custom = kwargs.get('custom') - if custom is not None: - custom = ct.CustomSelectors(**custom) - if isinstance(pattern, SoupSieve): if flags: raise ValueError("Cannot process 'flags' argument on a compiled selector list") @@ -59,53 +62,108 @@ def compile(pattern, namespaces=None, flags=0, **kwargs): # noqa: A001 raise ValueError("Cannot process 'custom' argument on a compiled selector list") return pattern - return cp._cached_css_compile(pattern, namespaces, custom, flags) + return cp._cached_css_compile( + pattern, + ct.Namespaces(namespaces) if namespaces is not None else namespaces, + ct.CustomSelectors(custom) if custom is not None else custom, + flags + ) -def purge(): +def purge() -> None: """Purge cached patterns.""" cp._purge_cache() -def closest(select, tag, namespaces=None, flags=0, **kwargs): +def closest( + select: str, + tag: 'bs4.Tag', + namespaces: dict[str, str] | None = None, + flags: int = 0, + *, + custom: dict[str, str] | None = None, + **kwargs: Any +) -> 'bs4.Tag': """Match closest ancestor.""" return compile(select, namespaces, flags, **kwargs).closest(tag) -def match(select, tag, namespaces=None, flags=0, **kwargs): +def match( + select: str, + tag: 'bs4.Tag', + namespaces: dict[str, str] | None = None, + flags: int = 0, + *, + custom: dict[str, str] | None = None, + **kwargs: Any +) -> bool: """Match node.""" return compile(select, namespaces, flags, **kwargs).match(tag) -def filter(select, iterable, namespaces=None, flags=0, **kwargs): # noqa: A001 +def filter( # noqa: A001 + select: str, + iterable: Iterable['bs4.Tag'], + namespaces: dict[str, str] | None = None, + flags: int = 0, + *, + custom: dict[str, str] | None = None, + **kwargs: Any +) -> list['bs4.Tag']: """Filter list of nodes.""" return compile(select, namespaces, flags, **kwargs).filter(iterable) -def select_one(select, tag, namespaces=None, flags=0, **kwargs): +def select_one( + select: str, + tag: 'bs4.Tag', + namespaces: dict[str, str] | None = None, + flags: int = 0, + *, + custom: dict[str, str] | None = None, + **kwargs: Any +) -> 'bs4.Tag': """Select a single tag.""" return compile(select, namespaces, flags, **kwargs).select_one(tag) -def select(select, tag, namespaces=None, limit=0, flags=0, **kwargs): +def select( + select: str, + tag: 'bs4.Tag', + namespaces: dict[str, str] | None = None, + limit: int = 0, + flags: int = 0, + *, + custom: dict[str, str] | None = None, + **kwargs: Any +) -> list['bs4.Tag']: """Select the specified tags.""" return compile(select, namespaces, flags, **kwargs).select(tag, limit) -def iselect(select, tag, namespaces=None, limit=0, flags=0, **kwargs): +def iselect( + select: str, + tag: 'bs4.Tag', + namespaces: dict[str, str] | None = None, + limit: int = 0, + flags: int = 0, + *, + custom: dict[str, str] | None = None, + **kwargs: Any +) -> Iterator['bs4.Tag']: """Iterate the specified tags.""" for el in compile(select, namespaces, flags, **kwargs).iselect(tag, limit): yield el -def escape(ident): +def escape(ident: str) -> str: """Escape identifier.""" return cp.escape(ident) diff --git a/script.module.soupsieve/lib/soupsieve/__meta__.py b/script.module.soupsieve/lib/soupsieve/__meta__.py index 90a3c7472..6f35e1527 100644 --- a/script.module.soupsieve/lib/soupsieve/__meta__.py +++ b/script.module.soupsieve/lib/soupsieve/__meta__.py @@ -1,4 +1,5 @@ """Meta related things.""" +from __future__ import annotations from collections import namedtuple import re @@ -79,7 +80,11 @@ class Version(namedtuple("Version", ["major", "minor", "micro", "release", "pre" """ - def __new__(cls, major, minor, micro, release="final", pre=0, post=0, dev=0): + def __new__( + cls, + major: int, minor: int, micro: int, release: str = "final", + pre: int = 0, post: int = 0, dev: int = 0 + ) -> Version: """Validate version info.""" # Ensure all parts are positive integers. @@ -115,27 +120,27 @@ def __new__(cls, major, minor, micro, release="final", pre=0, post=0, dev=0): return super(Version, cls).__new__(cls, major, minor, micro, release, pre, post, dev) - def _is_pre(self): + def _is_pre(self) -> bool: """Is prerelease.""" - return self.pre > 0 + return bool(self.pre > 0) - def _is_dev(self): + def _is_dev(self) -> bool: """Is development.""" return bool(self.release < "alpha") - def _is_post(self): + def _is_post(self) -> bool: """Is post.""" - return self.post > 0 + return bool(self.post > 0) - def _get_dev_status(self): # pragma: no cover + def _get_dev_status(self) -> str: # pragma: no cover """Get development status string.""" return DEV_STATUS[self.release] - def _get_canonical(self): + def _get_canonical(self) -> str: """Get the canonical output string.""" # Assemble major, minor, micro version and append `pre`, `post`, or `dev` if needed.. @@ -153,11 +158,14 @@ def _get_canonical(self): return ver -def parse_version(ver, pre=False): +def parse_version(ver: str) -> Version: """Parse version into a comparable Version tuple.""" m = RE_VER.match(ver) + if m is None: + raise ValueError("'{}' is not a valid version".format(ver)) + # Handle major, minor, micro major = int(m.group('major')) minor = int(m.group('minor')) if m.group('minor') else 0 @@ -185,5 +193,5 @@ def parse_version(ver, pre=False): return Version(major, minor, micro, release, pre, post, dev) -__version_info__ = Version(2, 1, 0, "final") +__version_info__ = Version(2, 4, 1, "final") __version__ = __version_info__._get_canonical() diff --git a/script.module.soupsieve/lib/soupsieve/css_match.py b/script.module.soupsieve/lib/soupsieve/css_match.py index 8e6bd313c..168e4be6c 100644 --- a/script.module.soupsieve/lib/soupsieve/css_match.py +++ b/script.module.soupsieve/lib/soupsieve/css_match.py @@ -1,11 +1,12 @@ """CSS matcher.""" +from __future__ import annotations from datetime import datetime from . import util import re -from .import css_types as ct +from . import css_types as ct import unicodedata - -import bs4 +import bs4 # type: ignore[import] +from typing import Iterator, Iterable, Any, Callable, Sequence, cast # noqa: F401 # Empty tag pattern (whitespace okay) RE_NOT_EMPTY = re.compile('[^ \t\r\n\f]') @@ -55,7 +56,7 @@ DAYS_IN_WEEK = 7 -class _FakeParent(object): +class _FakeParent: """ Fake parent class. @@ -64,87 +65,90 @@ class _FakeParent(object): fake parent so we can traverse the root element as a child. """ - def __init__(self, element): + def __init__(self, element: bs4.Tag) -> None: """Initialize.""" self.contents = [element] - def __len__(self): + def __len__(self) -> bs4.PageElement: """Length.""" return len(self.contents) -class _DocumentNav(object): +class _DocumentNav: """Navigate a Beautiful Soup document.""" @classmethod - def assert_valid_input(cls, tag): + def assert_valid_input(cls, tag: Any) -> None: """Check if valid input tag or document.""" # Fail on unexpected types. if not cls.is_tag(tag): - raise TypeError("Expected a BeautifulSoup 'Tag', but instead recieved type {}".format(type(tag))) + raise TypeError("Expected a BeautifulSoup 'Tag', but instead received type {}".format(type(tag))) @staticmethod - def is_doc(obj): + def is_doc(obj: bs4.Tag) -> bool: """Is `BeautifulSoup` object.""" return isinstance(obj, bs4.BeautifulSoup) @staticmethod - def is_tag(obj): + def is_tag(obj: bs4.PageElement) -> bool: """Is tag.""" return isinstance(obj, bs4.Tag) @staticmethod - def is_declaration(obj): # pragma: no cover + def is_declaration(obj: bs4.PageElement) -> bool: # pragma: no cover """Is declaration.""" return isinstance(obj, bs4.Declaration) @staticmethod - def is_cdata(obj): + def is_cdata(obj: bs4.PageElement) -> bool: """Is CDATA.""" return isinstance(obj, bs4.CData) @staticmethod - def is_processing_instruction(obj): # pragma: no cover + def is_processing_instruction(obj: bs4.PageElement) -> bool: # pragma: no cover """Is processing instruction.""" return isinstance(obj, bs4.ProcessingInstruction) @staticmethod - def is_navigable_string(obj): + def is_navigable_string(obj: bs4.PageElement) -> bool: """Is navigable string.""" return isinstance(obj, bs4.NavigableString) @staticmethod - def is_special_string(obj): + def is_special_string(obj: bs4.PageElement) -> bool: """Is special string.""" return isinstance(obj, (bs4.Comment, bs4.Declaration, bs4.CData, bs4.ProcessingInstruction, bs4.Doctype)) @classmethod - def is_content_string(cls, obj): + def is_content_string(cls, obj: bs4.PageElement) -> bool: """Check if node is content string.""" return cls.is_navigable_string(obj) and not cls.is_special_string(obj) @staticmethod - def create_fake_parent(el): + def create_fake_parent(el: bs4.Tag) -> _FakeParent: """Create fake parent for a given element.""" return _FakeParent(el) @staticmethod - def is_xml_tree(el): + def is_xml_tree(el: bs4.Tag) -> bool: """Check if element (or document) is from a XML tree.""" - return el._is_xml + return bool(el._is_xml) - def is_iframe(self, el): + def is_iframe(self, el: bs4.Tag) -> bool: """Check if element is an `iframe`.""" - return ((el.name if self.is_xml_tree(el) else util.lower(el.name)) == 'iframe') and self.is_html_tag(el) + return bool( + ((el.name if self.is_xml_tree(el) else util.lower(el.name)) == 'iframe') and + self.is_html_tag(el) # type: ignore[attr-defined] + ) - def is_root(self, el): + def is_root(self, el: bs4.Tag) -> bool: """ Return whether element is a root element. @@ -152,19 +156,26 @@ def is_root(self, el): and we check if it is the root element under an `iframe`. """ - root = self.root and self.root is el + root = self.root and self.root is el # type: ignore[attr-defined] if not root: parent = self.get_parent(el) - root = parent is not None and self.is_html and self.is_iframe(parent) + root = parent is not None and self.is_html and self.is_iframe(parent) # type: ignore[attr-defined] return root - def get_contents(self, el, no_iframe=False): + def get_contents(self, el: bs4.Tag, no_iframe: bool = False) -> Iterator[bs4.PageElement]: """Get contents or contents in reverse.""" if not no_iframe or not self.is_iframe(el): for content in el.contents: yield content - def get_children(self, el, start=None, reverse=False, tags=True, no_iframe=False): + def get_children( + self, + el: bs4.Tag, + start: int | None = None, + reverse: bool = False, + tags: bool = True, + no_iframe: bool = False + ) -> Iterator[bs4.PageElement]: """Get children.""" if not no_iframe or not self.is_iframe(el): @@ -183,7 +194,12 @@ def get_children(self, el, start=None, reverse=False, tags=True, no_iframe=False if not tags or self.is_tag(node): yield node - def get_descendants(self, el, tags=True, no_iframe=False): + def get_descendants( + self, + el: bs4.Tag, + tags: bool = True, + no_iframe: bool = False + ) -> Iterator[bs4.PageElement]: """Get descendants.""" if not no_iframe or not self.is_iframe(el): @@ -214,7 +230,7 @@ def get_descendants(self, el, tags=True, no_iframe=False): if not tags or is_tag: yield child - def get_parent(self, el, no_iframe=False): + def get_parent(self, el: bs4.Tag, no_iframe: bool = False) -> bs4.Tag: """Get parent.""" parent = el.parent @@ -223,25 +239,25 @@ def get_parent(self, el, no_iframe=False): return parent @staticmethod - def get_tag_name(el): + def get_tag_name(el: bs4.Tag) -> str | None: """Get tag.""" - return el.name + return cast('str | None', el.name) @staticmethod - def get_prefix_name(el): + def get_prefix_name(el: bs4.Tag) -> str | None: """Get prefix.""" - return el.prefix + return cast('str | None', el.prefix) @staticmethod - def get_uri(el): + def get_uri(el: bs4.Tag) -> str | None: """Get namespace `URI`.""" - return el.namespace + return cast('str | None', el.namespace) @classmethod - def get_next(cls, el, tags=True): + def get_next(cls, el: bs4.Tag, tags: bool = True) -> bs4.PageElement: """Get next sibling tag.""" sibling = el.next_sibling @@ -250,7 +266,7 @@ def get_next(cls, el, tags=True): return sibling @classmethod - def get_previous(cls, el, tags=True): + def get_previous(cls, el: bs4.Tag, tags: bool = True) -> bs4.PageElement: """Get previous sibling tag.""" sibling = el.previous_sibling @@ -259,7 +275,7 @@ def get_previous(cls, el, tags=True): return sibling @staticmethod - def has_html_ns(el): + def has_html_ns(el: bs4.Tag) -> bool: """ Check if element has an HTML namespace. @@ -268,65 +284,103 @@ def has_html_ns(el): """ ns = getattr(el, 'namespace') if el else None - return ns and ns == NS_XHTML + return bool(ns and ns == NS_XHTML) @staticmethod - def split_namespace(el, attr_name): + def split_namespace(el: bs4.Tag, attr_name: str) -> tuple[str | None, str | None]: """Return namespace and attribute name without the prefix.""" return getattr(attr_name, 'namespace', None), getattr(attr_name, 'name', None) - @staticmethod - def get_attribute_by_name(el, name, default=None): + @classmethod + def normalize_value(cls, value: Any) -> str | Sequence[str]: + """Normalize the value to be a string or list of strings.""" + + # Treat `None` as empty string. + if value is None: + return '' + + # Pass through strings + if (isinstance(value, str)): + return value + + # If it's a byte string, convert it to Unicode, treating it as UTF-8. + if isinstance(value, bytes): + return value.decode("utf8") + + # BeautifulSoup supports sequences of attribute values, so make sure the children are strings. + if isinstance(value, Sequence): + new_value = [] + for v in value: + if not isinstance(v, (str, bytes)) and isinstance(v, Sequence): + # This is most certainly a user error and will crash and burn later. + # To keep things working, we'll do what we do with all objects, + # And convert them to strings. + new_value.append(str(v)) + else: + # Convert the child to a string + new_value.append(cast(str, cls.normalize_value(v))) + return new_value + + # Try and make anything else a string + return str(value) + + @classmethod + def get_attribute_by_name( + cls, + el: bs4.Tag, + name: str, + default: str | Sequence[str] | None = None + ) -> str | Sequence[str] | None: """Get attribute by name.""" value = default if el._is_xml: try: - value = el.attrs[name] + value = cls.normalize_value(el.attrs[name]) except KeyError: pass else: for k, v in el.attrs.items(): if util.lower(k) == name: - value = v + value = cls.normalize_value(v) break return value - @staticmethod - def iter_attributes(el): + @classmethod + def iter_attributes(cls, el: bs4.Tag) -> Iterator[tuple[str, str | Sequence[str] | None]]: """Iterate attributes.""" for k, v in el.attrs.items(): - yield k, v + yield k, cls.normalize_value(v) @classmethod - def get_classes(cls, el): + def get_classes(cls, el: bs4.Tag) -> Sequence[str]: """Get classes.""" classes = cls.get_attribute_by_name(el, 'class', []) if isinstance(classes, str): classes = RE_NOT_WS.findall(classes) - return classes + return cast(Sequence[str], classes) - def get_text(self, el, no_iframe=False): + def get_text(self, el: bs4.Tag, no_iframe: bool = False) -> str: """Get text.""" return ''.join( [node for node in self.get_descendants(el, tags=False, no_iframe=no_iframe) if self.is_content_string(node)] ) - def get_own_text(self, el, no_iframe=False): + def get_own_text(self, el: bs4.Tag, no_iframe: bool = False) -> list[str]: """Get Own Text.""" return [node for node in self.get_contents(el, no_iframe=no_iframe) if self.is_content_string(node)] -class Inputs(object): +class Inputs: """Class for parsing and validating input items.""" @staticmethod - def validate_day(year, month, day): + def validate_day(year: int, month: int, day: int) -> bool: """Validate day.""" max_days = LONG_MONTH @@ -337,7 +391,7 @@ def validate_day(year, month, day): return 1 <= day <= max_days @staticmethod - def validate_week(year, week): + def validate_week(year: int, week: int) -> bool: """Validate week.""" max_week = datetime.strptime("{}-{}-{}".format(12, 31, year), "%m-%d-%Y").isocalendar()[1] @@ -346,34 +400,36 @@ def validate_week(year, week): return 1 <= week <= max_week @staticmethod - def validate_month(month): + def validate_month(month: int) -> bool: """Validate month.""" return 1 <= month <= 12 @staticmethod - def validate_year(year): + def validate_year(year: int) -> bool: """Validate year.""" return 1 <= year @staticmethod - def validate_hour(hour): + def validate_hour(hour: int) -> bool: """Validate hour.""" return 0 <= hour <= 23 @staticmethod - def validate_minutes(minutes): + def validate_minutes(minutes: int) -> bool: """Validate minutes.""" return 0 <= minutes <= 59 @classmethod - def parse_value(cls, itype, value): + def parse_value(cls, itype: str, value: str | None) -> tuple[float, ...] | None: """Parse the input value.""" - parsed = None + parsed = None # type: tuple[float, ...] | None + if value is None: + return value if itype == "date": m = RE_DATE.match(value) if m: @@ -412,30 +468,36 @@ def parse_value(cls, itype, value): hour = int(m.group('hour'), 10) minutes = int(m.group('minutes'), 10) if ( - cls.validate_year(year) and cls.validate_month(month) and cls.validate_day(year, month, day) - and cls.validate_hour(hour) and cls.validate_minutes(minutes) + cls.validate_year(year) and cls.validate_month(month) and cls.validate_day(year, month, day) and + cls.validate_hour(hour) and cls.validate_minutes(minutes) ): parsed = (year, month, day, hour, minutes) elif itype in ("number", "range"): m = RE_NUM.match(value) if m: - parsed = float(m.group('value')) + parsed = (float(m.group('value')),) return parsed -class _Match(object): +class CSSMatch(_DocumentNav): """Perform CSS matching.""" - def __init__(self, selectors, scope, namespaces, flags): + def __init__( + self, + selectors: ct.SelectorList, + scope: bs4.Tag, + namespaces: ct.Namespaces | None, + flags: int + ) -> None: """Initialize.""" self.assert_valid_input(scope) self.tag = scope - self.cached_meta_lang = [] - self.cached_default_forms = [] - self.cached_indeterminate_forms = [] + self.cached_meta_lang = [] # type: list[tuple[str, str]] + self.cached_default_forms = [] # type: list[tuple[bs4.Tag, bs4.Tag]] + self.cached_indeterminate_forms = [] # type: list[tuple[bs4.Tag, str, bool]] self.selectors = selectors - self.namespaces = {} if namespaces is None else namespaces + self.namespaces = {} if namespaces is None else namespaces # type: ct.Namespaces | dict[str, str] self.flags = flags self.iframe_restrict = False @@ -461,12 +523,12 @@ def __init__(self, selectors, scope, namespaces, flags): self.is_xml = self.is_xml_tree(doc) self.is_html = not self.is_xml or self.has_html_namespace - def supports_namespaces(self): + def supports_namespaces(self) -> bool: """Check if namespaces are supported in the HTML type.""" return self.is_xml or self.has_html_namespace - def get_tag_ns(self, el): + def get_tag_ns(self, el: bs4.Tag) -> str: """Get tag namespace.""" if self.supports_namespaces(): @@ -478,24 +540,24 @@ def get_tag_ns(self, el): namespace = NS_XHTML return namespace - def is_html_tag(self, el): + def is_html_tag(self, el: bs4.Tag) -> bool: """Check if tag is in HTML namespace.""" return self.get_tag_ns(el) == NS_XHTML - def get_tag(self, el): + def get_tag(self, el: bs4.Tag) -> str | None: """Get tag.""" name = self.get_tag_name(el) return util.lower(name) if name is not None and not self.is_xml else name - def get_prefix(self, el): + def get_prefix(self, el: bs4.Tag) -> str | None: """Get prefix.""" prefix = self.get_prefix_name(el) return util.lower(prefix) if prefix is not None and not self.is_xml else prefix - def find_bidi(self, el): + def find_bidi(self, el: bs4.Tag) -> int | None: """Get directionality from element text.""" for node in self.get_children(el, tags=False): @@ -506,9 +568,9 @@ def find_bidi(self, el): # Avoid analyzing certain elements specified in the specification. direction = DIR_MAP.get(util.lower(self.get_attribute_by_name(node, 'dir', '')), None) if ( - self.get_tag(node) in ('bdi', 'script', 'style', 'textarea', 'iframe') - or not self.is_html_tag(node) - or direction is not None + self.get_tag(node) in ('bdi', 'script', 'style', 'textarea', 'iframe') or + not self.is_html_tag(node) or + direction is not None ): continue # pragma: no cover @@ -531,7 +593,7 @@ def find_bidi(self, el): return ct.SEL_DIR_LTR if bidi == 'L' else ct.SEL_DIR_RTL return None - def extended_language_filter(self, lang_range, lang_tag): + def extended_language_filter(self, lang_range: str, lang_tag: str) -> bool: """Filter the language tags.""" match = True @@ -539,13 +601,18 @@ def extended_language_filter(self, lang_range, lang_tag): ranges = lang_range.split('-') subtags = lang_tag.lower().split('-') length = len(ranges) + slength = len(subtags) rindex = 0 sindex = 0 r = ranges[rindex] s = subtags[sindex] + # Empty specified language should match unspecified language attributes + if length == 1 and slength == 1 and not r and r == s: + return True + # Primary tag needs to match - if r != '*' and r != s: + if (r != '*' and r != s) or (r == '*' and slength == 1 and not s): match = False rindex += 1 @@ -582,7 +649,12 @@ def extended_language_filter(self, lang_range, lang_tag): return match - def match_attribute_name(self, el, attr, prefix): + def match_attribute_name( + self, + el: bs4.Tag, + attr: str, + prefix: str | None + ) -> str | Sequence[str] | None: """Match attribute name and return value if it exists.""" value = None @@ -630,13 +702,13 @@ def match_attribute_name(self, el, attr, prefix): break return value - def match_namespace(self, el, tag): + def match_namespace(self, el: bs4.Tag, tag: ct.SelectorTag) -> bool: """Match the namespace of the element.""" match = True namespace = self.get_tag_ns(el) default_namespace = self.namespaces.get('') - tag_ns = '' if tag.prefix is None else self.namespaces.get(tag.prefix, None) + tag_ns = '' if tag.prefix is None else self.namespaces.get(tag.prefix) # We must match the default namespace if one is not provided if tag.prefix is None and (default_namespace is not None and namespace != default_namespace): match = False @@ -645,42 +717,41 @@ def match_namespace(self, el, tag): match = False # Verify prefix matches elif ( - tag.prefix - and tag.prefix != '*' and (tag_ns is None or namespace != tag_ns) + tag.prefix and + tag.prefix != '*' and (tag_ns is None or namespace != tag_ns) ): match = False return match - def match_attributes(self, el, attributes): + def match_attributes(self, el: bs4.Tag, attributes: tuple[ct.SelectorAttribute, ...]) -> bool: """Match attributes.""" match = True if attributes: for a in attributes: - value = self.match_attribute_name(el, a.attribute, a.prefix) + temp = self.match_attribute_name(el, a.attribute, a.prefix) pattern = a.xml_type_pattern if self.is_xml and a.xml_type_pattern else a.pattern - if isinstance(value, list): - value = ' '.join(value) - if value is None: + if temp is None: match = False break - elif pattern is None: + value = temp if isinstance(temp, str) else ' '.join(temp) + if pattern is None: continue elif pattern.match(value) is None: match = False break return match - def match_tagname(self, el, tag): + def match_tagname(self, el: bs4.Tag, tag: ct.SelectorTag) -> bool: """Match tag name.""" name = (util.lower(tag.name) if not self.is_xml and tag.name is not None else tag.name) return not ( - name is not None - and name not in (self.get_tag(el), '*') + name is not None and + name not in (self.get_tag(el), '*') ) - def match_tag(self, el, tag): + def match_tag(self, el: bs4.Tag, tag: ct.SelectorTag | None) -> bool: """Match the tag.""" match = True @@ -692,10 +763,14 @@ def match_tag(self, el, tag): match = False return match - def match_past_relations(self, el, relation): + def match_past_relations(self, el: bs4.Tag, relation: ct.SelectorList) -> bool: """Match past relationship.""" found = False + # I don't think this can ever happen, but it makes `mypy` happy + if isinstance(relation[0], ct.SelectorNull): # pragma: no cover + return found + if relation[0].rel_type == REL_PARENT: parent = self.get_parent(el, no_iframe=self.iframe_restrict) while not found and parent: @@ -716,21 +791,28 @@ def match_past_relations(self, el, relation): found = self.match_selectors(sibling, relation) return found - def match_future_child(self, parent, relation, recursive=False): + def match_future_child(self, parent: bs4.Tag, relation: ct.SelectorList, recursive: bool = False) -> bool: """Match future child.""" match = False - children = self.get_descendants if recursive else self.get_children + if recursive: + children = self.get_descendants # type: Callable[..., Iterator[bs4.Tag]] + else: + children = self.get_children for child in children(parent, no_iframe=self.iframe_restrict): match = self.match_selectors(child, relation) if match: break return match - def match_future_relations(self, el, relation): + def match_future_relations(self, el: bs4.Tag, relation: ct.SelectorList) -> bool: """Match future relationship.""" found = False + # I don't think this can ever happen, but it makes `mypy` happy + if isinstance(relation[0], ct.SelectorNull): # pragma: no cover + return found + if relation[0].rel_type == REL_HAS_PARENT: found = self.match_future_child(el, relation, True) elif relation[0].rel_type == REL_HAS_CLOSE_PARENT: @@ -746,11 +828,14 @@ def match_future_relations(self, el, relation): found = self.match_selectors(sibling, relation) return found - def match_relations(self, el, relation): + def match_relations(self, el: bs4.Tag, relation: ct.SelectorList) -> bool: """Match relationship to other elements.""" found = False + if isinstance(relation[0], ct.SelectorNull) or relation[0].rel_type is None: + return found + if relation[0].rel_type.startswith(':'): found = self.match_future_relations(el, relation) else: @@ -758,7 +843,7 @@ def match_relations(self, el, relation): return found - def match_id(self, el, ids): + def match_id(self, el: bs4.Tag, ids: tuple[str, ...]) -> bool: """Match element's ID.""" found = True @@ -768,7 +853,7 @@ def match_id(self, el, ids): break return found - def match_classes(self, el, classes): + def match_classes(self, el: bs4.Tag, classes: tuple[str, ...]) -> bool: """Match element's classes.""" current_classes = self.get_classes(el) @@ -779,7 +864,7 @@ def match_classes(self, el, classes): break return found - def match_root(self, el): + def match_root(self, el: bs4.Tag) -> bool: """Match element as root.""" is_root = self.is_root(el) @@ -787,8 +872,8 @@ def match_root(self, el): sibling = self.get_previous(el, tags=False) while is_root and sibling is not None: if ( - self.is_tag(sibling) or (self.is_content_string(sibling) and sibling.strip()) - or self.is_cdata(sibling) + self.is_tag(sibling) or (self.is_content_string(sibling) and sibling.strip()) or + self.is_cdata(sibling) ): is_root = False else: @@ -797,28 +882,28 @@ def match_root(self, el): sibling = self.get_next(el, tags=False) while is_root and sibling is not None: if ( - self.is_tag(sibling) or (self.is_content_string(sibling) and sibling.strip()) - or self.is_cdata(sibling) + self.is_tag(sibling) or (self.is_content_string(sibling) and sibling.strip()) or + self.is_cdata(sibling) ): is_root = False else: sibling = self.get_next(sibling, tags=False) return is_root - def match_scope(self, el): + def match_scope(self, el: bs4.Tag) -> bool: """Match element as scope.""" return self.scope is el - def match_nth_tag_type(self, el, child): + def match_nth_tag_type(self, el: bs4.Tag, child: bs4.Tag) -> bool: """Match tag type for `nth` matches.""" - return( - (self.get_tag(child) == self.get_tag(el)) - and (self.get_tag_ns(child) == self.get_tag_ns(el)) + return ( + (self.get_tag(child) == self.get_tag(el)) and + (self.get_tag_ns(child) == self.get_tag_ns(el)) ) - def match_nth(self, el, nth): + def match_nth(self, el: bs4.Tag, nth: bs4.Tag) -> bool: """Match `nth` elements.""" matched = True @@ -919,7 +1004,7 @@ def match_nth(self, el, nth): break return matched - def match_empty(self, el): + def match_empty(self, el: bs4.Tag) -> bool: """Check if element is empty (if requested).""" is_empty = True @@ -932,7 +1017,7 @@ def match_empty(self, el): break return is_empty - def match_subselectors(self, el, selectors): + def match_subselectors(self, el: bs4.Tag, selectors: tuple[ct.SelectorList, ...]) -> bool: """Match selectors.""" match = True @@ -941,11 +1026,11 @@ def match_subselectors(self, el, selectors): match = False return match - def match_contains(self, el, contains): + def match_contains(self, el: bs4.Tag, contains: tuple[ct.SelectorContains, ...]) -> bool: """Match element if it contains text.""" match = True - content = None + content = None # type: str | Sequence[str] | None for contain_list in contains: if content is None: if contain_list.own: @@ -969,7 +1054,7 @@ def match_contains(self, el, contains): match = False return match - def match_default(self, el): + def match_default(self, el: bs4.Tag) -> bool: """Match default.""" match = False @@ -1002,19 +1087,19 @@ def match_default(self, el): if name in ('input', 'button'): v = self.get_attribute_by_name(child, 'type', '') if v and util.lower(v) == 'submit': - self.cached_default_forms.append([form, child]) + self.cached_default_forms.append((form, child)) if el is child: match = True break return match - def match_indeterminate(self, el): + def match_indeterminate(self, el: bs4.Tag) -> bool: """Match default.""" match = False - name = self.get_attribute_by_name(el, 'name') + name = cast(str, self.get_attribute_by_name(el, 'name')) - def get_parent_form(el): + def get_parent_form(el: bs4.Tag) -> bs4.Tag | None: """Find this input's form.""" form = None parent = self.get_parent(el, no_iframe=True) @@ -1065,11 +1150,11 @@ def get_parent_form(el): break if not checked: match = True - self.cached_indeterminate_forms.append([form, name, match]) + self.cached_indeterminate_forms.append((form, name, match)) return match - def match_lang(self, el, langs): + def match_lang(self, el: bs4.Tag, langs: tuple[ct.SelectorLang, ...]) -> bool: """Match languages.""" match = False @@ -1086,10 +1171,10 @@ def match_lang(self, el, langs): for k, v in self.iter_attributes(parent): attr_ns, attr = self.split_namespace(parent, k) if ( - ((not has_ns or has_html_ns) and (util.lower(k) if not self.is_xml else k) == 'lang') - or ( - has_ns and not has_html_ns and attr_ns == NS_XML - and (util.lower(attr) if not self.is_xml and attr is not None else attr) == 'lang' + ((not has_ns or has_html_ns) and (util.lower(k) if not self.is_xml else k) == 'lang') or + ( + has_ns and not has_html_ns and attr_ns == NS_XML and + (util.lower(attr) if not self.is_xml and attr is not None else attr) == 'lang' ) ): found_lang = v @@ -1104,7 +1189,7 @@ def match_lang(self, el, langs): break # Use cached meta language. - if not found_lang and self.cached_meta_lang: + if found_lang is None and self.cached_meta_lang: for cache in self.cached_meta_lang: if root is cache[0]: found_lang = cache[1] @@ -1136,26 +1221,26 @@ def match_lang(self, el, langs): content = v if c_lang and content: found_lang = content - self.cached_meta_lang.append((root, found_lang)) + self.cached_meta_lang.append((cast(str, root), cast(str, found_lang))) break - if found_lang: + if found_lang is not None: break - if not found_lang: - self.cached_meta_lang.append((root, False)) + if found_lang is None: + self.cached_meta_lang.append((cast(str, root), '')) # If we determined a language, compare. - if found_lang: + if found_lang is not None: for patterns in langs: match = False for pattern in patterns: - if self.extended_language_filter(pattern, found_lang): + if self.extended_language_filter(pattern, cast(str, found_lang)): match = True if not match: break return match - def match_dir(self, el, directionality): + def match_dir(self, el: bs4.Tag, directionality: int) -> bool: """Check directionality.""" # If we have to match both left and right, we can't match either. @@ -1187,13 +1272,13 @@ def match_dir(self, el, directionality): # Auto handling for text inputs if ((is_input and itype in ('text', 'search', 'tel', 'url', 'email')) or is_textarea) and direction == 0: if is_textarea: - value = [] + temp = [] for node in self.get_contents(el, no_iframe=True): if self.is_content_string(node): - value.append(node) - value = ''.join(value) + temp.append(node) + value = ''.join(temp) else: - value = self.get_attribute_by_name(el, 'value', '') + value = cast(str, self.get_attribute_by_name(el, 'value', '')) if value: for c in value: bidi = unicodedata.bidirectional(c) @@ -1218,7 +1303,7 @@ def match_dir(self, el, directionality): # Match parents direction return self.match_dir(self.get_parent(el, no_iframe=True), directionality) - def match_range(self, el, condition): + def match_range(self, el: bs4.Tag, condition: int) -> bool: """ Match range. @@ -1231,20 +1316,14 @@ def match_range(self, el, condition): out_of_range = False itype = util.lower(self.get_attribute_by_name(el, 'type')) - mn = self.get_attribute_by_name(el, 'min', None) - if mn is not None: - mn = Inputs.parse_value(itype, mn) - mx = self.get_attribute_by_name(el, 'max', None) - if mx is not None: - mx = Inputs.parse_value(itype, mx) + mn = Inputs.parse_value(itype, cast(str, self.get_attribute_by_name(el, 'min', None))) + mx = Inputs.parse_value(itype, cast(str, self.get_attribute_by_name(el, 'max', None))) # There is no valid min or max, so we cannot evaluate a range if mn is None and mx is None: return False - value = self.get_attribute_by_name(el, 'value', None) - if value is not None: - value = Inputs.parse_value(itype, value) + value = Inputs.parse_value(itype, cast(str, self.get_attribute_by_name(el, 'value', None))) if value is not None: if itype in ("date", "datetime-local", "month", "week", "number", "range"): if mn is not None and value < mn: @@ -1264,7 +1343,7 @@ def match_range(self, el, condition): return not out_of_range if condition & ct.SEL_IN_RANGE else out_of_range - def match_defined(self, el): + def match_defined(self, el: bs4.Tag) -> bool: """ Match defined. @@ -1280,12 +1359,14 @@ def match_defined(self, el): name = self.get_tag(el) return ( - name.find('-') == -1 - or name.find(':') != -1 - or self.get_prefix(el) is not None + name is not None and ( + name.find('-') == -1 or + name.find(':') != -1 or + self.get_prefix(el) is not None + ) ) - def match_placeholder_shown(self, el): + def match_placeholder_shown(self, el: bs4.Tag) -> bool: """ Match placeholder shown according to HTML spec. @@ -1300,7 +1381,7 @@ def match_placeholder_shown(self, el): return match - def match_selectors(self, el, selectors): + def match_selectors(self, el: bs4.Tag, selectors: ct.SelectorList) -> bool: """Check if element matches one of the selectors.""" match = False @@ -1372,7 +1453,7 @@ def match_selectors(self, el, selectors): if selector.flags & DIR_FLAGS and not self.match_dir(el, selector.flags & DIR_FLAGS): continue # Validate that the tag contains the specified text. - if not self.match_contains(el, selector.contains): + if selector.contains and not self.match_contains(el, selector.contains): continue match = not is_not break @@ -1384,21 +1465,20 @@ def match_selectors(self, el, selectors): return match - def select(self, limit=0): + def select(self, limit: int = 0) -> Iterator[bs4.Tag]: """Match all tags under the targeted tag.""" - if limit < 1: - limit = None + lim = None if limit < 1 else limit for child in self.get_descendants(self.tag): if self.match(child): yield child - if limit is not None: - limit -= 1 - if limit < 1: + if lim is not None: + lim -= 1 + if lim < 1: break - def closest(self): + def closest(self) -> bs4.Tag | None: """Match closest ancestor.""" current = self.tag @@ -1410,30 +1490,39 @@ def closest(self): current = self.get_parent(current) return closest - def filter(self): # noqa A001 + def filter(self) -> list[bs4.Tag]: # noqa A001 """Filter tag's children.""" return [tag for tag in self.get_contents(self.tag) if not self.is_navigable_string(tag) and self.match(tag)] - def match(self, el): + def match(self, el: bs4.Tag) -> bool: """Match.""" return not self.is_doc(el) and self.is_tag(el) and self.match_selectors(el, self.selectors) -class CSSMatch(_DocumentNav, _Match): - """The Beautiful Soup CSS match class.""" - - class SoupSieve(ct.Immutable): """Compiled Soup Sieve selector matching object.""" + pattern: str + selectors: ct.SelectorList + namespaces: ct.Namespaces | None + custom: dict[str, str] + flags: int + __slots__ = ("pattern", "selectors", "namespaces", "custom", "flags", "_hash") - def __init__(self, pattern, selectors, namespaces, custom, flags): + def __init__( + self, + pattern: str, + selectors: ct.SelectorList, + namespaces: ct.Namespaces | None, + custom: ct.CustomSelectors | None, + flags: int + ): """Initialize.""" - super(SoupSieve, self).__init__( + super().__init__( pattern=pattern, selectors=selectors, namespaces=namespaces, @@ -1441,17 +1530,17 @@ def __init__(self, pattern, selectors, namespaces, custom, flags): flags=flags ) - def match(self, tag): + def match(self, tag: bs4.Tag) -> bool: """Match.""" return CSSMatch(self.selectors, tag, self.namespaces, self.flags).match(tag) - def closest(self, tag): + def closest(self, tag: bs4.Tag) -> bs4.Tag: """Match closest ancestor.""" return CSSMatch(self.selectors, tag, self.namespaces, self.flags).closest() - def filter(self, iterable): # noqa A001 + def filter(self, iterable: Iterable[bs4.Tag]) -> list[bs4.Tag]: # noqa A001 """ Filter. @@ -1468,24 +1557,24 @@ def filter(self, iterable): # noqa A001 else: return [node for node in iterable if not CSSMatch.is_navigable_string(node) and self.match(node)] - def select_one(self, tag): + def select_one(self, tag: bs4.Tag) -> bs4.Tag: """Select a single tag.""" tags = self.select(tag, limit=1) return tags[0] if tags else None - def select(self, tag, limit=0): + def select(self, tag: bs4.Tag, limit: int = 0) -> list[bs4.Tag]: """Select the specified tags.""" return list(self.iselect(tag, limit)) - def iselect(self, tag, limit=0): + def iselect(self, tag: bs4.Tag, limit: int = 0) -> Iterator[bs4.Tag]: """Iterate the specified tags.""" for el in CSSMatch(self.selectors, tag, self.namespaces, self.flags).select(limit): yield el - def __repr__(self): # pragma: no cover + def __repr__(self) -> str: # pragma: no cover """Representation.""" return "SoupSieve(pattern={!r}, namespaces={!r}, custom={!r}, flags={!r})".format( diff --git a/script.module.soupsieve/lib/soupsieve/css_parser.py b/script.module.soupsieve/lib/soupsieve/css_parser.py index 0c62b25dd..10ac6f21b 100644 --- a/script.module.soupsieve/lib/soupsieve/css_parser.py +++ b/script.module.soupsieve/lib/soupsieve/css_parser.py @@ -1,4 +1,5 @@ """CSS selector parser.""" +from __future__ import annotations import re from functools import lru_cache from . import util @@ -6,6 +7,7 @@ from . import css_types as ct from .util import SelectorSyntaxError import warnings +from typing import Match, Any, Iterator, cast UNICODE_REPLACEMENT_CHAR = 0xFFFD @@ -111,7 +113,7 @@ '''.format(nl=NEWLINE, ident=IDENTIFIER) # Attribute value comparison. `!=` is handled special as it is non-standard. ATTR = r''' -(?:{ws}*(?P[!~^|*$]?=){ws}*(?P{value})(?:{ws}+(?P[is]))?)?{ws}*\] +(?:{ws}*(?P[!~^|*$]?=){ws}*(?P{value})(?:{ws}*(?P[is]))?)?{ws}*\] '''.format(ws=WSC, value=VALUE) # Selector patterns @@ -196,32 +198,42 @@ FLG_IN_RANGE = 0x80 FLG_OUT_OF_RANGE = 0x100 FLG_PLACEHOLDER_SHOWN = 0x200 +FLG_FORGIVE = 0x400 # Maximum cached patterns to store _MAXCACHE = 500 @lru_cache(maxsize=_MAXCACHE) -def _cached_css_compile(pattern, namespaces, custom, flags): +def _cached_css_compile( + pattern: str, + namespaces: ct.Namespaces | None, + custom: ct.CustomSelectors | None, + flags: int +) -> cm.SoupSieve: """Cached CSS compile.""" custom_selectors = process_custom(custom) return cm.SoupSieve( pattern, - CSSParser(pattern, custom=custom_selectors, flags=flags).process_selectors(), + CSSParser( + pattern, + custom=custom_selectors, + flags=flags + ).process_selectors(), namespaces, custom, flags ) -def _purge_cache(): +def _purge_cache() -> None: """Purge the cache.""" _cached_css_compile.cache_clear() -def process_custom(custom): +def process_custom(custom: ct.CustomSelectors | None) -> dict[str, str | ct.SelectorList]: """Process custom.""" custom_selectors = {} @@ -236,14 +248,14 @@ def process_custom(custom): return custom_selectors -def css_unescape(content, string=False): +def css_unescape(content: str, string: bool = False) -> str: """ Unescape CSS value. Strings allow for spanning the value on multiple strings by escaping a new line. """ - def replace(m): + def replace(m: Match[str]) -> str: """Replace with the appropriate substitute.""" if m.group(1): @@ -263,7 +275,7 @@ def replace(m): return (RE_CSS_ESC if not string else RE_CSS_STR_ESC).sub(replace, content) -def escape(ident): +def escape(ident: str) -> str: """Escape identifier.""" string = [] @@ -282,8 +294,8 @@ def escape(ident): elif (index == 0 or (start_dash and index == 1)) and (0x30 <= codepoint <= 0x39): string.append('\\{:x} '.format(codepoint)) elif ( - codepoint in (0x2D, 0x5F) or codepoint >= 0x80 or (0x30 <= codepoint <= 0x39) - or (0x30 <= codepoint <= 0x39) or (0x41 <= codepoint <= 0x5A) or (0x61 <= codepoint <= 0x7A) + codepoint in (0x2D, 0x5F) or codepoint >= 0x80 or (0x30 <= codepoint <= 0x39) or + (0x30 <= codepoint <= 0x39) or (0x41 <= codepoint <= 0x5A) or (0x61 <= codepoint <= 0x7A) ): string.append(c) else: @@ -291,21 +303,21 @@ def escape(ident): return ''.join(string) -class SelectorPattern(object): +class SelectorPattern: """Selector pattern.""" - def __init__(self, name, pattern): + def __init__(self, name: str, pattern: str) -> None: """Initialize.""" self.name = name self.re_pattern = re.compile(pattern, re.I | re.X | re.U) - def get_name(self): + def get_name(self) -> str: """Get name.""" return self.name - def match(self, selector, index, flags): + def match(self, selector: str, index: int, flags: int) -> Match[str] | None: """Match the selector.""" return self.re_pattern.match(selector, index) @@ -314,7 +326,7 @@ def match(self, selector, index, flags): class SpecialPseudoPattern(SelectorPattern): """Selector pattern.""" - def __init__(self, patterns): + def __init__(self, patterns: tuple[tuple[str, tuple[str, ...], str, type[SelectorPattern]], ...]) -> None: """Initialize.""" self.patterns = {} @@ -324,15 +336,15 @@ def __init__(self, patterns): for pseudo in p[1]: self.patterns[pseudo] = pattern - self.matched_name = None + self.matched_name = None # type: SelectorPattern | None self.re_pseudo_name = re.compile(PAT_PSEUDO_CLASS_SPECIAL, re.I | re.X | re.U) - def get_name(self): + def get_name(self) -> str: """Get name.""" - return self.matched_name.get_name() + return '' if self.matched_name is None else self.matched_name.get_name() - def match(self, selector, index, flags): + def match(self, selector: str, index: int, flags: int) -> Match[str] | None: """Match the selector.""" pseudo = None @@ -348,7 +360,7 @@ def match(self, selector, index, flags): return pseudo -class _Selector(object): +class _Selector: """ Intermediate selector class. @@ -357,23 +369,23 @@ class _Selector(object): the data in an object that can be pickled and hashed. """ - def __init__(self, **kwargs): + def __init__(self, **kwargs: Any) -> None: """Initialize.""" - self.tag = kwargs.get('tag', None) - self.ids = kwargs.get('ids', []) - self.classes = kwargs.get('classes', []) - self.attributes = kwargs.get('attributes', []) - self.nth = kwargs.get('nth', []) - self.selectors = kwargs.get('selectors', []) - self.relations = kwargs.get('relations', []) - self.rel_type = kwargs.get('rel_type', None) - self.contains = kwargs.get('contains', []) - self.lang = kwargs.get('lang', []) - self.flags = kwargs.get('flags', 0) - self.no_match = kwargs.get('no_match', False) - - def _freeze_relations(self, relations): + self.tag = kwargs.get('tag', None) # type: ct.SelectorTag | None + self.ids = kwargs.get('ids', []) # type: list[str] + self.classes = kwargs.get('classes', []) # type: list[str] + self.attributes = kwargs.get('attributes', []) # type: list[ct.SelectorAttribute] + self.nth = kwargs.get('nth', []) # type: list[ct.SelectorNth] + self.selectors = kwargs.get('selectors', []) # type: list[ct.SelectorList] + self.relations = kwargs.get('relations', []) # type: list[_Selector] + self.rel_type = kwargs.get('rel_type', None) # type: str | None + self.contains = kwargs.get('contains', []) # type: list[ct.SelectorContains] + self.lang = kwargs.get('lang', []) # type: list[ct.SelectorLang] + self.flags = kwargs.get('flags', 0) # type: int + self.no_match = kwargs.get('no_match', False) # type: bool + + def _freeze_relations(self, relations: list[_Selector]) -> ct.SelectorList: """Freeze relation.""" if relations: @@ -383,7 +395,7 @@ def _freeze_relations(self, relations): else: return ct.SelectorList() - def freeze(self): + def freeze(self) -> ct.Selector | ct.SelectorNull: """Freeze self.""" if self.no_match: @@ -403,7 +415,7 @@ def freeze(self): self.flags ) - def __str__(self): # pragma: no cover + def __str__(self) -> str: # pragma: no cover """String representation.""" return ( @@ -417,7 +429,7 @@ def __str__(self): # pragma: no cover __repr__ = __str__ -class CSSParser(object): +class CSSParser: """Parse CSS selectors.""" css_tokens = ( @@ -447,7 +459,12 @@ class CSSParser(object): SelectorPattern("combine", PAT_COMBINE) ) - def __init__(self, selector, custom=None, flags=0): + def __init__( + self, + selector: str, + custom: dict[str, str | ct.SelectorList] | None = None, + flags: int = 0 + ) -> None: """Initialize.""" self.pattern = selector.replace('\x00', '\ufffd') @@ -455,7 +472,7 @@ def __init__(self, selector, custom=None, flags=0): self.debug = self.flags & util.DEBUG self.custom = {} if custom is None else custom - def parse_attribute_selector(self, sel, m, has_selector): + def parse_attribute_selector(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool: """Create attribute selector from the returned regex match.""" inverse = False @@ -465,22 +482,22 @@ def parse_attribute_selector(self, sel, m, has_selector): attr = css_unescape(m.group('attr_name')) is_type = False pattern2 = None + value = '' if case: - flags = re.I if case == 'i' else 0 + flags = (re.I if case == 'i' else 0) | re.DOTALL elif util.lower(attr) == 'type': - flags = re.I + flags = re.I | re.DOTALL is_type = True else: - flags = 0 + flags = re.DOTALL if op: if m.group('value').startswith(('"', "'")): value = css_unescape(m.group('value')[1:-1], True) else: value = css_unescape(m.group('value')) - else: - value = None + if not op: # Attribute name pattern = None @@ -525,7 +542,7 @@ def parse_attribute_selector(self, sel, m, has_selector): has_selector = True return has_selector - def parse_tag_pattern(self, sel, m, has_selector): + def parse_tag_pattern(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool: """Parse tag pattern from regex match.""" prefix = css_unescape(m.group('tag_ns')[:-1]) if m.group('tag_ns') else None @@ -534,7 +551,7 @@ def parse_tag_pattern(self, sel, m, has_selector): has_selector = True return has_selector - def parse_pseudo_class_custom(self, sel, m, has_selector): + def parse_pseudo_class_custom(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool: """ Parse custom pseudo class alias. @@ -546,13 +563,13 @@ def parse_pseudo_class_custom(self, sel, m, has_selector): selector = self.custom.get(pseudo) if selector is None: raise SelectorSyntaxError( - "Undefined custom selector '{}' found at postion {}".format(pseudo, m.end(0)), + "Undefined custom selector '{}' found at position {}".format(pseudo, m.end(0)), self.pattern, m.end(0) ) if not isinstance(selector, ct.SelectorList): - self.custom[pseudo] = None + del self.custom[pseudo] selector = CSSParser( selector, custom=self.custom, flags=self.flags ).process_selectors(flags=FLG_PSEUDO) @@ -562,7 +579,14 @@ def parse_pseudo_class_custom(self, sel, m, has_selector): has_selector = True return has_selector - def parse_pseudo_class(self, sel, m, has_selector, iselector, is_html): + def parse_pseudo_class( + self, + sel: _Selector, + m: Match[str], + has_selector: bool, + iselector: Iterator[tuple[str, Match[str]]], + is_html: bool + ) -> tuple[bool, bool]: """Parse pseudo class.""" complex_pseudo = False @@ -650,7 +674,13 @@ def parse_pseudo_class(self, sel, m, has_selector, iselector, is_html): return has_selector, is_html - def parse_pseudo_nth(self, sel, m, has_selector, iselector): + def parse_pseudo_nth( + self, + sel: _Selector, + m: Match[str], + has_selector: bool, + iselector: Iterator[tuple[str, Match[str]]] + ) -> bool: """Parse `nth` pseudo.""" mdict = m.groupdict() @@ -671,23 +701,23 @@ def parse_pseudo_nth(self, sel, m, has_selector, iselector): s2 = 1 var = True else: - nth_parts = RE_NTH.match(content) - s1 = '-' if nth_parts.group('s1') and nth_parts.group('s1') == '-' else '' + nth_parts = cast(Match[str], RE_NTH.match(content)) + _s1 = '-' if nth_parts.group('s1') and nth_parts.group('s1') == '-' else '' a = nth_parts.group('a') var = a.endswith('n') if a.startswith('n'): - s1 += '1' + _s1 += '1' elif var: - s1 += a[:-1] + _s1 += a[:-1] else: - s1 += a - s2 = '-' if nth_parts.group('s2') and nth_parts.group('s2') == '-' else '' + _s1 += a + _s2 = '-' if nth_parts.group('s2') and nth_parts.group('s2') == '-' else '' if nth_parts.group('b'): - s2 += nth_parts.group('b') + _s2 += nth_parts.group('b') else: - s2 = '0' - s1 = int(s1, 10) - s2 = int(s2, 10) + _s2 = '0' + s1 = int(_s1, 10) + s2 = int(_s2, 10) pseudo_sel = mdict['name'] if postfix == '_child': @@ -709,34 +739,44 @@ def parse_pseudo_nth(self, sel, m, has_selector, iselector): has_selector = True return has_selector - def parse_pseudo_open(self, sel, name, has_selector, iselector, index): + def parse_pseudo_open( + self, + sel: _Selector, + name: str, + has_selector: bool, + iselector: Iterator[tuple[str, Match[str]]], + index: int + ) -> bool: """Parse pseudo with opening bracket.""" flags = FLG_PSEUDO | FLG_OPEN if name == ':not': flags |= FLG_NOT - if name == ':has': + elif name == ':has': flags |= FLG_RELATIVE + elif name in (':where', ':is'): + flags |= FLG_FORGIVE sel.selectors.append(self.parse_selectors(iselector, index, flags)) has_selector = True + return has_selector - def parse_has_combinator(self, sel, m, has_selector, selectors, rel_type, index): + def parse_has_combinator( + self, + sel: _Selector, + m: Match[str], + has_selector: bool, + selectors: list[_Selector], + rel_type: str, + index: int + ) -> tuple[bool, _Selector, str]: """Parse combinator tokens.""" combinator = m.group('relation').strip() if not combinator: combinator = WS_COMBINATOR if combinator == COMMA_COMBINATOR: - if not has_selector: - # If we've not captured any selector parts, the comma is either at the beginning of the pattern - # or following another comma, both of which are unexpected. Commas must split selectors. - raise SelectorSyntaxError( - "The combinator '{}' at postion {}, must have a selector before it".format(combinator, index), - self.pattern, - index - ) sel.rel_type = rel_type selectors[-1].relations.append(sel) rel_type = ":" + WS_COMBINATOR @@ -757,44 +797,63 @@ def parse_has_combinator(self, sel, m, has_selector, selectors, rel_type, index) self.pattern, index ) + # Set the leading combinator for the next selector. rel_type = ':' + combinator - sel = _Selector() + sel = _Selector() has_selector = False return has_selector, sel, rel_type - def parse_combinator(self, sel, m, has_selector, selectors, relations, is_pseudo, index): + def parse_combinator( + self, + sel: _Selector, + m: Match[str], + has_selector: bool, + selectors: list[_Selector], + relations: list[_Selector], + is_pseudo: bool, + is_forgive: bool, + index: int + ) -> tuple[bool, _Selector]: """Parse combinator tokens.""" combinator = m.group('relation').strip() if not combinator: combinator = WS_COMBINATOR if not has_selector: - raise SelectorSyntaxError( - "The combinator '{}' at postion {}, must have a selector before it".format(combinator, index), - self.pattern, - index - ) + if not is_forgive or combinator != COMMA_COMBINATOR: + raise SelectorSyntaxError( + "The combinator '{}' at position {}, must have a selector before it".format(combinator, index), + self.pattern, + index + ) - if combinator == COMMA_COMBINATOR: - if not sel.tag and not is_pseudo: - # Implied `*` - sel.tag = ct.SelectorTag('*', None) - sel.relations.extend(relations) - selectors.append(sel) - del relations[:] + # If we are in a forgiving pseudo class, just make the selector a "no match" + if combinator == COMMA_COMBINATOR: + sel.no_match = True + del relations[:] + selectors.append(sel) else: - sel.relations.extend(relations) - sel.rel_type = combinator - del relations[:] - relations.append(sel) - sel = _Selector() + if combinator == COMMA_COMBINATOR: + if not sel.tag and not is_pseudo: + # Implied `*` + sel.tag = ct.SelectorTag('*', None) + sel.relations.extend(relations) + selectors.append(sel) + del relations[:] + else: + sel.relations.extend(relations) + sel.rel_type = combinator + del relations[:] + relations.append(sel) + sel = _Selector() has_selector = False + return has_selector, sel - def parse_class_id(self, sel, m, has_selector): + def parse_class_id(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool: """Parse HTML classes and ids.""" selector = m.group(0) @@ -805,7 +864,7 @@ def parse_class_id(self, sel, m, has_selector): has_selector = True return has_selector - def parse_pseudo_contains(self, sel, m, has_selector): + def parse_pseudo_contains(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool: """Parse contains.""" pseudo = util.lower(css_unescape(m.group('name'))) @@ -826,11 +885,11 @@ def parse_pseudo_contains(self, sel, m, has_selector): else: value = css_unescape(value) patterns.append(value) - sel.contains.append(ct.SelectorContains(tuple(patterns), contains_own)) + sel.contains.append(ct.SelectorContains(patterns, contains_own)) has_selector = True return has_selector - def parse_pseudo_lang(self, sel, m, has_selector): + def parse_pseudo_lang(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool: """Parse pseudo language.""" values = m.group('values') @@ -851,7 +910,7 @@ def parse_pseudo_lang(self, sel, m, has_selector): return has_selector - def parse_pseudo_dir(self, sel, m, has_selector): + def parse_pseudo_dir(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool: """Parse pseudo direction.""" value = ct.SEL_DIR_LTR if util.lower(m.group('dir')) == 'ltr' else ct.SEL_DIR_RTL @@ -859,15 +918,23 @@ def parse_pseudo_dir(self, sel, m, has_selector): has_selector = True return has_selector - def parse_selectors(self, iselector, index=0, flags=0): + def parse_selectors( + self, + iselector: Iterator[tuple[str, Match[str]]], + index: int = 0, + flags: int = 0 + ) -> ct.SelectorList: """Parse selectors.""" + # Initialize important variables sel = _Selector() selectors = [] has_selector = False closed = False - relations = [] + relations = [] # type: list[_Selector] rel_type = ":" + WS_COMBINATOR + + # Setup various flags is_open = bool(flags & FLG_OPEN) is_pseudo = bool(flags & FLG_PSEUDO) is_relative = bool(flags & FLG_RELATIVE) @@ -878,7 +945,9 @@ def parse_selectors(self, iselector, index=0, flags=0): is_in_range = bool(flags & FLG_IN_RANGE) is_out_of_range = bool(flags & FLG_OUT_OF_RANGE) is_placeholder_shown = bool(flags & FLG_PLACEHOLDER_SHOWN) + is_forgive = bool(flags & FLG_FORGIVE) + # Print out useful debug stuff if self.debug: # pragma: no cover if is_pseudo: print(' is_pseudo: True') @@ -900,7 +969,10 @@ def parse_selectors(self, iselector, index=0, flags=0): print(' is_out_of_range: True') if is_placeholder_shown: print(' is_placeholder_shown: True') + if is_forgive: + print(' is_forgive: True') + # The algorithm for relative selectors require an initial selector in the selector list if is_relative: selectors.append(_Selector()) @@ -929,17 +1001,19 @@ def parse_selectors(self, iselector, index=0, flags=0): is_html = True elif key == 'pseudo_close': if not has_selector: - raise SelectorSyntaxError( - "Expected a selector at postion {}".format(m.start(0)), - self.pattern, - m.start(0) - ) + if not is_forgive: + raise SelectorSyntaxError( + "Expected a selector at position {}".format(m.start(0)), + self.pattern, + m.start(0) + ) + sel.no_match = True if is_open: closed = True break else: raise SelectorSyntaxError( - "Unmatched pseudo-class close at postion {}".format(m.start(0)), + "Unmatched pseudo-class close at position {}".format(m.start(0)), self.pattern, m.start(0) ) @@ -950,7 +1024,7 @@ def parse_selectors(self, iselector, index=0, flags=0): ) else: has_selector, sel = self.parse_combinator( - sel, m, has_selector, selectors, relations, is_pseudo, index + sel, m, has_selector, selectors, relations, is_pseudo, is_forgive, index ) elif key == 'attribute': has_selector = self.parse_attribute_selector(sel, m, has_selector) @@ -969,6 +1043,7 @@ def parse_selectors(self, iselector, index=0, flags=0): except StopIteration: pass + # Handle selectors that are not closed if is_open and not closed: raise SelectorSyntaxError( "Unclosed pseudo-class at position {}".format(index), @@ -976,6 +1051,7 @@ def parse_selectors(self, iselector, index=0, flags=0): index ) + # Cleanup completed selector piece if has_selector: if not sel.tag and not is_pseudo: # Implied `*` @@ -987,8 +1063,18 @@ def parse_selectors(self, iselector, index=0, flags=0): sel.relations.extend(relations) del relations[:] selectors.append(sel) - else: + + # Forgive empty slots in pseudo-classes that have lists (and are forgiving) + elif is_forgive and (not selectors or not relations): + # Handle normal pseudo-classes with empty slots like `:is()` etc. + sel.no_match = True + del relations[:] + selectors.append(sel) + has_selector = True + + if not has_selector: # We will always need to finish a selector when `:has()` is used as it leads with combining. + # May apply to others as well. raise SelectorSyntaxError( 'Expected a selector at position {}'.format(index), self.pattern, @@ -1009,9 +1095,10 @@ def parse_selectors(self, iselector, index=0, flags=0): if is_placeholder_shown: selectors[-1].flags = ct.SEL_PLACEHOLDER_SHOWN + # Return selector list return ct.SelectorList([s.freeze() for s in selectors], is_not, is_html) - def selector_iter(self, pattern): + def selector_iter(self, pattern: str) -> Iterator[tuple[str, Match[str]]]: """Iterate selector tokens.""" # Ignore whitespace and comments at start and end of pattern @@ -1052,7 +1139,7 @@ def selector_iter(self, pattern): if self.debug: # pragma: no cover print('## END PARSING') - def process_selectors(self, index=0, flags=0): + def process_selectors(self, index: int = 0, flags: int = 0) -> ct.SelectorList: """Process selectors.""" return self.parse_selectors(self.selector_iter(self.pattern), index, flags) @@ -1063,7 +1150,7 @@ def process_selectors(self, index=0, flags=0): # CSS pattern for `:link` and `:any-link` CSS_LINK = CSSParser( - 'html|*:is(a, area, link)[href]' + 'html|*:is(a, area)[href]' ).process_selectors(flags=FLG_PSEUDO | FLG_HTML) # CSS pattern for `:checked` CSS_CHECKED = CSSParser( diff --git a/script.module.soupsieve/lib/soupsieve/css_types.py b/script.module.soupsieve/lib/soupsieve/css_types.py index ffe1bc679..c263bb04d 100644 --- a/script.module.soupsieve/lib/soupsieve/css_types.py +++ b/script.module.soupsieve/lib/soupsieve/css_types.py @@ -1,6 +1,8 @@ """CSS selector structure items.""" +from __future__ import annotations import copyreg -from collections.abc import Hashable, Mapping +from .pretty import pretty +from typing import Any, Iterator, Hashable, Pattern, Iterable, Mapping __all__ = ( 'Selector', @@ -29,12 +31,14 @@ SEL_PLACEHOLDER_SHOWN = 0x400 -class Immutable(object): +class Immutable: """Immutable.""" - __slots__ = ('_hash',) + __slots__: tuple[str, ...] = ('_hash',) - def __init__(self, **kwargs): + _hash: int + + def __init__(self, **kwargs: Any) -> None: """Initialize.""" temp = [] @@ -45,84 +49,95 @@ def __init__(self, **kwargs): super(Immutable, self).__setattr__('_hash', hash(tuple(temp))) @classmethod - def __base__(cls): + def __base__(cls) -> "type[Immutable]": """Get base class.""" return cls - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: """Equal.""" return ( - isinstance(other, self.__base__()) - and all([getattr(other, key) == getattr(self, key) for key in self.__slots__ if key != '_hash']) + isinstance(other, self.__base__()) and + all([getattr(other, key) == getattr(self, key) for key in self.__slots__ if key != '_hash']) ) - def __ne__(self, other): + def __ne__(self, other: Any) -> bool: """Equal.""" return ( - not isinstance(other, self.__base__()) - or any([getattr(other, key) != getattr(self, key) for key in self.__slots__ if key != '_hash']) + not isinstance(other, self.__base__()) or + any([getattr(other, key) != getattr(self, key) for key in self.__slots__ if key != '_hash']) ) - def __hash__(self): + def __hash__(self) -> int: """Hash.""" return self._hash - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: """Prevent mutability.""" raise AttributeError("'{}' is immutable".format(self.__class__.__name__)) - def __repr__(self): # pragma: no cover + def __repr__(self) -> str: # pragma: no cover """Representation.""" return "{}({})".format( - self.__base__(), ', '.join(["{}={!r}".format(k, getattr(self, k)) for k in self.__slots__[:-1]]) + self.__class__.__name__, ', '.join(["{}={!r}".format(k, getattr(self, k)) for k in self.__slots__[:-1]]) ) __str__ = __repr__ + def pretty(self) -> None: # pragma: no cover + """Pretty print.""" + + print(pretty(self)) + -class ImmutableDict(Mapping): +class ImmutableDict(Mapping[Any, Any]): """Hashable, immutable dictionary.""" - def __init__(self, *args, **kwargs): + def __init__( + self, + arg: dict[Any, Any] | Iterable[tuple[Any, Any]] + ) -> None: """Initialize.""" - arg = args[0] if args else kwargs - is_dict = isinstance(arg, dict) - if ( - is_dict and not all([isinstance(v, Hashable) for v in arg.values()]) - or not is_dict and not all([isinstance(k, Hashable) and isinstance(v, Hashable) for k, v in arg]) - ): - raise TypeError('All values must be hashable') - - self._d = dict(*args, **kwargs) + self._validate(arg) + self._d = dict(arg) self._hash = hash(tuple([(type(x), x, type(y), y) for x, y in sorted(self._d.items())])) - def __iter__(self): + def _validate(self, arg: dict[Any, Any] | Iterable[tuple[Any, Any]]) -> None: + """Validate arguments.""" + + if isinstance(arg, dict): + if not all([isinstance(v, Hashable) for v in arg.values()]): + raise TypeError('{} values must be hashable'.format(self.__class__.__name__)) + elif not all([isinstance(k, Hashable) and isinstance(v, Hashable) for k, v in arg]): + raise TypeError('{} values must be hashable'.format(self.__class__.__name__)) + + def __iter__(self) -> Iterator[Any]: """Iterator.""" return iter(self._d) - def __len__(self): + def __len__(self) -> int: """Length.""" return len(self._d) - def __getitem__(self, key): + def __getitem__(self, key: Any) -> Any: """Get item: `namespace['key']`.""" + return self._d[key] - def __hash__(self): + def __hash__(self) -> int: """Hash.""" return self._hash - def __repr__(self): # pragma: no cover + def __repr__(self) -> str: # pragma: no cover """Representation.""" return "{!r}".format(self._d) @@ -133,39 +148,37 @@ def __repr__(self): # pragma: no cover class Namespaces(ImmutableDict): """Namespaces.""" - def __init__(self, *args, **kwargs): + def __init__(self, arg: dict[str, str] | Iterable[tuple[str, str]]) -> None: """Initialize.""" - # If there are arguments, check the first index. - # `super` should fail if the user gave multiple arguments, - # so don't bother checking that. - arg = args[0] if args else kwargs - is_dict = isinstance(arg, dict) - if is_dict and not all([isinstance(k, str) and isinstance(v, str) for k, v in arg.items()]): - raise TypeError('Namespace keys and values must be Unicode strings') - elif not is_dict and not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]): - raise TypeError('Namespace keys and values must be Unicode strings') + super().__init__(arg) + + def _validate(self, arg: dict[str, str] | Iterable[tuple[str, str]]) -> None: + """Validate arguments.""" - super(Namespaces, self).__init__(*args, **kwargs) + if isinstance(arg, dict): + if not all([isinstance(v, str) for v in arg.values()]): + raise TypeError('{} values must be hashable'.format(self.__class__.__name__)) + elif not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]): + raise TypeError('{} keys and values must be Unicode strings'.format(self.__class__.__name__)) class CustomSelectors(ImmutableDict): """Custom selectors.""" - def __init__(self, *args, **kwargs): + def __init__(self, arg: dict[str, str] | Iterable[tuple[str, str]]) -> None: """Initialize.""" - # If there are arguments, check the first index. - # `super` should fail if the user gave multiple arguments, - # so don't bother checking that. - arg = args[0] if args else kwargs - is_dict = isinstance(arg, dict) - if is_dict and not all([isinstance(k, str) and isinstance(v, str) for k, v in arg.items()]): - raise TypeError('CustomSelectors keys and values must be Unicode strings') - elif not is_dict and not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]): - raise TypeError('CustomSelectors keys and values must be Unicode strings') + super().__init__(arg) - super(CustomSelectors, self).__init__(*args, **kwargs) + def _validate(self, arg: dict[str, str] | Iterable[tuple[str, str]]) -> None: + """Validate arguments.""" + + if isinstance(arg, dict): + if not all([isinstance(v, str) for v in arg.values()]): + raise TypeError('{} values must be hashable'.format(self.__class__.__name__)) + elif not all([isinstance(k, str) and isinstance(v, str) for k, v in arg]): + raise TypeError('{} keys and values must be Unicode strings'.format(self.__class__.__name__)) class Selector(Immutable): @@ -176,13 +189,35 @@ class Selector(Immutable): 'relation', 'rel_type', 'contains', 'lang', 'flags', '_hash' ) + tag: SelectorTag | None + ids: tuple[str, ...] + classes: tuple[str, ...] + attributes: tuple[SelectorAttribute, ...] + nth: tuple[SelectorNth, ...] + selectors: tuple[SelectorList, ...] + relation: SelectorList + rel_type: str | None + contains: tuple[SelectorContains, ...] + lang: tuple[SelectorLang, ...] + flags: int + def __init__( - self, tag, ids, classes, attributes, nth, selectors, - relation, rel_type, contains, lang, flags + self, + tag: SelectorTag | None, + ids: tuple[str, ...], + classes: tuple[str, ...], + attributes: tuple[SelectorAttribute, ...], + nth: tuple[SelectorNth, ...], + selectors: tuple[SelectorList, ...], + relation: SelectorList, + rel_type: str | None, + contains: tuple[SelectorContains, ...], + lang: tuple[SelectorLang, ...], + flags: int ): """Initialize.""" - super(Selector, self).__init__( + super().__init__( tag=tag, ids=ids, classes=classes, @@ -200,10 +235,10 @@ def __init__( class SelectorNull(Immutable): """Null Selector.""" - def __init__(self): + def __init__(self) -> None: """Initialize.""" - super(SelectorNull, self).__init__() + super().__init__() class SelectorTag(Immutable): @@ -211,13 +246,13 @@ class SelectorTag(Immutable): __slots__ = ("name", "prefix", "_hash") - def __init__(self, name, prefix): + name: str + prefix: str | None + + def __init__(self, name: str, prefix: str | None) -> None: """Initialize.""" - super(SelectorTag, self).__init__( - name=name, - prefix=prefix - ) + super().__init__(name=name, prefix=prefix) class SelectorAttribute(Immutable): @@ -225,10 +260,21 @@ class SelectorAttribute(Immutable): __slots__ = ("attribute", "prefix", "pattern", "xml_type_pattern", "_hash") - def __init__(self, attribute, prefix, pattern, xml_type_pattern): + attribute: str + prefix: str + pattern: Pattern[str] | None + xml_type_pattern: Pattern[str] | None + + def __init__( + self, + attribute: str, + prefix: str, + pattern: Pattern[str] | None, + xml_type_pattern: Pattern[str] | None + ) -> None: """Initialize.""" - super(SelectorAttribute, self).__init__( + super().__init__( attribute=attribute, prefix=prefix, pattern=pattern, @@ -241,13 +287,13 @@ class SelectorContains(Immutable): __slots__ = ("text", "own", "_hash") - def __init__(self, text, own): + text: tuple[str, ...] + own: bool + + def __init__(self, text: Iterable[str], own: bool) -> None: """Initialize.""" - super(SelectorContains, self).__init__( - text=text, - own=own - ) + super().__init__(text=tuple(text), own=own) class SelectorNth(Immutable): @@ -255,10 +301,17 @@ class SelectorNth(Immutable): __slots__ = ("a", "n", "b", "of_type", "last", "selectors", "_hash") - def __init__(self, a, n, b, of_type, last, selectors): + a: int + n: bool + b: int + of_type: bool + last: bool + selectors: SelectorList + + def __init__(self, a: int, n: bool, b: int, of_type: bool, last: bool, selectors: SelectorList) -> None: """Initialize.""" - super(SelectorNth, self).__init__( + super().__init__( a=a, n=n, b=b, @@ -273,24 +326,24 @@ class SelectorLang(Immutable): __slots__ = ("languages", "_hash",) - def __init__(self, languages): + languages: tuple[str, ...] + + def __init__(self, languages: Iterable[str]): """Initialize.""" - super(SelectorLang, self).__init__( - languages=tuple(languages) - ) + super().__init__(languages=tuple(languages)) - def __iter__(self): + def __iter__(self) -> Iterator[str]: """Iterator.""" return iter(self.languages) - def __len__(self): # pragma: no cover + def __len__(self) -> int: # pragma: no cover """Length.""" return len(self.languages) - def __getitem__(self, index): # pragma: no cover + def __getitem__(self, index: int) -> str: # pragma: no cover """Get item.""" return self.languages[index] @@ -301,36 +354,45 @@ class SelectorList(Immutable): __slots__ = ("selectors", "is_not", "is_html", "_hash") - def __init__(self, selectors=tuple(), is_not=False, is_html=False): + selectors: tuple[Selector | SelectorNull, ...] + is_not: bool + is_html: bool + + def __init__( + self, + selectors: Iterable[Selector | SelectorNull] | None = None, + is_not: bool = False, + is_html: bool = False + ) -> None: """Initialize.""" - super(SelectorList, self).__init__( - selectors=tuple(selectors), + super().__init__( + selectors=tuple(selectors) if selectors is not None else tuple(), is_not=is_not, is_html=is_html ) - def __iter__(self): + def __iter__(self) -> Iterator[Selector | SelectorNull]: """Iterator.""" return iter(self.selectors) - def __len__(self): + def __len__(self) -> int: """Length.""" return len(self.selectors) - def __getitem__(self, index): + def __getitem__(self, index: int) -> Selector | SelectorNull: """Get item.""" return self.selectors[index] -def _pickle(p): +def _pickle(p: Any) -> Any: return p.__base__(), tuple([getattr(p, s) for s in p.__slots__[:-1]]) -def pickle_register(obj): +def pickle_register(obj: Any) -> None: """Allow object to be pickled.""" copyreg.pickle(obj, _pickle) diff --git a/script.module.soupsieve/lib/soupsieve/pretty.py b/script.module.soupsieve/lib/soupsieve/pretty.py new file mode 100644 index 000000000..f848d5e27 --- /dev/null +++ b/script.module.soupsieve/lib/soupsieve/pretty.py @@ -0,0 +1,138 @@ +""" +Format a pretty string of a `SoupSieve` object for easy debugging. + +This won't necessarily support all types and such, and definitely +not support custom outputs. + +It is mainly geared towards our types as the `SelectorList` +object is a beast to look at without some indentation and newlines. +The format and various output types is fairly known (though it +hasn't been tested extensively to make sure we aren't missing corners). + +Example: + +``` +>>> import soupsieve as sv +>>> sv.compile('this > that.class[name=value]').selectors.pretty() +SelectorList( + selectors=( + Selector( + tag=SelectorTag( + name='that', + prefix=None), + ids=(), + classes=( + 'class', + ), + attributes=( + SelectorAttribute( + attribute='name', + prefix='', + pattern=re.compile( + '^value$'), + xml_type_pattern=None), + ), + nth=(), + selectors=(), + relation=SelectorList( + selectors=( + Selector( + tag=SelectorTag( + name='this', + prefix=None), + ids=(), + classes=(), + attributes=(), + nth=(), + selectors=(), + relation=SelectorList( + selectors=(), + is_not=False, + is_html=False), + rel_type='>', + contains=(), + lang=(), + flags=0), + ), + is_not=False, + is_html=False), + rel_type=None, + contains=(), + lang=(), + flags=0), + ), + is_not=False, + is_html=False) +``` +""" +from __future__ import annotations +import re +from typing import Any + +RE_CLASS = re.compile(r'(?i)[a-z_][_a-z\d\.]+\(') +RE_PARAM = re.compile(r'(?i)[_a-z][_a-z\d]+=') +RE_EMPTY = re.compile(r'\(\)|\[\]|\{\}') +RE_LSTRT = re.compile(r'\[') +RE_DSTRT = re.compile(r'\{') +RE_TSTRT = re.compile(r'\(') +RE_LEND = re.compile(r'\]') +RE_DEND = re.compile(r'\}') +RE_TEND = re.compile(r'\)') +RE_INT = re.compile(r'\d+') +RE_KWORD = re.compile(r'(?i)[_a-z][_a-z\d]+') +RE_DQSTR = re.compile(r'"(?:\\.|[^"\\])*"') +RE_SQSTR = re.compile(r"'(?:\\.|[^'\\])*'") +RE_SEP = re.compile(r'\s*(,)\s*') +RE_DSEP = re.compile(r'\s*(:)\s*') + +TOKENS = { + 'class': RE_CLASS, + 'param': RE_PARAM, + 'empty': RE_EMPTY, + 'lstrt': RE_LSTRT, + 'dstrt': RE_DSTRT, + 'tstrt': RE_TSTRT, + 'lend': RE_LEND, + 'dend': RE_DEND, + 'tend': RE_TEND, + 'sqstr': RE_SQSTR, + 'sep': RE_SEP, + 'dsep': RE_DSEP, + 'int': RE_INT, + 'kword': RE_KWORD, + 'dqstr': RE_DQSTR +} + + +def pretty(obj: Any) -> str: # pragma: no cover + """Make the object output string pretty.""" + + sel = str(obj) + index = 0 + end = len(sel) - 1 + indent = 0 + output = [] + + while index <= end: + m = None + for k, v in TOKENS.items(): + m = v.match(sel, index) + + if m: + name = k + index = m.end(0) + if name in ('class', 'lstrt', 'dstrt', 'tstrt'): + indent += 4 + output.append('{}\n{}'.format(m.group(0), " " * indent)) + elif name in ('param', 'int', 'kword', 'sqstr', 'dqstr', 'empty'): + output.append(m.group(0)) + elif name in ('lend', 'dend', 'tend'): + indent -= 4 + output.append(m.group(0)) + elif name in ('sep',): + output.append('{}\n{}'.format(m.group(1), " " * indent)) + elif name in ('dsep',): + output.append('{} '.format(m.group(1))) + break + + return ''.join(output) diff --git a/script.module.soupsieve/lib/soupsieve/util.py b/script.module.soupsieve/lib/soupsieve/util.py index 7f5d9f890..9f91233bb 100644 --- a/script.module.soupsieve/lib/soupsieve/util.py +++ b/script.module.soupsieve/lib/soupsieve/util.py @@ -1,7 +1,9 @@ """Utility.""" +from __future__ import annotations from functools import wraps, lru_cache import warnings import re +from typing import Callable, Any DEBUG = 0x00001 @@ -12,7 +14,7 @@ @lru_cache(maxsize=512) -def lower(string): +def lower(string: str) -> str: """Lower.""" new_string = [] @@ -25,7 +27,7 @@ def lower(string): class SelectorSyntaxError(Exception): """Syntax error in a CSS selector.""" - def __init__(self, msg, pattern=None, index=None): + def __init__(self, msg: str, pattern: str | None = None, index: int | None = None) -> None: """Initialize.""" self.line = None @@ -37,30 +39,34 @@ def __init__(self, msg, pattern=None, index=None): self.context, self.line, self.col = get_pattern_context(pattern, index) msg = '{}\n line {}:\n{}'.format(msg, self.line, self.context) - super(SelectorSyntaxError, self).__init__(msg) + super().__init__(msg) -def deprecated(message, stacklevel=2): # pragma: no cover +def deprecated(message: str, stacklevel: int = 2) -> Callable[..., Any]: # pragma: no cover """ Raise a `DeprecationWarning` when wrapped function/method is called. - Borrowed from https://stackoverflow.com/a/48632082/866026 + Usage: + + @deprecated("This method will be removed in version X; use Y instead.") + def some_method()" + pass """ - def _decorator(func): + def _wrapper(func: Callable[..., Any]) -> Callable[..., Any]: @wraps(func) - def _func(*args, **kwargs): + def _deprecated_func(*args: Any, **kwargs: Any) -> Any: warnings.warn( - "'{}' is deprecated. {}".format(func.__name__, message), + f"'{func.__name__}' is deprecated. {message}", category=DeprecationWarning, stacklevel=stacklevel ) return func(*args, **kwargs) - return _func - return _decorator + return _deprecated_func + return _wrapper -def warn_deprecated(message, stacklevel=2): # pragma: no cover +def warn_deprecated(message: str, stacklevel: int = 2) -> None: # pragma: no cover """Warn deprecated.""" warnings.warn( @@ -70,14 +76,15 @@ def warn_deprecated(message, stacklevel=2): # pragma: no cover ) -def get_pattern_context(pattern, index): +def get_pattern_context(pattern: str, index: int) -> tuple[str, int, int]: """Get the pattern context.""" last = 0 current_line = 1 col = 1 - text = [] + text = [] # type: list[str] line = 1 + offset = None # type: int | None # Split pattern by newline and handle the text before the newline for m in RE_PATTERN_LINE_SPLIT.finditer(pattern): diff --git a/script.module.soupsieve/icon.png b/script.module.soupsieve/resources/icon.png similarity index 100% rename from script.module.soupsieve/icon.png rename to script.module.soupsieve/resources/icon.png From fb9b1df7d039a100915465619b2b30ab72dc8f8f Mon Sep 17 00:00:00 2001 From: L2501 Date: Sun, 16 Jul 2023 08:18:29 +0000 Subject: [PATCH 064/145] [script.module.beautifulsoup4] 4.12.2 --- script.module.beautifulsoup4/AUTHORS.txt | 49 - script.module.beautifulsoup4/LICENSE | 30 - .../{COPYING.txt => LICENSE.txt} | 10 +- script.module.beautifulsoup4/NEWS.txt | 1475 ----------------- script.module.beautifulsoup4/README.md | 102 -- script.module.beautifulsoup4/addon.xml | 6 +- .../lib/bs4/__init__.py | 247 +-- .../lib/bs4/builder/__init__.py | 202 ++- .../lib/bs4/builder/_html5lib.py | 66 +- .../lib/bs4/builder/_htmlparser.py | 232 +-- .../lib/bs4/builder/_lxml.py | 99 +- script.module.beautifulsoup4/lib/bs4/css.py | 280 ++++ .../lib/bs4/dammit.py | 863 ++++++---- .../lib/bs4/diagnose.py | 68 +- .../lib/bs4/element.py | 959 +++++++---- .../lib/bs4/formatter.py | 64 +- .../{ => resources}/icon.png | Bin 17 files changed, 1963 insertions(+), 2789 deletions(-) delete mode 100644 script.module.beautifulsoup4/AUTHORS.txt delete mode 100644 script.module.beautifulsoup4/LICENSE rename script.module.beautifulsoup4/{COPYING.txt => LICENSE.txt} (81%) delete mode 100644 script.module.beautifulsoup4/NEWS.txt delete mode 100644 script.module.beautifulsoup4/README.md create mode 100644 script.module.beautifulsoup4/lib/bs4/css.py rename script.module.beautifulsoup4/{ => resources}/icon.png (100%) diff --git a/script.module.beautifulsoup4/AUTHORS.txt b/script.module.beautifulsoup4/AUTHORS.txt deleted file mode 100644 index 1f14fe07d..000000000 --- a/script.module.beautifulsoup4/AUTHORS.txt +++ /dev/null @@ -1,49 +0,0 @@ -Behold, mortal, the origins of Beautiful Soup... -================================================ - -Leonard Richardson is the primary maintainer. - -Aaron DeVore and Isaac Muse have made significant contributions to the -code base. - -Mark Pilgrim provided the encoding detection code that forms the base -of UnicodeDammit. - -Thomas Kluyver and Ezio Melotti finished the work of getting Beautiful -Soup 4 working under Python 3. - -Simon Willison wrote soupselect, which was used to make Beautiful Soup -support CSS selectors. Isaac Muse wrote SoupSieve, which made it -possible to _remove_ the CSS selector code from Beautiful Soup. - -Sam Ruby helped with a lot of edge cases. - -Jonathan Ellis was awarded the prestigious Beau Potage D'Or for his -work in solving the nestable tags conundrum. - -An incomplete list of people have contributed patches to Beautiful -Soup: - - Istvan Albert, Andrew Lin, Anthony Baxter, Oliver Beattie, Andrew -Boyko, Tony Chang, Francisco Canas, "Delong", Zephyr Fang, Fuzzy, -Roman Gaufman, Yoni Gilad, Richie Hindle, Toshihiro Kamiya, Peteris -Krumins, Kent Johnson, Marek Kapolka, Andreas Kostyrka, Roel Kramer, -Ben Last, Robert Leftwich, Stefaan Lippens, "liquider", Staffan -Malmgren, Ksenia Marasanova, JP Moins, Adam Monsen, John Nagle, "Jon", -Ed Oskiewicz, Martijn Peters, Greg Phillips, Giles Radford, Stefano -Revera, Arthur Rudolph, Marko Samastur, James Salter, Jouni Seppnen, -Alexander Schmolck, Tim Shirley, Geoffrey Sneddon, Ville Skytt, -"Vikas", Jens Svalgaard, Andy Theyers, Eric Weiser, Glyn Webster, John -Wiseman, Paul Wright, Danny Yoo - -An incomplete list of people who made suggestions or found bugs or -found ways to break Beautiful Soup: - - Hanno Bck, Matteo Bertini, Chris Curvey, Simon Cusack, Bruce Eckel, - Matt Ernst, Michael Foord, Tom Harris, Bill de hOra, Donald Howes, - Matt Patterson, Scott Roberts, Steve Strassmann, Mike Williams, - warchild at redho dot com, Sami Kuisma, Carlos Rocha, Bob Hutchison, - Joren Mc, Michal Migurski, John Kleven, Tim Heaney, Tripp Lilley, Ed - Summers, Dennis Sutch, Chris Smith, Aaron Swartz, Stuart - Turner, Greg Edwards, Kevin J Kalupson, Nikos Kouremenos, Artur de - Sousa Rocha, Yichun Wei, Per Vognsen diff --git a/script.module.beautifulsoup4/LICENSE b/script.module.beautifulsoup4/LICENSE deleted file mode 100644 index 4c068bab2..000000000 --- a/script.module.beautifulsoup4/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Beautiful Soup is made available under the MIT license: - - Copyright (c) 2004-2019 Leonard Richardson - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - -Beautiful Soup incorporates code from the html5lib library, which is -also made available under the MIT license. Copyright (c) 2006-2013 -James Graham and other contributors - -Beautiful Soup depends on the soupsieve library, which is also made -available under the MIT license. Copyright (c) 2018 Isaac Muse diff --git a/script.module.beautifulsoup4/COPYING.txt b/script.module.beautifulsoup4/LICENSE.txt similarity index 81% rename from script.module.beautifulsoup4/COPYING.txt rename to script.module.beautifulsoup4/LICENSE.txt index fb6ae69cd..08e3a9cf8 100644 --- a/script.module.beautifulsoup4/COPYING.txt +++ b/script.module.beautifulsoup4/LICENSE.txt @@ -1,6 +1,6 @@ Beautiful Soup is made available under the MIT license: - Copyright (c) 2004-2017 Leonard Richardson + Copyright (c) Leonard Richardson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -23,5 +23,9 @@ Beautiful Soup is made available under the MIT license: SOFTWARE. Beautiful Soup incorporates code from the html5lib library, which is -also made available under the MIT license. Copyright (c) 2006-2013 -James Graham and other contributors +also made available under the MIT license. Copyright (c) James Graham +and other contributors + +Beautiful Soup has an optional dependency on the soupsieve library, +which is also made available under the MIT license. Copyright (c) +Isaac Muse diff --git a/script.module.beautifulsoup4/NEWS.txt b/script.module.beautifulsoup4/NEWS.txt deleted file mode 100644 index 2758e620f..000000000 --- a/script.module.beautifulsoup4/NEWS.txt +++ /dev/null @@ -1,1475 +0,0 @@ -= 4.8.2 (20191224) - -* Added Python docstrings to all public methods of the most commonly - used classes. - -* Added a Chinese translation by Deron Wang and a Brazilian Portuguese - translation by Cezar Peixeiro to the repository. - -* Fixed two deprecation warnings. Patches by Colin - Watson and Nicholas Neumann. [bug=1847592] [bug=1855301] - -* The html.parser tree builder now correctly handles DOCTYPEs that are - not uppercase. [bug=1848401] - -* PageElement.select() now returns a ResultSet rather than a regular - list, making it consistent with methods like find_all(). - -= 4.8.1 (20191006) - -* When the html.parser or html5lib parsers are in use, Beautiful Soup - will, by default, record the position in the original document where - each tag was encountered. This includes line number (Tag.sourceline) - and position within a line (Tag.sourcepos). Based on code by Chris - Mayo. [bug=1742921] - -* When instantiating a BeautifulSoup object, it's now possible to - provide a dictionary ('element_classes') of the classes you'd like to be - instantiated instead of Tag, NavigableString, etc. - -* Fixed the definition of the default XML namespace when using - lxml 4.4. Patch by Isaac Muse. [bug=1840141] - -* Fixed a crash when pretty-printing tags that were not created - during initial parsing. [bug=1838903] - -* Copying a Tag preserves information that was originally obtained from - the TreeBuilder used to build the original Tag. [bug=1838903] - -* Raise an explanatory exception when the underlying parser - completely rejects the incoming markup. [bug=1838877] - -* Avoid a crash when trying to detect the declared encoding of a - Unicode document. [bug=1838877] - -* Avoid a crash when unpickling certain parse trees generated - using html5lib on Python 3. [bug=1843545] - -= 4.8.0 (20190720, "One Small Soup") - -This release focuses on making it easier to customize Beautiful Soup's -input mechanism (the TreeBuilder) and output mechanism (the Formatter). - -* You can customize the TreeBuilder object by passing keyword - arguments into the BeautifulSoup constructor. Those keyword - arguments will be passed along into the TreeBuilder constructor. - - The main reason to do this right now is to change how which - attributes are treated as multi-valued attributes (the way 'class' - is treated by default). You can do this with the - 'multi_valued_attributes' argument. [bug=1832978] - -* The role of Formatter objects has been greatly expanded. The Formatter - class now controls the following: - - - The function to call to perform entity substitution. (This was - previously Formatter's only job.) - - Which tags should be treated as containing CDATA and have their - contents exempt from entity substitution. - - The order in which a tag's attributes are output. [bug=1812422] - - Whether or not to put a '/' inside a void element, e.g. '
' vs '
' - - All preexisting code should work as before. - -* Added a new method to the API, Tag.smooth(), which consolidates - multiple adjacent NavigableString elements. [bug=1697296] - -* ' (which is valid in XML, XHTML, and HTML 5, but not HTML 4) is always - recognized as a named entity and converted to a single quote. [bug=1818721] - -= 4.7.1 (20190106) - -* Fixed a significant performance problem introduced in 4.7.0. [bug=1810617] - -* Fixed an incorrectly raised exception when inserting a tag before or - after an identical tag. [bug=1810692] - -* Beautiful Soup will no longer try to keep track of namespaces that - are not defined with a prefix; this can confuse soupselect. [bug=1810680] - -* Tried even harder to avoid the deprecation warning originally fixed in - 4.6.1. [bug=1778909] - -= 4.7.0 (20181231) - -* Beautiful Soup's CSS Selector implementation has been replaced by a - dependency on Isaac Muse's SoupSieve project (the soupsieve package - on PyPI). The good news is that SoupSieve has a much more robust and - complete implementation of CSS selectors, resolving a large number - of longstanding issues. The bad news is that from this point onward, - SoupSieve must be installed if you want to use the select() method. - - You don't have to change anything lf you installed Beautiful Soup - through pip (SoupSieve will be automatically installed when you - upgrade Beautiful Soup) or if you don't use CSS selectors from - within Beautiful Soup. - - SoupSieve documentation: https://facelessuser.github.io/soupsieve/ - -* Added the PageElement.extend() method, which works like list.append(). - [bug=1514970] - -* PageElement.insert_before() and insert_after() now take a variable - number of arguments. [bug=1514970] - -* Fix a number of problems with the tree builder that caused - trees that were superficially okay, but which fell apart when bits - were extracted. Patch by Isaac Muse. [bug=1782928,1809910] - -* Fixed a problem with the tree builder in which elements that - contained no content (such as empty comments and all-whitespace - elements) were not being treated as part of the tree. Patch by Isaac - Muse. [bug=1798699] - -* Fixed a problem with multi-valued attributes where the value - contained whitespace. Thanks to Jens Svalgaard for the - fix. [bug=1787453] - -* Clarified ambiguous license statements in the source code. Beautiful - Soup is released under the MIT license, and has been since 4.4.0. - -* This file has been renamed from NEWS.txt to CHANGELOG. - -= 4.6.3 (20180812) - -* Exactly the same as 4.6.2. Re-released to make the README file - render properly on PyPI. - -= 4.6.2 (20180812) - -* Fix an exception when a custom formatter was asked to format a void - element. [bug=1784408] - -= 4.6.1 (20180728) - -* Stop data loss when encountering an empty numeric entity, and - possibly in other cases. Thanks to tos.kamiya for the fix. [bug=1698503] - -* Preserve XML namespaces introduced inside an XML document, not just - the ones introduced at the top level. [bug=1718787] - -* Added a new formatter, "html5", which represents void elements - as "" rather than "". [bug=1716272] - -* Fixed a problem where the html.parser tree builder interpreted - a string like "&foo " as the character entity "&foo;" [bug=1728706] - -* Correctly handle invalid HTML numeric character entities like “ - which reference code points that are not Unicode code points. Note - that this is only fixed when Beautiful Soup is used with the - html.parser parser -- html5lib already worked and I couldn't fix it - with lxml. [bug=1782933] - -* Improved the warning given when no parser is specified. [bug=1780571] - -* When markup contains duplicate elements, a select() call that - includes multiple match clauses will match all relevant - elements. [bug=1770596] - -* Fixed code that was causing deprecation warnings in recent Python 3 - versions. Includes a patch from Ville Skyttä. [bug=1778909] [bug=1689496] - -* Fixed a Windows crash in diagnose() when checking whether a long - markup string is a filename. [bug=1737121] - -* Stopped HTMLParser from raising an exception in very rare cases of - bad markup. [bug=1708831] - -* Fixed a bug where find_all() was not working when asked to find a - tag with a namespaced name in an XML document that was parsed as - HTML. [bug=1723783] - -* You can get finer control over formatting by subclassing - bs4.element.Formatter and passing a Formatter instance into (e.g.) - encode(). [bug=1716272] - -* You can pass a dictionary of `attrs` into - BeautifulSoup.new_tag. This makes it possible to create a tag with - an attribute like 'name' that would otherwise be masked by another - argument of new_tag. [bug=1779276] - -* Clarified the deprecation warning when accessing tag.fooTag, to cover - the possibility that you might really have been looking for a tag - called 'fooTag'. - -= 4.6.0 (20170507) = - -* Added the `Tag.get_attribute_list` method, which acts like `Tag.get` for - getting the value of an attribute, but which always returns a list, - whether or not the attribute is a multi-value attribute. [bug=1678589] - -* It's now possible to use a tag's namespace prefix when searching, - e.g. soup.find('namespace:tag') [bug=1655332] - -* Improved the handling of empty-element tags like
when using the - html.parser parser. [bug=1676935] - -* HTML parsers treat all HTML4 and HTML5 empty element tags (aka void - element tags) correctly. [bug=1656909] - -* Namespace prefix is preserved when an XML tag is copied. Thanks - to Vikas for a patch and test. [bug=1685172] - -= 4.5.3 (20170102) = - -* Fixed foster parenting when html5lib is the tree builder. Thanks to - Geoffrey Sneddon for a patch and test. - -* Fixed yet another problem that caused the html5lib tree builder to - create a disconnected parse tree. [bug=1629825] - -= 4.5.2 (20170102) = - -* Apart from the version number, this release is identical to - 4.5.3. Due to user error, it could not be completely uploaded to - PyPI. Use 4.5.3 instead. - -= 4.5.1 (20160802) = - -* Fixed a crash when passing Unicode markup that contained a - processing instruction into the lxml HTML parser on Python - 3. [bug=1608048] - -= 4.5.0 (20160719) = - -* Beautiful Soup is no longer compatible with Python 2.6. This - actually happened a few releases ago, but it's now official. - -* Beautiful Soup will now work with versions of html5lib greater than - 0.99999999. [bug=1603299] - -* If a search against each individual value of a multi-valued - attribute fails, the search will be run one final time against the - complete attribute value considered as a single string. That is, if - a tag has class="foo bar" and neither "foo" nor "bar" matches, but - "foo bar" does, the tag is now considered a match. - - This happened in previous versions, but only when the value being - searched for was a string. Now it also works when that value is - a regular expression, a list of strings, etc. [bug=1476868] - -* Fixed a bug that deranged the tree when a whitespace element was - reparented into a tag that contained an identical whitespace - element. [bug=1505351] - -* Added support for CSS selector values that contain quoted spaces, - such as tag[style="display: foo"]. [bug=1540588] - -* Corrected handling of XML processing instructions. [bug=1504393] - -* Corrected an encoding error that happened when a BeautifulSoup - object was copied. [bug=1554439] - -* The contents of